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