Skip to content
Snippets Groups Projects
Commit 7711c2e7 authored by Nick Mathewson's avatar Nick Mathewson :game_die:
Browse files

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
parent c09de55f
No related branches found
No related tags found
No related merge requests found
......@@ -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;
static void
logv(int severity, const char *funcname, const char *format, va_list ap)
/* 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)
{
char buf[201];
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[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;
}
......@@ -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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment