Browse Source

Merge remote branch 'origin/maint-0.2.2'

Nick Mathewson 13 years ago
parent
commit
46b07462ae
6 changed files with 127 additions and 16 deletions
  1. 12 0
      changes/log_domains
  2. 28 0
      doc/tor.1.txt
  3. 77 15
      src/common/log.c
  4. 1 0
      src/common/torlog.h
  5. 6 1
      src/or/config.c
  6. 3 0
      src/or/or.h

+ 12 - 0
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.

+ 28 - 0
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

+ 77 - 15
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;
@@ -236,13 +242,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)
@@ -324,6 +351,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;
@@ -582,8 +610,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);
@@ -602,6 +629,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).
  */
@@ -794,7 +831,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();
@@ -851,18 +887,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
@@ -938,7 +997,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;

+ 1 - 0
src/common/torlog.h

@@ -134,6 +134,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);

+ 6 - 1
src/or/config.c

@@ -293,6 +293,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"),
@@ -3888,7 +3889,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. */
@@ -4495,6 +4497,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;
 }
 

+ 3 - 0
src/or/or.h

@@ -2501,6 +2501,9 @@ typedef struct {
                         * for logs */
   int LogTimeGranularity; /**< Log resolution in milliseconds. */
 
+  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. */