Merge branch 'master' into mpr_rework
[oonf.git] / src-api / core / oonf_logging.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <assert.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <time.h>
52
53 #include "common/autobuf.h"
54 #include "common/list.h"
55 #include "common/string.h"
56 #include "core/oonf_libdata.h"
57 #include "core/oonf_logging.h"
58 #include "core/os_core.h"
59
60
61 static struct list_entity _handler_list;
62 static struct autobuf _logbuffer;
63 static const struct oonf_appdata *_appdata;
64 static const struct oonf_libdata *_libdata;
65 static uint8_t _default_mask;
66 static size_t _max_sourcetext_len, _max_severitytext_len, _source_count;
67
68 /*! global mask of all active logging levels per source */
69 uint8_t log_global_mask[LOG_MAXIMUM_SOURCES];
70
71 /*! names for build-in logging targets */
72 const char *LOG_SOURCE_NAMES[LOG_MAXIMUM_SOURCES] = {
73   /* all logging sources */
74   [LOG_ALL]           = "all",
75
76   /* the 'default' logging source */
77   [LOG_MAIN]          = "main",
78
79   /* the 'default' logging source */
80   [LOG_LOGGING]       = "logging",
81   [LOG_CONFIG]        = "config",
82   [LOG_PLUGINS]       = "plugins",
83   [LOG_SUBSYSTEMS]    = "subsystems",
84 };
85
86 /*! names of logging severities */
87 const char *LOG_SEVERITY_NAMES[LOG_SEVERITY_MAX+1] = {
88   [LOG_SEVERITY_DEBUG] = "DEBUG",
89   [LOG_SEVERITY_INFO]  = "INFO",
90   [LOG_SEVERITY_WARN]  = "WARN",
91 };
92
93 static uint32_t _log_warnings[LOG_MAXIMUM_SOURCES];
94
95 /**
96  * Initialize logging system
97  * @param data builddata defined by application
98  * @param def_severity default severity level
99  * @return -1 if an error happened, 0 otherwise
100  */
101 int
102 oonf_log_init(const struct oonf_appdata *data, enum oonf_log_severity def_severity)
103 {
104   enum oonf_log_severity sev;
105   enum oonf_log_source src;
106   size_t len;
107
108   _appdata = data;
109   _libdata = oonf_libdata_get();
110   _source_count = LOG_CORESOURCE_COUNT;
111
112   list_init_head(&_handler_list);
113
114   if (abuf_init(&_logbuffer)) {
115     fputs("Not enough memory for logging buffer\n", stderr);
116     return -1;
117   }
118
119   /* initialize maximum severity length */
120   _max_severitytext_len = 0;
121   OONF_FOR_ALL_LOGSEVERITIES(sev) {
122     len = strlen(LOG_SEVERITY_NAMES[sev]);
123     if (len > _max_severitytext_len) {
124       _max_severitytext_len = len;
125     }
126   }
127
128   /* initialize maximum source length */
129   _max_sourcetext_len = 0;
130   for (src = 0; src < LOG_CORESOURCE_COUNT; src++) {
131     len = strlen(LOG_SOURCE_NAMES[src]);
132     if (len > _max_sourcetext_len) {
133       _max_sourcetext_len = len;
134     }
135   }
136
137   /* set default mask */
138   _default_mask = 0;
139   OONF_FOR_ALL_LOGSEVERITIES(sev) {
140     if (sev >= def_severity) {
141       _default_mask |= sev;
142     }
143   }
144
145   /* clear global mask */
146   memset(&log_global_mask, _default_mask, sizeof(log_global_mask));
147
148   /* clear warning counter */
149   memset(_log_warnings, 0, sizeof(_log_warnings));
150   return 0;
151 }
152
153 /**
154  * Cleanup all resources allocated by logging system
155  */
156 void
157 oonf_log_cleanup(void)
158 {
159   struct oonf_log_handler_entry *h, *iterator;
160   enum oonf_log_source src;
161
162   /* remove all handlers */
163   list_for_each_element_safe(&_handler_list, h, _node, iterator) {
164     oonf_log_removehandler(h);
165   }
166
167   for (src = LOG_CORESOURCE_COUNT; src < LOG_MAXIMUM_SOURCES; src++) {
168     free ((void *)LOG_SOURCE_NAMES[src]);
169     LOG_SOURCE_NAMES[src] = NULL;
170   }
171   abuf_free(&_logbuffer);
172 }
173
174 /**
175  * Registers a custom logevent handler. Handler and bitmask_ptr have to
176  * be initialized.
177  * @param h pointer to log event handler struct
178  * @return -1 if an out of memory error happened, 0 otherwise
179  */
180 void
181 oonf_log_addhandler(struct oonf_log_handler_entry *h)
182 {
183   list_add_tail(&_handler_list, &h->_node);
184   oonf_log_updatemask();
185 }
186
187 /**
188  * Unregister a logevent handler
189  * @param h pointer to handler entry
190  */
191 void
192 oonf_log_removehandler(struct oonf_log_handler_entry *h)
193 {
194   list_remove(&h->_node);
195   oonf_log_updatemask();
196 }
197
198 /**
199  * register a new logging source in the logger
200  * @param name pointer to the name of the logging source
201  * @return index of the new logging source, LOG_MAIN if out of memory
202  */
203 int
204 oonf_log_register_source(const char *name) {
205   size_t i, len;
206
207   /* maybe the source is already there ? */
208   for (i=0; i<_source_count; i++) {
209     if (strcmp(name, LOG_SOURCE_NAMES[i]) == 0) {
210       return i;
211     }
212   }
213
214   if (i == LOG_MAXIMUM_SOURCES) {
215     OONF_WARN(LOG_LOGGING, "Maximum number of logging sources reached,"
216         " cannot allocate %s", name);
217     return LOG_MAIN;
218   }
219
220   if ((LOG_SOURCE_NAMES[i] = strdup(name)) == NULL) {
221     OONF_WARN(LOG_LOGGING, "Not enough memory for duplicating source name %s", name);
222     return LOG_MAIN;
223   }
224
225   _source_count++;
226   len = strlen(name);
227   if (len > _max_sourcetext_len) {
228     _max_sourcetext_len = len;
229   }
230   return i;
231 }
232
233 /**
234  * @return maximum text length of a log severity string
235  */
236 size_t
237 oonf_log_get_max_severitytextlen(void) {
238   return _max_severitytext_len;
239 }
240
241 /**
242  * @return maximum text length of a log source string
243  */
244 size_t
245 oonf_log_get_max_sourcetextlen(void) {
246   return _max_sourcetext_len;
247 }
248
249 /**
250  * @return current number of logging sources
251  */
252 size_t
253 oonf_log_get_sourcecount(void) {
254   return _source_count;
255 }
256
257 /**
258  * @param source logging source
259  * @return number of warnings since start for this source
260  */
261 uint32_t
262 oonf_log_get_warning_count(enum oonf_log_source source) {
263   return _log_warnings[source];
264 }
265
266 /**
267  * @return pointer to application data
268  */
269 const struct oonf_appdata *
270 oonf_log_get_appdata(void) {
271   return _appdata;
272 }
273
274 /**
275  * @return pointer to library data
276  */
277 const struct oonf_libdata *
278 oonf_log_get_libdata(void) {
279   return _libdata;
280 }
281
282 /**
283  * Print version string
284  * @param abuf target output buffer
285  */
286 void
287 oonf_log_printversion(struct autobuf *abuf) {
288   abuf_appendf(abuf," %s version %s\n",
289             _appdata->app_name,
290             _libdata->version);
291   abuf_appendf(abuf, " Git commit: %s\n", _libdata->git_commit);
292   abuf_puts(abuf, _appdata->versionstring_trailer);
293 }
294
295 /**
296  * Recalculate the combination of the oonf_cnf log event mask and all (if any)
297  * custom masks of logfile handlers. Must be called every times a event mask
298  * changes without a logevent handler being added or removed.
299  */
300 void
301 oonf_log_updatemask(void)
302 {
303   enum oonf_log_source src;
304   struct oonf_log_handler_entry *h, *iterator;
305   uint8_t mask;
306
307   /* first reset global mask */
308   oonf_log_mask_clear(log_global_mask);
309
310   list_for_each_element_safe(&_handler_list, h, _node, iterator) {
311     for (src = 0; src < LOG_MAXIMUM_SOURCES; src++) {
312       /* copy user defined mask */
313       mask = h->user_bitmask[src];
314
315       /* apply 'all' source mask */
316       mask |= h->user_bitmask[LOG_ALL];
317
318       /* propagate severities from lower to higher level */
319       mask |= mask << 1;
320       mask |= mask << 2;
321
322       /*
323        * we don't need the third shift because we have
324        * 4 or less severity level
325        */
326 #if 0
327       mask |= mask << 4;
328 #endif
329
330       /* write calculated mask into internal buffer */
331       h->_processed_bitmask[src] = mask;
332
333       /* apply calculated mask to the global one */
334       log_global_mask[src] |= mask;
335     }
336   }
337 }
338
339 /**
340  * @param buf buffer to storage object for time string
341  * @return pointer to string containing the current walltime
342  */
343 const char *
344 oonf_log_get_walltime(struct oonf_walltime_str *buf) {
345 struct timeval now;
346   struct tm *tm;
347
348   if (os_core_gettimeofday(&now)) {
349     return NULL;
350   }
351
352   tm = localtime(&now.tv_sec);
353   if (tm == NULL) {
354     return NULL;
355   }
356   snprintf(buf->buf, sizeof(buf->buf), "%02d:%02d:%02d.%03ld",
357       tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000);
358   return buf->buf;
359 }
360
361 /**
362  * This function should not be called directly, use the macros OONF_{DEBUG,INFO,WARN} !
363  *
364  * Generates a logfile entry and calls all log handler to store/output it.
365  *
366  * @param severity severity of the log event (LOG_SEVERITY_DEBUG to LOG_SEVERITY_WARN)
367  * @param source source of the log event (LOG_LOGGING, ... )
368  * @param no_header true if time header should not be created
369  * @param file filename where the logging macro have been called
370  * @param line line number where the logging macro have been called
371  * @param hexptr pointer to binary buffer that should be appended as a hexdump
372  * @param hexlen length of binary buffer to hexdump
373  * @param format printf format string for log output plus a variable number of arguments
374  */
375 void
376 oonf_log(enum oonf_log_severity severity, enum oonf_log_source source, bool no_header,
377     const char *file, int line, const void *hexptr, size_t hexlen, const char *format, ...)
378 {
379   struct oonf_log_handler_entry *h, *iterator;
380   struct oonf_log_parameters param;
381   struct oonf_walltime_str tbuf;
382   char *last;
383   va_list ap;
384   int p1 = 0, p2 = 0;
385
386   if (severity == LOG_SEVERITY_WARN) {
387     /* count warnings */
388     _log_warnings[source]++;
389     _log_warnings[LOG_ALL]++;
390   }
391
392   va_start(ap, format);
393
394   /* generate log string */
395   abuf_clear(&_logbuffer);
396   if (!no_header) {
397     p1 = abuf_puts(&_logbuffer, oonf_log_get_walltime(&tbuf));
398
399     p2 = abuf_appendf(&_logbuffer, " %s(%s) %s %d: ",
400         LOG_SEVERITY_NAMES[severity], LOG_SOURCE_NAMES[source], file, line);
401   }
402   abuf_vappendf(&_logbuffer, format, ap);
403
404   last = &abuf_getptr(&_logbuffer)[abuf_getlen(&_logbuffer)-1];
405   if (hexptr) {
406     /* append \n at the end of the line if necessary */
407     if (*last != '\n') {
408       abuf_puts(&_logbuffer, "\n");
409     }
410
411     abuf_hexdump(&_logbuffer, "", hexptr, hexlen);
412   }
413   else {
414     /* remove \n at the end of the line if necessary */
415     if (*last == '\n') {
416       *last = 0;
417     }
418   }
419
420   param.severity = severity;
421   param.source = source;
422   param.no_header = no_header;
423   param.file = file;
424   param.line = line;
425   param.buffer = abuf_getptr(&_logbuffer);
426   param.timeLength = p1;
427   param.prefixLength = p2;
428
429   /* use stderr logger if nothing has been configured */
430   if (list_is_empty(&_handler_list)) {
431     oonf_log_stderr(NULL, &param);
432   }
433   else {
434     /* call all log handlers */
435     list_for_each_element_safe(&_handler_list, h, _node, iterator) {
436       if (oonf_log_mask_test(h->_processed_bitmask, source, severity)) {
437         h->handler(h, &param);
438       }
439     }
440   }
441   va_end(ap);
442 }
443
444 /**
445  * Logger for stderr output
446  * @param entry logging handler, might be NULL because this is the
447  *   default logger
448  * @param param logging parameter set
449  */
450 void
451 oonf_log_stderr(struct oonf_log_handler_entry *entry __attribute__ ((unused)),
452     struct oonf_log_parameters *param)
453 {
454   fputs(param->buffer, stderr);
455   fputc('\n', stderr);
456 }
457
458 /**
459  * Logger for file output
460  * @param entry logging handler
461  * @param param logging parameter set
462  */
463 void
464 oonf_log_file(struct oonf_log_handler_entry *entry,
465     struct oonf_log_parameters *param)
466 {
467   FILE *f;
468
469   f = entry->custom;
470   fputs(param->buffer, f);
471   fputc('\n', f);
472   fflush(f);
473 }
474
475 /**
476  * Logger for syslog output
477  * @param entry logging handler, might be NULL
478  * @param param logging parameter set
479  */
480 void
481 oonf_log_syslog(struct oonf_log_handler_entry *entry __attribute__ ((unused)),
482     struct oonf_log_parameters *param)
483 {
484   os_core_syslog(param->severity, param->buffer + param->timeLength);
485 }