c00fb835d1c668a1b38505237257eb1b6e0e5b49
[vpp.git] / src / vpp / app / vpp_get_stats.c
1 /*
2  *------------------------------------------------------------------
3  * vpp_get_stats.c
4  *
5  * Copyright (c) 2018 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vpp-api/client/stat_client.h>
21 #include <vlib/vlib.h>
22
23 static int
24 stat_poll_loop (u8 ** patterns)
25 {
26   struct timespec ts, tsrem;
27   stat_segment_data_t *res;
28   int i, j, k, lost_connection = 0;
29   f64 heartbeat, prev_heartbeat = 0;
30   u32 *stats = stat_segment_ls (patterns);
31   if (!stats)
32     {
33       return -1;
34     }
35
36   printf ("\033[2J");           /*  clear the screen  */
37   while (1)
38     {
39       heartbeat = stat_segment_heartbeat ();
40       if (heartbeat > prev_heartbeat)
41         {
42           prev_heartbeat = heartbeat;
43           lost_connection = 0;
44         }
45       else
46         {
47           lost_connection++;
48         }
49       if (lost_connection > 10)
50         {
51           fformat (stderr, "Lost connection to VPP...\n");
52           return -1;
53         }
54
55       printf ("\033[H");        /* Cursor top left corner */
56       res = stat_segment_dump (stats);
57       if (!res)
58         {
59           stats = stat_segment_ls (patterns);
60           continue;
61         }
62       for (i = 0; i < vec_len (res); i++)
63         {
64           switch (res[i].type)
65             {
66             case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
67               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
68                 for (j = 0; j < vec_len (res[i].simple_counter_vec[k]); j++)
69                   fformat (stdout, "[%d]: %llu packets %s\n",
70                            j, res[i].simple_counter_vec[k][j], res[i].name);
71               break;
72
73             case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
74               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
75                 for (j = 0; j < vec_len (res[i].combined_counter_vec[k]); j++)
76                   fformat (stdout, "[%d]: %llu packets, %llu bytes %s\n",
77                            j, res[i].combined_counter_vec[k][j].packets,
78                            res[i].combined_counter_vec[k][j].bytes,
79                            res[i].name);
80               break;
81
82             case STAT_DIR_TYPE_ERROR_INDEX:
83               for (j = 0; j < vec_len (res[i].error_vector); j++)
84                 fformat (stdout, "%llu %s\n", res[i].error_vector[j],
85                          res[i].name);
86               break;
87
88             case STAT_DIR_TYPE_SCALAR_INDEX:
89               fformat (stdout, "%.2f %s\n", res[i].scalar_value, res[i].name);
90               break;
91
92             default:
93               printf ("Unknown value\n");
94               ;
95             }
96         }
97       stat_segment_data_free (res);
98       /* Scrape stats every 5 seconds */
99       ts.tv_sec = 1;
100       ts.tv_nsec = 0;
101       while (nanosleep (&ts, &tsrem) < 0)
102         ts = tsrem;
103
104     }
105 }
106
107 enum stat_client_cmd_e
108 {
109   STAT_CLIENT_CMD_UNKNOWN,
110   STAT_CLIENT_CMD_LS,
111   STAT_CLIENT_CMD_POLL,
112   STAT_CLIENT_CMD_DUMP,
113   STAT_CLIENT_CMD_TIGHTPOLL,
114 };
115
116 int
117 main (int argc, char **argv)
118 {
119   unformat_input_t _argv, *a = &_argv;
120   u8 *stat_segment_name, *pattern = 0, **patterns = 0;
121   int rv;
122   enum stat_client_cmd_e cmd = STAT_CLIENT_CMD_UNKNOWN;
123
124   /* Create a heap of 64MB */
125   clib_mem_init (0, 64 << 20);
126
127   unformat_init_command_line (a, argv);
128
129   stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
130
131   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
132     {
133       if (unformat (a, "socket-name %s", &stat_segment_name))
134         ;
135       else if (unformat (a, "ls"))
136         {
137           cmd = STAT_CLIENT_CMD_LS;
138         }
139       else if (unformat (a, "dump"))
140         {
141           cmd = STAT_CLIENT_CMD_DUMP;
142         }
143       else if (unformat (a, "poll"))
144         {
145           cmd = STAT_CLIENT_CMD_POLL;
146         }
147       else if (unformat (a, "tightpoll"))
148         {
149           cmd = STAT_CLIENT_CMD_TIGHTPOLL;
150         }
151       else if (unformat (a, "%s", &pattern))
152         {
153           vec_add1 (patterns, pattern);
154         }
155       else
156         {
157           fformat (stderr,
158                    "%s: usage [socket-name <name>] [ls|dump|poll] <patterns> ...\n",
159                    argv[0]);
160           exit (1);
161         }
162     }
163 reconnect:
164   rv = stat_segment_connect ((char *) stat_segment_name);
165   if (rv)
166     {
167       fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
168                stat_segment_name);
169       exit (1);
170     }
171
172   u32 *dir;
173   int i, j, k;
174   stat_segment_data_t *res;
175
176   dir = stat_segment_ls (patterns);
177
178   switch (cmd)
179     {
180     case STAT_CLIENT_CMD_LS:
181       /* List all counters */
182       for (i = 0; i < vec_len (dir); i++)
183         {
184           char *n = stat_segment_index_to_name (dir[i]);
185           printf ("%s\n", n);
186           free (n);
187         }
188       break;
189
190     case STAT_CLIENT_CMD_DUMP:
191       res = stat_segment_dump (dir);
192       for (i = 0; i < vec_len (res); i++)
193         {
194           switch (res[i].type)
195             {
196             case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
197               if (res[i].simple_counter_vec == 0)
198                 continue;
199               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
200                 for (j = 0; j < vec_len (res[i].simple_counter_vec[k]); j++)
201                   fformat (stdout, "[%d @ %d]: %llu packets %s\n",
202                            j, k, res[i].simple_counter_vec[k][j],
203                            res[i].name);
204               break;
205
206             case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
207               if (res[i].combined_counter_vec == 0)
208                 continue;
209               for (k = 0; k < vec_len (res[i].combined_counter_vec); k++)
210                 for (j = 0; j < vec_len (res[i].combined_counter_vec[k]); j++)
211                   fformat (stdout, "[%d @ %d]: %llu packets, %llu bytes %s\n",
212                            j, k, res[i].combined_counter_vec[k][j].packets,
213                            res[i].combined_counter_vec[k][j].bytes,
214                            res[i].name);
215               break;
216
217             case STAT_DIR_TYPE_ERROR_INDEX:
218               for (j = 0; j < vec_len (res[i].error_vector); j++)
219                 fformat (stdout, "[@%d] %llu %s\n", j, res[i].error_vector[j],
220                          res[i].name);
221               break;
222
223             case STAT_DIR_TYPE_SCALAR_INDEX:
224               fformat (stdout, "%.2f %s\n", res[i].scalar_value, res[i].name);
225               break;
226
227             case STAT_DIR_TYPE_NAME_VECTOR:
228               if (res[i].name_vector == 0)
229                 continue;
230               for (k = 0; k < vec_len (res[i].name_vector); k++)
231                 if (res[i].name_vector[k])
232                   fformat (stdout, "[%d]: %s %s\n", k, res[i].name_vector[k],
233                            res[i].name);
234               break;
235
236             default:
237               ;
238             }
239         }
240       stat_segment_data_free (res);
241       break;
242
243     case STAT_CLIENT_CMD_POLL:
244       stat_poll_loop (patterns);
245       /* We can only exist the pool loop if we lost connection to VPP */
246       stat_segment_disconnect ();
247       goto reconnect;
248       break;
249
250     case STAT_CLIENT_CMD_TIGHTPOLL:
251       while (1)
252         {
253           res = stat_segment_dump (dir);
254           if (res == 0)
255             {
256               /* Refresh */
257               vec_free (dir);
258               dir = stat_segment_ls (patterns);
259               continue;
260             }
261           stat_segment_data_free (res);
262         }
263       break;
264
265     default:
266       fformat (stderr,
267                "%s: usage [socket-name <name>] [ls|dump|poll] <patterns> ...\n",
268                argv[0]);
269     }
270
271   stat_segment_disconnect ();
272
273   exit (0);
274 }
275
276 /*
277  * fd.io coding-style-patch-verification: ON
278  *
279  * Local Variables:
280  * eval: (c-set-style "gnu")
281  * End:
282  */