Resolve many DOCDOCs.
[tor/rransom.git] / src / common / log.c
blobd93bc8a5563b77a97ab94b4d7f0e02010b1c5ff4
1 /* Copyright (c) 2001, Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2008, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 /* $Id$ */
7 const char log_c_id[] = "$Id$";
9 /**
10 * \file log.c
11 * \brief Functions to send messages to log files or the console.
12 **/
14 #include "orconfig.h"
15 #include <stdarg.h>
16 #include <assert.h>
17 // #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #ifdef HAVE_SYS_TIME_H
21 #include <sys/time.h>
22 #endif
23 #ifdef HAVE_TIME_H
24 #include <time.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_FCNTL_H
33 #include <fcntl.h>
34 #endif
35 #include "compat.h"
36 #include "util.h"
37 #define LOG_PRIVATE
38 #include "log.h"
39 #include "container.h"
41 #include <event.h>
43 #define TRUNCATED_STR "[...truncated]"
44 #define TRUNCATED_STR_LEN 14
46 /** Information for a single logfile; only used in log.c */
47 typedef struct logfile_t {
48 struct logfile_t *next; /**< Next logfile_t in the linked list. */
49 char *filename; /**< Filename to open. */
50 int fd; /**< fd to receive log messages, or -1 for none. */
51 int seems_dead; /**< Boolean: true if the stream seems to be kaput. */
52 int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
53 int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
54 int is_syslog; /**< Boolean: send messages to syslog. */
55 log_callback callback; /**< If not NULL, send messages to this function. */
56 log_severity_list_t *severities; /**< Which severity of messages should we
57 * log for each log domain? */
58 } logfile_t;
60 static void log_free(logfile_t *victim);
62 /** Helper: map a log severity to descriptive string. */
63 static INLINE const char *
64 sev_to_string(int severity)
66 switch (severity) {
67 case LOG_DEBUG: return "debug";
68 case LOG_INFO: return "info";
69 case LOG_NOTICE: return "notice";
70 case LOG_WARN: return "warn";
71 case LOG_ERR: return "err";
72 default: /* Call assert, not tor_assert, since tor_assert
73 * calls log on failure. */
74 assert(0); return "UNKNOWN";
78 /** Helper: decide whether to include the function name in the log message. */
79 static INLINE int
80 should_log_function_name(log_domain_mask_t domain, int severity)
82 switch (severity) {
83 case LOG_DEBUG:
84 case LOG_INFO:
85 /* All debugging messages occur in interesting places. */
86 return 1;
87 case LOG_NOTICE:
88 case LOG_WARN:
89 case LOG_ERR:
90 /* We care about places where bugs occur. */
91 return (domain == LD_BUG);
92 default:
93 /* Call assert, not tor_assert, since tor_assert calls log on failure. */
94 assert(0); return 0;
98 #define USE_LOG_MUTEX
100 #ifdef USE_LOG_MUTEX
101 /** A mutex to guard changes to logfiles and logging. */
102 static tor_mutex_t *log_mutex = NULL;
103 #endif
104 /** Linked list of logfile_t. */
105 static logfile_t *logfiles = NULL;
106 #ifdef HAVE_SYSLOG_H
107 static int syslog_count = 0;
108 #endif
110 #ifdef USE_LOG_MUTEX
111 #define LOCK_LOGS() STMT_BEGIN \
112 tor_mutex_acquire(log_mutex); \
113 STMT_END
114 #define UNLOCK_LOGS() STMT_BEGIN tor_mutex_release(log_mutex); STMT_END
115 #else
116 #define LOCK_LOGS() STMT_NIL
117 #define UNLOCK_LOGS() STMT_NIL
118 #endif
120 /* What's the lowest log level anybody cares about? */
121 int _log_global_min_severity = LOG_NOTICE;
123 static void delete_log(logfile_t *victim);
124 static void close_log(logfile_t *victim);
126 /** Name of the application: used to generate the message we write at the
127 * start of each new log. */
128 static char *appname = NULL;
130 /** Set the "application name" for the logs to <b>name</b>: we'll use this
131 * name in the message we write when starting up, and at the start of each new
132 * log.
134 * Tor uses this string to write the version number to the log file. */
135 void
136 log_set_application_name(const char *name)
138 tor_free(appname);
139 appname = name ? tor_strdup(name) : NULL;
142 /** Helper: Write the standard prefix for log lines to a
143 * <b>buf_len</b> character buffer in <b>buf</b>.
145 static INLINE size_t
146 _log_prefix(char *buf, size_t buf_len, int severity)
148 time_t t;
149 struct timeval now;
150 struct tm tm;
151 size_t n;
152 int r;
154 tor_gettimeofday(&now);
155 t = (time_t)now.tv_sec;
157 n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm));
158 r = tor_snprintf(buf+n, buf_len-n, ".%.3ld [%s] ",
159 (long)now.tv_usec / 1000, sev_to_string(severity));
160 if (r<0)
161 return buf_len-1;
162 else
163 return n+r;
166 /** If lf refers to an actual file that we have just opened, and the file
167 * contains no data, log an "opening new logfile" message at the top.
169 * Return -1 if the log is broken and needs to be deleted, else return 0.
171 static int
172 log_tor_version(logfile_t *lf, int reset)
174 char buf[256];
175 size_t n;
176 int is_new;
178 if (!lf->needs_close)
179 /* If it doesn't get closed, it isn't really a file. */
180 return 0;
181 if (lf->is_temporary)
182 /* If it's temporary, it isn't really a file. */
183 return 0;
185 is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0;
187 if (reset && !is_new)
188 /* We are resetting, but we aren't at the start of the file; no
189 * need to log again. */
190 return 0;
191 n = _log_prefix(buf, sizeof(buf), LOG_NOTICE);
192 if (appname) {
193 tor_snprintf(buf+n, sizeof(buf)-n,
194 "%s opening %slog file.\n", appname, is_new?"new ":"");
195 } else {
196 tor_snprintf(buf+n, sizeof(buf)-n,
197 "Tor %s opening %slog file.\n", VERSION, is_new?"new ":"");
199 if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */
200 return -1; /* failed */
201 return 0;
204 /** Helper: Format a log message into a fixed-sized buffer. (This is
205 * factored out of <b>logv</b> so that we never format a message more
206 * than once.) Return a pointer to the first character of the message
207 * portion of the formatted string.
209 static INLINE char *
210 format_msg(char *buf, size_t buf_len,
211 log_domain_mask_t domain, int severity, const char *funcname,
212 const char *format, va_list ap, size_t *msg_len_out)
214 size_t n;
215 int r;
216 char *end_of_prefix;
218 assert(buf_len >= 2); /* prevent integer underflow */
219 buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
221 n = _log_prefix(buf, buf_len, severity);
222 end_of_prefix = buf+n;
224 if (funcname && should_log_function_name(domain, severity)) {
225 r = tor_snprintf(buf+n, buf_len-n, "%s(): ", funcname);
226 if (r<0)
227 n = strlen(buf);
228 else
229 n += r;
232 if (domain == LD_BUG && buf_len-n > 6) {
233 memcpy(buf+n, "Bug: ", 6);
234 n += 5;
237 r = tor_vsnprintf(buf+n,buf_len-n,format,ap);
238 if (r < 0) {
239 /* The message was too long; overwrite the end of the buffer with
240 * "[...truncated]" */
241 if (buf_len >= TRUNCATED_STR_LEN) {
242 size_t offset = buf_len-TRUNCATED_STR_LEN;
243 /* We have an extra 2 characters after buf_len to hold the \n\0,
244 * so it's safe to add 1 to the size here. */
245 strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1);
247 /* Set 'n' to the end of the buffer, where we'll be writing \n\0.
248 * Since we already subtracted 2 from buf_len, this is safe.*/
249 n = buf_len;
250 } else {
251 n += r;
253 buf[n]='\n';
254 buf[n+1]='\0';
255 *msg_len_out = n+1;
256 return end_of_prefix;
259 /** Helper: sends a message to the appropriate logfiles, at loglevel
260 * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
261 * message. The actual message is derived as from tor_snprintf(format,ap).
263 static void
264 logv(int severity, log_domain_mask_t domain, const char *funcname,
265 const char *format, va_list ap)
267 char buf[10024];
268 size_t msg_len = 0;
269 int formatted = 0;
270 logfile_t *lf;
271 char *end_of_prefix=NULL;
273 /* Call assert, not tor_assert, since tor_assert calls log on failure. */
274 assert(format);
275 /* check that severity is sane. Overrunning the masks array leads to
276 * interesting and hard to diagnose effects */
277 assert(severity >= LOG_ERR && severity <= LOG_DEBUG);
278 LOCK_LOGS();
279 lf = logfiles;
280 while (lf) {
281 if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
282 lf = lf->next;
283 continue;
285 if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
286 lf = lf->next;
287 continue;
289 if (lf->seems_dead) {
290 lf = lf->next;
291 continue;
294 if (!formatted) {
295 end_of_prefix =
296 format_msg(buf, sizeof(buf), domain, severity, funcname, format, ap,
297 &msg_len);
298 formatted = 1;
300 if (lf->is_syslog) {
301 #ifdef HAVE_SYSLOG_H
302 /* XXXX Some syslog implementations have scary limits on the length of
303 * what you can pass them. Can/should we detect this? */
304 syslog(severity, "%s", end_of_prefix);
305 #endif
306 lf = lf->next;
307 continue;
308 } else if (lf->callback) {
309 lf->callback(severity, domain, end_of_prefix);
310 lf = lf->next;
311 continue;
313 if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */
314 /* don't log the error! mark this log entry to be blown away, and
315 * continue. */
316 lf->seems_dead = 1;
318 lf = lf->next;
320 UNLOCK_LOGS();
323 /** Output a message to the log. */
324 void
325 _log(int severity, log_domain_mask_t domain, const char *format, ...)
327 va_list ap;
328 if (severity > _log_global_min_severity)
329 return;
330 va_start(ap,format);
331 logv(severity, domain, NULL, format, ap);
332 va_end(ap);
335 /** Output a message to the log, prefixed with a function name <b>fn</b>. */
336 #ifdef __GNUC__
337 void
338 _log_fn(int severity, log_domain_mask_t domain, const char *fn,
339 const char *format, ...)
341 va_list ap;
342 if (severity > _log_global_min_severity)
343 return;
344 va_start(ap,format);
345 logv(severity, domain, fn, format, ap);
346 va_end(ap);
348 #else
349 const char *_log_fn_function_name=NULL;
350 void
351 _log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
353 va_list ap;
354 if (severity > _log_global_min_severity)
355 return;
356 va_start(ap,format);
357 logv(severity, domain, _log_fn_function_name, format, ap);
358 va_end(ap);
359 _log_fn_function_name = NULL;
361 void
362 _log_debug(log_domain_mask_t domain, const char *format, ...)
364 va_list ap;
365 /* For GCC we do this check in the macro. */
366 if (PREDICT_LIKELY(LOG_DEBUG > _log_global_min_severity))
367 return;
368 va_start(ap,format);
369 logv(LOG_DEBUG, domain, _log_fn_function_name, format, ap);
370 va_end(ap);
371 _log_fn_function_name = NULL;
373 void
374 _log_info(log_domain_mask_t domain, const char *format, ...)
376 va_list ap;
377 if (LOG_INFO > _log_global_min_severity)
378 return;
379 va_start(ap,format);
380 logv(LOG_INFO, domain, _log_fn_function_name, format, ap);
381 va_end(ap);
382 _log_fn_function_name = NULL;
384 void
385 _log_notice(log_domain_mask_t domain, const char *format, ...)
387 va_list ap;
388 if (LOG_NOTICE > _log_global_min_severity)
389 return;
390 va_start(ap,format);
391 logv(LOG_NOTICE, domain, _log_fn_function_name, format, ap);
392 va_end(ap);
393 _log_fn_function_name = NULL;
395 void
396 _log_warn(log_domain_mask_t domain, const char *format, ...)
398 va_list ap;
399 if (LOG_WARN > _log_global_min_severity)
400 return;
401 va_start(ap,format);
402 logv(LOG_WARN, domain, _log_fn_function_name, format, ap);
403 va_end(ap);
404 _log_fn_function_name = NULL;
406 void
407 _log_err(log_domain_mask_t domain, const char *format, ...)
409 va_list ap;
410 if (LOG_ERR > _log_global_min_severity)
411 return;
412 va_start(ap,format);
413 logv(LOG_ERR, domain, _log_fn_function_name, format, ap);
414 va_end(ap);
415 _log_fn_function_name = NULL;
417 #endif
419 /** Free all storage held by <b>victim</b>. */
420 static void
421 log_free(logfile_t *victim)
423 tor_free(victim->severities);
424 tor_free(victim->filename);
425 tor_free(victim);
428 /** Close all open log files, and free other static memory. */
429 void
430 logs_free_all(void)
432 logfile_t *victim, *next;
433 LOCK_LOGS();
434 next = logfiles;
435 logfiles = NULL;
436 UNLOCK_LOGS();
437 while (next) {
438 victim = next;
439 next = next->next;
440 close_log(victim);
441 log_free(victim);
443 tor_free(appname);
444 tor_mutex_free(log_mutex);
445 log_mutex = NULL;
448 /** Remove and free the log entry <b>victim</b> from the linked-list
449 * logfiles (it is probably present, but it might not be due to thread
450 * racing issues). After this function is called, the caller shouldn't
451 * refer to <b>victim</b> anymore.
453 * Long-term, we need to do something about races in the log subsystem
454 * in general. See bug 222 for more details.
456 static void
457 delete_log(logfile_t *victim)
459 logfile_t *tmpl;
460 if (victim == logfiles)
461 logfiles = victim->next;
462 else {
463 for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ;
464 // tor_assert(tmpl);
465 // tor_assert(tmpl->next == victim);
466 if (!tmpl)
467 return;
468 tmpl->next = victim->next;
470 log_free(victim);
473 /** Helper: release system resources (but not memory) held by a single
474 * logfile_t. */
475 static void
476 close_log(logfile_t *victim)
478 if (victim->needs_close && victim->fd >= 0) {
479 close(victim->fd);
480 victim->fd = -1;
481 } else if (victim->is_syslog) {
482 #ifdef HAVE_SYSLOG_H
483 if (--syslog_count == 0) {
484 /* There are no other syslogs; close the logging facility. */
485 closelog();
487 #endif
491 /** Adjust a log severity configuration in <b>severity_out</b> to contain
492 * every domain between <b>loglevelMin</b> and <b>loglevelMax</b>, inclusive.
494 void
495 set_log_severity_config(int loglevelMin, int loglevelMax,
496 log_severity_list_t *severity_out)
498 int i;
499 tor_assert(loglevelMin >= loglevelMax);
500 tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG);
501 tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG);
502 memset(severity_out, 0, sizeof(log_severity_list_t));
503 for (i = loglevelMin; i >= loglevelMax; --i) {
504 severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u;
508 /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
509 * to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
510 static void
511 add_stream_log_impl(const log_severity_list_t *severity,
512 const char *name, int fd)
514 logfile_t *lf;
515 lf = tor_malloc_zero(sizeof(logfile_t));
516 lf->fd = fd;
517 lf->filename = tor_strdup(name);
518 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
519 lf->next = logfiles;
521 logfiles = lf;
522 _log_global_min_severity = get_min_log_level();
525 /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
526 * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must
527 * not use it after calling this function. */
528 void
529 add_stream_log(const log_severity_list_t *severity,
530 const char *name, int fd)
532 LOCK_LOGS();
533 add_stream_log_impl(severity, name, fd);
534 UNLOCK_LOGS();
537 /** Initialize the global logging facility */
538 void
539 init_logging(void)
541 if (!log_mutex)
542 log_mutex = tor_mutex_new();
545 /** Add a log handler to receive messages during startup (before the real
546 * logs are initialized).
548 void
549 add_temp_log(int min_severity)
551 log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
552 set_log_severity_config(min_severity, LOG_ERR, s);
553 LOCK_LOGS();
554 add_stream_log_impl(s, "<temp>", fileno(stdout));
555 tor_free(s);
556 logfiles->is_temporary = 1;
557 UNLOCK_LOGS();
561 * Add a log handler to send messages in <b>severity</b>
562 * to the function <b>cb</b>.
565 add_callback_log(const log_severity_list_t *severity, log_callback cb)
567 logfile_t *lf;
568 lf = tor_malloc_zero(sizeof(logfile_t));
569 lf->fd = -1;
570 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
571 lf->filename = tor_strdup("<callback>");
572 lf->callback = cb;
573 lf->next = logfiles;
575 LOCK_LOGS();
576 logfiles = lf;
577 _log_global_min_severity = get_min_log_level();
578 UNLOCK_LOGS();
579 return 0;
582 /** Adjust the configured severity of any logs whose callback function is
583 * <b>cb</b>. */
584 void
585 change_callback_log_severity(int loglevelMin, int loglevelMax,
586 log_callback cb)
588 logfile_t *lf;
589 log_severity_list_t severities;
590 set_log_severity_config(loglevelMin, loglevelMax, &severities);
591 LOCK_LOGS();
592 for (lf = logfiles; lf; lf = lf->next) {
593 if (lf->callback == cb) {
594 memcpy(lf->severities, &severities, sizeof(severities));
597 _log_global_min_severity = get_min_log_level();
598 UNLOCK_LOGS();
601 /** Close any log handlers added by add_temp_log() or marked by
602 * mark_logs_temp(). */
603 void
604 close_temp_logs(void)
606 logfile_t *lf, **p;
608 LOCK_LOGS();
609 for (p = &logfiles; *p; ) {
610 if ((*p)->is_temporary) {
611 lf = *p;
612 /* we use *p here to handle the edge case of the head of the list */
613 *p = (*p)->next;
614 close_log(lf);
615 log_free(lf);
616 } else {
617 p = &((*p)->next);
621 _log_global_min_severity = get_min_log_level();
622 UNLOCK_LOGS();
625 /** Make all currently temporary logs (set to be closed by close_temp_logs)
626 * live again, and close all non-temporary logs. */
627 void
628 rollback_log_changes(void)
630 logfile_t *lf;
631 LOCK_LOGS();
632 for (lf = logfiles; lf; lf = lf->next)
633 lf->is_temporary = ! lf->is_temporary;
634 UNLOCK_LOGS();
635 close_temp_logs();
638 /** Configure all log handles to be closed by close_temp_logs(). */
639 void
640 mark_logs_temp(void)
642 logfile_t *lf;
643 LOCK_LOGS();
644 for (lf = logfiles; lf; lf = lf->next)
645 lf->is_temporary = 1;
646 UNLOCK_LOGS();
650 * Add a log handler to send messages to <b>filename</b>. If opening the
651 * logfile fails, -1 is returned and errno is set appropriately (by open(2)).
654 add_file_log(const log_severity_list_t *severity, const char *filename)
656 int fd;
657 logfile_t *lf;
659 fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
660 if (fd<0)
661 return -1;
662 if (tor_fd_seekend(fd)<0)
663 return -1;
665 LOCK_LOGS();
666 add_stream_log_impl(severity, filename, fd);
667 logfiles->needs_close = 1;
668 lf = logfiles;
669 _log_global_min_severity = get_min_log_level();
670 UNLOCK_LOGS();
672 if (log_tor_version(lf, 0) < 0) {
673 LOCK_LOGS();
674 delete_log(lf);
675 UNLOCK_LOGS();
678 return 0;
681 #ifdef HAVE_SYSLOG_H
683 * Add a log handler to send messages to they system log facility.
686 add_syslog_log(const log_severity_list_t *severity)
688 logfile_t *lf;
689 if (syslog_count++ == 0)
690 /* This is the first syslog. */
691 openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY);
693 lf = tor_malloc_zero(sizeof(logfile_t));
694 lf->fd = -1;
695 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
696 lf->filename = tor_strdup("<syslog>");
698 lf->is_syslog = 1;
700 LOCK_LOGS();
701 lf->next = logfiles;
702 logfiles = lf;
703 _log_global_min_severity = get_min_log_level();
704 UNLOCK_LOGS();
705 return 0;
707 #endif
709 /** If <b>level</b> is a valid log severity, return the corresponding
710 * numeric value. Otherwise, return -1. */
712 parse_log_level(const char *level)
714 if (!strcasecmp(level, "err"))
715 return LOG_ERR;
716 if (!strcasecmp(level, "warn"))
717 return LOG_WARN;
718 if (!strcasecmp(level, "notice"))
719 return LOG_NOTICE;
720 if (!strcasecmp(level, "info"))
721 return LOG_INFO;
722 if (!strcasecmp(level, "debug"))
723 return LOG_DEBUG;
724 return -1;
727 /** Return the string equivalent of a given log level. */
728 const char *
729 log_level_to_string(int level)
731 return sev_to_string(level);
734 /** NULL-terminated array of names for log domains such that domain_list[dom]
735 * is a description of <b>dom</b>. */
736 static const char *domain_list[] = {
737 "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
738 "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
739 "OR", "EDGE", "ACCT", "HIST", NULL
742 /** Return the log domain for which <b>domain</b> is the name, or 0 if there
743 * is no such name. */
744 /*XXXX021 0 could mean "no such domain" or LD_GENERAL. Fix that. */
745 static log_domain_mask_t
746 parse_log_domain(const char *domain)
748 int i;
749 for (i=0; domain_list[i]; ++i) {
750 if (!strcasecmp(domain, domain_list[i]))
751 return (1u<<i);
753 return 0;
755 #if 0
756 /** DOCDOC */
757 static const char *
758 domain_to_string(log_domain_mask_t domain)
760 int bit = tor_log2(domain);
761 if ((bit == 0 && domain == 0) || bit >= N_LOGGING_DOMAINS)
762 return NULL;
763 return domain_list[bit];
765 #endif
767 /** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after
768 * the end of the severityPattern. Set the value of <b>severity_out</b> to
769 * the parsed pattern. Return 0 on success, -1 on failure.
771 * The syntax for a SeverityPattern is:
772 * <pre>
773 * SeverityPattern = *(DomainSeverity SP)* DomainSeverity
774 * DomainSeverity = (DomainList SP)? SeverityRange
775 * SeverityRange = MinSeverity ("-" MaxSeverity )?
776 * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
777 * DomainSpec = "*" | Domain | "~" Domain
778 * </pre>
779 * A missing MaxSeverity defaults to ERR. Severities and domains are
780 * case-insensitive. "~" indicates negation for a domain; negation happens
781 * last inside a DomainList. Only one SeverityRange without a DomainList is
782 * allowed per line.
785 parse_log_severity_config(const char **cfg_ptr,
786 log_severity_list_t *severity_out)
788 const char *cfg = *cfg_ptr;
789 int got_anything = 0;
790 int got_an_unqualified_range = 0;
791 memset(severity_out, 0, sizeof(*severity_out));
793 cfg = eat_whitespace(cfg);
794 while (*cfg) {
795 const char *dash, *space;
796 char *sev_lo, *sev_hi;
797 int low, high, i;
798 log_domain_mask_t domains = ~0u;
800 if (*cfg == '[') {
801 int err = 0;
802 char *domains_str;
803 smartlist_t *domains_list;
804 log_domain_mask_t neg_domains = 0;
805 const char *closebracket = strchr(cfg, ']');
806 if (!closebracket)
807 return -1;
808 domains = 0;
809 domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
810 domains_list = smartlist_create();
811 smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
812 -1);
813 tor_free(domains_str);
814 SMARTLIST_FOREACH(domains_list, const char *, domain,
816 if (!strcmp(domain, "*")) {
817 domains = ~0u;
818 } else {
819 int d;
820 int negate=0;
821 if (*domain == '~') {
822 negate = 1;
823 ++domain;
825 d = parse_log_domain(domain);
826 if (!d) {
827 log_warn(LD_CONFIG, "No such loggging domain as %s", domain);
828 err = 1;
829 } else {
830 if (negate)
831 neg_domains |= d;
832 else
833 domains |= d;
837 SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
838 smartlist_free(domains_list);
839 if (err)
840 return -1;
841 domains &= ~neg_domains;
842 cfg = eat_whitespace(closebracket+1);
843 } else {
844 ++got_an_unqualified_range;
846 if (!strcasecmpstart(cfg, "file") ||
847 !strcasecmpstart(cfg, "stderr") ||
848 !strcasecmpstart(cfg, "stdout") ||
849 !strcasecmpstart(cfg, "syslog")) {
850 goto done;
852 if (got_an_unqualified_range > 1)
853 return -1;
855 space = strchr(cfg, ' ');
856 dash = strchr(cfg, '-');
857 if (!space)
858 space = strchr(cfg, '\0');
859 if (dash && dash < space) {
860 sev_lo = tor_strndup(cfg, dash-cfg);
861 sev_hi = tor_strndup(dash+1, space-(dash+1));
862 } else {
863 sev_lo = tor_strndup(cfg, space-cfg);
864 sev_hi = tor_strdup("ERR");
866 low = parse_log_level(sev_lo);
867 high = parse_log_level(sev_hi);
868 tor_free(sev_lo);
869 tor_free(sev_hi);
870 if (low == -1)
871 return -1;
872 if (high == -1)
873 return -1;
875 got_anything = 1;
876 for (i=low; i >= high; --i)
877 severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains;
879 cfg = eat_whitespace(space);
882 done:
883 *cfg_ptr = cfg;
884 return got_anything ? 0 : -1;
887 /** Return the least severe log level that any current log is interested in. */
889 get_min_log_level(void)
891 logfile_t *lf;
892 int i;
893 int min = LOG_ERR;
894 for (lf = logfiles; lf; lf = lf->next) {
895 for (i = LOG_DEBUG; i > min; --i)
896 if (lf->severities->masks[SEVERITY_MASK_IDX(i)])
897 min = i;
899 return min;
902 /** Switch all logs to output at most verbose level. */
903 void
904 switch_logs_debug(void)
906 logfile_t *lf;
907 int i;
908 LOCK_LOGS();
909 for (lf = logfiles; lf; lf=lf->next) {
910 for (i = LOG_DEBUG; i >= LOG_ERR; --i)
911 lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u;
913 _log_global_min_severity = get_min_log_level();
914 UNLOCK_LOGS();
917 #ifdef HAVE_EVENT_SET_LOG_CALLBACK
918 /** A string which, if it appears in a libevent log, should be ignored. */
919 static const char *suppress_msg = NULL;
920 /** Callback function passed to event_set_log() so we can intercept
921 * log messages from libevent. */
922 static void
923 libevent_logging_callback(int severity, const char *msg)
925 char buf[1024];
926 size_t n;
927 if (suppress_msg && strstr(msg, suppress_msg))
928 return;
929 n = strlcpy(buf, msg, sizeof(buf));
930 if (n && n < sizeof(buf) && buf[n-1] == '\n') {
931 buf[n-1] = '\0';
933 switch (severity) {
934 case _EVENT_LOG_DEBUG:
935 log(LOG_DEBUG, LD_NET, "Message from libevent: %s", buf);
936 break;
937 case _EVENT_LOG_MSG:
938 log(LOG_INFO, LD_NET, "Message from libevent: %s", buf);
939 break;
940 case _EVENT_LOG_WARN:
941 log(LOG_WARN, LD_GENERAL, "Warning from libevent: %s", buf);
942 break;
943 case _EVENT_LOG_ERR:
944 log(LOG_ERR, LD_GENERAL, "Error from libevent: %s", buf);
945 break;
946 default:
947 log(LOG_WARN, LD_GENERAL, "Message [%d] from libevent: %s",
948 severity, buf);
949 break;
952 /** Set hook to intercept log messages from libevent. */
953 void
954 configure_libevent_logging(void)
956 event_set_log_callback(libevent_logging_callback);
958 /** Ignore any libevent log message that contains <b>msg</b>. */
959 void
960 suppress_libevent_log_msg(const char *msg)
962 suppress_msg = msg;
964 #else
965 void
966 configure_libevent_logging(void)
969 void
970 suppress_libevent_log_msg(const char *msg)
972 (void)msg;
974 #endif
976 #if 0
977 static void
978 dump_log_info(logfile_t *lf)
980 const char *tp;
982 if (lf->filename) {
983 printf("=== log into \"%s\" (%s-%s) (%stemporary)\n", lf->filename,
984 sev_to_string(lf->min_loglevel),
985 sev_to_string(lf->max_loglevel),
986 lf->is_temporary?"":"not ");
987 } else if (lf->is_syslog) {
988 printf("=== syslog (%s-%s) (%stemporary)\n",
989 sev_to_string(lf->min_loglevel),
990 sev_to_string(lf->max_loglevel),
991 lf->is_temporary?"":"not ");
992 } else {
993 printf("=== log (%s-%s) (%stemporary)\n",
994 sev_to_string(lf->min_loglevel),
995 sev_to_string(lf->max_loglevel),
996 lf->is_temporary?"":"not ");
1000 void
1001 describe_logs(void)
1003 logfile_t *lf;
1004 printf("==== BEGIN LOGS ====\n");
1005 for (lf = logfiles; lf; lf = lf->next)
1006 dump_log_info(lf);
1007 printf("==== END LOGS ====\n");
1009 #endif