go.ligato.io/vpp-agent/v3@v3.5.0/examples/vpp_stats/main.go (about) 1 // Copyright (c) 2020 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // The VPP stats example shows how to use telemetry API to access 16 // VPP stats via the GoVPP stats socket API and the telemetry vpp calls. 17 18 package main 19 20 import ( 21 "context" 22 "fmt" 23 "log" 24 "time" 25 26 "go.fd.io/govpp/api" 27 "go.ligato.io/cn-infra/v2/agent" 28 "go.ligato.io/cn-infra/v2/config" 29 "go.ligato.io/cn-infra/v2/logging" 30 "go.ligato.io/cn-infra/v2/logging/logrus" 31 32 "go.ligato.io/vpp-agent/v3/plugins/govppmux" 33 "go.ligato.io/vpp-agent/v3/plugins/telemetry" 34 "go.ligato.io/vpp-agent/v3/plugins/telemetry/vppcalls" 35 ) 36 37 const PluginName = "stats-example" 38 39 func main() { 40 ep := &StatsExamplePlugin{ 41 Log: logging.DefaultLogger, 42 Telemetry: &telemetry.DefaultPlugin, 43 } 44 stopExample := make(chan struct{}) 45 46 a := agent.NewAgent( 47 agent.AllPlugins(ep), 48 agent.QuitOnClose(stopExample), 49 ) 50 if err := a.Run(); err != nil { 51 log.Fatal(err) 52 } 53 54 go closeExample("Stats example finished", stopExample) 55 } 56 57 // StatsExamplePlugin displays VPP stats using telemetry plugin 58 type StatsExamplePlugin struct { 59 handler vppcalls.TelemetryVppAPI 60 61 config.PluginConfig 62 Log logging.Logger 63 Telemetry *telemetry.Plugin 64 } 65 66 func (p *StatsExamplePlugin) Init() error { 67 var err error 68 p.handler, err = vppcalls.NewHandler(&govppmux.DefaultPlugin) 69 if err != nil { 70 panic(err) 71 } 72 73 go p.processStats() 74 return nil 75 } 76 77 func (p *StatsExamplePlugin) Close() error { 78 p.Log.Info("Stats example closed") 79 return nil 80 } 81 82 func (p *StatsExamplePlugin) String() string { 83 return PluginName 84 } 85 86 func closeExample(message string, stopExample chan struct{}) { 87 time.Sleep(10 * time.Second) 88 logrus.DefaultLogger().Info(message) 89 close(stopExample) 90 } 91 92 func (p *StatsExamplePlugin) processStats() { 93 // give the Agent some time to initialize 94 // so the output is not mixed 95 time.Sleep(1 * time.Second) 96 p.Log.Infoln("Processing stats") 97 98 var errors []error 99 100 // collect stats 101 ifStats, err := p.handler.GetInterfaceStats(context.Background()) 102 if err != nil { 103 errors = append(errors, fmt.Errorf("eroror retireving interface stats: %v", err)) 104 } 105 nodeCounters, err := p.handler.GetNodeCounters(context.Background()) 106 if err != nil { 107 errors = append(errors, fmt.Errorf("eroror retireving node counters: %v", err)) 108 } 109 110 systemStats, err := p.handler.GetSystemStats(context.Background()) 111 if err != nil { 112 errors = append(errors, fmt.Errorf("eroror retireving system stats: %v", err)) 113 } 114 115 runtimeInfo, err := p.handler.GetRuntimeInfo(context.Background()) 116 if err != nil { 117 errors = append(errors, fmt.Errorf("eroror retireving runtime info: %v", err)) 118 } 119 120 bufferInfo, err := p.handler.GetBuffersInfo(context.Background()) 121 if err != nil { 122 errors = append(errors, fmt.Errorf("eroror retireving buffers info: %v", err)) 123 } 124 125 threadsInfo, err := p.handler.GetThreads(context.Background()) 126 if err != nil { 127 errors = append(errors, fmt.Errorf("eroror retireving threads: %v", err)) 128 } 129 130 memoryInfo, err := p.handler.GetMemory(context.Background()) 131 fmt.Printf("mem %v, err %v", memoryInfo, err) 132 if err != nil { 133 errors = append(errors, fmt.Errorf("eroror retireving memory info: %v", err)) 134 } 135 136 // print all errors and return if there is any 137 if len(errors) != 0 { 138 for _, err := range errors { 139 p.Log.Error(err) 140 } 141 return 142 } 143 144 // print collected stats 145 printIfStats(ifStats) 146 printNodeCounters(nodeCounters) 147 printSystemStats(systemStats) 148 printRuntimeInfo(runtimeInfo) 149 printBufferInfo(bufferInfo) 150 printThreadsInfo(threadsInfo) 151 printMemoryInfo(memoryInfo) 152 } 153 154 func printIfStats(ifStats *api.InterfaceStats) { 155 for _, ifStat := range ifStats.Interfaces { 156 fmt.Printf(` 157 Interface name: %s (sw_if_idx %d) 158 Received: %d (rx errors %d) 159 Transmitted: %d (tx errors %d) 160 Drops: %d 161 `, ifStat.InterfaceName, ifStat.InterfaceIndex, ifStat.Rx, ifStat.RxErrors, 162 ifStat.Tx, ifStat.TxErrors, ifStat.Drops) 163 } 164 } 165 166 func printNodeCounters(nodeCountersInfo *vppcalls.NodeCounterInfo) { 167 maxLen := 5 168 for i, nodeCounters := range nodeCountersInfo.GetCounters() { 169 if i >= maxLen { 170 // do not print everything, it is not necessary 171 break 172 } 173 fmt.Printf(` 174 Node name: %s 175 Node: %s 176 177 `, nodeCounters.Name, nodeCounters.Node) 178 } 179 if len(nodeCountersInfo.GetCounters()) >= maxLen { 180 fmt.Printf("... and another %d nodes\n", len(nodeCountersInfo.GetCounters())-maxLen) 181 } 182 } 183 184 func printSystemStats(systemStats *api.SystemStats) { 185 fmt.Printf(` 186 Last update: %d 187 Last stats clear: %d 188 Input rate: %d 189 Num. Worker Threads: %d 190 Vector rate: %d (per worker: %+v) 191 Heartbeat: %d 192 `, systemStats.LastUpdate, systemStats.LastStatsClear, systemStats.InputRate, systemStats.NumWorkerThreads, 193 systemStats.VectorRate, systemStats.VectorRatePerWorker, systemStats.Heartbeat) 194 } 195 196 func printRuntimeInfo(runtimeInfo *vppcalls.RuntimeInfo) { 197 for _, thread := range runtimeInfo.GetThreads() { 198 fmt.Printf("\nThread: %s (ID %d)", thread.Name, thread.ID) 199 } 200 } 201 202 func printBufferInfo(bufferInfo *vppcalls.BuffersInfo) { 203 for _, buffer := range bufferInfo.GetItems() { 204 fmt.Printf(` 205 206 Buffer name: %s (index %d) 207 Alloc: %d (num %d) 208 Free: %d (num %d) 209 Size: %d 210 Thread ID: %d 211 `, buffer.Name, buffer.Index, buffer.Alloc, buffer.NumAlloc, buffer.Free, buffer.NumFree, buffer.Size, buffer.ThreadID) 212 } 213 } 214 215 func printThreadsInfo(threadsInfo *vppcalls.ThreadsInfo) { 216 for _, thread := range threadsInfo.GetItems() { 217 fmt.Printf(` 218 Thread name: %s (ID %d) 219 Type: %s 220 PID: %d 221 Core: %d (CPU ID %d, CPU socket %d) 222 `, thread.Name, thread.ID, thread.Type, thread.PID, thread.Core, thread.CPUID, thread.CPUSocket) 223 } 224 } 225 226 func printMemoryInfo(memoryInfo *vppcalls.MemoryInfo) { 227 for _, thread := range memoryInfo.GetThreads() { 228 fmt.Printf(` 229 Thread %d %s 230 size %d, %d pages, page size %d 231 total: %d, used: %d, free: %d, trimmable: %d 232 free chunks %d free fastbin blks %d 233 max total allocated %d 234 `, thread.ID, thread.Name, thread.Size, thread.Pages, thread.PageSize, thread.Total, thread.Used, 235 thread.Free, thread.Trimmable, thread.FreeChunks, thread.FreeFastbinBlks, thread.MaxTotalAlloc) 236 } 237 }