5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
23 /* SilcLogSettings context */
25 SilcUInt32 flushdelay;
27 char debug_string[128];
28 SilcLogDebugCb debug_cb;
30 SilcLogHexdumpCb hexdump_cb;
31 void *hexdump_context;
33 unsigned int timestamp : 1;
34 unsigned int quick : 1;
35 unsigned int debug : 1;
36 unsigned int debug_hexdump : 1;
37 unsigned int scheduled : 1;
38 unsigned int no_init : 1;
39 unsigned int starting : 1;
40 } *SilcLogSettings, SilcLogSettingsStruct;
51 } *SilcLog, SilcLogStruct;
55 /* Default settings */
56 static SilcLogSettingsStruct silclog =
71 #endif /* !SILC_SYMBIAN */
73 /* Default log contexts */
75 static SilcLogStruct silclogs[4] =
77 const SilcLogStruct silclogs[4] =
78 #endif /* !SILC_SYMBIAN */
80 {"", NULL, 0, "Info", SILC_LOG_INFO, NULL, NULL},
81 {"", NULL, 0, "Warning", SILC_LOG_WARNING, NULL, NULL},
82 {"", NULL, 0, "Error", SILC_LOG_ERROR, NULL, NULL},
83 {"", NULL, 0, "Fatal", SILC_LOG_FATAL, NULL, NULL},
86 /* Return log context by type */
88 static SilcLog silc_log_get_context(SilcLogType type)
90 if (type < 1 || type > 4)
92 return (SilcLog)&silclogs[(int)type - 1];
95 /* Check log file site and cycle log file if it is over max size. */
97 static void silc_log_checksize(SilcLog log)
102 if (!log || !log->fp || !log->maxsize)
105 size = silc_file_size(log->filename);
111 if (size < log->maxsize)
116 "[%s] [%s] Cycling log file, over max log size (%lu kilobytes)\n",
117 silc_time_string(0), log->typename,
118 (unsigned long)log->maxsize / 1024);
122 memset(newname, 0, sizeof(newname));
123 silc_snprintf(newname, sizeof(newname) - 1, "%s.old", log->filename);
125 rename(log->filename, newname);
127 log->fp = fopen(log->filename, "w");
129 SILC_LOG_WARNING(("Couldn't reopen log file '%s' for type '%s': %s",
130 log->filename, log->typename, strerror(errno)));
132 chmod(log->filename, 0600);
133 #endif /* HAVE_CHMOD */
136 /* Internal timeout callback to flush log channels and check file sizes */
138 SILC_TASK_CALLBACK(silc_log_fflush_callback)
143 if (!silclog.quick) {
144 silc_log_flush_all();
145 log = silc_log_get_context(SILC_LOG_INFO);
146 silc_log_checksize(log);
147 log = silc_log_get_context(SILC_LOG_WARNING);
148 silc_log_checksize(log);
149 log = silc_log_get_context(SILC_LOG_ERROR);
150 silc_log_checksize(log);
151 log = silc_log_get_context(SILC_LOG_FATAL);
152 silc_log_checksize(log);
155 silclog.starting = FALSE;
157 if (silclog.flushdelay < 2)
158 silclog.flushdelay = 2;
159 silc_schedule_task_add_timeout(context, silc_log_fflush_callback, context,
160 silclog.flushdelay, 0);
161 #endif /* !SILC_SYMBIAN */
164 /* Output log message to log file */
166 void silc_log_output(SilcLogType type, char *string)
168 const char *typename = NULL;
169 SilcLog log = silc_log_get_context(type);
175 /* Forward to callback if set */
177 if ((*log->cb)(type, string, log->context))
180 typename = log->typename;
183 if (!silclog.scheduled) {
184 if (silclog.no_init == FALSE) {
186 "Warning, trying to output without log files initialization, "
187 "log output is going to stderr\n");
188 silclog.no_init = TRUE;
195 #endif /* !SILC_SYMBIAN */
197 /* Find open log file */
204 log = silc_log_get_context(--type);
206 if (!log || !log->fp)
211 if (silclog.timestamp)
212 fprintf(fp, "[%s] [%s] %s\n", silc_time_string(0), typename, string);
214 fprintf(fp, "[%s] %s\n", typename, string);
216 if (silclog.quick || silclog.starting) {
219 silc_log_checksize(log);
221 #endif /* !SILC_SYMBIAN */
225 /* Output log to stderr if debugging */
226 if (typename && silclog.debug) {
227 fprintf(stderr, "[Logging] [%s] %s\n", typename, string);
231 fprintf(stderr, "[Logging] [%s] %s\n", typename, string);
232 #endif /* !SILC_SYMBIAN */
237 /* Set and initialize the specified log file. */
239 SilcBool silc_log_set_file(SilcLogType type, char *filename,
240 SilcUInt32 maxsize, SilcSchedule scheduler)
246 log = silc_log_get_context(type);
250 SILC_LOG_DEBUG(("Setting '%s' file to %s (max size=%d)",
251 log->typename, filename, maxsize));
255 fp = fopen(filename, "a+");
257 fprintf(stderr, "warning: couldn't open log file '%s': %s\n",
258 filename, strerror(errno));
262 chmod(filename, 0600);
263 #endif /* HAVE_CHMOD */
266 /* Close previous log file if it exists */
267 if (strlen(log->filename)) {
270 memset(log->filename, 0, sizeof(log->filename));
274 /* Set new log file */
277 log->maxsize = maxsize;
279 memset(log->filename, 0, sizeof(log->filename));
280 silc_strncat(log->filename, sizeof(log->filename), filename,
284 /* Add flush timeout */
286 silc_schedule_task_del_by_callback(scheduler, silc_log_fflush_callback);
287 silc_schedule_task_add_timeout(scheduler, silc_log_fflush_callback,
289 silclog.scheduled = TRUE;
292 #endif /* !SILC_SYMBIAN */
296 /* Return log filename */
298 char *silc_log_get_file(SilcLogType type)
300 SilcLog log = silc_log_get_context(type);
301 return log && log->fp ? log->filename : NULL;
304 /* Sets a log callback, set callback to NULL to return to default behaviour */
306 void silc_log_set_callback(SilcLogType type, SilcLogCb cb, void *context)
309 SilcLog log = silc_log_get_context(type);
312 log->context = context;
314 #endif /* !SILC_SYMBIAN */
317 /* Reset log callbacks */
319 void silc_log_reset_callbacks(void)
323 log = silc_log_get_context(SILC_LOG_INFO);
324 log->cb = log->context = NULL;
325 log = silc_log_get_context(SILC_LOG_WARNING);
326 log->cb = log->context = NULL;
327 log = silc_log_get_context(SILC_LOG_ERROR);
328 log->cb = log->context = NULL;
329 log = silc_log_get_context(SILC_LOG_FATAL);
330 log->cb = log->context = NULL;
331 #endif /* !SILC_SYMBIAN */
334 /* Flush all log files */
336 void silc_log_flush_all(void)
339 log = silc_log_get_context(SILC_LOG_INFO);
342 log = silc_log_get_context(SILC_LOG_WARNING);
345 log = silc_log_get_context(SILC_LOG_ERROR);
348 log = silc_log_get_context(SILC_LOG_FATAL);
353 /* Reset a log file */
355 static void silc_log_reset(SilcLog log)
362 if (!strlen(log->filename))
365 log->fp = fopen(log->filename, "a+");
367 SILC_LOG_WARNING(("Couldn't reset log file '%s' for type '%s': %s",
368 log->filename, log->typename, strerror(errno)));
371 /* Reset all log files */
373 void silc_log_reset_all(void)
376 log = silc_log_get_context(SILC_LOG_INFO);
379 log = silc_log_get_context(SILC_LOG_WARNING);
382 log = silc_log_get_context(SILC_LOG_ERROR);
385 log = silc_log_get_context(SILC_LOG_FATAL);
388 silc_log_flush_all();
391 /* Sets debug callbacks */
393 void silc_log_set_debug_callbacks(SilcLogDebugCb debug_cb,
395 SilcLogHexdumpCb hexdump_cb,
396 void *hexdump_context)
399 silclog.debug_cb = debug_cb;
400 silclog.debug_context = debug_context;
401 silclog.hexdump_cb = hexdump_cb;
402 silclog.hexdump_context = hexdump_context;
403 #endif /* !SILC_SYMBIAN */
406 /* Resets debug callbacks */
408 void silc_log_reset_debug_callbacks()
411 silclog.debug_cb = NULL;
412 silclog.debug_context = NULL;
413 silclog.hexdump_cb = NULL;
414 silclog.hexdump_context = NULL;
415 #endif /* !SILC_SYMBIAN */
418 /* Set current debug string */
420 void silc_log_set_debug_string(const char *debug_string)
425 if ((strchr(debug_string, '(') && strchr(debug_string, ')')) ||
426 strchr(debug_string, '$'))
427 string = strdup(debug_string);
429 string = silc_string_regexify(debug_string);
430 len = strlen(string);
431 if (len >= sizeof(silclog.debug_string))
432 len = sizeof(silclog.debug_string) - 1;
433 memset(silclog.debug_string, 0, sizeof(silclog.debug_string));
434 strncpy(silclog.debug_string, string, len);
436 #endif /* !SILC_SYMBIAN */
441 void silc_log_timestamp(SilcBool enable)
444 silclog.timestamp = enable;
445 #endif /* !SILC_SYMBIAN */
450 void silc_log_flushdelay(SilcUInt32 flushdelay)
453 silclog.flushdelay = flushdelay;
454 #endif /* !SILC_SYMBIAN */
457 /* Set quick logging */
459 void silc_log_quick(SilcBool enable)
462 silclog.quick = enable;
463 #endif /* !SILC_SYMBIAN */
468 void silc_log_debug(SilcBool enable)
471 silclog.debug = enable;
472 #endif /* !SILC_SYMBIAN */
475 /* Set debug hexdump */
477 void silc_log_debug_hexdump(SilcBool enable)
480 silclog.debug_hexdump = enable;
481 #endif /* !SILC_SYMBIAN */
484 /* Outputs the debug message to stderr. */
486 void silc_log_output_debug(char *file, const char *function,
487 int line, char *string)
489 SilcTimeStruct curtime;
495 if (!silc_string_regex_match(silclog.debug_string, file) &&
496 !silc_string_regex_match(silclog.debug_string, function))
499 if (silclog.debug_cb) {
500 if ((*silclog.debug_cb)(file, (char *)function, line, string,
501 silclog.debug_context))
504 #endif /* !SILC_SYMBIAN */
506 silc_time_value(0, &curtime);
509 if (strrchr(function, '\\'))
510 fprintf(stderr, "%s:%d: %s\n", strrchr(function, '\\') + 1, line, string);
512 #endif /* SILC_WIN32 */
514 silc_symbian_debug(function, line, string);
516 fprintf(stderr, "%02d:%02d:%02d %s:%d: %s\n", curtime.hour,
517 curtime.minute, curtime.second, function, line,
520 #endif /* SILC_SYMBIAN */
526 /* Hexdumps a message */
528 void silc_log_output_hexdump(char *file, const char *function,
529 int line, void *data_in,
530 SilcUInt32 len, char *string)
534 unsigned char *data = (unsigned char *)data_in;
537 if (!silclog.debug_hexdump)
540 if (!silc_string_regex_match(silclog.debug_string, file) &&
541 !silc_string_regex_match(silclog.debug_string, function))
544 if (silclog.hexdump_cb) {
545 if ((*silclog.hexdump_cb)(file, (char *)function, line,
546 data_in, len, string, silclog.hexdump_context))
549 #endif /* !SILC_SYMBIAN */
551 fprintf(stderr, "%s:%d: %s\n", function, line, string);
559 if ((len - pos) < 16 && (len - pos <= len - off))
569 fprintf(stderr, "%08X ", k++ * 16);
571 for (i = 0; i < count; i++) {
572 fprintf(stderr, "%02X ", data[pos + i]);
574 if ((i + 1) % 4 == 0)
575 fprintf(stderr, " ");
578 if (count && count < 16) {
581 for (j = 0; j < 16 - count; j++) {
582 fprintf(stderr, " ");
584 if ((j + count + 1) % 4 == 0)
585 fprintf(stderr, " ");
589 for (i = 0; i < count; i++) {
592 if (data[pos] < 32 || data[pos] >= 127)
597 fprintf(stderr, "%c", ch);
602 fprintf(stderr, "\n");