STATS: Python binding to access VPP statistics and counters.
[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 #include <vpp/stats/stats.h>
23
24 static int
25 stat_poll_loop (stat_segment_cached_pointer_t * cp)
26 {
27   struct timespec ts, tsrem;
28   stat_segment_data_t *res;
29   int i, j, k, lost_connection = 0;
30   f64 heartbeat, prev_heartbeat = 0;
31
32   printf ("\033[2J");           /*  clear the screen  */
33   while (1)
34     {
35       heartbeat = stat_segment_heartbeat ();
36       if (heartbeat > prev_heartbeat)
37         {
38           prev_heartbeat = heartbeat;
39           lost_connection = 0;
40         }
41       else
42         {
43           lost_connection++;
44         }
45       if (lost_connection > 10)
46         {
47           fformat (stderr, "Lost connection to VPP...\n");
48           return -1;
49         }
50
51       printf ("\033[H");        /* Cursor top left corner */
52       res = stat_segment_collect (cp);
53       for (i = 0; i < vec_len (res); i++)
54         {
55           switch (res[i].type)
56             {
57             case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
58               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
59                 for (j = 0; j < vec_len (res[i].simple_counter_vec[k]); j++)
60                   fformat (stdout, "[%d]: %lld packets %s\n",
61                            j, res[i].simple_counter_vec[k][j], res[i].name);
62               break;
63
64             case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
65               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
66                 for (j = 0; j < vec_len (res[i].combined_counter_vec[k]); j++)
67                   fformat (stdout, "[%d]: %lld packets, %lld bytes %s\n",
68                            j, res[i].combined_counter_vec[k][j].packets,
69                            res[i].combined_counter_vec[k][j].bytes,
70                            res[i].name);
71               break;
72
73             case STAT_DIR_TYPE_ERROR_INDEX:
74               fformat (stdout, "%lld %s\n", res[i].error_value, res[i].name);
75               break;
76
77             case STAT_DIR_TYPE_SCALAR_POINTER:
78               fformat (stdout, "%.2f %s\n", res[i].scalar_value, res[i].name);
79               break;
80
81             default:
82               printf ("Unknown value\n");
83               ;
84             }
85         }
86       stat_segment_data_free (res);
87       /* Scrape stats every 5 seconds */
88       ts.tv_sec = 1;
89       ts.tv_nsec = 0;
90       while (nanosleep (&ts, &tsrem) < 0)
91         ts = tsrem;
92
93     }
94 }
95
96 enum stat_client_cmd_e
97 {
98   STAT_CLIENT_CMD_UNKNOWN,
99   STAT_CLIENT_CMD_LS,
100   STAT_CLIENT_CMD_POLL,
101   STAT_CLIENT_CMD_DUMP,
102 };
103
104 int
105 main (int argc, char **argv)
106 {
107   unformat_input_t _argv, *a = &_argv;
108   u8 *stat_segment_name, *pattern = 0, **patterns = 0;
109   int rv;
110   enum stat_client_cmd_e cmd = STAT_CLIENT_CMD_UNKNOWN;
111   void *heap_base;
112
113   heap_base = clib_mem_vm_map ((void *) 0x10000000ULL, 128 << 20);
114   clib_mem_init (heap_base, 128 << 20);
115
116   unformat_init_command_line (a, argv);
117
118   stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
119
120   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
121     {
122       if (unformat (a, "socket-name %s", &stat_segment_name))
123         ;
124       else if (unformat (a, "ls"))
125         {
126           cmd = STAT_CLIENT_CMD_LS;
127         }
128       else if (unformat (a, "dump"))
129         {
130           cmd = STAT_CLIENT_CMD_DUMP;
131         }
132       else if (unformat (a, "poll"))
133         {
134           cmd = STAT_CLIENT_CMD_POLL;
135         }
136       else if (unformat (a, "%s", &pattern))
137         {
138           vec_add1 (patterns, pattern);
139         }
140       else
141         {
142           fformat (stderr,
143                    "%s: usage [socket-name <name>] [ls|dump|poll] <patterns> ...\n",
144                    argv[0]);
145           exit (1);
146         }
147     }
148 reconnect:
149   rv = stat_segment_connect ((char *) stat_segment_name);
150   if (rv)
151     {
152       fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
153                stat_segment_name);
154       exit (1);
155     }
156
157   u8 **dir;
158   int i, j, k;
159   stat_segment_data_t *res;
160   stat_segment_cached_pointer_t *cp;
161
162   dir = stat_segment_ls (patterns);
163
164   switch (cmd)
165     {
166     case STAT_CLIENT_CMD_LS:
167       /* List all counters */
168       for (i = 0; i < vec_len (dir); i++)
169         {
170           printf ("%s\n", (char *) dir[i]);
171         }
172       break;
173
174     case STAT_CLIENT_CMD_DUMP:
175       res = stat_segment_dump (dir);
176       for (i = 0; i < vec_len (res); i++)
177         {
178           switch (res[i].type)
179             {
180             case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
181               for (k = 0; k < vec_len (res[i].simple_counter_vec) - 1; k++)
182                 for (j = 0; j < vec_len (res[i].simple_counter_vec[k]); j++)
183                   fformat (stdout, "[%d @ %d]: %lld packets %s\n",
184                            j, k, res[i].simple_counter_vec[k][j],
185                            res[i].name);
186               break;
187
188             case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
189               for (k = 0; k < vec_len (res[i].combined_counter_vec); k++)
190                 for (j = 0; j < vec_len (res[i].combined_counter_vec[k]); j++)
191                   fformat (stdout, "[%d @ %d]: %lld packets, %lld bytes %s\n",
192                            j, k, res[i].combined_counter_vec[k][j].packets,
193                            res[i].combined_counter_vec[k][j].bytes,
194                            res[i].name);
195               break;
196
197             case STAT_DIR_TYPE_ERROR_INDEX:
198               fformat (stdout, "%lld %s\n", res[i].error_value, dir[i]);
199               break;
200
201             case STAT_DIR_TYPE_SCALAR_POINTER:
202               fformat (stdout, "%.2f %s\n", dir[i], res[i].scalar_value,
203                        res[i].name);
204               break;
205
206             default:
207               ;
208             }
209         }
210       stat_segment_data_free (res);
211       break;
212
213     case STAT_CLIENT_CMD_POLL:
214       cp = stat_segment_register (dir);
215       if (!cp)
216         {
217           fformat (stderr,
218                    "Couldn't register required counters with stat segment\n");
219           exit (1);
220         }
221       stat_poll_loop (cp);
222       /* We can only exist the pool loop if we lost connection to VPP */
223       stat_segment_disconnect ();
224       goto reconnect;
225       break;
226
227     default:
228       fformat (stderr,
229                "%s: usage [socket-name <name>] [ls|dump|poll] <patterns> ...\n",
230                argv[0]);
231     }
232
233   stat_segment_disconnect ();
234
235   exit (0);
236 }
237
238 /*
239  * fd.io coding-style-patch-verification: ON
240  *
241  * Local Variables:
242  * eval: (c-set-style "gnu")
243  * End:
244  */