Cleanup logging system so it can be used by the config parser
[olsrd.git] / src / olsr_logging.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, 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 #include <assert.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48
49 #include "common/list.h"
50 #include "olsr.h"
51 #include "olsr_cfg.h"
52 #include "olsr_cfg_data.h"
53 #include "os_system.h"
54 #include "os_time.h"
55 #include "olsr_logging.h"
56
57 #define FOR_ALL_LOGHANDLERS(handler, iterator) list_for_each_element_safe(&log_handler_list, handler, node, iterator)
58
59 bool log_global_mask[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
60
61 static struct list_entity log_handler_list;
62 static FILE *log_fileoutput = NULL;
63
64 static void olsr_log_stderr(enum log_severity severity, enum log_source source,
65                             bool no_header, const char *file, int line, char *buffer,
66                             int timeLength, int prefixLength);
67 static void olsr_log_syslog(enum log_severity severity, enum log_source source,
68                             bool no_header, const char *file, int line, char *buffer,
69                             int timeLength, int prefixLength);
70 static void olsr_log_file(enum log_severity severity, enum log_source source,
71                           bool no_header, const char *file, int line, char *buffer,
72                           int timeLength, int prefixLength);
73
74 /**
75  * Called by main method just after configuration options have been parsed
76  */
77 void
78 olsr_log_init(void)
79 {
80   int i,j;
81
82   list_init_head(&log_handler_list);
83
84   /* clear global mask */
85   for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
86     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
87 #ifdef DEBUG
88       log_global_mask[j][i] = j >= SEVERITY_INFO;
89 #else
90       log_global_mask[j][i] = j >= SEVERITY_WARN;
91 #endif
92     }
93   }
94 }
95
96 /**
97  * Called just before olsr_shutdown finishes
98  */
99 void
100 olsr_log_cleanup(void)
101 {
102   struct log_handler_entry *h, *iterator;
103
104   /* remove all handlers */
105   FOR_ALL_LOGHANDLERS(h, iterator) {
106     olsr_log_removehandler(h);
107   }
108
109   /* close file output if necessary */
110   if (log_fileoutput) {
111     fflush(log_fileoutput);
112     fclose(log_fileoutput);
113   }
114 }
115
116 /**
117  * Configure logger according to olsr settings
118  */
119 void
120 olsr_log_applyconfig(void) {
121   if (olsr_cnf->log_target_file) {
122     log_fileoutput = fopen(olsr_cnf->log_target_file, "a");
123     if (log_fileoutput) {
124       olsr_log_addhandler(&olsr_log_file, &olsr_cnf->log_event);
125     } else {
126       OLSR_WARN(LOG_LOGGING, "Cannot open log output file %s.", olsr_cnf->log_target_file);
127     }
128   }
129   if (olsr_cnf->log_target_syslog) {
130     olsr_log_addhandler(&olsr_log_syslog, &olsr_cnf->log_event);
131   }
132   if (olsr_cnf->log_target_stderr) {
133     olsr_log_addhandler(&olsr_log_stderr, &olsr_cnf->log_event);
134   }
135 }
136
137 /**
138  * Registers a custom logevent handler
139  * @param handler pointer to handler function
140  * @param mask pointer to custom event filter or NULL if handler use filter
141  *   from olsr_cnf
142  */
143 struct log_handler_entry *
144 olsr_log_addhandler(void (*handler) (enum log_severity, enum log_source, bool,
145                                      const char *, int, char *, int, int),
146                     bool(*mask)[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT])
147 {
148   struct log_handler_entry *h;
149
150   /*
151    * The logging system is used in the memory cookie manager, so the logging
152    * system has to allocate its memory directly. Do not try to use
153    * olsr_memcookie_malloc() here.
154    */
155   h = olsr_malloc(sizeof(*h), "Log handler");
156   h->handler = handler;
157   h->bitmask_ptr = mask;
158
159   list_add_tail(&log_handler_list, &h->node);
160   olsr_log_updatemask();
161
162   return h;
163 }
164
165 /**
166  * Call this function to remove a logevent handler
167  * @param handler pointer to handler function
168  */
169 void
170 olsr_log_removehandler(struct log_handler_entry *h)
171 {
172   list_remove(&h->node);
173   olsr_log_updatemask();
174
175   free(h);
176 }
177
178 /**
179  * Recalculate the combination of the olsr_cnf log event mask and all (if any)
180  * custom masks of logfile handlers. Must be called every times a event mask
181  * changes.
182  */
183 void
184 olsr_log_updatemask(void)
185 {
186   int i, j;
187   struct log_handler_entry *h, *iterator;
188
189   /* first copy bitmasks to internal memory */
190   FOR_ALL_LOGHANDLERS(h, iterator) {
191     memcpy (&h->int_bitmask, h->bitmask_ptr, sizeof(h->int_bitmask));
192   }
193
194   /* second propagate source ALL to all other sources for each logger */
195   FOR_ALL_LOGHANDLERS(h, iterator) {
196     for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
197       if (h->int_bitmask[j][LOG_ALL]) {
198         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
199           h->int_bitmask[j][i] = true;
200         }
201       }
202     }
203   }
204
205   /* third, propagate events from debug to info to warn to error */
206   FOR_ALL_LOGHANDLERS(h, iterator) {
207     for (j = 0; j < LOG_SOURCE_COUNT; j++) {
208       bool active = false;
209
210       for (i = 0; i < LOG_SEVERITY_COUNT; i++) {
211         active |= h->int_bitmask[i][j];
212         h->int_bitmask[i][j] = active;
213       }
214     }
215   }
216
217   /* finally calculate the global logging bitmask */
218   for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
219     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
220       log_global_mask[j][i] = false;
221
222       FOR_ALL_LOGHANDLERS(h, iterator) {
223         log_global_mask[j][i] |= h->int_bitmask[j][i];
224       }
225     }
226   }
227 }
228
229 /**
230  * This function should not be called directly, use the macros OLSR_{DEBUG,INFO,WARN,ERROR} !
231  *
232  * Generates a logfile entry and calls all log handler to store/output it.
233  *
234  * @param severity severity of the log event (LOG_DEBUG to LOG_ERROR)
235  * @param source source of the log event (LOG_LOGGING, ... )
236  * @param file filename where the logging macro have been called
237  * @param line line number where the logging macro have been called
238  * @param format printf format string for log output plus a variable number of arguments
239  */
240 void
241 olsr_log(enum log_severity severity, enum log_source source, bool no_header, const char *file, int line, const char *format, ...)
242 {
243   static char logbuffer[LOGBUFFER_SIZE];
244   struct log_handler_entry *h, *iterator;
245   va_list ap;
246   int p1 = 0, p2 = 0, p3 = 0;
247   struct tm now, *tm_ptr;
248   struct timeval timeval;
249
250   /* test if event is consumed by any log handler */
251   if (!log_global_mask[severity][source])
252     return;                     /* no log handler is interested in this event, so drop it */
253
254   va_start(ap, format);
255
256   /* calculate local time */
257   os_gettimeofday(&timeval, NULL);
258
259   /* there is no localtime_r in win32 */
260   tm_ptr = localtime((time_t *) & timeval.tv_sec);
261   now = *tm_ptr;
262
263   /* generate log string (insert file/line in DEBUG mode) */
264   if (!no_header) {
265     p1 = snprintf(logbuffer, LOGBUFFER_SIZE, "%d:%02d:%02d.%03ld ",
266                   now.tm_hour, now.tm_min, now.tm_sec, (long)(timeval.tv_usec / 1000));
267
268     p2 = snprintf(&logbuffer[p1], LOGBUFFER_SIZE - p1, "%s(%s) %s %d: ",
269         LOG_SEVERITY_NAMES[severity], LOG_SOURCE_NAMES[source], file, line);
270   }
271   p3 = vsnprintf(&logbuffer[p1+p2], LOGBUFFER_SIZE - p1 - p2, format, ap);
272
273   assert(p1 + p2 +p3 < LOGBUFFER_SIZE);
274
275   /* remove \n at the end of the line if necessary */
276   if (logbuffer[p1 + p2 + p3 - 1] == '\n') {
277     logbuffer[p1 + p2 + p3 - 1] = 0;
278     p3--;
279   }
280
281   /* use stderr logger if nothing has been configured */
282   if (list_is_empty(&log_handler_list)) {
283     olsr_log_stderr(severity, source, no_header, file, line, logbuffer, p1, p2-p1);
284     return;
285   }
286
287   /* call all log handlers */
288   FOR_ALL_LOGHANDLERS(h, iterator) {
289     if (h->int_bitmask[severity][source]) {
290       h->handler(severity, source, no_header, file, line, logbuffer, p1, p2-p1);
291     }
292   }
293   va_end(ap);
294 }
295
296 static void
297 olsr_log_stderr(enum log_severity severity __attribute__ ((unused)),
298                 enum log_source source __attribute__ ((unused)),
299                 bool no_header __attribute__ ((unused)),
300                 const char *file __attribute__ ((unused)), int line __attribute__ ((unused)),
301                 char *buffer,
302                 int timeLength __attribute__ ((unused)),
303                 int prefixLength __attribute__ ((unused)))
304 {
305   fprintf(stderr, "%s\n", buffer);
306 }
307
308 static void
309 olsr_log_file(enum log_severity severity __attribute__ ((unused)),
310               enum log_source source __attribute__ ((unused)),
311               bool no_header __attribute__ ((unused)),
312               const char *file __attribute__ ((unused)), int line __attribute__ ((unused)),
313               char *buffer,
314               int timeLength __attribute__ ((unused)),
315               int prefixLength __attribute__ ((unused)))
316 {
317   fprintf(log_fileoutput, "%s\n", buffer);
318 }
319
320 static void
321 olsr_log_syslog(enum log_severity severity __attribute__ ((unused)),
322                 enum log_source source __attribute__ ((unused)),
323                 bool no_header __attribute__ ((unused)),
324                 const char *file __attribute__ ((unused)), int line __attribute__ ((unused)),
325                 char *buffer, int timeLength,
326                 int prefixLength __attribute__ ((unused)))
327 {
328   os_printline(severity, &buffer[timeLength]);
329 }