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);
121 memset(newname, 0, sizeof(newname));
122 silc_snprintf(newname, sizeof(newname) - 1, "%s.old", log->filename);
124 if (rename(log->filename, newname)) {
126 "[%s] [%s] Couldn't recycle log file '%s' for type '%s': %s",
127 silc_time_string(0), log->typename,
128 log->filename, log->typename, strerror(errno));
134 log->fp = fopen(log->filename, "w");
136 SILC_LOG_WARNING(("Couldn't reopen log file '%s' for type '%s': %s",
137 log->filename, log->typename, strerror(errno)));
141 chmod(log->filename, 0600);
142 #endif /* HAVE_CHMOD */
145 /* Internal timeout callback to flush log channels and check file sizes */
147 SILC_TASK_CALLBACK(silc_log_fflush_callback)
152 if (!silclog.quick) {
153 silc_log_flush_all();
154 log = silc_log_get_context(SILC_LOG_INFO);
155 silc_log_checksize(log);
156 log = silc_log_get_context(SILC_LOG_WARNING);
157 silc_log_checksize(log);
158 log = silc_log_get_context(SILC_LOG_ERROR);
159 silc_log_checksize(log);
160 log = silc_log_get_context(SILC_LOG_FATAL);
161 silc_log_checksize(log);
164 silclog.starting = FALSE;
166 if (silclog.flushdelay < 2)
167 silclog.flushdelay = 2;
168 silc_schedule_task_add_timeout(context, silc_log_fflush_callback, context,
169 silclog.flushdelay, 0);
170 #endif /* !SILC_SYMBIAN */
173 /* Output log message to log file */
175 void silc_log_output(SilcLogType type, char *string)
177 const char *typename = NULL;
178 SilcLog log = silc_log_get_context(type);
184 /* Forward to callback if set */
186 if ((*log->cb)(type, string, log->context))
189 typename = log->typename;
192 if (!silclog.scheduled) {
193 if (silclog.no_init == FALSE) {
195 "Warning, trying to output without log files initialization, "
196 "log output is going to stderr\n");
197 silclog.no_init = TRUE;
204 #endif /* !SILC_SYMBIAN */
206 /* Find open log file */
213 log = silc_log_get_context(--type);
215 if (!log || !log->fp)
220 if (silclog.timestamp)
221 fprintf(fp, "[%s] [%s] %s\n", silc_time_string(0), typename, string);
223 fprintf(fp, "[%s] %s\n", typename, string);
225 if (silclog.quick || silclog.starting) {
228 silc_log_checksize(log);
230 #endif /* !SILC_SYMBIAN */
234 /* Output log to stderr if debugging */
235 if (typename && silclog.debug) {
236 fprintf(stderr, "[Logging] [%s] %s\n", typename, string);
240 fprintf(stderr, "[Logging] [%s] %s\n", typename, string);
241 #endif /* !SILC_SYMBIAN */
246 /* Set and initialize the specified log file. */
248 SilcBool silc_log_set_file(SilcLogType type, char *filename,
249 SilcUInt32 maxsize, SilcSchedule scheduler)
255 log = silc_log_get_context(type);
259 SILC_LOG_DEBUG(("Setting '%s' file to %s (max size=%d)",
260 log->typename, filename, maxsize));
264 fp = fopen(filename, "a+");
266 fprintf(stderr, "warning: couldn't open log file '%s': %s\n",
267 filename, strerror(errno));
271 chmod(filename, 0600);
272 #endif /* HAVE_CHMOD */
275 /* Close previous log file if it exists */
276 if (strlen(log->filename)) {
279 memset(log->filename, 0, sizeof(log->filename));
283 /* Set new log file */
286 log->maxsize = maxsize;
288 memset(log->filename, 0, sizeof(log->filename));
289 silc_strncat(log->filename, sizeof(log->filename), filename,
293 /* Add flush timeout */
295 silc_schedule_task_del_by_callback(scheduler, silc_log_fflush_callback);
296 silc_schedule_task_add_timeout(scheduler, silc_log_fflush_callback,
298 silclog.scheduled = TRUE;
301 #endif /* !SILC_SYMBIAN */
305 /* Return log filename */
307 char *silc_log_get_file(SilcLogType type)
309 SilcLog log = silc_log_get_context(type);
310 return log && log->fp ? log->filename : NULL;
313 /* Sets a log callback, set callback to NULL to return to default behaviour */
315 void silc_log_set_callback(SilcLogType type, SilcLogCb cb, void *context)
318 SilcLog log = silc_log_get_context(type);
321 log->context = context;
323 #endif /* !SILC_SYMBIAN */
326 /* Reset log callbacks */
328 void silc_log_reset_callbacks(void)
332 log = silc_log_get_context(SILC_LOG_INFO);
333 log->cb = log->context = NULL;
334 log = silc_log_get_context(SILC_LOG_WARNING);
335 log->cb = log->context = NULL;
336 log = silc_log_get_context(SILC_LOG_ERROR);
337 log->cb = log->context = NULL;
338 log = silc_log_get_context(SILC_LOG_FATAL);
339 log->cb = log->context = NULL;
340 #endif /* !SILC_SYMBIAN */
343 /* Flush all log files */
345 void silc_log_flush_all(void)
348 log = silc_log_get_context(SILC_LOG_INFO);
351 log = silc_log_get_context(SILC_LOG_WARNING);
354 log = silc_log_get_context(SILC_LOG_ERROR);
357 log = silc_log_get_context(SILC_LOG_FATAL);
362 /* Reset a log file */
364 static void silc_log_reset(SilcLog log)
371 if (!strlen(log->filename))
374 log->fp = fopen(log->filename, "a+");
376 SILC_LOG_WARNING(("Couldn't reset log file '%s' for type '%s': %s",
377 log->filename, log->typename, strerror(errno)));
380 /* Reset all log files */
382 void silc_log_reset_all(void)
385 log = silc_log_get_context(SILC_LOG_INFO);
388 log = silc_log_get_context(SILC_LOG_WARNING);
391 log = silc_log_get_context(SILC_LOG_ERROR);
394 log = silc_log_get_context(SILC_LOG_FATAL);
397 silc_log_flush_all();
400 /* Sets debug callbacks */
402 void silc_log_set_debug_callbacks(SilcLogDebugCb debug_cb,
404 SilcLogHexdumpCb hexdump_cb,
405 void *hexdump_context)
408 silclog.debug_cb = debug_cb;
409 silclog.debug_context = debug_context;
410 silclog.hexdump_cb = hexdump_cb;
411 silclog.hexdump_context = hexdump_context;
412 #endif /* !SILC_SYMBIAN */
415 /* Resets debug callbacks */
417 void silc_log_reset_debug_callbacks()
420 silclog.debug_cb = NULL;
421 silclog.debug_context = NULL;
422 silclog.hexdump_cb = NULL;
423 silclog.hexdump_context = NULL;
424 #endif /* !SILC_SYMBIAN */
427 /* Set current debug string */
429 void silc_log_set_debug_string(const char *debug_string)
434 if ((strchr(debug_string, '(') && strchr(debug_string, ')')) ||
435 strchr(debug_string, '$'))
436 string = strdup(debug_string);
438 string = silc_string_regexify(debug_string);
439 len = strlen(string);
440 if (len >= sizeof(silclog.debug_string))
441 len = sizeof(silclog.debug_string) - 1;
442 memset(silclog.debug_string, 0, sizeof(silclog.debug_string));
443 strncpy(silclog.debug_string, string, len);
445 #endif /* !SILC_SYMBIAN */
450 void silc_log_timestamp(SilcBool enable)
453 silclog.timestamp = enable;
454 #endif /* !SILC_SYMBIAN */
459 void silc_log_flushdelay(SilcUInt32 flushdelay)
462 silclog.flushdelay = flushdelay;
463 #endif /* !SILC_SYMBIAN */
466 /* Set quick logging */
468 void silc_log_quick(SilcBool enable)
471 silclog.quick = enable;
472 #endif /* !SILC_SYMBIAN */
477 void silc_log_debug(SilcBool enable)
480 silclog.debug = enable;
481 #endif /* !SILC_SYMBIAN */
484 /* Set debug hexdump */
486 void silc_log_debug_hexdump(SilcBool enable)
489 silclog.debug_hexdump = enable;
490 #endif /* !SILC_SYMBIAN */
493 /* Outputs the debug message to stderr. */
495 void silc_log_output_debug(char *file, const char *function,
496 int line, char *string)
498 SilcTimeStruct curtime;
504 if (!silc_string_regex_match(silclog.debug_string, file) &&
505 !silc_string_regex_match(silclog.debug_string, function))
508 if (silclog.debug_cb) {
509 if ((*silclog.debug_cb)(file, (char *)function, line, string,
510 silclog.debug_context))
513 #endif /* !SILC_SYMBIAN */
515 silc_time_value(0, &curtime);
518 if (strrchr(function, '\\'))
519 fprintf(stderr, "%s:%d: %s\n", strrchr(function, '\\') + 1, line, string);
521 #endif /* SILC_WIN32 */
523 silc_symbian_debug(function, line, string);
525 fprintf(stderr, "%02d:%02d:%02d %s:%d: %s\n", curtime.hour,
526 curtime.minute, curtime.second, function, line,
529 #endif /* SILC_SYMBIAN */
535 /* Hexdumps a message */
537 void silc_log_output_hexdump(char *file, const char *function,
538 int line, void *data_in,
539 SilcUInt32 len, char *string)
543 unsigned char *data = (unsigned char *)data_in;
546 if (!silclog.debug_hexdump)
549 if (!silc_string_regex_match(silclog.debug_string, file) &&
550 !silc_string_regex_match(silclog.debug_string, function))
553 if (silclog.hexdump_cb) {
554 if ((*silclog.hexdump_cb)(file, (char *)function, line,
555 data_in, len, string, silclog.hexdump_context))
558 #endif /* !SILC_SYMBIAN */
560 fprintf(stderr, "%s:%d: %s\n", function, line, string);
568 if ((len - pos) < 16 && (len - pos <= len - off))
578 fprintf(stderr, "%08X ", k++ * 16);
580 for (i = 0; i < count; i++) {
581 fprintf(stderr, "%02X ", data[pos + i]);
583 if ((i + 1) % 4 == 0)
584 fprintf(stderr, " ");
587 if (count && count < 16) {
590 for (j = 0; j < 16 - count; j++) {
591 fprintf(stderr, " ");
593 if ((j + count + 1) % 4 == 0)
594 fprintf(stderr, " ");
598 for (i = 0; i < count; i++) {
601 if (data[pos] < 32 || data[pos] >= 127)
606 fprintf(stderr, "%c", ch);
611 fprintf(stderr, "\n");