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