diff options
-rw-r--r-- | changes/log_domains | 12 | ||||
-rw-r--r-- | doc/tor.1.txt | 28 | ||||
-rw-r--r-- | src/common/log.c | 92 | ||||
-rw-r--r-- | src/common/torlog.h | 1 | ||||
-rw-r--r-- | src/or/config.c | 7 | ||||
-rw-r--r-- | src/or/or.h | 3 |
6 files changed, 127 insertions, 16 deletions
diff --git a/changes/log_domains b/changes/log_domains new file mode 100644 index 0000000000..7fc0506cdf --- /dev/null +++ b/changes/log_domains @@ -0,0 +1,12 @@ + o Minor features + - Make it simpler to specify "All log domains except for A and B". + Previously you needed to say "[*,~A,~B]". Now you can just say + "[~A,~B]". + - Add a LogMessageDomains option to include the domains of log messages + along with the messages. Without this, there's no way to use + log domains without reading the source or doing a lot of guessing + + o Documentation + - Add documentation for configuring logging at different severities in + different log domains. We've had this feature since 0.2.1.1-alpha, but + for some reason it never made it into the manpage. Fixes bug 2215. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index e5dae8cb27..033f0a28e1 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -323,6 +323,34 @@ Other options can be specified either on the command-line (--option Messages are sent to all the logs that match their severity level. +**Log** **[**__domain__,...**]**__minSeverity__[-__maxSeverity__] ... **file** __FILENAME__ + + +**Log** **[**__domain__,...**]**__minSeverity__[-__maxSeverity__] ... **stderr**|**stdout**|**syslog** :: + As above, but select messages by range of log severity __and__ by a + set of "logging domains". Each logging domain corresponds to an area of + functionality inside Tor. You can specify any number of severity ranges + for a single log statement, each of them prefixed by a comma-separated + list of logging domains. You can prefix a domain with ~ to indicate + negation, and use * to indicate "all domains". If you specify a severity + range without a list of domains, it matches all domains. + + + + This is an advanced feature which is most useful for debugging one or two + of Tor's subsystems at a time. + + + + The currently recognized domains are: general, crypto, net, config, fs, + protocol, mm, http, app, control, circ, rend, bug, dir, dirserv, or, edge, + acct, hist, and handshake. Domain names are case-insensitive. + + + + For example, "`Log [handshake]debug [~net,~mm]info notice stdout`" sends + to stdout: all handshake messages of any severity, all info-and-higher + messages from domains other than networking and memory management, and all + messages of severity notice or higher. + +**LogMessageDomains** **0**|**1**:: + If 1, Tor includes message domains with each log message. Every log + message currently has at least one domain; most currently have exactly + one. This doesn't affect controller log messages. (Default: 0) + **OutboundBindAddress** __IP__:: Make all outbound connections originate from the IP address specified. This is only useful when you have multiple network interfaces, and you want all diff --git a/src/common/log.c b/src/common/log.c index 2fef2cc5d9..cfa0721c27 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -97,6 +97,9 @@ static int log_mutex_initialized = 0; /** Linked list of logfile_t. */ static logfile_t *logfiles = NULL; +/** Boolean: do we report logging domains? */ +static int log_domains_are_logged = 0; + #ifdef HAVE_SYSLOG_H /** The number of open syslog log handlers that we have. When this reaches 0, * we can close our connection to the syslog facility. */ @@ -126,6 +129,9 @@ int _log_global_min_severity = LOG_NOTICE; static void delete_log(logfile_t *victim); static void close_log(logfile_t *victim); +static char *domain_to_string(log_domain_mask_t domain, + char *buf, size_t buflen); + /** Name of the application: used to generate the message we write at the * start of each new log. */ static char *appname = NULL; @@ -217,13 +223,34 @@ format_msg(char *buf, size_t buf_len, size_t n; int r; char *end_of_prefix; + char *buf_end; - assert(buf_len >= 2); /* prevent integer underflow */ + assert(buf_len >= 16); /* prevent integer underflow and general stupidity */ buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */ + buf_end = buf+buf_len; /* point *after* the last char we can write to */ n = _log_prefix(buf, buf_len, severity); end_of_prefix = buf+n; + if (log_domains_are_logged) { + char *cp = buf+n; + if (cp == buf_end) goto format_msg_no_room_for_domains; + *cp++ = '{'; + if (cp == buf_end) goto format_msg_no_room_for_domains; + cp = domain_to_string(domain, cp, (buf+buf_len-cp)); + if (cp == buf_end) goto format_msg_no_room_for_domains; + *cp++ = '}'; + if (cp == buf_end) goto format_msg_no_room_for_domains; + *cp++ = ' '; + if (cp == buf_end) goto format_msg_no_room_for_domains; + end_of_prefix = cp; + n = cp-buf; + format_msg_no_room_for_domains: + /* This will leave end_of_prefix and n unchanged, and thus cause + * whatever log domain string we had written to be clobbered. */ + ; + } + if (funcname && should_log_function_name(domain, severity)) { r = tor_snprintf(buf+n, buf_len-n, "%s(): ", funcname); if (r<0) @@ -305,6 +332,7 @@ logv(int severity, log_domain_mask_t domain, const char *funcname, &msg_len); formatted = 1; } + if (lf->is_syslog) { #ifdef HAVE_SYSLOG_H char *m = end_of_prefix; @@ -563,8 +591,7 @@ add_stream_log_impl(const log_severity_list_t *severity, * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must * not use it after calling this function. */ void -add_stream_log(const log_severity_list_t *severity, - const char *name, int fd) +add_stream_log(const log_severity_list_t *severity, const char *name, int fd) { LOCK_LOGS(); add_stream_log_impl(severity, name, fd); @@ -583,6 +610,16 @@ init_logging(void) pending_cb_messages = smartlist_create(); } +/** Set whether we report logging domains as a part of our log messages. + */ +void +logs_set_domain_logging(int enabled) +{ + LOCK_LOGS(); + log_domains_are_logged = enabled; + UNLOCK_LOGS(); +} + /** Add a log handler to receive messages during startup (before the real * logs are initialized). */ @@ -775,7 +812,6 @@ add_syslog_log(const log_severity_list_t *severity) lf->fd = -1; lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); lf->filename = tor_strdup("<syslog>"); - lf->is_syslog = 1; LOCK_LOGS(); @@ -832,18 +868,41 @@ parse_log_domain(const char *domain) } return 0; } -#if 0 -/** Translate a bitmask of log domains to a string, or NULL if the bitmask - * is undecodable. */ -static const char * -domain_to_string(log_domain_mask_t domain) + +/** Translate a bitmask of log domains to a string. */ +static char * +domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen) { - int bit = tor_log2(domain); - if ((bit == 0 && domain == 0) || bit >= N_LOGGING_DOMAINS) - return NULL; - return domain_list[bit]; + char *cp = buf; + char *eos = buf+buflen; + + buf[0] = '\0'; + if (! domain) + return buf; + while (1) { + const char *d; + int bit = tor_log2(domain); + size_t n; + if (bit >= N_LOGGING_DOMAINS) { + tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain); + return buf+strlen(buf); + } + d = domain_list[bit]; + n = strlcpy(cp, d, eos-cp); + if (n >= buflen) { + tor_snprintf(buf, buflen, "<BUG:Truncating domain %lx>", (long)domain); + return buf+strlen(buf); + } + cp += n; + domain &= ~(1<<bit); + + if (domain == 0 || (eos-cp) < 2) + return cp; + + memcpy(cp, ",", 2); /*Nul-terminated ,"*/ + cp++; + } } -#endif /** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after * the end of the severityPattern. Set the value of <b>severity_out</b> to @@ -919,7 +978,10 @@ parse_log_severity_config(const char **cfg_ptr, smartlist_free(domains_list); if (err) return -1; - domains &= ~neg_domains; + if (domains == 0 && neg_domains) + domains = ~neg_domains; + else + domains &= ~neg_domains; cfg = eat_whitespace(closebracket+1); } else { ++got_an_unqualified_range; diff --git a/src/common/torlog.h b/src/common/torlog.h index f0be732270..791e363946 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -132,6 +132,7 @@ int add_file_log(const log_severity_list_t *severity, const char *filename); int add_syslog_log(const log_severity_list_t *severity); #endif int add_callback_log(const log_severity_list_t *severity, log_callback cb); +void logs_set_domain_logging(int enabled); int get_min_log_level(void); void switch_logs_debug(void); void logs_free_all(void); diff --git a/src/or/config.c b/src/or/config.c index ec86dbca56..178ed1e385 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -288,6 +288,7 @@ static config_var_t _option_vars[] = { OBSOLETE("IgnoreVersion"), V(KeepalivePeriod, INTERVAL, "5 minutes"), VAR("Log", LINELIST, Logs, NULL), + V(LogMessageDomains, BOOL, "0"), OBSOLETE("LinkPadding"), OBSOLETE("LogLevel"), OBSOLETE("LogFile"), @@ -3817,7 +3818,8 @@ options_transition_affects_workers(or_options_t *old_options, old_options->SafeLogging != new_options->SafeLogging || old_options->ClientOnly != new_options->ClientOnly || public_server_mode(old_options) != public_server_mode(new_options) || - !config_lines_eq(old_options->Logs, new_options->Logs)) + !config_lines_eq(old_options->Logs, new_options->Logs) || + old_options->LogMessageDomains != new_options->LogMessageDomains) return 1; /* Check whether log options match. */ @@ -4393,6 +4395,9 @@ options_init_logs(or_options_t *options, int validate_only) } smartlist_free(elts); + if (ok && !validate_only) + logs_set_domain_logging(options->LogMessageDomains); + return ok?0:-1; } diff --git a/src/or/or.h b/src/or/or.h index 752de219ef..2a55668404 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2345,6 +2345,9 @@ typedef struct { config_line_t *Logs; /**< New-style list of configuration lines * for logs */ + int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which + * each log message occurs? */ + char *DebugLogFile; /**< Where to send verbose log messages. */ char *DataDirectory; /**< OR only: where to store long-term data. */ char *Nickname; /**< OR only: nickname of this onion router. */ |