mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-19 18:00:33 +01:00
Add SysLog option to direct log messages to the system log instead of a FILE*.
svn:r2591
This commit is contained in:
parent
64fc462a3a
commit
26f3cb8652
@ -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)
|
||||
|
@ -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
|
||||
|
108
src/common/log.c
108
src/common/log.c
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user