rephist: Introduce a fraction and period for overload onionskin
[tor.git] / src / lib / log / log.c
blobdb57ee61a26f358a7d12ebf93507e7b61f431ff3
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-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 /**
8 * \file log.c
9 * \brief Functions to send messages to log files or the console.
10 **/
12 #include "orconfig.h"
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #ifdef HAVE_SYS_TIME_H
18 #include <sys/time.h>
19 #endif
20 #ifdef HAVE_TIME_H
21 #include <time.h>
22 #endif
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_SYS_TYPES_H
27 #include <sys/types.h>
28 #endif
29 #ifdef HAVE_FCNTL_H
30 #include <fcntl.h>
31 #endif
33 #define LOG_PRIVATE
34 #include "lib/log/log.h"
35 #include "lib/log/log_sys.h"
36 #include "lib/version/git_revision.h"
37 #include "lib/log/ratelim.h"
38 #include "lib/lock/compat_mutex.h"
39 #include "lib/smartlist_core/smartlist_core.h"
40 #include "lib/smartlist_core/smartlist_foreach.h"
41 #include "lib/smartlist_core/smartlist_split.h"
42 #include "lib/err/torerr.h"
43 #include "lib/intmath/bits.h"
44 #include "lib/string/compat_string.h"
45 #include "lib/string/printf.h"
46 #include "lib/malloc/malloc.h"
47 #include "lib/string/util_string.h"
48 #include "lib/wallclock/tor_gettimeofday.h"
49 #include "lib/wallclock/approx_time.h"
50 #include "lib/wallclock/time_to_tm.h"
51 #include "lib/fdio/fdio.h"
52 #include "lib/cc/ctassert.h"
54 /** @{ */
55 /** The string we stick at the end of a log message when it is too long,
56 * and its length. */
57 #define TRUNCATED_STR "[...truncated]"
58 #define TRUNCATED_STR_LEN 14
59 /** @} */
61 /** Defining compile-time constants for Tor log levels (used by the Rust
62 * log wrapper at src/rust/tor_log) */
63 const int LOG_WARN_ = LOG_WARN;
64 const int LOG_NOTICE_ = LOG_NOTICE;
65 const log_domain_mask_t LD_GENERAL_ = LD_GENERAL;
66 const log_domain_mask_t LD_NET_ = LD_NET;
68 /** Information for a single logfile; only used in log.c */
69 typedef struct logfile_t {
70 struct logfile_t *next; /**< Next logfile_t in the linked list. */
71 char *filename; /**< Filename to open. */
72 int fd; /**< fd to receive log messages, or -1 for none. */
73 int seems_dead; /**< Boolean: true if the stream seems to be kaput. */
74 int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
75 int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
76 int is_syslog; /**< Boolean: send messages to syslog. */
77 log_callback callback; /**< If not NULL, send messages to this function. */
78 log_severity_list_t *severities; /**< Which severity of messages should we
79 * log for each log domain? */
80 } logfile_t;
82 static void log_free_(logfile_t *victim);
83 #define log_free(lg) \
84 FREE_AND_NULL(logfile_t, log_free_, (lg))
86 /** Helper: map a log severity to descriptive string. */
87 static inline const char *
88 sev_to_string(int severity)
90 switch (severity) {
91 case LOG_DEBUG: return "debug";
92 case LOG_INFO: return "info";
93 case LOG_NOTICE: return "notice";
94 case LOG_WARN: return "warn";
95 case LOG_ERR: return "err";
96 default: /* Call raw_assert, not tor_assert, since tor_assert
97 * calls log on failure. */
98 raw_assert_unreached(); return "UNKNOWN"; // LCOV_EXCL_LINE
102 /** Helper: decide whether to include the function name in the log message. */
103 static inline int
104 should_log_function_name(log_domain_mask_t domain, int severity)
106 switch (severity) {
107 case LOG_DEBUG:
108 case LOG_INFO:
109 /* All debugging messages occur in interesting places. */
110 return (domain & LD_NOFUNCNAME) == 0;
111 case LOG_NOTICE:
112 case LOG_WARN:
113 case LOG_ERR:
114 /* We care about places where bugs occur. */
115 return (domain & (LD_BUG|LD_NOFUNCNAME)) == LD_BUG;
116 default:
117 /* Call raw_assert, not tor_assert, since tor_assert calls
118 * log on failure. */
119 raw_assert(0); return 0; // LCOV_EXCL_LINE
123 /** A mutex to guard changes to logfiles and logging. */
124 static tor_mutex_t log_mutex;
125 /** True iff we have initialized log_mutex */
126 static int log_mutex_initialized = 0;
128 /** Linked list of logfile_t. */
129 static logfile_t *logfiles = NULL;
130 /** Boolean: do we report logging domains? */
131 static int log_domains_are_logged = 0;
133 #ifdef HAVE_SYSLOG_H
134 /** The number of open syslog log handlers that we have. When this reaches 0,
135 * we can close our connection to the syslog facility. */
136 static int syslog_count = 0;
137 #endif
139 /** Represents a log message that we are going to send to callback-driven
140 * loggers once we can do so in a non-reentrant way. */
141 typedef struct pending_log_message_t {
142 int severity; /**< The severity of the message */
143 log_domain_mask_t domain; /**< The domain of the message */
144 char *fullmsg; /**< The message, with all decorations */
145 char *msg; /**< The content of the message */
146 } pending_log_message_t;
148 /** Log messages waiting to be replayed onto callback-based logs */
149 static smartlist_t *pending_cb_messages = NULL;
151 /** Callback to invoke when pending_cb_messages becomes nonempty. */
152 static pending_callback_callback pending_cb_cb = NULL;
154 /** Log messages waiting to be replayed once the logging system is initialized.
156 static smartlist_t *pending_startup_messages = NULL;
158 /** Number of bytes of messages queued in pending_startup_messages. (This is
159 * the length of the messages, not the number of bytes used to store
160 * them.) */
161 static size_t pending_startup_messages_len;
163 /** True iff we should store messages while waiting for the logs to get
164 * configured. */
165 static int queue_startup_messages = 1;
167 /** True iff __PRETTY_FUNCTION__ includes parenthesized arguments. */
168 static int pretty_fn_has_parens = 0;
170 /** Don't store more than this many bytes of messages while waiting for the
171 * logs to get configured. */
172 #define MAX_STARTUP_MSG_LEN (1<<16)
174 /** Lock the log_mutex to prevent others from changing the logfile_t list */
175 #define LOCK_LOGS() STMT_BEGIN \
176 raw_assert(log_mutex_initialized); \
177 tor_mutex_acquire(&log_mutex); \
178 STMT_END
179 /** Unlock the log_mutex */
180 #define UNLOCK_LOGS() STMT_BEGIN \
181 raw_assert(log_mutex_initialized); \
182 tor_mutex_release(&log_mutex); \
183 STMT_END
185 /** What's the lowest log level anybody cares about? Checking this lets us
186 * bail out early from log_debug if we aren't debugging. */
187 int log_global_min_severity_ = LOG_NOTICE;
189 static void delete_log(logfile_t *victim);
190 static void close_log(logfile_t *victim);
191 static void close_log_sigsafe(logfile_t *victim);
193 static char *domain_to_string(log_domain_mask_t domain,
194 char *buf, size_t buflen);
195 static inline char *format_msg(char *buf, size_t buf_len,
196 log_domain_mask_t domain, int severity, const char *funcname,
197 const char *suffix,
198 const char *format, va_list ap, size_t *msg_len_out)
199 CHECK_PRINTF(7,0);
201 /** Name of the application: used to generate the message we write at the
202 * start of each new log. */
203 static char *appname = NULL;
205 /** Set the "application name" for the logs to <b>name</b>: we'll use this
206 * name in the message we write when starting up, and at the start of each new
207 * log.
209 * Tor uses this string to write the version number to the log file. */
210 void
211 log_set_application_name(const char *name)
213 tor_free(appname);
214 appname = name ? tor_strdup(name) : NULL;
217 /** Return true if some of the running logs might be interested in a log
218 * message of the given severity in the given domains. If this function
219 * returns true, the log message might be ignored anyway, but if it returns
220 * false, it is definitely_ safe not to log the message. */
222 log_message_is_interesting(int severity, log_domain_mask_t domain)
224 (void) domain;
225 return (severity <= log_global_min_severity_);
229 * As tor_log, but takes an optional function name, and does not treat its
230 * <b>string</b> as a printf format.
232 * For use by Rust integration.
234 void
235 tor_log_string(int severity, log_domain_mask_t domain,
236 const char *function, const char *string)
238 log_fn_(severity, domain, function, "%s", string);
241 /** Log time granularity in milliseconds. */
242 static int log_time_granularity = 1;
244 /** Define log time granularity for all logs to be <b>granularity_msec</b>
245 * milliseconds. */
246 MOCK_IMPL(void,
247 set_log_time_granularity,(int granularity_msec))
249 log_time_granularity = granularity_msec;
250 tor_log_sigsafe_err_set_granularity(granularity_msec);
253 /** Helper: Write the standard prefix for log lines to a
254 * <b>buf_len</b> character buffer in <b>buf</b>.
256 static inline size_t
257 log_prefix_(char *buf, size_t buf_len, int severity)
259 time_t t;
260 struct timeval now;
261 struct tm tm;
262 size_t n;
263 int r, ms;
265 tor_gettimeofday(&now);
266 t = (time_t)now.tv_sec;
267 ms = (int)now.tv_usec / 1000;
268 if (log_time_granularity >= 1000) {
269 t -= t % (log_time_granularity / 1000);
270 ms = 0;
271 } else {
272 ms -= ((int)now.tv_usec / 1000) % log_time_granularity;
275 n = strftime(buf, buf_len, "%b %d %H:%M:%S",
276 tor_localtime_r_msg(&t, &tm, NULL));
277 r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms,
278 sev_to_string(severity));
280 if (r<0)
281 return buf_len-1;
282 else
283 return n+r;
286 /** If lf refers to an actual file that we have just opened, and the file
287 * contains no data, log an "opening new logfile" message at the top.
289 * Return -1 if the log is broken and needs to be deleted, else return 0.
291 static int
292 log_tor_version(logfile_t *lf, int reset)
294 char buf[256];
295 size_t n;
296 int is_new;
298 if (!lf->needs_close)
299 /* If it doesn't get closed, it isn't really a file. */
300 return 0;
301 if (lf->is_temporary)
302 /* If it's temporary, it isn't really a file. */
303 return 0;
305 is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0;
307 if (reset && !is_new)
308 /* We are resetting, but we aren't at the start of the file; no
309 * need to log again. */
310 return 0;
311 n = log_prefix_(buf, sizeof(buf), LOG_NOTICE);
312 if (appname) {
313 tor_snprintf(buf+n, sizeof(buf)-n,
314 "%s opening %slog file.\n", appname, is_new?"new ":"");
315 } else {
316 tor_snprintf(buf+n, sizeof(buf)-n,
317 "Tor %s opening %slog file.\n", VERSION, is_new?"new ":"");
319 if (write_all_to_fd_minimal(lf->fd, buf, strlen(buf)) < 0) /* error */
320 return -1; /* failed */
321 return 0;
324 /** Helper: Format a log message into a fixed-sized buffer. (This is
325 * factored out of <b>logv</b> so that we never format a message more
326 * than once.) Return a pointer to the first character of the message
327 * portion of the formatted string.
329 static inline char *
330 format_msg(char *buf, size_t buf_len,
331 log_domain_mask_t domain, int severity, const char *funcname,
332 const char *suffix,
333 const char *format, va_list ap, size_t *msg_len_out)
335 size_t n;
336 int r;
337 char *end_of_prefix;
338 char *buf_end;
340 raw_assert(buf_len >= 16); /* prevent integer underflow and stupidity */
341 buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
342 buf_end = buf+buf_len; /* point *after* the last char we can write to */
344 n = log_prefix_(buf, buf_len, severity);
345 end_of_prefix = buf+n;
347 if (log_domains_are_logged) {
348 char *cp = buf+n;
349 if (cp == buf_end) goto format_msg_no_room_for_domains;
350 *cp++ = '{';
351 if (cp == buf_end) goto format_msg_no_room_for_domains;
352 cp = domain_to_string(domain, cp, (buf+buf_len-cp));
353 if (cp == buf_end) goto format_msg_no_room_for_domains;
354 *cp++ = '}';
355 if (cp == buf_end) goto format_msg_no_room_for_domains;
356 *cp++ = ' ';
357 if (cp == buf_end) goto format_msg_no_room_for_domains;
358 end_of_prefix = cp;
359 n = cp-buf;
360 format_msg_no_room_for_domains:
361 /* This will leave end_of_prefix and n unchanged, and thus cause
362 * whatever log domain string we had written to be clobbered. */
366 if (funcname && should_log_function_name(domain, severity)) {
367 r = tor_snprintf(buf+n, buf_len-n,
368 pretty_fn_has_parens ? "%s: " : "%s(): ",
369 funcname);
370 if (r<0)
371 n = strlen(buf);
372 else
373 n += r;
376 if (domain == LD_BUG && buf_len-n > 6) {
377 memcpy(buf+n, "Bug: ", 6);
378 n += 5;
381 r = tor_vsnprintf(buf+n,buf_len-n,format,ap);
382 if (r < 0) {
383 /* The message was too long; overwrite the end of the buffer with
384 * "[...truncated]" */
385 if (buf_len >= TRUNCATED_STR_LEN) {
386 size_t offset = buf_len-TRUNCATED_STR_LEN;
387 /* We have an extra 2 characters after buf_len to hold the \n\0,
388 * so it's safe to add 1 to the size here. */
389 strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1);
391 /* Set 'n' to the end of the buffer, where we'll be writing \n\0.
392 * Since we already subtracted 2 from buf_len, this is safe.*/
393 n = buf_len;
394 } else {
395 n += r;
396 if (suffix) {
397 size_t suffix_len = strlen(suffix);
398 if (buf_len-n >= suffix_len) {
399 memcpy(buf+n, suffix, suffix_len);
400 n += suffix_len;
405 if (domain == LD_BUG &&
406 buf_len - n > strlen(tor_bug_suffix)+1) {
407 memcpy(buf+n, tor_bug_suffix, strlen(tor_bug_suffix));
408 n += strlen(tor_bug_suffix);
411 buf[n]='\n';
412 buf[n+1]='\0';
413 *msg_len_out = n+1;
414 return end_of_prefix;
417 /* Create a new pending_log_message_t with appropriate values */
418 static pending_log_message_t *
419 pending_log_message_new(int severity, log_domain_mask_t domain,
420 const char *fullmsg, const char *shortmsg)
422 pending_log_message_t *m = tor_malloc(sizeof(pending_log_message_t));
423 m->severity = severity;
424 m->domain = domain;
425 m->fullmsg = fullmsg ? tor_strdup(fullmsg) : NULL;
426 m->msg = tor_strdup(shortmsg);
427 return m;
430 #define pending_log_message_free(msg) \
431 FREE_AND_NULL(pending_log_message_t, pending_log_message_free_, (msg))
433 /** Release all storage held by <b>msg</b>. */
434 static void
435 pending_log_message_free_(pending_log_message_t *msg)
437 if (!msg)
438 return;
439 tor_free(msg->msg);
440 tor_free(msg->fullmsg);
441 tor_free(msg);
444 /** Helper function: returns true iff the log file, given in <b>lf</b>, is
445 * handled externally via the system log API, or is an
446 * external callback function. */
447 static inline int
448 logfile_is_external(const logfile_t *lf)
450 raw_assert(lf);
451 return lf->is_syslog || lf->callback;
454 /** Return true iff <b>lf</b> would like to receive a message with the
455 * specified <b>severity</b> in the specified <b>domain</b>.
457 static inline int
458 logfile_wants_message(const logfile_t *lf, int severity,
459 log_domain_mask_t domain)
461 if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
462 return 0;
464 if (! (lf->fd >= 0 || logfile_is_external(lf))) {
465 return 0;
467 if (lf->seems_dead) {
468 return 0;
471 return 1;
474 /** Send a message to <b>lf</b>. The full message, with time prefix and
475 * severity, is in <b>buf</b>. The message itself is in
476 * <b>msg_after_prefix</b>. If <b>callbacks_deferred</b> points to true, then
477 * we already deferred this message for pending callbacks and don't need to do
478 * it again. Otherwise, if we need to do it, do it, and set
479 * <b>callbacks_deferred</b> to 1. */
480 static inline void
481 logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
482 const char *msg_after_prefix, log_domain_mask_t domain,
483 int severity, int *callbacks_deferred)
486 if (lf->is_syslog) {
487 #ifdef HAVE_SYSLOG_H
488 #ifdef MAXLINE
489 /* Some syslog implementations have limits on the length of what you can
490 * pass them, and some very old ones do not detect overflow so well.
491 * Regrettably, they call their maximum line length MAXLINE. */
492 #if MAXLINE < 64
493 #warning "MAXLINE is very low; it might not be from syslog.h."
494 #endif
495 char *m = msg_after_prefix;
496 if (msg_len >= MAXLINE)
497 m = tor_strndup(msg_after_prefix, MAXLINE-1);
498 syslog(severity, "%s", m);
499 if (m != msg_after_prefix) {
500 tor_free(m);
502 #else /* !defined(MAXLINE) */
503 /* We have syslog but not MAXLINE. That's promising! */
504 syslog(severity, "%s", msg_after_prefix);
505 #endif /* defined(MAXLINE) */
506 #endif /* defined(HAVE_SYSLOG_H) */
507 } else if (lf->callback) {
508 if (domain & LD_NOCB) {
509 if (!*callbacks_deferred && pending_cb_messages) {
510 smartlist_add(pending_cb_messages,
511 pending_log_message_new(severity,domain,NULL,msg_after_prefix));
512 *callbacks_deferred = 1;
513 if (smartlist_len(pending_cb_messages) == 1 && pending_cb_cb) {
514 pending_cb_cb();
517 } else {
518 lf->callback(severity, domain, msg_after_prefix);
520 } else {
521 if (write_all_to_fd_minimal(lf->fd, buf, msg_len) < 0) { /* error */
522 /* don't log the error! mark this log entry to be blown away, and
523 * continue. */
524 lf->seems_dead = 1;
529 /** Helper: sends a message to the appropriate logfiles, at loglevel
530 * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
531 * message. The actual message is derived as from tor_snprintf(format,ap).
533 MOCK_IMPL(STATIC void,
534 logv,(int severity, log_domain_mask_t domain, const char *funcname,
535 const char *suffix, const char *format, va_list ap))
537 char buf[10240];
538 size_t msg_len = 0;
539 int formatted = 0;
540 logfile_t *lf;
541 char *end_of_prefix=NULL;
542 int callbacks_deferred = 0;
544 /* Call raw_assert, not tor_assert, since tor_assert calls log on failure. */
545 raw_assert(format);
546 /* check that severity is sane. Overrunning the masks array leads to
547 * interesting and hard to diagnose effects */
548 raw_assert(severity >= LOG_ERR && severity <= LOG_DEBUG);
550 LOCK_LOGS();
552 if ((! (domain & LD_NOCB)) && pending_cb_messages
553 && smartlist_len(pending_cb_messages))
554 flush_pending_log_callbacks();
556 if (queue_startup_messages &&
557 pending_startup_messages_len < MAX_STARTUP_MSG_LEN) {
558 end_of_prefix =
559 format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
560 format, ap, &msg_len);
561 formatted = 1;
563 smartlist_add(pending_startup_messages,
564 pending_log_message_new(severity,domain,buf,end_of_prefix));
565 pending_startup_messages_len += msg_len;
568 for (lf = logfiles; lf; lf = lf->next) {
569 if (! logfile_wants_message(lf, severity, domain))
570 continue;
572 if (!formatted) {
573 end_of_prefix =
574 format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
575 format, ap, &msg_len);
576 formatted = 1;
579 logfile_deliver(lf, buf, msg_len, end_of_prefix, domain, severity,
580 &callbacks_deferred);
582 UNLOCK_LOGS();
585 /** Output a message to the log. It gets logged to all logfiles that
586 * care about messages with <b>severity</b> in <b>domain</b>. The content
587 * is formatted printf-style based on <b>format</b> and extra arguments.
588 * */
589 void
590 tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
592 va_list ap;
594 /* check that domain is composed of known domains and flags */
595 raw_assert((domain & (LD_ALL_DOMAINS|LD_ALL_FLAGS)) == domain);
597 if (severity > log_global_min_severity_)
598 return;
599 va_start(ap,format);
600 #ifdef TOR_UNIT_TESTS
601 if (domain & LD_NO_MOCK)
602 logv__real(severity, domain, NULL, NULL, format, ap);
603 else
604 #endif
605 logv(severity, domain, NULL, NULL, format, ap);
606 va_end(ap);
609 /** Helper function; return true iff the <b>n</b>-element array <b>array</b>
610 * contains <b>item</b>. */
611 static int
612 int_array_contains(const int *array, int n, int item)
614 int j;
615 for (j = 0; j < n; ++j) {
616 if (array[j] == item)
617 return 1;
619 return 0;
622 /** Function to call whenever the list of logs changes to get ready to log
623 * from signal handlers. */
624 void
625 tor_log_update_sigsafe_err_fds(void)
627 const logfile_t *lf;
628 int found_real_stderr = 0;
630 /* The fds are the file descriptors of tor's stdout, stderr, and file
631 * logs. The log and err modules flush these fds during their shutdowns. */
632 int fds[TOR_SIGSAFE_LOG_MAX_FDS];
633 int n_fds;
635 LOCK_LOGS();
636 /* Reserve the first one for stderr. This is safe because when we daemonize,
637 * we dup2 /dev/null to stderr. */
638 fds[0] = STDERR_FILENO;
639 n_fds = 1;
641 for (lf = logfiles; lf; lf = lf->next) {
642 /* Don't try callback to the control port, syslogs, or any
643 * other non-file descriptor log: We can't call arbitrary functions from a
644 * signal handler.
646 if (lf->is_temporary || logfile_is_external(lf)
647 || lf->seems_dead || lf->fd < 0)
648 continue;
649 if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
650 (LD_BUG|LD_GENERAL)) {
651 if (lf->fd == STDERR_FILENO)
652 found_real_stderr = 1;
653 /* Avoid duplicates by checking the log module fd against fds */
654 if (int_array_contains(fds, n_fds, lf->fd))
655 continue;
656 /* Update fds using the log module's fd */
657 fds[n_fds] = lf->fd;
658 n_fds++;
659 if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
660 break;
664 if (!found_real_stderr &&
665 int_array_contains(fds, n_fds, STDOUT_FILENO)) {
666 /* Don't use a virtual stderr when we're also logging to stdout.
667 * If we reached max_fds logs, we'll now have (max_fds - 1) logs.
668 * That's ok, max_fds is large enough that most tor instances don't exceed
669 * it. */
670 raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
671 --n_fds;
672 fds[0] = fds[n_fds];
675 UNLOCK_LOGS();
677 tor_log_set_sigsafe_err_fds(fds, n_fds);
680 /** Add to <b>out</b> a copy of every currently configured log file name. Used
681 * to enable access to these filenames with the sandbox code. */
682 void
683 tor_log_get_logfile_names(smartlist_t *out)
685 logfile_t *lf;
686 raw_assert(out);
688 LOCK_LOGS();
690 for (lf = logfiles; lf; lf = lf->next) {
691 if (lf->is_temporary || logfile_is_external(lf))
692 continue;
693 if (lf->filename == NULL)
694 continue;
695 smartlist_add_strdup(out, lf->filename);
698 UNLOCK_LOGS();
701 /** Implementation of the log_fn backend, used when we have
702 * variadic macros. All arguments are as for log_fn, except for
703 * <b>fn</b>, which is the name of the calling function. */
704 void
705 log_fn_(int severity, log_domain_mask_t domain, const char *fn,
706 const char *format, ...)
708 va_list ap;
709 if (severity > log_global_min_severity_)
710 return;
711 va_start(ap,format);
712 logv(severity, domain, fn, NULL, format, ap);
713 va_end(ap);
715 void
716 log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
717 const char *fn, const char *format, ...)
719 va_list ap;
720 char *m;
721 if (severity > log_global_min_severity_)
722 return;
723 m = rate_limit_log(ratelim, approx_time());
724 if (m == NULL)
725 return;
726 va_start(ap, format);
727 logv(severity, domain, fn, m, format, ap);
728 va_end(ap);
729 tor_free(m);
732 /** Free all storage held by <b>victim</b>. */
733 static void
734 log_free_(logfile_t *victim)
736 if (!victim)
737 return;
738 tor_free(victim->severities);
739 tor_free(victim->filename);
740 tor_free(victim);
743 /** Close all open log files, and free other static memory. */
744 void
745 logs_free_all(void)
747 logfile_t *victim, *next;
748 smartlist_t *messages, *messages2;
749 LOCK_LOGS();
750 next = logfiles;
751 logfiles = NULL;
752 messages = pending_cb_messages;
753 pending_cb_messages = NULL;
754 pending_cb_cb = NULL;
755 messages2 = pending_startup_messages;
756 pending_startup_messages = NULL;
757 UNLOCK_LOGS();
758 while (next) {
759 victim = next;
760 next = next->next;
761 close_log(victim);
762 log_free(victim);
764 tor_free(appname);
766 SMARTLIST_FOREACH(messages, pending_log_message_t *, msg, {
767 pending_log_message_free(msg);
769 smartlist_free(messages);
771 if (messages2) {
772 SMARTLIST_FOREACH(messages2, pending_log_message_t *, msg, {
773 pending_log_message_free(msg);
775 smartlist_free(messages2);
778 /* We _could_ destroy the log mutex here, but that would screw up any logs
779 * that happened between here and the end of execution.
780 * If tor is re-initialized, log_mutex_initialized will still be 1. So we
781 * won't trigger any undefined behaviour by trying to re-initialize the
782 * log mutex. */
785 /** Flush the signal-safe log files.
787 * This function is safe to call from a signal handler. It is currently called
788 * by the BUG() macros, when terminating the process on an abnormal condition.
790 void
791 logs_flush_sigsafe(void)
793 /* If we don't have fsync() in unistd.h, we can't flush the logs. */
794 #ifdef HAVE_FSYNC
795 logfile_t *victim, *next;
796 /* We can't LOCK_LOGS() in a signal handler, because it may call
797 * signal-unsafe functions. And we can't deallocate memory, either. */
798 next = logfiles;
799 logfiles = NULL;
800 while (next) {
801 victim = next;
802 next = next->next;
803 if (victim->needs_close) {
804 /* We can't do anything useful if the flush fails. */
805 (void)fsync(victim->fd);
808 #endif /* defined(HAVE_FSYNC) */
811 /** Remove and free the log entry <b>victim</b> from the linked-list
812 * logfiles (it is probably present, but it might not be due to thread
813 * racing issues). After this function is called, the caller shouldn't
814 * refer to <b>victim</b> anymore.
816 static void
817 delete_log(logfile_t *victim)
819 logfile_t *tmpl;
820 if (victim == logfiles)
821 logfiles = victim->next;
822 else {
823 for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ;
824 // raw_assert(tmpl);
825 // raw_assert(tmpl->next == victim);
826 if (!tmpl)
827 return;
828 tmpl->next = victim->next;
830 log_free(victim);
833 /** Helper: release system resources (but not memory) held by a single
834 * signal-safe logfile_t. If the log's resources can not be released in
835 * a signal handler, does nothing. */
836 static void
837 close_log_sigsafe(logfile_t *victim)
839 if (victim->needs_close && victim->fd >= 0) {
840 /* We can't do anything useful here if close() fails: we're shutting
841 * down logging, and the err module only does fatal errors. */
842 close(victim->fd);
843 victim->fd = -1;
847 /** Helper: release system resources (but not memory) held by a single
848 * logfile_t. */
849 static void
850 close_log(logfile_t *victim)
852 if (victim->needs_close) {
853 close_log_sigsafe(victim);
854 } else if (victim->is_syslog) {
855 #ifdef HAVE_SYSLOG_H
856 if (--syslog_count == 0) {
857 /* There are no other syslogs; close the logging facility. */
858 closelog();
860 #endif /* defined(HAVE_SYSLOG_H) */
864 /** Adjust a log severity configuration in <b>severity_out</b> to contain
865 * every domain between <b>loglevelMin</b> and <b>loglevelMax</b>, inclusive.
867 void
868 set_log_severity_config(int loglevelMin, int loglevelMax,
869 log_severity_list_t *severity_out)
871 int i;
872 raw_assert(loglevelMin >= loglevelMax);
873 raw_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG);
874 raw_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG);
875 memset(severity_out, 0, sizeof(log_severity_list_t));
876 for (i = loglevelMin; i >= loglevelMax; --i) {
877 severity_out->masks[SEVERITY_MASK_IDX(i)] = LD_ALL_DOMAINS;
881 /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
882 * to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
883 MOCK_IMPL(STATIC void,
884 add_stream_log_impl,(const log_severity_list_t *severity,
885 const char *name, int fd))
887 logfile_t *lf;
888 lf = tor_malloc_zero(sizeof(logfile_t));
889 lf->fd = fd;
890 lf->filename = tor_strdup(name);
891 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
892 lf->next = logfiles;
894 logfiles = lf;
895 log_global_min_severity_ = get_min_log_level();
898 /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
899 * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must
900 * not use it after calling this function. */
901 void
902 add_stream_log(const log_severity_list_t *severity, const char *name, int fd)
904 LOCK_LOGS();
905 add_stream_log_impl(severity, name, fd);
906 UNLOCK_LOGS();
909 /** Initialize the global logging facility */
910 void
911 init_logging(int disable_startup_queue)
913 if (!log_mutex_initialized) {
914 tor_mutex_init(&log_mutex);
915 log_mutex_initialized = 1;
917 #ifdef __GNUC__
918 if (strchr(__PRETTY_FUNCTION__, '(')) {
919 pretty_fn_has_parens = 1;
921 #endif
922 if (pending_cb_messages == NULL)
923 pending_cb_messages = smartlist_new();
924 if (disable_startup_queue)
925 queue_startup_messages = 0;
926 if (pending_startup_messages == NULL && queue_startup_messages) {
927 pending_startup_messages = smartlist_new();
931 /** Set whether we report logging domains as a part of our log messages.
933 void
934 logs_set_domain_logging(int enabled)
936 LOCK_LOGS();
937 log_domains_are_logged = enabled;
938 UNLOCK_LOGS();
941 /** Add a log handler to accept messages when no other log is configured.
943 void
944 add_default_log(int min_severity)
946 log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
947 set_log_severity_config(min_severity, LOG_ERR, s);
948 LOCK_LOGS();
949 add_stream_log_impl(s, "<default>", fileno(stdout));
950 tor_free(s);
951 UNLOCK_LOGS();
955 * Register "cb" as the callback to call when there are new pending log
956 * callbacks to be flushed with flush_pending_log_callbacks().
958 * Note that this callback, if present, can be invoked from any thread.
960 * This callback must not log.
962 * It is intentional that this function contains the name "callback" twice: it
963 * sets a "callback" to be called on the condition that there is a "pending
964 * callback".
966 void
967 logs_set_pending_callback_callback(pending_callback_callback cb)
969 pending_cb_cb = cb;
973 * Add a log handler to send messages in <b>severity</b>
974 * to the function <b>cb</b>.
977 add_callback_log(const log_severity_list_t *severity, log_callback cb)
979 logfile_t *lf;
980 lf = tor_malloc_zero(sizeof(logfile_t));
981 lf->fd = -1;
982 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
983 lf->filename = tor_strdup("<callback>");
984 lf->callback = cb;
985 lf->next = logfiles;
987 LOCK_LOGS();
988 logfiles = lf;
989 log_global_min_severity_ = get_min_log_level();
990 UNLOCK_LOGS();
991 return 0;
994 /** Adjust the configured severity of any logs whose callback function is
995 * <b>cb</b>. */
996 void
997 change_callback_log_severity(int loglevelMin, int loglevelMax,
998 log_callback cb)
1000 logfile_t *lf;
1001 log_severity_list_t severities;
1002 set_log_severity_config(loglevelMin, loglevelMax, &severities);
1003 LOCK_LOGS();
1004 for (lf = logfiles; lf; lf = lf->next) {
1005 if (lf->callback == cb) {
1006 memcpy(lf->severities, &severities, sizeof(severities));
1009 log_global_min_severity_ = get_min_log_level();
1010 UNLOCK_LOGS();
1013 /** If there are any log messages that were generated with LD_NOCB waiting to
1014 * be sent to callback-based loggers, send them now. */
1015 void
1016 flush_pending_log_callbacks(void)
1018 logfile_t *lf;
1019 smartlist_t *messages, *messages_tmp;
1021 LOCK_LOGS();
1022 if (!pending_cb_messages || 0 == smartlist_len(pending_cb_messages)) {
1023 UNLOCK_LOGS();
1024 return;
1027 messages = pending_cb_messages;
1028 pending_cb_messages = smartlist_new();
1029 do {
1030 SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) {
1031 const int severity = msg->severity;
1032 const log_domain_mask_t domain = msg->domain;
1033 for (lf = logfiles; lf; lf = lf->next) {
1034 if (! lf->callback || lf->seems_dead ||
1035 ! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
1036 continue;
1038 lf->callback(severity, domain, msg->msg);
1040 pending_log_message_free(msg);
1041 } SMARTLIST_FOREACH_END(msg);
1042 smartlist_clear(messages);
1044 messages_tmp = pending_cb_messages;
1045 pending_cb_messages = messages;
1046 messages = messages_tmp;
1047 } while (smartlist_len(messages));
1049 smartlist_free(messages);
1051 UNLOCK_LOGS();
1054 /** Flush all the messages we stored from startup while waiting for log
1055 * initialization.
1057 void
1058 flush_log_messages_from_startup(void)
1060 logfile_t *lf;
1062 LOCK_LOGS();
1063 queue_startup_messages = 0;
1064 pending_startup_messages_len = 0;
1065 if (! pending_startup_messages)
1066 goto out;
1068 SMARTLIST_FOREACH_BEGIN(pending_startup_messages, pending_log_message_t *,
1069 msg) {
1070 int callbacks_deferred = 0;
1071 for (lf = logfiles; lf; lf = lf->next) {
1072 if (! logfile_wants_message(lf, msg->severity, msg->domain))
1073 continue;
1075 /* We configure a temporary startup log that goes to stdout, so we
1076 * shouldn't replay to stdout/stderr*/
1077 if (lf->fd == STDOUT_FILENO || lf->fd == STDERR_FILENO) {
1078 continue;
1081 logfile_deliver(lf, msg->fullmsg, strlen(msg->fullmsg), msg->msg,
1082 msg->domain, msg->severity, &callbacks_deferred);
1084 pending_log_message_free(msg);
1085 } SMARTLIST_FOREACH_END(msg);
1086 smartlist_free(pending_startup_messages);
1087 pending_startup_messages = NULL;
1089 out:
1090 UNLOCK_LOGS();
1093 /** Close any log handlers marked by mark_logs_temp(). */
1094 void
1095 close_temp_logs(void)
1097 logfile_t *lf, **p;
1099 LOCK_LOGS();
1100 for (p = &logfiles; *p; ) {
1101 if ((*p)->is_temporary) {
1102 lf = *p;
1103 /* we use *p here to handle the edge case of the head of the list */
1104 *p = (*p)->next;
1105 close_log(lf);
1106 log_free(lf);
1107 } else {
1108 p = &((*p)->next);
1112 log_global_min_severity_ = get_min_log_level();
1113 UNLOCK_LOGS();
1116 /** Make all currently temporary logs (set to be closed by close_temp_logs)
1117 * live again, and close all non-temporary logs. */
1118 void
1119 rollback_log_changes(void)
1121 logfile_t *lf;
1122 LOCK_LOGS();
1123 for (lf = logfiles; lf; lf = lf->next)
1124 lf->is_temporary = ! lf->is_temporary;
1125 UNLOCK_LOGS();
1126 close_temp_logs();
1129 /** Configure all log handles to be closed by close_temp_logs(). */
1130 void
1131 mark_logs_temp(void)
1133 logfile_t *lf;
1134 LOCK_LOGS();
1135 for (lf = logfiles; lf; lf = lf->next)
1136 lf->is_temporary = 1;
1137 UNLOCK_LOGS();
1141 * Add a log handler to send messages to <b>filename</b> via <b>fd</b>. If
1142 * opening the logfile failed, -1 is returned and errno is set appropriately
1143 * (by open(2)). Takes ownership of fd.
1145 MOCK_IMPL(int,
1146 add_file_log,(const log_severity_list_t *severity,
1147 const char *filename,
1148 int fd))
1150 logfile_t *lf;
1152 if (fd<0)
1153 return -1;
1154 if (tor_fd_seekend(fd)<0) {
1155 close(fd);
1156 return -1;
1159 LOCK_LOGS();
1160 add_stream_log_impl(severity, filename, fd);
1161 logfiles->needs_close = 1;
1162 lf = logfiles;
1163 log_global_min_severity_ = get_min_log_level();
1165 if (log_tor_version(lf, 0) < 0) {
1166 delete_log(lf);
1168 UNLOCK_LOGS();
1170 return 0;
1173 #ifdef HAVE_SYSLOG_H
1175 * Add a log handler to send messages to they system log facility.
1177 * If this is the first log handler, opens syslog with ident Tor or
1178 * Tor-<syslog_identity_tag> if that is not NULL.
1181 add_syslog_log(const log_severity_list_t *severity,
1182 const char* syslog_identity_tag)
1184 logfile_t *lf;
1185 if (syslog_count++ == 0) {
1186 /* This is the first syslog. */
1187 static char buf[256];
1188 if (syslog_identity_tag) {
1189 tor_snprintf(buf, sizeof(buf), "Tor-%s", syslog_identity_tag);
1190 } else {
1191 tor_snprintf(buf, sizeof(buf), "Tor");
1193 openlog(buf, LOG_PID | LOG_NDELAY, LOGFACILITY);
1196 lf = tor_malloc_zero(sizeof(logfile_t));
1197 lf->fd = -1;
1198 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
1199 lf->filename = tor_strdup("<syslog>");
1200 lf->is_syslog = 1;
1202 LOCK_LOGS();
1203 lf->next = logfiles;
1204 logfiles = lf;
1205 log_global_min_severity_ = get_min_log_level();
1206 UNLOCK_LOGS();
1207 return 0;
1209 #endif /* defined(HAVE_SYSLOG_H) */
1211 /** If <b>level</b> is a valid log severity, return the corresponding
1212 * numeric value. Otherwise, return -1. */
1214 parse_log_level(const char *level)
1216 if (!strcasecmp(level, "err"))
1217 return LOG_ERR;
1218 if (!strcasecmp(level, "warn"))
1219 return LOG_WARN;
1220 if (!strcasecmp(level, "notice"))
1221 return LOG_NOTICE;
1222 if (!strcasecmp(level, "info"))
1223 return LOG_INFO;
1224 if (!strcasecmp(level, "debug"))
1225 return LOG_DEBUG;
1226 return -1;
1229 /** Return the string equivalent of a given log level. */
1230 const char *
1231 log_level_to_string(int level)
1233 return sev_to_string(level);
1236 /** NULL-terminated array of names for log domains such that domain_list[dom]
1237 * is a description of <b>dom</b>.
1239 * Remember to update doc/man/tor.1.txt if you modify this list.
1240 * */
1241 static const char *domain_list[] = {
1242 "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
1243 "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
1244 "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
1245 "SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", "MESG",
1246 NULL
1249 CTASSERT(ARRAY_LENGTH(domain_list) == N_LOGGING_DOMAINS + 1);
1251 CTASSERT(HIGHEST_RESERVED_LD_DOMAIN_ < LD_ALL_DOMAINS);
1252 CTASSERT(LD_ALL_DOMAINS < LOWEST_RESERVED_LD_FLAG_);
1253 CTASSERT(LOWEST_RESERVED_LD_FLAG_ < LD_ALL_FLAGS);
1255 /** Return a bitmask for the log domain for which <b>domain</b> is the name,
1256 * or 0 if there is no such name. */
1257 static log_domain_mask_t
1258 parse_log_domain(const char *domain)
1260 int i;
1261 for (i=0; domain_list[i]; ++i) {
1262 if (!strcasecmp(domain, domain_list[i]))
1263 return (UINT64_C(1)<<i);
1265 return 0;
1268 /** Translate a bitmask of log domains to a string. */
1269 static char *
1270 domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen)
1272 char *cp = buf;
1273 char *eos = buf+buflen;
1275 buf[0] = '\0';
1276 if (! domain)
1277 return buf;
1278 while (1) {
1279 const char *d;
1280 int bit = tor_log2(domain);
1281 size_t n;
1282 if ((unsigned)bit >= ARRAY_LENGTH(domain_list)-1 ||
1283 bit >= N_LOGGING_DOMAINS) {
1284 tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain);
1285 return buf+strlen(buf);
1287 d = domain_list[bit];
1288 n = strlcpy(cp, d, eos-cp);
1289 if (n >= buflen) {
1290 tor_snprintf(buf, buflen, "<BUG:Truncating domain %lx>", (long)domain);
1291 return buf+strlen(buf);
1293 cp += n;
1294 domain &= ~(1<<bit);
1296 if (domain == 0 || (eos-cp) < 2)
1297 return cp;
1299 memcpy(cp, ",", 2); /*Nul-terminated ,"*/
1300 cp++;
1304 /** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after
1305 * the end of the severityPattern. Set the value of <b>severity_out</b> to
1306 * the parsed pattern. Return 0 on success, -1 on failure.
1308 * The syntax for a SeverityPattern is:
1309 * <pre>
1310 * SeverityPattern = *(DomainSeverity SP)* DomainSeverity
1311 * DomainSeverity = (DomainList SP)? SeverityRange
1312 * SeverityRange = MinSeverity ("-" MaxSeverity )?
1313 * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
1314 * DomainSpec = "*" | Domain | "~" Domain
1315 * </pre>
1316 * A missing MaxSeverity defaults to ERR. Severities and domains are
1317 * case-insensitive. "~" indicates negation for a domain; negation happens
1318 * last inside a DomainList. Only one SeverityRange without a DomainList is
1319 * allowed per line.
1322 parse_log_severity_config(const char **cfg_ptr,
1323 log_severity_list_t *severity_out)
1325 const char *cfg = *cfg_ptr;
1326 int got_anything = 0;
1327 int got_an_unqualified_range = 0;
1328 memset(severity_out, 0, sizeof(*severity_out));
1330 cfg = eat_whitespace(cfg);
1331 while (*cfg) {
1332 const char *dash, *space;
1333 char *sev_lo, *sev_hi;
1334 int low, high, i;
1335 log_domain_mask_t domains = LD_ALL_DOMAINS;
1337 if (*cfg == '[') {
1338 int err = 0;
1339 char *domains_str;
1340 smartlist_t *domains_list;
1341 log_domain_mask_t neg_domains = 0;
1342 const char *closebracket = strchr(cfg, ']');
1343 if (!closebracket)
1344 return -1;
1345 domains = 0;
1346 domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
1347 domains_list = smartlist_new();
1348 smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
1349 -1);
1350 tor_free(domains_str);
1351 SMARTLIST_FOREACH_BEGIN(domains_list, const char *, domain) {
1352 if (!strcmp(domain, "*")) {
1353 domains = LD_ALL_DOMAINS;
1354 } else {
1355 log_domain_mask_t d;
1356 int negate=0;
1357 if (*domain == '~') {
1358 negate = 1;
1359 ++domain;
1361 d = parse_log_domain(domain);
1362 if (!d) {
1363 log_warn(LD_CONFIG, "No such logging domain as %s", domain);
1364 err = 1;
1365 } else {
1366 if (negate)
1367 neg_domains |= d;
1368 else
1369 domains |= d;
1372 } SMARTLIST_FOREACH_END(domain);
1373 SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
1374 smartlist_free(domains_list);
1375 if (err)
1376 return -1;
1377 if (domains == 0 && neg_domains)
1378 domains = ~neg_domains;
1379 else
1380 domains &= ~neg_domains;
1381 cfg = eat_whitespace(closebracket+1);
1382 } else {
1383 ++got_an_unqualified_range;
1385 if (!strcasecmpstart(cfg, "file") ||
1386 !strcasecmpstart(cfg, "stderr") ||
1387 !strcasecmpstart(cfg, "stdout") ||
1388 !strcasecmpstart(cfg, "syslog")) {
1389 goto done;
1391 if (got_an_unqualified_range > 1)
1392 return -1;
1394 space = find_whitespace(cfg);
1395 dash = strchr(cfg, '-');
1396 if (dash && dash < space) {
1397 sev_lo = tor_strndup(cfg, dash-cfg);
1398 sev_hi = tor_strndup(dash+1, space-(dash+1));
1399 } else {
1400 sev_lo = tor_strndup(cfg, space-cfg);
1401 sev_hi = tor_strdup("ERR");
1403 low = parse_log_level(sev_lo);
1404 high = parse_log_level(sev_hi);
1405 tor_free(sev_lo);
1406 tor_free(sev_hi);
1407 if (low == -1)
1408 return -1;
1409 if (high == -1)
1410 return -1;
1412 got_anything = 1;
1413 for (i=low; i >= high; --i)
1414 severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains;
1416 cfg = eat_whitespace(space);
1419 done:
1420 *cfg_ptr = cfg;
1421 return got_anything ? 0 : -1;
1424 /** Return the least severe log level that any current log is interested in. */
1426 get_min_log_level(void)
1428 logfile_t *lf;
1429 int i;
1430 int min = LOG_ERR;
1431 for (lf = logfiles; lf; lf = lf->next) {
1432 for (i = LOG_DEBUG; i > min; --i)
1433 if (lf->severities->masks[SEVERITY_MASK_IDX(i)])
1434 min = i;
1436 return min;
1439 /** Switch all logs to output at most verbose level. */
1440 void
1441 switch_logs_debug(void)
1443 logfile_t *lf;
1444 int i;
1445 LOCK_LOGS();
1446 for (lf = logfiles; lf; lf=lf->next) {
1447 for (i = LOG_DEBUG; i >= LOG_ERR; --i)
1448 lf->severities->masks[SEVERITY_MASK_IDX(i)] = LD_ALL_DOMAINS;
1450 log_global_min_severity_ = get_min_log_level();
1451 UNLOCK_LOGS();
1454 /** Truncate all the log files. */
1455 void
1456 truncate_logs(void)
1458 logfile_t *lf;
1459 for (lf = logfiles; lf; lf = lf->next) {
1460 if (lf->fd >= 0) {
1461 tor_ftruncate(lf->fd);