Tinker with log behavior: never send error messages about logs into the bitbucket
[tor.git] / src / common / log.c
blob1b77cc49aea033e6893383698d283166d954b2d0
1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
5 /**
6 * \file log.c
8 * \brief Functions to send messages to log files or the console.
9 */
11 #include <stdarg.h>
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include "orconfig.h"
16 #include "./util.h"
17 #include "./log.h"
20 #ifdef MS_WINDOWS
21 #define vsnprintf _vsnprintf
22 #define snprintf _snprintf
23 #endif
25 /** Information for a single logfile; only used in log.c */
26 typedef struct logfile_t {
27 struct logfile_t *next; /**< Next logfile_t in the linked list. */
28 char *filename; /**< Filename to open. */
29 FILE *file; /**< Stream to receive log messages. */
30 int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
31 int loglevel; /**< Lowest severity level to send to this stream. */
32 int max_loglevel; /**< Highest severity level to send to this stream. */
33 int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
34 } logfile_t;
36 /** Helper: map a log severity to descriptive string. */
37 static INLINE const char *sev_to_string(int severity) {
38 switch(severity) {
39 case LOG_DEBUG: return "debug";
40 case LOG_INFO: return "info";
41 case LOG_NOTICE: return "notice";
42 case LOG_WARN: return "warn";
43 case LOG_ERR: return "err";
44 default: assert(0); return "UNKNOWN";
48 /** Linked list of logfile_t. */
49 static logfile_t *logfiles = NULL;
51 /** Helper: Format a log message into a fixed-sized buffer. (This is
52 * factored out of <b>logv</b> so that we never format a message more
53 * than once.)
55 static INLINE void format_msg(char *buf, size_t buf_len,
56 int severity, const char *funcname,
57 const char *format, va_list ap)
59 time_t t;
60 struct timeval now;
61 size_t n;
63 buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
65 tor_gettimeofday(&now);
66 t = (time_t)now.tv_sec;
68 n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
69 n += snprintf(buf+n, buf_len-n,
70 ".%.3ld [%s] ",
71 (long)now.tv_usec / 1000, sev_to_string(severity));
72 if(n > buf_len)
73 n = buf_len-1; /* the *nprintf funcs return how many bytes they
74 * _would_ print, if the output is truncated.
75 * Subtract one because the count doesn't include the \0 */
77 if (funcname) {
78 n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
79 if(n > buf_len)
80 n = buf_len-1;
83 n += vsnprintf(buf+n,buf_len-n,format,ap);
84 if(n > buf_len)
85 n = buf_len-1;
86 buf[n]='\n';
87 buf[n+1]='\0';
90 /** Helper: sends a message to the appropriate logfiles, at loglevel
91 * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
92 * message. The actual message is derived as from vsprintf(format,ap).
94 static void
95 logv(int severity, const char *funcname, const char *format, va_list ap)
97 char buf[10024];
98 int formatted = 0;
99 logfile_t *lf;
101 assert(format);
102 for (lf = logfiles; lf; lf = lf->next) {
103 if (severity < lf->loglevel || severity > lf->max_loglevel)
104 continue;
105 if (!lf->file)
106 continue;
108 if (!formatted) {
109 format_msg(buf, 10024, severity, funcname, format, ap);
110 formatted = 1;
112 if(fputs(buf, lf->file) == EOF) { /* error */
113 assert(0); /* XXX */
115 if(fflush(lf->file) == EOF) { /* error */
116 /* don't log the error! */
117 assert(0); /* XXX fail for now. what's better to do? */
122 /** Output a message to the log. */
123 void _log(int severity, const char *format, ...)
125 va_list ap;
126 va_start(ap,format);
127 logv(severity, NULL, format, ap);
128 va_end(ap);
131 /** Output a message to the log, prefixed with a function name <b>fn</b>. */
132 void _log_fn(int severity, const char *fn, const char *format, ...)
134 va_list ap;
135 va_start(ap,format);
136 logv(severity, fn, format, ap);
137 va_end(ap);
140 /** Close all open log files. */
141 void close_logs()
143 logfile_t *victim;
144 while(logfiles) {
145 victim = logfiles;
146 logfiles = logfiles->next;
147 if (victim->needs_close)
148 fclose(victim->file);
149 tor_free(victim->filename);
150 tor_free(victim);
154 /** Close and re-open all log files; used to rotate logs on SIGHUP. */
155 void reset_logs()
157 logfile_t *lf;
158 for (lf = logfiles; lf; lf = lf->next) {
159 if (lf->needs_close) {
160 fclose(lf->file);
161 lf->file = fopen(lf->filename, "a");
166 /** Add a log handler to send all messages of severity <b>loglevel</b>
167 * or higher to <b>stream</b>. */
168 void add_stream_log(int loglevelMin, int loglevelMax, const char *name, FILE *stream)
170 logfile_t *lf;
171 lf = tor_malloc(sizeof(logfile_t));
172 lf->filename = tor_strdup(name);
173 lf->needs_close = 0;
174 lf->loglevel = loglevelMin;
175 lf->max_loglevel = loglevelMax;
176 lf->file = stream;
177 lf->next = logfiles;
178 lf->is_temporary = 0;
179 logfiles = lf;
182 /** Add a log handler to receive messages during startup (before the real
183 * logs are initialized).
185 void add_temp_log(void)
187 add_stream_log(LOG_INFO, LOG_ERR, "<temp>", stdout);
188 logfiles->is_temporary = 1;
191 void close_temp_logs(void)
193 logfile_t *lf, **p;
194 for (p = &logfiles; *p; ) {
195 if ((*p)->is_temporary) {
196 lf = *p;
197 *p = (*p)->next;
198 if (lf->needs_close)
199 fclose(lf->file);
200 tor_free(lf->filename);
201 tor_free(lf);
202 } else {
203 p = &((*p)->next);
209 * Add a log handler to send messages to <b>filename</b>. If opening
210 * the logfile fails, -1 is returned and errno is set appropriately
211 * (by fopen).
213 int add_file_log(int loglevelMin, int loglevelMax, const char *filename)
215 FILE *f;
216 f = fopen(filename, "a");
217 if (!f) return -1;
218 add_stream_log(loglevelMin, loglevelMax, filename, f);
219 logfiles->needs_close = 1;
220 return 0;
223 /** If <b>level</b> is a valid log severity, return the corresponding
224 * numeric value. Otherwise, return -1. */
225 int parse_log_level(const char *level) {
226 if (!strcasecmp(level, "err"))
227 return LOG_ERR;
228 else if (!strcasecmp(level, "notice"))
229 return LOG_NOTICE;
230 else if (!strcasecmp(level, "info"))
231 return LOG_INFO;
232 else if (!strcasecmp(level, "debug"))
233 return LOG_DEBUG;
234 else
235 return -1;
238 int get_min_log_level(void)
240 logfile_t *lf;
241 int min = LOG_ERR;
242 for (lf = logfiles; lf; lf = lf->next) {
243 if (lf->loglevel < min)
244 min = lf->loglevel;
246 return min;
251 Local Variables:
252 mode:c
253 indent-tabs-mode:nil
254 c-basic-offset:2
255 End: