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