Provide error counters per worker for statsclient
[govpp.git] / examples / stats-client / stats_api.go
1 // Copyright (c) 2018 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 package main
16
17 import (
18         "flag"
19         "fmt"
20         "log"
21         "os"
22         "strings"
23         "time"
24
25         "git.fd.io/govpp.git/adapter"
26         "git.fd.io/govpp.git/adapter/statsclient"
27         "git.fd.io/govpp.git/api"
28         "git.fd.io/govpp.git/core"
29 )
30
31 // ------------------------------------------------------------------
32 // Example - Stats API
33 // ------------------------------------------------------------------
34 // The example stats_api demonstrates how to retrieve stats
35 // from the VPP using the new stats API.
36 // ------------------------------------------------------------------
37
38 var (
39         statsSocket = flag.String("socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
40         dumpAll     = flag.Bool("all", false, "Dump all stats including ones with zero values")
41         pollPeriod  = flag.Duration("period", time.Second*5, "Polling interval period")
42         async       = flag.Bool("async", false, "Use asynchronous connection")
43 )
44
45 func init() {
46         flag.Usage = func() {
47                 fmt.Fprintf(os.Stderr, "%s: usage [ls|dump|poll|errors|interfaces|nodes|system|buffers|memory] <patterns>...\n", os.Args[0])
48                 flag.PrintDefaults()
49                 os.Exit(1)
50         }
51 }
52
53 func main() {
54         flag.Parse()
55         skipZeros := !*dumpAll
56
57         var patterns []string
58         if flag.NArg() > 0 {
59                 patterns = flag.Args()[1:]
60         }
61
62         var (
63                 client *statsclient.StatsClient
64                 c      *core.StatsConnection
65                 err    error
66         )
67
68         if *async {
69                 var statsChan chan core.ConnectionEvent
70                 client = statsclient.NewStatsClient(*statsSocket)
71                 c, statsChan, err = core.AsyncConnectStats(client, core.DefaultMaxReconnectAttempts, core.DefaultReconnectInterval)
72                 if err != nil {
73                         log.Fatalln("Asynchronous connecting failed:", err)
74                 }
75                 select {
76                 case e := <-statsChan:
77                         if e.State == core.Connected {
78                                 // OK
79                         } else {
80                                 log.Fatalf("VPP stats asynchronous connection failed: %s\n", e.State.String())
81                         }
82                 }
83         } else {
84                 client = statsclient.NewStatsClient(*statsSocket)
85                 c, err = core.ConnectStats(client)
86                 if err != nil {
87                         log.Fatalln("Connecting failed:", err)
88                 }
89         }
90         defer c.Disconnect()
91
92         switch cmd := flag.Arg(0); cmd {
93         case "system":
94                 stats := new(api.SystemStats)
95                 if err := c.GetSystemStats(stats); err != nil {
96                         log.Fatalln("getting system stats failed:", err)
97                 }
98                 fmt.Printf("System stats: %+v\n", stats)
99
100         case "poll-system":
101                 pollSystem(c)
102
103         case "nodes":
104                 fmt.Println("Listing node stats..")
105                 stats := new(api.NodeStats)
106                 if err := c.GetNodeStats(stats); err != nil {
107                         log.Fatalln("getting node stats failed:", err)
108                 }
109
110                 for _, node := range stats.Nodes {
111                         if skipZeros && node.Calls == 0 && node.Suspends == 0 && node.Clocks == 0 && node.Vectors == 0 {
112                                 continue
113                         }
114                         fmt.Printf(" - %+v\n", node)
115                 }
116                 fmt.Printf("Listed %d node counters\n", len(stats.Nodes))
117
118         case "interfaces":
119                 fmt.Println("Listing interface stats..")
120                 stats := new(api.InterfaceStats)
121                 if err := c.GetInterfaceStats(stats); err != nil {
122                         log.Fatalln("getting interface stats failed:", err)
123                 }
124                 for _, iface := range stats.Interfaces {
125                         fmt.Printf(" - %+v\n", iface)
126                 }
127                 fmt.Printf("Listed %d interface counters\n", len(stats.Interfaces))
128
129         case "poll-interfaces":
130                 pollInterfaces(c)
131
132         case "errors":
133                 fmt.Printf("Listing error stats.. %s\n", strings.Join(patterns, " "))
134                 stats := new(api.ErrorStats)
135                 if err := c.GetErrorStats(stats); err != nil {
136                         log.Fatalln("getting error stats failed:", err)
137                 }
138                 n := 0
139                 for _, counter := range stats.Errors {
140                         var sum uint32
141                         for _, valuePerWorker := range counter.Values {
142                                 sum += uint32(valuePerWorker)
143                         }
144
145                         if skipZeros && sum == 0 {
146                                 continue
147                         }
148                         fmt.Printf(" - %v %d (per worker: %v)\n", counter.CounterName, sum, counter.Values)
149                         n++
150                 }
151                 fmt.Printf("Listed %d (%d) error counters\n", n, len(stats.Errors))
152
153         case "buffers":
154                 stats := new(api.BufferStats)
155                 if err := c.GetBufferStats(stats); err != nil {
156                         log.Fatalln("getting buffer stats failed:", err)
157                 }
158                 fmt.Printf("Buffer stats: %+v\n", stats)
159
160         case "memory":
161                 stats := new(api.MemoryStats)
162                 if err := c.GetMemoryStats(stats); err != nil {
163                         log.Fatalln("getting memory stats failed:", err)
164                 }
165                 fmt.Printf("Memory stats: %+v\n", stats)
166
167         case "dump":
168                 fmt.Printf("Dumping stats.. %s\n", strings.Join(patterns, " "))
169
170                 dumpStats(client, patterns, skipZeros)
171
172         case "poll":
173                 fmt.Printf("Polling stats.. %s\n", strings.Join(patterns, " "))
174
175                 pollStats(client, patterns, skipZeros)
176
177         case "list", "ls", "":
178                 fmt.Printf("Listing stats.. %s\n", strings.Join(patterns, " "))
179
180                 listStats(client, patterns)
181
182         default:
183                 fmt.Printf("invalid command: %q\n", cmd)
184         }
185 }
186
187 func listStats(client adapter.StatsAPI, patterns []string) {
188         list, err := client.ListStats(patterns...)
189         if err != nil {
190                 log.Fatalln("listing stats failed:", err)
191         }
192
193         for _, stat := range list {
194                 fmt.Printf(" - %v\n", stat)
195         }
196
197         fmt.Printf("Listed %d stats\n", len(list))
198 }
199
200 func dumpStats(client adapter.StatsAPI, patterns []string, skipZeros bool) {
201         stats, err := client.DumpStats(patterns...)
202         if err != nil {
203                 log.Fatalln("dumping stats failed:", err)
204         }
205
206         n := 0
207         for _, stat := range stats {
208                 if skipZeros && (stat.Data == nil || stat.Data.IsZero()) {
209                         continue
210                 }
211                 fmt.Printf(" - %-50s %25v %+v\n", stat.Name, stat.Type, stat.Data)
212                 n++
213         }
214
215         fmt.Printf("Dumped %d (%d) stats\n", n, len(stats))
216 }
217
218 func pollStats(client adapter.StatsAPI, patterns []string, skipZeros bool) {
219         dir, err := client.PrepareDir(patterns...)
220         if err != nil {
221                 log.Fatalln("preparing dir failed:", err)
222         }
223
224         tick := time.Tick(*pollPeriod)
225         for {
226                 n := 0
227                 fmt.Println(time.Now().Format(time.Stamp))
228                 for _, stat := range dir.Entries {
229                         if skipZeros && (stat.Data == nil || stat.Data.IsZero()) {
230                                 continue
231                         }
232                         fmt.Printf("%-50s %+v\n", stat.Name, stat.Data)
233                         n++
234                 }
235                 fmt.Println()
236
237                 select {
238                 case <-tick:
239                         if err := client.UpdateDir(dir); err != nil {
240                                 if err == adapter.ErrStatsDirStale {
241                                         if dir, err = client.PrepareDir(patterns...); err != nil {
242                                                 log.Fatalln("preparing dir failed:", err)
243                                         }
244                                         continue
245                                 }
246                                 log.Fatalln("updating dir failed:", err)
247                         }
248                 }
249         }
250 }
251
252 func pollSystem(client api.StatsProvider) {
253         stats := new(api.SystemStats)
254
255         if err := client.GetSystemStats(stats); err != nil {
256                 log.Fatalln("updating system stats failed:", err)
257         }
258
259         tick := time.Tick(*pollPeriod)
260         for {
261                 fmt.Printf("System stats: %+v\n", stats)
262                 fmt.Println()
263
264                 select {
265                 case <-tick:
266                         if err := client.GetSystemStats(stats); err != nil {
267                                 log.Println("updating system stats failed:", err)
268                         }
269                 }
270         }
271 }
272
273 func pollInterfaces(client api.StatsProvider) {
274         stats := new(api.InterfaceStats)
275
276         if err := client.GetInterfaceStats(stats); err != nil {
277                 log.Fatalln("updating system stats failed:", err)
278         }
279
280         tick := time.Tick(*pollPeriod)
281         for {
282                 fmt.Printf("Interface stats (%d interfaces)\n", len(stats.Interfaces))
283                 for i := range stats.Interfaces {
284                         fmt.Printf(" - %+v\n", stats.Interfaces[i])
285                 }
286                 fmt.Println()
287
288                 select {
289                 case <-tick:
290                         if err := client.GetInterfaceStats(stats); err != nil {
291                                 log.Println("updating system stats failed:", err)
292                         }
293                 }
294         }
295 }