Add SysLog option to direct log messages to the system log instead of a FILE*.

svn:r2591
This commit is contained in:
Nick Mathewson 2004-10-26 21:48:41 +00:00
parent 64fc462a3a
commit 26f3cb8652
7 changed files with 139 additions and 39 deletions

View File

@ -143,7 +143,7 @@ AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/stat.h sy
dnl These headers are not essential
AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h)
AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h syslog.h)
AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime)
AC_REPLACE_FUNCS(strlcat strlcpy)

View File

@ -32,6 +32,10 @@ Set the verboseness level of the primary log. (Default: warn)
\fBlogfile \fR\fIFILE\fP
Rather than logging to stdout, log to FILE.
.TP
\fBsyslog\fP
Rather than logging to stdout, send messages to the system log. (Not
supported on all platforms)
.TP
\fBbandwidthrate \fR\fINUM\fP
A token bucket limits the average incoming bandwidth on this node to NUM bytes per second. (Default: 800000)
.TP

View File

@ -34,6 +34,7 @@ typedef struct logfile_t {
int 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. */
} logfile_t;
/** Helper: map a log severity to descriptive string. */
@ -50,8 +51,13 @@ static INLINE const char *sev_to_string(int severity) {
/** Linked list of logfile_t. */
static logfile_t *logfiles = NULL;
#ifdef HAVE_SYSLOG_H
static int syslog_count = 0;
#endif
static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim);
static int reset_log(logfile_t *lf);
static INLINE size_t
_log_prefix(char *buf, size_t buf_len, int severity)
@ -104,16 +110,19 @@ static void log_tor_version(logfile_t *lf, int reset)
/** Helper: Format a log message into a fixed-sized buffer. (This is
* factored out of <b>logv</b> so that we never format a message more
* than once.)
* than once.) Return a pointer to the first character of the message
* portion of the formatted string.
*/
static INLINE void format_msg(char *buf, size_t buf_len,
static INLINE char *format_msg(char *buf, size_t buf_len,
int severity, const char *funcname,
const char *format, va_list ap)
{
size_t n;
char *end_of_prefix;
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
n = _log_prefix(buf, buf_len, severity);
end_of_prefix = buf+n;
if (funcname) {
n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
@ -128,6 +137,7 @@ static INLINE void format_msg(char *buf, size_t buf_len,
}
buf[n]='\n';
buf[n+1]='\0';
return end_of_prefix;
}
/** Helper: sends a message to the appropriate logfiles, at loglevel
@ -140,23 +150,32 @@ logv(int severity, const char *funcname, const char *format, va_list ap)
char buf[10024];
int formatted = 0;
logfile_t *lf;
char *end_of_prefix=NULL;
assert(format);
lf = logfiles;
while(lf) {
if (severity < lf->loglevel || severity > lf->max_loglevel) {
if (severity > lf->loglevel || severity < lf->max_loglevel) {
lf = lf->next;
continue;
}
if (!lf->file) {
if (! (lf->file || lf->is_syslog)) {
lf = lf->next;
continue;
}
if (!formatted) {
format_msg(buf, sizeof(buf), severity, funcname, format, ap);
end_of_prefix =
format_msg(buf, sizeof(buf), severity, funcname, format, ap);
formatted = 1;
}
if (lf->is_syslog) {
#ifdef HAVE_SYSLOG_H
syslog(severity, "%s", end_of_prefix);
#endif
lf = lf->next;
continue;
}
if(fputs(buf, lf->file) == EOF ||
fflush(lf->file) == EOF) { /* error */
/* don't log the error! Blow away this log entry and continue. */
@ -194,8 +213,7 @@ void close_logs()
while(logfiles) {
victim = logfiles;
logfiles = logfiles->next;
if (victim->needs_close)
fclose(victim->file);
close_log(victim);
tor_free(victim->filename);
tor_free(victim);
}
@ -206,17 +224,12 @@ void reset_logs()
{
logfile_t *lf = logfiles;
while(lf) {
if (lf->needs_close) {
if(fclose(lf->file)==EOF ||
!(lf->file = fopen(lf->filename, "a"))) {
/* error. don't log it. delete the log entry and continue. */
logfile_t *victim = lf;
lf = victim->next;
delete_log(victim);
continue;
} else {
log_tor_version(lf, 1);
}
if (reset_log(lf)) {
/* error. don't log it. delete the log entry and continue. */
logfile_t *victim = lf;
lf = victim->next;
delete_log(victim);
continue;
}
lf = lf->next;
}
@ -241,19 +254,43 @@ static void delete_log(logfile_t *victim) {
tor_free(victim);
}
static void close_log(logfile_t *victim)
{
if (victim->needs_close && victim->file) {
fclose(victim->file);
} else if (victim->is_syslog) {
#ifdef HAVE_SYSLOG_H
if (--syslog_count == 0)
/* There are no other syslogs; close the logging facility. */
closelog();
#endif
}
}
static int reset_log(logfile_t *lf)
{
if (lf->needs_close) {
if(fclose(lf->file)==EOF ||
!(lf->file = fopen(lf->filename, "a"))) {
return -1;
} else {
log_tor_version(lf, 1);
}
}
return 0;
}
/** Add a log handler to send all messages of severity <b>loglevel</b>
* or higher to <b>stream</b>. */
void add_stream_log(int loglevelMin, int loglevelMax, const char *name, FILE *stream)
{
logfile_t *lf;
lf = tor_malloc(sizeof(logfile_t));
lf = tor_malloc_zero(sizeof(logfile_t));
lf->filename = tor_strdup(name);
lf->needs_close = 0;
lf->loglevel = loglevelMin;
lf->max_loglevel = loglevelMax;
lf->file = stream;
lf->next = logfiles;
lf->is_temporary = 0;
logfiles = lf;
}
@ -266,6 +303,7 @@ void add_temp_log(void)
logfiles->is_temporary = 1;
}
/** Close any log handlers added by add_temp_log or marked by mark_logs_temp */
void close_temp_logs(void)
{
logfile_t *lf, **p;
@ -273,8 +311,7 @@ void close_temp_logs(void)
if ((*p)->is_temporary) {
lf = *p;
*p = (*p)->next;
if (lf->needs_close)
fclose(lf->file);
close_log(lf);
tor_free(lf->filename);
tor_free(lf);
} else {
@ -283,6 +320,7 @@ void close_temp_logs(void)
}
}
/** Configure all log handles to be closed by close_temp_logs */
void mark_logs_temp(void)
{
logfile_t *lf;
@ -306,6 +344,28 @@ int add_file_log(int loglevelMin, int loglevelMax, const char *filename)
return 0;
}
#ifdef HAVE_SYSLOG_H
/**
* Add a log handler to send messages to they system log facility.
*/
int add_syslog_log(int loglevelMin, int loglevelMax)
{
logfile_t *lf;
if (syslog_count++ == 0)
/* This is the the first syslog. */
openlog("Tor", LOG_NDELAY, LOG_DAEMON);
lf = tor_malloc_zero(sizeof(logfile_t));
lf->loglevel = loglevelMin;
lf->filename = tor_strdup("<syslog>");
lf->max_loglevel = loglevelMax;
lf->is_syslog = 1;
lf->next = logfiles;
logfiles = lf;
return 0;
}
#endif
/** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */
int parse_log_level(const char *level) {
@ -327,7 +387,7 @@ int get_min_log_level(void)
logfile_t *lf;
int min = LOG_ERR;
for (lf = logfiles; lf; lf = lf->next) {
if (lf->loglevel < min)
if (lf->loglevel > min)
min = lf->loglevel;
}
return min;

View File

@ -18,24 +18,37 @@
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#define LOG_WARN LOG_WARNING
#if LOG_DEBUG < LOG_ERR
#error "Your syslog.h thinks high numbers are more important. We aren't prepared to deal with that."
#endif
#else
/* XXXX Note: The code was originally written to refer to severities,
* with 0 being the least severe; while syslog's logging code refers to
* priorities, with 0 being the most important. Thus, all our comparisons
* needed to be reversed when we added syslog support.
*
* The upshot of this is that comments about log levels may be messed
* up: for "maximum severity" read "most severe" and "numerically
* *lowest* severity".
*/
/** Debug-level severity: for hyper-verbose messages of no interest to
* anybody but developers. */
#define LOG_DEBUG 0
#define LOG_DEBUG 7
/** Info-level severity: for messages that appear frequently during normal
* operation. */
#define LOG_INFO 1
#define LOG_INFO 6
/** Notice-level severity: for messages that appear infrequently
* during normal operation; that the user will probably care about;
* and that are not errors.
*/
#define LOG_NOTICE 2
#define LOG_NOTICE 5
/** Warn-level severity: for messages that only appear when something has gone
* wrong. */
#define LOG_WARN 3
#define LOG_WARN 4
/** Error-level severity: for messages that only appear when something has gone
* very wrong, and the Tor process can no longer proceed. */
#define LOG_ERR 4
#define LOG_ERR 3
#endif
/* magic to make GCC check for proper format strings. */
@ -49,9 +62,12 @@
int parse_log_level(const char *level);
void add_stream_log(int severityMin, int severityMax, const char *name, FILE *stream);
int add_file_log(int severityMin, int severityMax, const char *filename);
#ifdef HAVE_SYSLOG_H
int add_syslog_log(int loglevelMin, int loglevelMax);
#endif
int get_min_log_level(void);
void close_logs();
void reset_logs();
void close_logs(void);
void reset_logs(void);
void add_temp_log(void);
void close_temp_logs(void);
void mark_logs_temp(void);

View File

@ -1740,13 +1740,17 @@ try_next_line:
while(*value && isspace((int)*value))
value++;
#if 0
if(!*end || !*value) { /* only a key on this line. no value. */
*end = 0;
log_fn(LOG_WARN,"Line has keyword '%s' but no value. Failing.",key);
return -1;
}
#endif
*end = 0; /* null it out */
tor_assert(key);
tor_assert(value);
log_fn(LOG_DEBUG,"got keyword '%s', value '%s'", key, value);
*key_out = key, *value_out = value;
return 1;

View File

@ -29,6 +29,9 @@ AllowUnverifiedNodes middle,rendezvous
### Send all debug messages ONLY to /var/log/tor/debug
#LogFile /var/log/tor/debug
#LogLevel debug-debug
### To use the system log instead of Tor's logfiles, uncomment these lines:
#SysLog
#LogLevel notice
# Uncomment this to start the process in the background
#RunAsDaemon 1

View File

@ -292,7 +292,7 @@ config_assign(or_options_t *options, struct config_line_t *list)
config_compare(list, "SocksPort", CONFIG_TYPE_UINT, &options->SocksPort) ||
config_compare(list, "SocksBindAddress",CONFIG_TYPE_LINELIST,&options->SocksBindAddress) ||
config_compare(list, "SocksPolicy", CONFIG_TYPE_LINELIST,&options->SocksPolicy) ||
config_compare(list, "SysLog", CONFIG_TYPE_LINELIST,&options->LogOptions) ||
config_compare(list, "TrafficShaping", CONFIG_TYPE_OBSOLETE, NULL) ||
config_compare(list, "User", CONFIG_TYPE_STRING, &options->User)
@ -964,7 +964,8 @@ add_single_log(struct config_line_t *level_opt,
} else {
levelMax = LOG_ERR;
}
if (file_opt) {
if (file_opt && !strcasecmp(file_opt->key, "LogFile")) {
if (add_file_log(levelMin, levelMax, file_opt->value) < 0) {
log_fn(LOG_WARN, "Cannot write to LogFile '%s': %s.", file_opt->value,
strerror(errno));
@ -972,6 +973,16 @@ add_single_log(struct config_line_t *level_opt,
}
log_fn(LOG_NOTICE, "Successfully opened LogFile '%s', redirecting output.",
file_opt->value);
} else if (file_opt && !strcasecmp(file_opt->key, "SysLog")) {
#ifdef HAVE_SYSLOG_H
if (add_syslog_log(levelMin, levelMax) < 0) {
log_fn(LOG_WARN, "Cannot open system log facility");
return -1;
}
log_fn(LOG_NOTICE, "Successfully opened system log, redirecting output.");
#else
log_fn(LOG_WARN, "Tor was compiled without system logging enabled; can't enable SysLog.");
#endif
} else if (!isDaemon) {
add_stream_log(levelMin, levelMax, "<stdout>", stdout);
close_temp_logs();
@ -998,7 +1009,8 @@ config_init_logs(or_options_t *options)
/* Special case for if first option is LogLevel. */
if (opt && !strcasecmp(opt->key, "LogLevel")) {
if (opt->next && !strcasecmp(opt->next->key, "LogFile")) {
if (opt->next && (!strcasecmp(opt->next->key, "LogFile") ||
!strcasecmp(opt->next->key, "SysLog"))) {
if (add_single_log(opt, opt->next, options->RunAsDaemon) < 0)
return -1;
opt = opt->next->next;
@ -1013,17 +1025,18 @@ config_init_logs(or_options_t *options)
while (opt) {
if (!strcasecmp(opt->key, "LogLevel")) {
log_fn(LOG_WARN, "Two LogLevel options in a row without intervening LogFile");
log_fn(LOG_WARN, "Two LogLevel options in a row without intervening LogFile or SysLog");
opt = opt->next;
} else {
tor_assert(!strcasecmp(opt->key, "LogFile"));
tor_assert(!strcasecmp(opt->key, "LogFile") ||
!strcasecmp(opt->key, "SysLog"));
if (opt->next && !strcasecmp(opt->next->key, "LogLevel")) {
/* LogFile followed by LogLevel */
/* LogFile/SysLog followed by LogLevel */
if (add_single_log(opt->next, opt, options->RunAsDaemon) < 0)
return -1;
opt = opt->next->next;
} else {
/* LogFile followed by LogFile or end of list. */
/* LogFile/SysLog followed by LogFile/SysLog or end of list. */
if (add_single_log(NULL, opt, options->RunAsDaemon) < 0)
return -1;
opt = opt->next;