add "get base" function for Class memory block extensions
[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 /**
94  * Initialize logging system
95  * @param data builddata defined by application
96  * @param def_severity default severity level
97  * @return -1 if an error happened, 0 otherwise
98  */
99 int
100 oonf_log_init(const struct oonf_appdata *data, enum oonf_log_severity def_severity)
101 {
102   enum oonf_log_severity sev;
103   enum oonf_log_source src;
104   size_t len;
105
106   _appdata = data;
107   _libdata = oonf_libdata_get();
108   _source_count = LOG_CORESOURCE_COUNT;
109
110   list_init_head(&_handler_list);
111
112   if (abuf_init(&_logbuffer)) {
113     fputs("Not enough memory for logging buffer\n", stderr);
114     return -1;
115   }
116
117   /* initialize maximum severity length */
118   _max_severitytext_len = 0;
119   OONF_FOR_ALL_LOGSEVERITIES(sev) {
120     len = strlen(LOG_SEVERITY_NAMES[sev]);
121     if (len > _max_severitytext_len) {
122       _max_severitytext_len = len;
123     }
124   }
125
126   /* initialize maximum source length */
127   _max_sourcetext_len = 0;
128   for (src = 0; src < LOG_CORESOURCE_COUNT; src++) {
129     len = strlen(LOG_SOURCE_NAMES[src]);
130     if (len > _max_sourcetext_len) {
131       _max_sourcetext_len = len;
132     }
133   }
134
135   /* set default mask */
136   _default_mask = 0;
137   OONF_FOR_ALL_LOGSEVERITIES(sev) {
138     if (sev >= def_severity) {
139       _default_mask |= sev;
140     }
141   }
142
143   /* clear global mask */
144   memset(&log_global_mask, _default_mask, sizeof(log_global_mask));
145
146   return 0;
147 }
148
149 /**
150  * Cleanup all resources allocated by logging system
151  */
152 void
153 oonf_log_cleanup(void)
154 {
155   struct oonf_log_handler_entry *h, *iterator;
156   enum oonf_log_source src;
157
158   /* remove all handlers */
159   list_for_each_element_safe(&_handler_list, h, _node, iterator) {
160     oonf_log_removehandler(h);
161   }
162
163   for (src = LOG_CORESOURCE_COUNT; src < LOG_MAXIMUM_SOURCES; src++) {
164     free ((void *)LOG_SOURCE_NAMES[src]);
165     LOG_SOURCE_NAMES[src] = NULL;
166   }
167   abuf_free(&_logbuffer);
168 }
169
170 /**
171  * Registers a custom logevent handler. Handler and bitmask_ptr have to
172  * be initialized.
173  * @param h pointer to log event handler struct
174  * @return -1 if an out of memory error happened, 0 otherwise
175  */
176 void
177 oonf_log_addhandler(struct oonf_log_handler_entry *h)
178 {
179   list_add_tail(&_handler_list, &h->_node);
180   oonf_log_updatemask();
181 }
182
183 /**
184  * Unregister a logevent handler
185  * @param h pointer to handler entry
186  */
187 void
188 oonf_log_removehandler(struct oonf_log_handler_entry *h)
189 {
190   list_remove(&h->_node);
191   oonf_log_updatemask();
192 }
193
194 /**
195  * register a new logging source in the logger
196  * @param name pointer to the name of the logging source
197  * @return index of the new logging source, LOG_MAIN if out of memory
198  */
199 int
200 oonf_log_register_source(const char *name) {
201   size_t i, len;
202
203   /* maybe the source is already there ? */
204   for (i=0; i<_source_count; i++) {
205     if (strcmp(name, LOG_SOURCE_NAMES[i]) == 0) {
206       return i;
207     }
208   }
209
210   if (i == LOG_MAXIMUM_SOURCES) {
211     OONF_WARN(LOG_LOGGING, "Maximum number of logging sources reached,"
212         " cannot allocate %s", name);
213     return LOG_MAIN;
214   }
215
216   if ((LOG_SOURCE_NAMES[i] = strdup(name)) == NULL) {
217     OONF_WARN(LOG_LOGGING, "Not enough memory for duplicating source name %s", name);
218     return LOG_MAIN;
219   }
220
221   _source_count++;
222   len = strlen(name);
223   if (len > _max_sourcetext_len) {
224     _max_sourcetext_len = len;
225   }
226   return i;
227 }
228
229 /**
230  * @return maximum text length of a log severity string
231  */
232 size_t
233 oonf_log_get_max_severitytextlen(void) {
234   return _max_severitytext_len;
235 }
236
237 /**
238  * @return maximum text length of a log source string
239  */
240 size_t
241 oonf_log_get_max_sourcetextlen(void) {
242   return _max_sourcetext_len;
243 }
244
245 /**
246  * @return current number of logging sources
247  */
248 size_t
249 oonf_log_get_sourcecount(void) {
250   return _source_count;
251 }
252
253 /**
254  * @return pointer to application data
255  */
256 const struct oonf_appdata *
257 oonf_log_get_appdata(void) {
258   return _appdata;
259 }
260
261 /**
262  * @return pointer to library data
263  */
264 const struct oonf_libdata *
265 oonf_log_get_libdata(void) {
266   return _libdata;
267 }
268
269 /**
270  * Print version string
271  * @param abuf target output buffer
272  */
273 void
274 oonf_log_printversion(struct autobuf *abuf) {
275   abuf_appendf(abuf," %s version %s\n",
276             _appdata->app_name,
277             _libdata->version);
278   abuf_appendf(abuf, " Git commit: %s\n", _libdata->git_commit);
279   abuf_puts(abuf, _appdata->versionstring_trailer);
280 }
281
282 /**
283  * Recalculate the combination of the oonf_cnf log event mask and all (if any)
284  * custom masks of logfile handlers. Must be called every times a event mask
285  * changes without a logevent handler being added or removed.
286  */
287 void
288 oonf_log_updatemask(void)
289 {
290   enum oonf_log_source src;
291   struct oonf_log_handler_entry *h, *iterator;
292   uint8_t mask;
293
294   /* first reset global mask */
295   oonf_log_mask_clear(log_global_mask);
296
297   list_for_each_element_safe(&_handler_list, h, _node, iterator) {
298     for (src = 0; src < LOG_MAXIMUM_SOURCES; src++) {
299       /* copy user defined mask */
300       mask = h->user_bitmask[src];
301
302       /* apply 'all' source mask */
303       mask |= h->user_bitmask[LOG_ALL];
304
305       /* propagate severities from lower to higher level */
306       mask |= mask << 1;
307       mask |= mask << 2;
308
309       /*
310        * we don't need the third shift because we have
311        * 4 or less severity level
312        */
313 #if 0
314       mask |= mask << 4;
315 #endif
316
317       /* write calculated mask into internal buffer */
318       h->_processed_bitmask[src] = mask;
319
320       /* apply calculated mask to the global one */
321       log_global_mask[src] |= mask;
322     }
323   }
324 }
325
326 /**
327  * @param buf buffer to storage object for time string
328  * @return pointer to string containing the current walltime
329  */
330 const char *
331 oonf_log_get_walltime(struct oonf_walltime_str *buf) {
332 struct timeval now;
333   struct tm *tm;
334
335   if (os_core_gettimeofday(&now)) {
336     return NULL;
337   }
338
339   tm = localtime(&now.tv_sec);
340   if (tm == NULL) {
341     return NULL;
342   }
343   snprintf(buf->buf, sizeof(buf->buf), "%02d:%02d:%02d.%03ld",
344       tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000);
345   return buf->buf;
346 }
347
348 /**
349  * This function should not be called directly, use the macros OONF_{DEBUG,INFO,WARN} !
350  *
351  * Generates a logfile entry and calls all log handler to store/output it.
352  *
353  * @param severity severity of the log event (LOG_SEVERITY_DEBUG to LOG_SEVERITY_WARN)
354  * @param source source of the log event (LOG_LOGGING, ... )
355  * @param no_header true if time header should not be created
356  * @param file filename where the logging macro have been called
357  * @param line line number where the logging macro have been called
358  * @param hexptr pointer to binary buffer that should be appended as a hexdump
359  * @param hexlen length of binary buffer to hexdump
360  * @param format printf format string for log output plus a variable number of arguments
361  */
362 void
363 oonf_log(enum oonf_log_severity severity, enum oonf_log_source source, bool no_header,
364     const char *file, int line, const void *hexptr, size_t hexlen, const char *format, ...)
365 {
366   struct oonf_log_handler_entry *h, *iterator;
367   struct oonf_log_parameters param;
368   struct oonf_walltime_str tbuf;
369   char *last;
370   va_list ap;
371   int p1 = 0, p2 = 0;
372
373   va_start(ap, format);
374
375   /* generate log string */
376   abuf_clear(&_logbuffer);
377   if (!no_header) {
378     p1 = abuf_puts(&_logbuffer, oonf_log_get_walltime(&tbuf));
379
380     p2 = abuf_appendf(&_logbuffer, " %s(%s) %s %d: ",
381         LOG_SEVERITY_NAMES[severity], LOG_SOURCE_NAMES[source], file, line);
382   }
383   abuf_vappendf(&_logbuffer, format, ap);
384
385   last = &abuf_getptr(&_logbuffer)[abuf_getlen(&_logbuffer)-1];
386   if (hexptr) {
387     /* append \n at the end of the line if necessary */
388     if (*last != '\n') {
389       abuf_puts(&_logbuffer, "\n");
390     }
391
392     abuf_hexdump(&_logbuffer, "", hexptr, hexlen);
393   }
394   else {
395     /* remove \n at the end of the line if necessary */
396     if (*last == '\n') {
397       *last = 0;
398     }
399   }
400
401   param.severity = severity;
402   param.source = source;
403   param.no_header = no_header;
404   param.file = file;
405   param.line = line;
406   param.buffer = abuf_getptr(&_logbuffer);
407   param.timeLength = p1;
408   param.prefixLength = p2;
409
410   /* use stderr logger if nothing has been configured */
411   if (list_is_empty(&_handler_list)) {
412     oonf_log_stderr(NULL, &param);
413   }
414   else {
415     /* call all log handlers */
416     list_for_each_element_safe(&_handler_list, h, _node, iterator) {
417       if (oonf_log_mask_test(h->_processed_bitmask, source, severity)) {
418         h->handler(h, &param);
419       }
420     }
421   }
422   va_end(ap);
423 }
424
425 /**
426  * Logger for stderr output
427  * @param entry logging handler, might be NULL because this is the
428  *   default logger
429  * @param param logging parameter set
430  */
431 void
432 oonf_log_stderr(struct oonf_log_handler_entry *entry __attribute__ ((unused)),
433     struct oonf_log_parameters *param)
434 {
435   fputs(param->buffer, stderr);
436   fputc('\n', stderr);
437 }
438
439 /**
440  * Logger for file output
441  * @param entry logging handler
442  * @param param logging parameter set
443  */
444 void
445 oonf_log_file(struct oonf_log_handler_entry *entry,
446     struct oonf_log_parameters *param)
447 {
448   FILE *f;
449
450   f = entry->custom;
451   fputs(param->buffer, f);
452   fputc('\n', f);
453   fflush(f);
454 }
455
456 /**
457  * Logger for syslog output
458  * @param entry logging handler, might be NULL
459  * @param param logging parameter set
460  */
461 void
462 oonf_log_syslog(struct oonf_log_handler_entry *entry __attribute__ ((unused)),
463     struct oonf_log_parameters *param)
464 {
465   os_core_syslog(param->severity, param->buffer + param->timeLength);
466 }