Add backend support for multiple logfiles, including console logs.

Also optimize logging by formatting messages in memory before sending
them through stdio.  (It turns out (according to gprof) that logging
performance matters.)


svn:r463
This commit is contained in:
Nick Mathewson 2003-09-16 17:58:36 +00:00
parent c09de55fb8
commit 7711c2e745
2 changed files with 108 additions and 12 deletions

View File

@ -5,7 +5,18 @@
#include "../or/or.h"
#include "util.h"
static const char *sev_to_string(int severity) {
struct logfile_t;
typedef struct logfile_t {
struct logfile_t *next;
const char *filename;
FILE *file;
int needs_close;
int loglevel;
int max_loglevel;
} logfile_t;
static INLINE const char *sev_to_string(int severity) {
switch(severity) {
case LOG_DEBUG: return "debug";
case LOG_INFO: return "info";
@ -20,26 +31,63 @@ static const char *sev_to_string(int severity) {
}
static int loglevel = LOG_DEBUG;
static logfile_t *logfiles = NULL;
/* Format a log message into a fixed-sized buffer. (This is factored out
* of 'logv' so that we never format a message more than once.
*/
static INLINE void format_msg(char *buf, size_t buf_len,
int severity, const char *funcname,
const char *format, va_list ap)
{
time_t t;
struct timeval now;
int n;
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
my_gettimeofday(&now);
t = (time_t)now.tv_sec;
n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
n += snprintf(buf+n, buf_len-n,
".%.3ld [%s] ",
(long)now.tv_usec / 1000, sev_to_string(severity));
if (funcname)
n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
n += vsnprintf(buf+n,buf_len-n,format,ap);
buf[n]='\n';
buf[n+1]='\0';
}
static void
logv(int severity, const char *funcname, const char *format, va_list ap)
{
char buf[201];
time_t t;
struct timeval now;
char buf[1024];
int formatted = 0;
logfile_t *lf;
assert(format);
if (severity < loglevel)
return;
my_gettimeofday(&now);
if (!logfiles) {
/* XXX This is a temporary measure until we get configuration support
for logfiles. */
add_stream_log(loglevel, "<stdout>", stdout);
}
for (lf = logfiles; lf; lf = lf->next) {
if (severity < lf->loglevel || severity > lf->max_loglevel)
continue;
if (!lf->file)
continue;
t = time(NULL);
strftime(buf, 200, "%b %d %H:%M:%S", localtime(&t));
printf("%s.%.3ld [%s] ", buf, (long)now.tv_usec / 1000, sev_to_string(severity));
if (funcname)
printf("%s(): ", funcname);
vprintf(format,ap);
printf("\n");
if (!formatted) {
format_msg(buf, 1024, severity, funcname, format, ap);
formatted = 1;
}
fputs(buf, lf->file);
}
}
void
@ -65,4 +113,47 @@ void _log_fn(int severity, const char *fn, const char *format, ...)
va_end(ap);
}
void close_logs()
{
logfile_t *next, *lf;
for (lf = logfiles; lf; lf = lf->next) {
if (lf->needs_close)
fclose(lf->file);
next = lf->next;
free(lf);
}
logfiles = NULL;
}
void reset_logs()
{
logfile_t *lf;
for (lf = logfiles; lf; lf = lf->next) {
if (lf->needs_close) {
fclose(lf->file);
lf->file = fopen(lf->filename, "a");
}
}
}
void add_stream_log(int loglevel, const char *name, FILE *stream)
{
logfile_t *lf;
lf = tor_malloc(sizeof(logfile_t));
lf->filename = name;
lf->needs_close = 0;
lf->loglevel = loglevel;
lf->max_loglevel = LOG_EMERG;
lf->file = stream;
lf->next = logfiles;
logfiles = lf;
}
void add_file_log(int loglevel, const char *filename)
{
FILE *f;
f = fopen(filename, "a");
if (!f) return;
add_stream_log(loglevel, filename, f);
logfiles->needs_close = 1;
}

View File

@ -30,6 +30,11 @@
void log_set_severity(int severity);
void add_stream_log(int loglevel, const char *name, FILE *stream);
void add_file_log(int severity, const char *filename);
void close_logs();
void reset_logs();
/* Outputs a message to stdout */
void log(int severity, const char *format, ...) CHECK_PRINTF(2,3);