r18630@catbus: nickm | 2008-03-05 17:31:33 -0500

Implement domain-selection for logging.  Source is documented; needs documentation in manpage (maybe).  For now, see doxygen comment on parse_log_severity_config in log.c


svn:r13875
This commit is contained in:
Nick Mathewson 2008-03-05 22:31:39 +00:00
parent d3589553bc
commit f56ba5f3d6
7 changed files with 337 additions and 190 deletions

View File

@ -8,6 +8,12 @@ Changes in version 0.2.1.1-alpha - 2008-??-??
from lodger, Karsten Loesing and Sebastian Hahn. Fixes bug 616. from lodger, Karsten Loesing and Sebastian Hahn. Fixes bug 616.
Bugfix on 0.2.0.20-rc. Bugfix on 0.2.0.20-rc.
o Minor features:
- Allow separate log levels to be configured for different logging
domains. For example, this allows one to log all notices, warnings, or
errors, plus all memory management messages of level debug or higher,
with: Log [MM] debug-err [*] notice-err file /var/log/tor.
Changes in version 0.2.0.21-rc - 2008-03-02 Changes in version 0.2.0.21-rc - 2008-03-02
o Major bugfixes: o Major bugfixes:

View File

@ -23,8 +23,9 @@ const char log_c_id[] = "$Id$";
#ifdef HAVE_TIME_H #ifdef HAVE_TIME_H
#include <time.h> #include <time.h>
#endif #endif
#include "./util.h" #include "util.h"
#include "./log.h" #include "log.h"
#include "container.h"
#include <event.h> #include <event.h>
@ -38,13 +39,14 @@ typedef struct logfile_t {
FILE *file; /**< Stream to receive log messages. */ FILE *file; /**< Stream to receive log messages. */
int seems_dead; /**< Boolean: true if the stream seems to be kaput. */ int seems_dead; /**< Boolean: true if the stream seems to be kaput. */
int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */ int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
int min_loglevel; /**< Lowest severity level to send to this stream. */
int max_loglevel; /**< Highest severity level to send to this stream. */
int is_temporary; /**< Boolean: close after initializing logging subsystem.*/ int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
int is_syslog; /**< Boolean: send messages to syslog. */ int is_syslog; /**< Boolean: send messages to syslog. */
log_callback callback; /**< If not NULL, send messages to this function. */ log_callback callback; /**< If not NULL, send messages to this function. */
log_severity_list_t *severities; /**< DOCDOC */
} logfile_t; } logfile_t;
static void log_free(logfile_t *victim);
/** Helper: map a log severity to descriptive string. */ /** Helper: map a log severity to descriptive string. */
static INLINE const char * static INLINE const char *
sev_to_string(int severity) sev_to_string(int severity)
@ -61,7 +63,7 @@ sev_to_string(int severity)
/** Helper: decide whether to include the function name in the log message. */ /** Helper: decide whether to include the function name in the log message. */
static INLINE int static INLINE int
should_log_function_name(uint32_t domain, int severity) should_log_function_name(log_domain_mask_t domain, int severity)
{ {
switch (severity) { switch (severity) {
case LOG_DEBUG: case LOG_DEBUG:
@ -69,7 +71,7 @@ should_log_function_name(uint32_t domain, int severity)
/* All debugging messages occur in interesting places. */ /* All debugging messages occur in interesting places. */
return 1; return 1;
case LOG_NOTICE: case LOG_NOTICE:
case LOG_WARN: case LOG_WARN:
case LOG_ERR: case LOG_ERR:
/* We care about places where bugs occur. */ /* We care about places where bugs occur. */
return (domain == LD_BUG); return (domain == LD_BUG);
@ -194,7 +196,7 @@ log_tor_version(logfile_t *lf, int reset)
*/ */
static INLINE char * static INLINE char *
format_msg(char *buf, size_t buf_len, format_msg(char *buf, size_t buf_len,
uint32_t domain, int severity, const char *funcname, log_domain_mask_t domain, int severity, const char *funcname,
const char *format, va_list ap) const char *format, va_list ap)
{ {
size_t n; size_t n;
@ -246,8 +248,8 @@ format_msg(char *buf, size_t buf_len,
* message. The actual message is derived as from tor_snprintf(format,ap). * message. The actual message is derived as from tor_snprintf(format,ap).
*/ */
static void static void
logv(int severity, uint32_t domain, const char *funcname, const char *format, logv(int severity, log_domain_mask_t domain, const char *funcname,
va_list ap) const char *format, va_list ap)
{ {
char buf[10024]; char buf[10024];
int formatted = 0; int formatted = 0;
@ -258,7 +260,7 @@ logv(int severity, uint32_t domain, const char *funcname, const char *format,
LOCK_LOGS(); LOCK_LOGS();
lf = logfiles; lf = logfiles;
while (lf) { while (lf) {
if (severity > lf->min_loglevel || severity < lf->max_loglevel) { if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
lf = lf->next; lf = lf->next;
continue; continue;
} }
@ -302,7 +304,7 @@ logv(int severity, uint32_t domain, const char *funcname, const char *format,
/** Output a message to the log. */ /** Output a message to the log. */
void void
_log(int severity, uint32_t domain, const char *format, ...) _log(int severity, log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
if (severity > _log_global_min_severity) if (severity > _log_global_min_severity)
@ -315,7 +317,8 @@ _log(int severity, uint32_t domain, const char *format, ...)
/** Output a message to the log, prefixed with a function name <b>fn</b>. */ /** Output a message to the log, prefixed with a function name <b>fn</b>. */
#ifdef __GNUC__ #ifdef __GNUC__
void void
_log_fn(int severity, uint32_t domain, const char *fn, const char *format, ...) _log_fn(int severity, log_domain_mask_t domain, const char *fn,
const char *format, ...)
{ {
va_list ap; va_list ap;
if (severity > _log_global_min_severity) if (severity > _log_global_min_severity)
@ -327,7 +330,7 @@ _log_fn(int severity, uint32_t domain, const char *fn, const char *format, ...)
#else #else
const char *_log_fn_function_name=NULL; const char *_log_fn_function_name=NULL;
void void
_log_fn(int severity, uint32_t domain, const char *format, ...) _log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
if (severity > _log_global_min_severity) if (severity > _log_global_min_severity)
@ -338,7 +341,7 @@ _log_fn(int severity, uint32_t domain, const char *format, ...)
_log_fn_function_name = NULL; _log_fn_function_name = NULL;
} }
void void
_log_debug(uint32_t domain, const char *format, ...) _log_debug(log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
/* For GCC we do this check in the macro. */ /* For GCC we do this check in the macro. */
@ -350,7 +353,7 @@ _log_debug(uint32_t domain, const char *format, ...)
_log_fn_function_name = NULL; _log_fn_function_name = NULL;
} }
void void
_log_info(uint32_t domain, const char *format, ...) _log_info(log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
if (LOG_INFO > _log_global_min_severity) if (LOG_INFO > _log_global_min_severity)
@ -361,7 +364,7 @@ _log_info(uint32_t domain, const char *format, ...)
_log_fn_function_name = NULL; _log_fn_function_name = NULL;
} }
void void
_log_notice(uint32_t domain, const char *format, ...) _log_notice(log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
if (LOG_NOTICE > _log_global_min_severity) if (LOG_NOTICE > _log_global_min_severity)
@ -372,7 +375,7 @@ _log_notice(uint32_t domain, const char *format, ...)
_log_fn_function_name = NULL; _log_fn_function_name = NULL;
} }
void void
_log_warn(uint32_t domain, const char *format, ...) _log_warn(log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
if (LOG_WARN > _log_global_min_severity) if (LOG_WARN > _log_global_min_severity)
@ -383,7 +386,7 @@ _log_warn(uint32_t domain, const char *format, ...)
_log_fn_function_name = NULL; _log_fn_function_name = NULL;
} }
void void
_log_err(uint32_t domain, const char *format, ...) _log_err(log_domain_mask_t domain, const char *format, ...)
{ {
va_list ap; va_list ap;
if (LOG_ERR > _log_global_min_severity) if (LOG_ERR > _log_global_min_severity)
@ -395,6 +398,15 @@ _log_err(uint32_t domain, const char *format, ...)
} }
#endif #endif
/** DOCDOC */
static void
log_free(logfile_t *victim)
{
tor_free(victim->severities);
tor_free(victim->filename);
tor_free(victim);
}
/** Close all open log files, and free other static memory. */ /** Close all open log files, and free other static memory. */
void void
logs_free_all(void) logs_free_all(void)
@ -408,8 +420,7 @@ logs_free_all(void)
victim = next; victim = next;
next = next->next; next = next->next;
close_log(victim); close_log(victim);
tor_free(victim->filename); log_free(victim);
tor_free(victim);
} }
tor_free(appname); tor_free(appname);
} }
@ -436,8 +447,7 @@ delete_log(logfile_t *victim)
return; return;
tmpl->next = victim->next; tmpl->next = victim->next;
} }
tor_free(victim->filename); log_free(victim);
tor_free(victim);
} }
/** Helper: release system resources (but not memory) held by a single /** Helper: release system resources (but not memory) held by a single
@ -457,18 +467,29 @@ close_log(logfile_t *victim)
} }
} }
/** Add a log handler named <b>name</b> to send all messages of severity /** DOCDOC XXXX021 remove me. */
* between <b>loglevelMin</b> and <b>loglevelMax</b> (inclusive) to static log_severity_list_t *
* <b>stream</b>. */ new_severity_list(int loglevelMin, int loglevelMax)
{
log_severity_list_t *out = tor_malloc_zero(sizeof(log_severity_list_t));
int i;
for (i = loglevelMin; i >= loglevelMax; --i) {
out->masks[SEVERITY_MASK_IDX(i)] = ~0u;
}
return out;
}
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
* to <b>stream</b>. Steals a reference to <b>severity</b>; the caller must
* not use it after calling this function. Helper: does no locking. */
static void static void
add_stream_log_impl(int loglevelMin, int loglevelMax, add_stream_log_impl(log_severity_list_t *severity,
const char *name, FILE *stream) const char *name, FILE *stream)
{ {
logfile_t *lf; logfile_t *lf;
lf = tor_malloc_zero(sizeof(logfile_t)); lf = tor_malloc_zero(sizeof(logfile_t));
lf->filename = tor_strdup(name); lf->filename = tor_strdup(name);
lf->min_loglevel = loglevelMin; lf->severities = severity;
lf->max_loglevel = loglevelMax;
lf->file = stream; lf->file = stream;
lf->next = logfiles; lf->next = logfiles;
@ -476,14 +497,15 @@ add_stream_log_impl(int loglevelMin, int loglevelMax,
_log_global_min_severity = get_min_log_level(); _log_global_min_severity = get_min_log_level();
} }
/** Add a log handler to send all messages of severity <b>loglevel</b> /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
* or higher to <b>stream</b>. */ * to <b>stream</b>. Steals a reference to <b>severity</b>; the caller must
* not use it after calling this function. */
void void
add_stream_log(int loglevelMin, int loglevelMax, add_stream_log(log_severity_list_t *severity,
const char *name, FILE *stream) const char *name, FILE *stream)
{ {
LOCK_LOGS(); LOCK_LOGS();
add_stream_log_impl(loglevelMin, loglevelMax, name, stream); add_stream_log_impl(severity, name, stream);
UNLOCK_LOGS(); UNLOCK_LOGS();
} }
@ -502,23 +524,22 @@ void
add_temp_log(void) add_temp_log(void)
{ {
LOCK_LOGS(); LOCK_LOGS();
add_stream_log_impl(LOG_NOTICE, LOG_ERR, "<temp>", stdout); add_stream_log_impl(new_severity_list(LOG_NOTICE, LOG_ERR),
"<temp>", stdout);
logfiles->is_temporary = 1; logfiles->is_temporary = 1;
UNLOCK_LOGS(); UNLOCK_LOGS();
} }
/** /**
* Add a log handler to send messages of severity between * Add a log handler to send messages in <b>severity</b>
* <b>logLevelmin</b> and <b>logLevelMax</b> to the function * to the function <b>cb</b>.
* <b>cb</b>.
*/ */
int int
add_callback_log(int loglevelMin, int loglevelMax, log_callback cb) add_callback_log(log_severity_list_t *severity, log_callback cb)
{ {
logfile_t *lf; logfile_t *lf;
lf = tor_malloc_zero(sizeof(logfile_t)); lf = tor_malloc_zero(sizeof(logfile_t));
lf->min_loglevel = loglevelMin; lf->severities = severity;
lf->max_loglevel = loglevelMax;
lf->filename = tor_strdup("<callback>"); lf->filename = tor_strdup("<callback>");
lf->callback = cb; lf->callback = cb;
lf->next = logfiles; lf->next = logfiles;
@ -540,8 +561,8 @@ change_callback_log_severity(int loglevelMin, int loglevelMax,
LOCK_LOGS(); LOCK_LOGS();
for (lf = logfiles; lf; lf = lf->next) { for (lf = logfiles; lf; lf = lf->next) {
if (lf->callback == cb) { if (lf->callback == cb) {
lf->min_loglevel = loglevelMin; tor_free(lf->severities);
lf->max_loglevel = loglevelMax; lf->severities = new_severity_list(loglevelMin, loglevelMax);
} }
} }
_log_global_min_severity = get_min_log_level(); _log_global_min_severity = get_min_log_level();
@ -561,8 +582,7 @@ close_temp_logs(void)
/* we use *p here to handle the edge case of the head of the list */ /* we use *p here to handle the edge case of the head of the list */
*p = (*p)->next; *p = (*p)->next;
close_log(lf); close_log(lf);
tor_free(lf->filename); log_free(lf);
tor_free(lf);
} else { } else {
p = &((*p)->next); p = &((*p)->next);
} }
@ -602,14 +622,14 @@ mark_logs_temp(void)
* (by fopen). * (by fopen).
*/ */
int int
add_file_log(int loglevelMin, int loglevelMax, const char *filename) add_file_log(log_severity_list_t *severity, const char *filename)
{ {
FILE *f; FILE *f;
logfile_t *lf; logfile_t *lf;
f = fopen(filename, "a"); f = fopen(filename, "a");
if (!f) return -1; if (!f) return -1;
LOCK_LOGS(); LOCK_LOGS();
add_stream_log_impl(loglevelMin, loglevelMax, filename, f); add_stream_log_impl(severity, filename, f);
logfiles->needs_close = 1; logfiles->needs_close = 1;
lf = logfiles; lf = logfiles;
_log_global_min_severity = get_min_log_level(); _log_global_min_severity = get_min_log_level();
@ -629,7 +649,7 @@ add_file_log(int loglevelMin, int loglevelMax, const char *filename)
* Add a log handler to send messages to they system log facility. * Add a log handler to send messages to they system log facility.
*/ */
int int
add_syslog_log(int loglevelMin, int loglevelMax) add_syslog_log(log_severity_list_t *severity)
{ {
logfile_t *lf; logfile_t *lf;
if (syslog_count++ == 0) if (syslog_count++ == 0)
@ -637,9 +657,9 @@ add_syslog_log(int loglevelMin, int loglevelMax)
openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY); openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY);
lf = tor_malloc_zero(sizeof(logfile_t)); lf = tor_malloc_zero(sizeof(logfile_t));
lf->min_loglevel = loglevelMin; lf->severities = severity;
lf->filename = tor_strdup("<syslog>"); lf->filename = tor_strdup("<syslog>");
lf->max_loglevel = loglevelMax;
lf->is_syslog = 1; lf->is_syslog = 1;
LOCK_LOGS(); LOCK_LOGS();
@ -676,15 +696,163 @@ log_level_to_string(int level)
return sev_to_string(level); return sev_to_string(level);
} }
/** DOCDOC */
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
"OR", "EDGE", "ACCT", NULL
};
/** DOCDOC */
static log_domain_mask_t
parse_log_domain(const char *domain)
{
int i;
for (i=0; domain_list[i]; ++i) {
if (!strcasecmp(domain, domain_list[i]))
return (1u<<i);
}
return 0;
}
#if 0
/** DOCDOC */
static const char *
domain_to_string(log_domain_mask_t domain)
{
int bit = tor_log2(domain);
if ((bit == 0 && domain == 0) || bit >= N_LOGGING_DOMAINS)
return NULL;
return domain_list[bit];
}
#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
* the parsed pattern. Return 0 on success, -1 on failure.
*
* The syntax for a SeverityPattern is:
* <pre>
* SeverityPattern = *(DomainSeverity SP)* DomainSeverity
* DomainSeverity = (DomainList SP)? SeverityRange
* SeverityRange = MinSeverity ("-" MaxSeverity )?
* DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
* DomainSpec = "*" | Domain | "~" Domain
* </pre>
* A missing MaxSeverity defaults to ERR. Severities and domains are
* case-insensitive. "~" indicates negation for a domain; negation happens
* last inside a DomainList. Only one SeverityRange without a DomainList is
* allowed per line.
*/
int
parse_log_severity_config(const char **cfg_ptr,
log_severity_list_t *severity_out)
{
const char *cfg = *cfg_ptr;
int got_anything = 0;
int got_an_unqualified_range = 0;
memset(severity_out, 0, sizeof(*severity_out));
cfg = eat_whitespace(cfg);
while (*cfg) {
const char *dash, *space;
char *sev_lo, *sev_hi;
int low, high, i;
log_domain_mask_t domains = ~0u;
if (*cfg == '[') {
int err = 0;
char *domains_str;
smartlist_t *domains_list;
log_domain_mask_t neg_domains = 0;
const char *closebracket = strchr(cfg, ']');
if (!closebracket)
return -1;
domains = 0;
domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
domains_list = smartlist_create();
smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
-1);
tor_free(domains_str);
SMARTLIST_FOREACH(domains_list, const char *, domain,
{
if (!strcmp(domain, "*")) {
domains = ~0u;
} else {
int d;
int negate=0;
if (*domain == '~') {
negate = 1;
++domain;
}
d = parse_log_domain(domain);
if (!d) {
log_warn(LD_CONFIG, "No such loggging domain as %s", domain);
err = 1;
} else {
if (negate)
neg_domains |= d;
else
domains |= d;
}
}
});
SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
smartlist_free(domains_list);
if (err)
return -1;
domains &= ~neg_domains;
cfg = eat_whitespace(closebracket+1);
} else {
++got_an_unqualified_range;
}
if (!strcasecmpstart(cfg, "file") ||
!strcasecmpstart(cfg, "stderr") ||
!strcasecmpstart(cfg, "stdout") ||
!strcasecmpstart(cfg, "syslog")) {
goto done;
}
if (got_an_unqualified_range > 1)
return -1;
space = strchr(cfg, ' ');
dash = strchr(cfg, '-');
if (!space)
space = strchr(cfg, '\0');
if (dash && dash < space) {
sev_lo = tor_strndup(cfg, dash-cfg);
sev_hi = tor_strndup(dash+1, space-(dash+1));
} else {
sev_lo = tor_strndup(cfg, space-cfg);
sev_hi = tor_strdup("ERR");
}
if ((low = parse_log_level(sev_lo)) == -1)
return -1;
if ((high = parse_log_level(sev_hi)) == -1)
return -1;
got_anything = 1;
for (i=low; i >= high; --i)
severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains;
cfg = eat_whitespace(space);
}
done:
*cfg_ptr = cfg;
return got_anything ? 0 : -1;
}
/** Return the least severe log level that any current log is interested in. */ /** Return the least severe log level that any current log is interested in. */
int int
get_min_log_level(void) get_min_log_level(void)
{ {
logfile_t *lf; logfile_t *lf;
int i;
int min = LOG_ERR; int min = LOG_ERR;
for (lf = logfiles; lf; lf = lf->next) { for (lf = logfiles; lf; lf = lf->next) {
if (lf->min_loglevel > min) for (i = LOG_DEBUG; i > min; --i)
min = lf->min_loglevel; if (lf->severities->masks[SEVERITY_MASK_IDX(i)])
min = i;
} }
return min; return min;
} }
@ -694,9 +862,11 @@ void
switch_logs_debug(void) switch_logs_debug(void)
{ {
logfile_t *lf; logfile_t *lf;
int i;
LOCK_LOGS(); LOCK_LOGS();
for (lf = logfiles; lf; lf=lf->next) { for (lf = logfiles; lf; lf=lf->next) {
lf->min_loglevel = LOG_DEBUG; for (i = LOG_DEBUG; i >= LOG_ERR; --i)
lf->severities->masks[i] = ~0u;
} }
UNLOCK_LOGS(); UNLOCK_LOGS();
} }

View File

@ -91,19 +91,38 @@
/** Bandwidth accounting. */ /** Bandwidth accounting. */
#define LD_ACCT (1u<<17) #define LD_ACCT (1u<<17)
/** Number of logging domains in the code. */
#define N_LOGGING_DOMAINS 18
typedef uint32_t log_domain_mask_t;
/** Configures which severities are logged for each logging domain for a given
* log target. */
typedef struct log_severity_list_t {
/** For each log severity, a bitmask of which domains a given logger is
* logging. */
log_domain_mask_t masks[LOG_DEBUG-LOG_ERR+1];
} log_severity_list_t;
/** Given a severity, yields an index into log_severity_list_t.masks to use
* for that severity. */
#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR)
/** Callback type used for add_callback_log. */ /** Callback type used for add_callback_log. */
typedef void (*log_callback)(int severity, uint32_t domain, const char *msg); typedef void (*log_callback)(int severity, uint32_t domain, const char *msg);
void init_logging(void); void init_logging(void);
int parse_log_level(const char *level); int parse_log_level(const char *level);
const char *log_level_to_string(int level); const char *log_level_to_string(int level);
void add_stream_log(int severityMin, int severityMax, const char *name, int parse_log_severity_config(const char **cfg,
log_severity_list_t *severity_out);
void add_stream_log(log_severity_list_t *severity, const char *name,
FILE *stream); FILE *stream);
int add_file_log(int severityMin, int severityMax, const char *filename); int add_file_log(log_severity_list_t *severity, const char *filename);
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
int add_syslog_log(int loglevelMin, int loglevelMax); int add_syslog_log(log_severity_list_t *severity);
#endif #endif
int add_callback_log(int loglevelMin, int loglevelMax, log_callback cb); int add_callback_log(log_severity_list_t *severity, log_callback cb);
int get_min_log_level(void); int get_min_log_level(void);
void switch_logs_debug(void); void switch_logs_debug(void);
void logs_free_all(void); void logs_free_all(void);
@ -118,14 +137,14 @@ void change_callback_log_severity(int loglevelMin, int loglevelMax,
void log_set_application_name(const char *name); void log_set_application_name(const char *name);
/* Outputs a message to stdout */ /* Outputs a message to stdout */
void _log(int severity, uint32_t domain, const char *format, ...) void _log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4); CHECK_PRINTF(3,4);
#define log _log /* hack it so we don't conflict with log() as much */ #define log _log /* hack it so we don't conflict with log() as much */
#ifdef __GNUC__ #ifdef __GNUC__
extern int _log_global_min_severity; extern int _log_global_min_severity;
void _log_fn(int severity, uint32_t domain, void _log_fn(int severity, log_domain_mask_t domain,
const char *funcname, const char *format, ...) const char *funcname, const char *format, ...)
CHECK_PRINTF(4,5); CHECK_PRINTF(4,5);
/** Log a message at level <b>severity</b>, using a pretty-printed version /** Log a message at level <b>severity</b>, using a pretty-printed version
@ -148,12 +167,12 @@ void _log_fn(int severity, uint32_t domain,
#else /* ! defined(__GNUC__) */ #else /* ! defined(__GNUC__) */
void _log_fn(int severity, uint32_t domain, const char *format, ...); void _log_fn(int severity, log_domain_mask_t domain, const char *format, ...);
void _log_debug(uint32_t domain, const char *format, ...); void _log_debug(log_domain_mask_t domain, const char *format, ...);
void _log_info(uint32_t domain, const char *format, ...); void _log_info(log_domain_mask_t domain, const char *format, ...);
void _log_notice(uint32_t domain, const char *format, ...); void _log_notice(log_domain_mask_t domain, const char *format, ...);
void _log_warn(uint32_t domain, const char *format, ...); void _log_warn(log_domain_mask_t domain, const char *format, ...);
void _log_err(uint32_t domain, const char *format, ...); void _log_err(log_domain_mask_t domain, const char *format, ...);
#if defined(_MSC_VER) && _MSC_VER < 1300 #if defined(_MSC_VER) && _MSC_VER < 1300
/* MSVC 6 and earlier don't have __func__, or even __LINE__. */ /* MSVC 6 and earlier don't have __func__, or even __LINE__. */

View File

@ -630,8 +630,6 @@ static int parse_dir_server_line(const char *line,
int validate_only); int validate_only);
static int parse_redirect_line(smartlist_t *result, static int parse_redirect_line(smartlist_t *result,
config_line_t *line, char **msg); config_line_t *line, char **msg);
static int parse_log_severity_range(const char *range, int *min_out,
int *max_out);
static int validate_data_directory(or_options_t *options); static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname, or_options_t *options); static int write_configuration_file(const char *fname, or_options_t *options);
static config_line_t *get_assigned_option(config_format_t *fmt, static config_line_t *get_assigned_option(config_format_t *fmt,
@ -1052,8 +1050,10 @@ options_act_reversible(or_options_t *old_options, char **msg)
commit: commit:
r = 0; r = 0;
if (logs_marked) { if (logs_marked) {
log_severity_list_t *severity =
tor_malloc_zero(sizeof(log_severity_list_t));
close_temp_logs(); close_temp_logs();
add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg); add_callback_log(severity, control_event_logmsg);
control_adjust_event_log_severity(); control_adjust_event_log_severity();
} }
SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn, SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
@ -3722,58 +3722,6 @@ config_register_addressmaps(or_options_t *options)
smartlist_free(elts); smartlist_free(elts);
} }
/** If <b>range</b> is of the form MIN-MAX, for MIN and MAX both
* recognized log severity levels, set *<b>min_out</b> to MIN and
* *<b>max_out</b> to MAX and return 0. Else, if <b>range</b> is of
* the form MIN, act as if MIN-err had been specified. Else, warn and
* return -1.
*/
static int
parse_log_severity_range(const char *range, int *min_out, int *max_out)
{
int levelMin, levelMax;
const char *cp;
cp = strchr(range, '-');
if (cp) {
if (cp == range) {
levelMin = LOG_DEBUG;
} else {
char *tmp_sev = tor_strndup(range, cp - range);
levelMin = parse_log_level(tmp_sev);
if (levelMin < 0) {
log_warn(LD_CONFIG, "Unrecognized minimum log severity '%s': must be "
"one of err|warn|notice|info|debug", tmp_sev);
tor_free(tmp_sev);
return -1;
}
tor_free(tmp_sev);
}
if (!*(cp+1)) {
levelMax = LOG_ERR;
} else {
levelMax = parse_log_level(cp+1);
if (levelMax < 0) {
log_warn(LD_CONFIG, "Unrecognized maximum log severity '%s': must be "
"one of err|warn|notice|info|debug", cp+1);
return -1;
}
}
} else {
levelMin = parse_log_level(range);
if (levelMin < 0) {
log_warn(LD_CONFIG, "Unrecognized log severity '%s': must be one of "
"err|warn|notice|info|debug", range);
return -1;
}
levelMax = LOG_ERR;
}
*min_out = levelMin;
*max_out = levelMax;
return 0;
}
/** /**
* Initialize the logs based on the configuration file. * Initialize the logs based on the configuration file.
*/ */
@ -3794,84 +3742,73 @@ options_init_logs(or_options_t *options, int validate_only)
elts = smartlist_create(); elts = smartlist_create();
for (opt = options->Logs; opt; opt = opt->next) { for (opt = options->Logs; opt; opt = opt->next) {
int levelMin=LOG_DEBUG, levelMax=LOG_ERR; log_severity_list_t *severity;
smartlist_split_string(elts, opt->value, NULL, const char *cfg = opt->value;
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3); severity = tor_malloc_zero(sizeof(log_severity_list_t));
if (smartlist_len(elts) == 0) { if (parse_log_severity_config(&cfg, severity) < 0) {
log_warn(LD_CONFIG, "No arguments to Log option 'Log %s'", opt->value); log_warn(LD_CONFIG, "Couldn't parse log levels in Log option 'Log %s'",
ok = 0; goto cleanup;
}
if (parse_log_severity_range(smartlist_get(elts,0), &levelMin,
&levelMax)) {
ok = 0; goto cleanup;
}
if (smartlist_len(elts) < 2) { /* only loglevels were provided */
if (!validate_only) {
if (daemon) {
log_warn(LD_CONFIG,
"Can't log to stdout with RunAsDaemon set; skipping stdout");
} else {
add_stream_log(levelMin, levelMax, "<stdout>", stdout);
}
}
goto cleanup;
}
if (!strcasecmp(smartlist_get(elts,1), "file")) {
if (smartlist_len(elts) != 3) {
log_warn(LD_CONFIG, "Bad syntax on file Log option 'Log %s'",
opt->value);
ok = 0; goto cleanup;
}
if (!validate_only) {
if (add_file_log(levelMin, levelMax, smartlist_get(elts, 2)) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s'", opt->value);
ok = 0;
}
}
goto cleanup;
}
if (smartlist_len(elts) != 2) {
log_warn(LD_CONFIG, "Wrong number of arguments on Log option 'Log %s'",
opt->value); opt->value);
ok = 0; goto cleanup; ok = 0; goto cleanup;
} }
if (!strcasecmp(smartlist_get(elts,1), "stdout")) {
if (daemon) { smartlist_split_string(elts, cfg, NULL,
log_warn(LD_CONFIG, "Can't log to stdout with RunAsDaemon set."); SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
ok = 0; goto cleanup;
} if (smartlist_len(elts) == 0)
smartlist_add(elts, tor_strdup("stdout"));
if (smartlist_len(elts) == 1 &&
(!strcasecmp(smartlist_get(elts,0), "stdout") ||
!strcasecmp(smartlist_get(elts,0), "stderr"))) {
int err = smartlist_len(elts) &&
!strcasecmp(smartlist_get(elts,0), "stderr");
if (!validate_only) { if (!validate_only) {
add_stream_log(levelMin, levelMax, "<stdout>", stdout); if (daemon) {
log_warn(LD_CONFIG,
"Can't log to %s with RunAsDaemon set; skipping stdout",
err?"stderr":"stdout");
} else {
add_stream_log(severity, err?"<stderr>":"<stdout>",
err?stderr:stdout);
severity=NULL;
}
} }
} else if (!strcasecmp(smartlist_get(elts,1), "stderr")) { goto cleanup;
if (daemon) { }
log_warn(LD_CONFIG, "Can't log to stderr with RunAsDaemon set."); if (smartlist_len(elts) == 1 &&
ok = 0; goto cleanup; !strcasecmp(smartlist_get(elts,0), "syslog")) {
}
if (!validate_only) {
add_stream_log(levelMin, levelMax, "<stderr>", stderr);
}
} else if (!strcasecmp(smartlist_get(elts,1), "syslog")) {
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
if (!validate_only) if (!validate_only) {
add_syslog_log(levelMin, levelMax); add_syslog_log(severity);
severity=NULL;
}
#else #else
log_warn(LD_CONFIG, "Syslog is not supported on this system. Sorry."); log_warn(LD_CONFIG, "Syslog is not supported on this system. Sorry.");
#endif #endif
} else { goto cleanup;
log_warn(LD_CONFIG, "Unrecognized log type %s",
(const char*)smartlist_get(elts,1));
if (strchr(smartlist_get(elts,1), '/') ||
strchr(smartlist_get(elts,1), '\\')) {
log_warn(LD_CONFIG, "Did you mean to say 'Log %s file %s' ?",
(const char *)smartlist_get(elts,0),
(const char *)smartlist_get(elts,1));
}
ok = 0; goto cleanup;
} }
if (smartlist_len(elts) == 2 &&
!strcasecmp(smartlist_get(elts,0), "file")) {
if (!validate_only) {
if (add_file_log(severity, smartlist_get(elts, 1)) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s'", opt->value);
ok = 0;
} else {
tor_free(severity);
}
}
goto cleanup;
}
log_warn(LD_CONFIG, "Bad syntax on file Log option 'Log %s'",
opt->value);
ok = 0; goto cleanup;
cleanup: cleanup:
SMARTLIST_FOREACH(elts, char*, cp, tor_free(cp)); SMARTLIST_FOREACH(elts, char*, cp, tor_free(cp));
smartlist_clear(elts); smartlist_clear(elts);
tor_free(severity);
} }
smartlist_free(elts); smartlist_free(elts);

View File

@ -3634,7 +3634,12 @@ main(int c, char**v)
} }
} }
add_stream_log(loglevel, LOG_ERR, "", stdout); {
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
for (i = loglevel; i >= LOG_ERR; --i)
s->masks[SEVERITY_MASK_IDX(i)] = ~0u;
add_stream_log(s, "", stdout);
}
options->command = CMD_RUN_UNITTESTS; options->command = CMD_RUN_UNITTESTS;
rep_hist_init(); rep_hist_init();

