log.c 3.71 KB
Newer Older
1
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2
3
/* See LICENSE for licensing information */
/* $Id$ */
Roger Dingledine's avatar
Roger Dingledine committed
4

5
#include "../or/or.h"
6

7
8
9
10
11
12
13
14
15
16
17
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) {
18
  switch(severity) {
19
20
    case LOG_DEBUG:   return "debug";
    case LOG_INFO:    return "info";
Roger Dingledine's avatar
Roger Dingledine committed
21
    case LOG_WARN:    return "warn";
22
    case LOG_ERR:     return "err";
23
    default:          assert(0); return "UNKNOWN";
24
25
26
  }
}

27
static int loglevel = LOG_DEBUG;
28
static logfile_t *logfiles = NULL;
29

30
31
32
33
34
35
/* 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) 
Roger Dingledine's avatar
Roger Dingledine committed
36
{
37
  time_t t;
38
  struct timeval now;
39
40
41
42
  int n;

  buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
  
43
  tor_gettimeofday(&now);
44
45
  t = (time_t)now.tv_sec;
  
46
  n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
47
  n += snprintf(buf+n, buf_len-n,
48
49
50
                ".%.3ld [%s] ", 
                (long)now.tv_usec / 1000, sev_to_string(severity));
  if(n > buf_len)
51
52
53
54
    n = buf_len-1; /* the *nprintf funcs return how many bytes they
                    * _would_ print, if the output is truncated.
                    * Subtract one because the count doesn't include the \0 */

55
  if (funcname) {
56
    n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
57
    if(n > buf_len)
58
      n = buf_len-1;
59
  }
60
61

  n += vsnprintf(buf+n,buf_len-n,format,ap);
62
  if(n > buf_len)
63
    n = buf_len-1;
64
65
66
67
68
69
70
  buf[n]='\n';
  buf[n+1]='\0';
}

static void 
logv(int severity, const char *funcname, const char *format, va_list ap)
{
71
  char buf[10024];
72
73
  int formatted = 0;
  logfile_t *lf;
74
  
75
  assert(format);
76
  if (severity < loglevel)
77
    return;
78
79
80
81
82
83
84
85
86
87
  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;
88

89
    if (!formatted) {
90
      format_msg(buf, 10024, severity, funcname, format, ap);
91
92
93
      formatted = 1;
    }
    fputs(buf, lf->file);
Nick Mathewson's avatar
Nick Mathewson committed
94
    fflush(lf->file);
95
    /* XXX check for EOF */
96
  }
97
}
98

99
100
101
102
void 
log_set_severity(int severity)
{
  loglevel = severity;
103
104
105
}

/* Outputs a message to stdout */
Roger Dingledine's avatar
Roger Dingledine committed
106
void _log(int severity, const char *format, ...)
107
108
109
110
111
{
  va_list ap;
  va_start(ap,format);
  logv(severity, NULL, format, ap);
  va_end(ap);
Roger Dingledine's avatar
Roger Dingledine committed
112
}
113

114
115
116
117
118
119
120
121
void _log_fn(int severity, const char *fn, const char *format, ...)
{
  va_list ap;
  va_start(ap,format);
  logv(severity, fn, format, ap);
  va_end(ap);
}

122
123
124
125
126
127
128
129
130
131
132
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;
}
133

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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;
Roger Dingledine's avatar
Roger Dingledine committed
152
  lf->max_loglevel = LOG_ERR;
153
154
155
156
157
  lf->file = stream;
  lf->next = logfiles;
  logfiles = lf;
}

158
int add_file_log(int loglevel, const char *filename) 
159
160
161
{
  FILE *f;
  f = fopen(filename, "a");
162
  if (!f) return -1;
163
164
  add_stream_log(loglevel, filename, f);
  logfiles->needs_close = 1;
165
  return 0;
166
}
167