paragraph for gnunet devs that don't know how to use the web
[oweals/gnunet.git] / src / statistics / gnunet-statistics.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2004-2007, 2009, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file statistics/gnunet-statistics.c
21  * @brief tool to obtain statistics
22  * @author Christian Grothoff
23  * @author Igor Wronsky
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_statistics_service.h"
28 #include "statistics.h"
29
30
31 /**
32  * Final status code.
33  */
34 static int ret;
35
36 /**
37  * Set to subsystem that we're going to get stats for (or NULL for all).
38  */
39 static char *subsystem;
40
41 /**
42  * Set to the specific stat value that we are after (or NULL for all).
43  */
44 static char *name;
45
46 /**
47  * Make the value that is being set persistent.
48  */
49 static int persistent;
50
51 /**
52  * Watch value continuously
53  */
54 static int watch;
55
56 /**
57  * Quiet mode
58  */
59 static int quiet;
60
61 /**
62  * Remote host
63  */
64 static char *remote_host;
65
66 /**
67  * Remote host's port
68  */
69 static unsigned long long remote_port;
70
71 /**
72  * Value to set
73  */
74 static unsigned long long set_val;
75
76 /**
77  * Set operation
78  */
79 static int set_value;
80
81 /**
82  * Handle for pending GET operation.
83  */
84 static struct GNUNET_STATISTICS_GetHandle *gh;
85
86
87 /**
88  * Callback function to process statistic values.
89  *
90  * @param cls closure
91  * @param subsystem name of subsystem that created the statistic
92  * @param name the name of the datum
93  * @param value the current value
94  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
95  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
96  */
97 static int
98 printer (void *cls,
99          const char *subsystem,
100          const char *name,
101          uint64_t value,
102          int is_persistent)
103 {
104   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
105   const char *now_str;
106
107   if (quiet == GNUNET_NO)
108   {
109     if (GNUNET_YES == watch)
110     {
111       now_str = GNUNET_STRINGS_absolute_time_to_string (now);
112       FPRINTF (stdout,
113                "%24s %s%12s %50s: %16llu\n",
114                now_str,
115                is_persistent ? "!" : " ",
116                subsystem,
117                _(name),
118                (unsigned long long) value);
119     }
120     else
121     {
122       FPRINTF (stdout,
123                "%s%12s %50s: %16llu\n",
124                is_persistent ? "!" : " ",
125                subsystem,
126                _(name),
127                (unsigned long long) value);
128     }
129   }
130   else
131     FPRINTF (stdout,
132              "%llu\n",
133              (unsigned long long) value);
134
135   return GNUNET_OK;
136 }
137
138
139 /**
140  * Function called last by the statistics code.
141  *
142  * @param cls closure
143  * @param success #GNUNET_OK if statistics were
144  *        successfully obtained, #GNUNET_SYSERR if not.
145  */
146 static void
147 cleanup (void *cls,
148          int success)
149 {
150   gh = NULL;
151   if (GNUNET_OK != success)
152   {
153     if (NULL == remote_host)
154       FPRINTF (stderr,
155                "%s",
156                _("Failed to obtain statistics.\n"));
157     else
158       FPRINTF (stderr,
159                _("Failed to obtain statistics from host `%s:%llu'\n"),
160                remote_host,
161                remote_port);
162     ret = 1;
163   }
164   GNUNET_SCHEDULER_shutdown ();
165 }
166
167
168 /**
169  * Function run on shutdown to clean up.
170  *
171  * @param cls the statistics handle
172  */
173 static void
174 shutdown_task (void *cls)
175 {
176   struct GNUNET_STATISTICS_Handle *h = cls;
177
178   if (NULL == h)
179     return;
180   if (NULL != gh)
181   {
182     GNUNET_STATISTICS_get_cancel (gh);
183     gh = NULL;
184   }
185   if ( (GNUNET_YES == watch) &&
186        (NULL != subsystem) &&
187        (NULL != name) )
188     GNUNET_assert (GNUNET_OK ==
189                    GNUNET_STATISTICS_watch_cancel (h,
190                                                    subsystem,
191                                                    name,
192                                                    &printer,
193                                                    h));
194   GNUNET_STATISTICS_destroy (h,
195                              GNUNET_NO);
196   h = NULL;
197 }
198
199
200 /**
201  * Main task that does the actual work.
202  *
203  * @param cls closure with our configuration
204  */
205 static void
206 main_task (void *cls)
207 {
208   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
209   struct GNUNET_STATISTICS_Handle *h;
210
211   if (set_value)
212   {
213     if (NULL == subsystem)
214     {
215       FPRINTF (stderr,
216                "%s",
217                _("Missing argument: subsystem \n"));
218       ret = 1;
219       return;
220     }
221     if (NULL == name)
222     {
223       FPRINTF (stderr,
224                "%s",
225                _("Missing argument: name\n"));
226       ret = 1;
227       return;
228     }
229     h = GNUNET_STATISTICS_create (subsystem,
230                                   cfg);
231     if (NULL == h)
232     {
233       ret = 1;
234       return;
235     }
236     GNUNET_STATISTICS_set (h,
237                            name,
238                            (uint64_t) set_val,
239                            persistent);
240     GNUNET_STATISTICS_destroy (h,
241                                GNUNET_YES);
242     h = NULL;
243     return;
244   }
245   if (NULL == (h = GNUNET_STATISTICS_create ("gnunet-statistics",
246                                              cfg)))
247   {
248     ret = 1;
249     return;
250   }
251   if (GNUNET_NO == watch)
252   {
253     if (NULL ==
254         (gh = GNUNET_STATISTICS_get (h,
255                                      subsystem,
256                                      name,
257                                      &cleanup,
258                                      &printer,
259                                      h)) )
260       cleanup (h,
261                GNUNET_SYSERR);
262   }
263   else
264   {
265     if ( (NULL == subsystem) ||
266          (NULL == name) )
267     {
268       printf (_("No subsystem or name given\n"));
269       GNUNET_STATISTICS_destroy (h,
270                                  GNUNET_NO);
271       h = NULL;
272       ret = 1;
273       return;
274     }
275     if (GNUNET_OK !=
276         GNUNET_STATISTICS_watch (h,
277                                  subsystem,
278                                  name,
279                                  &printer,
280                                  h))
281     {
282       fprintf (stderr,
283                _("Failed to initialize watch routine\n"));
284       GNUNET_SCHEDULER_add_now (&shutdown_task,
285                                 h);
286       return;
287     }
288   }
289   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
290                                  h);
291 }
292
293
294 /**
295  * Main function that will be run by the scheduler.
296  *
297  * @param cls closure
298  * @param args remaining command-line arguments
299  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
300  * @param cfg configuration
301  */
302 static void
303 run (void *cls,
304      char *const *args,
305      const char *cfgfile,
306      const struct GNUNET_CONFIGURATION_Handle *cfg)
307 {
308   struct GNUNET_CONFIGURATION_Handle *c;
309
310   c = (struct GNUNET_CONFIGURATION_Handle *) cfg;
311   set_value = GNUNET_NO;
312   if (NULL != args[0])
313   {
314     if (1 != SSCANF (args[0],
315                      "%llu",
316                      &set_val))
317     {
318       FPRINTF (stderr,
319                _("Invalid argument `%s'\n"),
320                args[0]);
321       ret = 1;
322       return;
323     }
324     set_value = GNUNET_YES;
325   }
326   if (NULL != remote_host)
327   {
328     if (0 == remote_port)
329     {
330       if (GNUNET_SYSERR ==
331           GNUNET_CONFIGURATION_get_value_number (cfg,
332                                                  "statistics",
333                                                  "PORT",
334                                                  &remote_port))
335       {
336         FPRINTF (stderr,
337                  _("A port is required to connect to host `%s'\n"),
338                  remote_host);
339         return;
340       }
341     }
342     else if (65535 <= remote_port)
343     {
344       FPRINTF (stderr,
345                _("A port has to be between 1 and 65535 to connect to host `%s'\n"),
346                remote_host);
347       return;
348     }
349
350     /* Manipulate configuration */
351     GNUNET_CONFIGURATION_set_value_string (c,
352                                            "statistics",
353                                            "UNIXPATH",
354                                            "");
355     GNUNET_CONFIGURATION_set_value_string (c,
356                                            "statistics",
357                                            "HOSTNAME",
358                                            remote_host);
359     GNUNET_CONFIGURATION_set_value_number (c,
360                                            "statistics",
361                                            "PORT",
362                                            remote_port);
363   }
364   GNUNET_SCHEDULER_add_now (&main_task,
365                             c);
366 }
367
368
369 /**
370  * The main function to obtain statistics in GNUnet.
371  *
372  * @param argc number of arguments from the command line
373  * @param argv command line arguments
374  * @return 0 ok, 1 on error
375  */
376 int
377 main (int argc, char *const *argv)
378 {
379   struct GNUNET_GETOPT_CommandLineOption options[] = {
380     GNUNET_GETOPT_option_string ('n',
381                                  "name",
382                                  "NAME",
383                                  gettext_noop ("limit output to statistics for the given NAME"),
384                                  &name),
385
386     GNUNET_GETOPT_option_flag ('p',
387                                   "persistent",
388                                   gettext_noop ("make the value being set persistent"),
389                                   &persistent),
390
391     GNUNET_GETOPT_option_string ('s',
392                                  "subsystem",
393                                  "SUBSYSTEM",
394                                  gettext_noop ("limit output to the given SUBSYSTEM"),
395                                  &subsystem),
396
397     GNUNET_GETOPT_option_flag ('q',
398                                   "quiet",
399                                   gettext_noop ("just print the statistics value"),
400                                   &quiet),
401
402     GNUNET_GETOPT_option_flag ('w',
403                                   "watch",
404                                   gettext_noop ("watch value continuously"),
405                                   &watch),
406
407     GNUNET_GETOPT_option_string ('r',
408                                  "remote",
409                                  "REMOTE",
410                                  gettext_noop ("connect to remote host"),
411                                  &remote_host),
412     GNUNET_GETOPT_option_ulong ('o',
413                                     "port",
414                                     "PORT",
415                                     gettext_noop ("port for remote host"),
416                                     &remote_port),
417     GNUNET_GETOPT_OPTION_END
418   };
419   remote_port = 0;
420   remote_host = NULL;
421   if (GNUNET_OK !=
422       GNUNET_STRINGS_get_utf8_args (argc, argv,
423                                     &argc, &argv))
424     return 2;
425
426   ret = (GNUNET_OK ==
427          GNUNET_PROGRAM_run (argc,
428                              argv,
429                              "gnunet-statistics [options [value]]",
430                              gettext_noop
431                              ("Print statistics about GNUnet operations."),
432                              options,
433                              &run,
434                              NULL)) ? ret : 1;
435   GNUNET_free_non_null (remote_host);
436   GNUNET_free ((void*) argv);
437   return ret;
438 }
439
440 /* end of gnunet-statistics.c */