diff options
author | Nick Mathewson <nickm@torproject.org> | 2008-03-05 22:31:39 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2008-03-05 22:31:39 +0000 |
commit | f56ba5f3d62cc6a50432466d7202733d909a1ca6 (patch) | |
tree | 9357d7b1860a492c10d435f6ab8c4208aa618e64 /src/common/log.c | |
parent | d3589553bc7b091538ee93bd86867232b50b0f78 (diff) | |
download | tor-f56ba5f3d62cc6a50432466d7202733d909a1ca6.tar.gz tor-f56ba5f3d62cc6a50432466d7202733d909a1ca6.zip |
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
Diffstat (limited to 'src/common/log.c')
-rw-r--r-- | src/common/log.c | 272 |
1 files changed, 221 insertions, 51 deletions
diff --git a/src/common/log.c b/src/common/log.c index 6dfed6ca77..6c63019f7c 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -23,8 +23,9 @@ const char log_c_id[] = "$Id$"; #ifdef HAVE_TIME_H #include <time.h> #endif -#include "./util.h" -#include "./log.h" +#include "util.h" +#include "log.h" +#include "container.h" #include <event.h> @@ -38,13 +39,14 @@ typedef struct logfile_t { FILE *file; /**< Stream to receive log messages. */ 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 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_syslog; /**< Boolean: send messages to syslog. */ log_callback callback; /**< If not NULL, send messages to this function. */ + log_severity_list_t *severities; /**< DOCDOC */ } logfile_t; +static void log_free(logfile_t *victim); + /** Helper: map a log severity to descriptive string. */ static INLINE const char * 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. */ 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) { case LOG_DEBUG: @@ -69,7 +71,7 @@ should_log_function_name(uint32_t domain, int severity) /* All debugging messages occur in interesting places. */ return 1; case LOG_NOTICE: - case LOG_WARN: + case LOG_WARN: case LOG_ERR: /* We care about places where bugs occur. */ return (domain == LD_BUG); @@ -194,7 +196,7 @@ log_tor_version(logfile_t *lf, int reset) */ static INLINE char * 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) { 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). */ static void -logv(int severity, uint32_t domain, const char *funcname, const char *format, - va_list ap) +logv(int severity, log_domain_mask_t domain, const char *funcname, + const char *format, va_list ap) { char buf[10024]; int formatted = 0; @@ -258,7 +260,7 @@ logv(int severity, uint32_t domain, const char *funcname, const char *format, LOCK_LOGS(); lf = logfiles; while (lf) { - if (severity > lf->min_loglevel || severity < lf->max_loglevel) { + if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { lf = lf->next; continue; } @@ -302,7 +304,7 @@ logv(int severity, uint32_t domain, const char *funcname, const char *format, /** Output a message to the log. */ void -_log(int severity, uint32_t domain, const char *format, ...) +_log(int severity, log_domain_mask_t domain, const char *format, ...) { va_list ap; 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>. */ #ifdef __GNUC__ 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; if (severity > _log_global_min_severity) @@ -327,7 +330,7 @@ _log_fn(int severity, uint32_t domain, const char *fn, const char *format, ...) #else const char *_log_fn_function_name=NULL; 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; 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; } void -_log_debug(uint32_t domain, const char *format, ...) +_log_debug(log_domain_mask_t domain, const char *format, ...) { va_list ap; /* 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; } void -_log_info(uint32_t domain, const char *format, ...) +_log_info(log_domain_mask_t domain, const char *format, ...) { va_list ap; if (LOG_INFO > _log_global_min_severity) @@ -361,7 +364,7 @@ _log_info(uint32_t domain, const char *format, ...) _log_fn_function_name = NULL; } void -_log_notice(uint32_t domain, const char *format, ...) +_log_notice(log_domain_mask_t domain, const char *format, ...) { va_list ap; if (LOG_NOTICE > _log_global_min_severity) @@ -372,7 +375,7 @@ _log_notice(uint32_t domain, const char *format, ...) _log_fn_function_name = NULL; } void -_log_warn(uint32_t domain, const char *format, ...) +_log_warn(log_domain_mask_t domain, const char *format, ...) { va_list ap; if (LOG_WARN > _log_global_min_severity) @@ -383,7 +386,7 @@ _log_warn(uint32_t domain, const char *format, ...) _log_fn_function_name = NULL; } void -_log_err(uint32_t domain, const char *format, ...) +_log_err(log_domain_mask_t domain, const char *format, ...) { va_list ap; if (LOG_ERR > _log_global_min_severity) @@ -395,6 +398,15 @@ _log_err(uint32_t domain, const char *format, ...) } #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. */ void logs_free_all(void) @@ -408,8 +420,7 @@ logs_free_all(void) victim = next; next = next->next; close_log(victim); - tor_free(victim->filename); - tor_free(victim); + log_free(victim); } tor_free(appname); } @@ -436,8 +447,7 @@ delete_log(logfile_t *victim) return; tmpl->next = victim->next; } - tor_free(victim->filename); - tor_free(victim); + log_free(victim); } /** 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 - * between <b>loglevelMin</b> and <b>loglevelMax</b> (inclusive) to - * <b>stream</b>. */ +/** DOCDOC XXXX021 remove me. */ +static log_severity_list_t * +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 -add_stream_log_impl(int loglevelMin, int loglevelMax, +add_stream_log_impl(log_severity_list_t *severity, const char *name, FILE *stream) { logfile_t *lf; lf = tor_malloc_zero(sizeof(logfile_t)); lf->filename = tor_strdup(name); - lf->min_loglevel = loglevelMin; - lf->max_loglevel = loglevelMax; + lf->severities = severity; lf->file = stream; lf->next = logfiles; @@ -476,14 +497,15 @@ add_stream_log_impl(int loglevelMin, int loglevelMax, _log_global_min_severity = get_min_log_level(); } -/** Add a log handler to send all messages of severity <b>loglevel</b> - * or higher to <b>stream</b>. */ +/** 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. */ void -add_stream_log(int loglevelMin, int loglevelMax, +add_stream_log(log_severity_list_t *severity, const char *name, FILE *stream) { LOCK_LOGS(); - add_stream_log_impl(loglevelMin, loglevelMax, name, stream); + add_stream_log_impl(severity, name, stream); UNLOCK_LOGS(); } @@ -502,23 +524,22 @@ void add_temp_log(void) { 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; UNLOCK_LOGS(); } /** - * Add a log handler to send messages of severity between - * <b>logLevelmin</b> and <b>logLevelMax</b> to the function - * <b>cb</b>. + * Add a log handler to send messages in <b>severity</b> + * to the function <b>cb</b>. */ 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; lf = tor_malloc_zero(sizeof(logfile_t)); - lf->min_loglevel = loglevelMin; - lf->max_loglevel = loglevelMax; + lf->severities = severity; lf->filename = tor_strdup("<callback>"); lf->callback = cb; lf->next = logfiles; @@ -540,8 +561,8 @@ change_callback_log_severity(int loglevelMin, int loglevelMax, LOCK_LOGS(); for (lf = logfiles; lf; lf = lf->next) { if (lf->callback == cb) { - lf->min_loglevel = loglevelMin; - lf->max_loglevel = loglevelMax; + tor_free(lf->severities); + lf->severities = new_severity_list(loglevelMin, loglevelMax); } } _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 */ *p = (*p)->next; close_log(lf); - tor_free(lf->filename); - tor_free(lf); + log_free(lf); } else { p = &((*p)->next); } @@ -602,14 +622,14 @@ mark_logs_temp(void) * (by fopen). */ int -add_file_log(int loglevelMin, int loglevelMax, const char *filename) +add_file_log(log_severity_list_t *severity, const char *filename) { FILE *f; logfile_t *lf; f = fopen(filename, "a"); if (!f) return -1; LOCK_LOGS(); - add_stream_log_impl(loglevelMin, loglevelMax, filename, f); + add_stream_log_impl(severity, filename, f); logfiles->needs_close = 1; lf = logfiles; _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. */ int -add_syslog_log(int loglevelMin, int loglevelMax) +add_syslog_log(log_severity_list_t *severity) { logfile_t *lf; if (syslog_count++ == 0) @@ -637,9 +657,9 @@ add_syslog_log(int loglevelMin, int loglevelMax) openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY); lf = tor_malloc_zero(sizeof(logfile_t)); - lf->min_loglevel = loglevelMin; + lf->severities = severity; lf->filename = tor_strdup("<syslog>"); - lf->max_loglevel = loglevelMax; + lf->is_syslog = 1; LOCK_LOGS(); @@ -676,15 +696,163 @@ log_level_to_string(int 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. */ int get_min_log_level(void) { logfile_t *lf; + int i; int min = LOG_ERR; for (lf = logfiles; lf; lf = lf->next) { - if (lf->min_loglevel > min) - min = lf->min_loglevel; + for (i = LOG_DEBUG; i > min; --i) + if (lf->severities->masks[SEVERITY_MASK_IDX(i)]) + min = i; } return min; } @@ -694,9 +862,11 @@ void switch_logs_debug(void) { logfile_t *lf; + int i; LOCK_LOGS(); 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(); } |