View File

@ -123,6 +123,7 @@ static int
parse_commandline(int argc, char **argv) parse_commandline(int argc, char **argv)
{ {
int i; int i;
log_severity_list_t *s;
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
show_help(); show_help();
@ -188,11 +189,15 @@ parse_commandline(int argc, char **argv)
} }
} }
s = tor_malloc_zero(sizeof(log_severity_list_t));
s->masks[SEVERITY_MASK_IDX(LOG_ERR)] = ~0u;
s->masks[SEVERITY_MASK_IDX(LOG_WARN)] = ~0u;
if (verbose) { if (verbose) {
add_stream_log(LOG_INFO, LOG_ERR, "<stderr>", stderr); s->masks[SEVERITY_MASK_IDX(LOG_NOTICE)] = ~0u;
} else { s->masks[SEVERITY_MASK_IDX(LOG_INFO)] = ~0u;
add_stream_log(LOG_NOTICE, LOG_ERR, "<stderr>", stderr); s->masks[SEVERITY_MASK_IDX(LOG_DEBUG)] = ~0u;
} }
add_stream_log(s, "<stderr>", stderr);
if (!identity_key_file) { if (!identity_key_file) {
identity_key_file = tor_strdup("./authority_identity_key"); identity_key_file = tor_strdup("./authority_identity_key");

View File

@ -280,6 +280,7 @@ main(int argc, char **argv)
uint32_t result = 0; uint32_t result = 0;
char *result_hostname = NULL; char *result_hostname = NULL;
char buf[INET_NTOA_BUF_LEN]; char buf[INET_NTOA_BUF_LEN];
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
init_logging(); init_logging();
@ -317,11 +318,15 @@ main(int argc, char **argv)
usage(); usage();
} }
s->masks[SEVERITY_MASK_IDX(LOG_ERR)] = ~0u;
s->masks[SEVERITY_MASK_IDX(LOG_WARN)] = ~0u;
if (isVerbose) { if (isVerbose) {
add_stream_log(LOG_DEBUG, LOG_ERR, "<stderr>", stderr); s->masks[SEVERITY_MASK_IDX(LOG_NOTICE)] = ~0u;
} else { s->masks[SEVERITY_MASK_IDX(LOG_INFO)] = ~0u;
add_stream_log(LOG_WARN, LOG_ERR, "<stderr>", stderr); s->masks[SEVERITY_MASK_IDX(LOG_DEBUG)] = ~0u;
} }
add_stream_log(s, "<stderr>", stderr);
if (n_args == 1) { if (n_args == 1) {
log_debug(LD_CONFIG, "defaulting to localhost:9050"); log_debug(LD_CONFIG, "defaulting to localhost:9050");
sockshost = 0x7f000001u; /* localhost */ sockshost = 0x7f000001u; /* localhost */