summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/log.c115
-rw-r--r--src/common/log.h5
2 files changed, 108 insertions, 12 deletions
diff --git a/src/common/log.c b/src/common/log.c
index f38089a40f..c4a5e683c9 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -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;
+}
diff --git a/src/common/log.h b/src/common/log.h
index 38f330c081..9b9d072eec 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -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);