1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
8 * \brief Functions to send messages to log files or the console.
21 #define vsnprintf _vsnprintf
22 #define snprintf _snprintf
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.*/
36 /** Helper: map a log severity to descriptive string. */
37 static INLINE
const char *sev_to_string(int 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
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
)
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
,
71 (long)now
.tv_usec
/ 1000, sev_to_string(severity
));
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 */
78 n
+= snprintf(buf
+n
, buf_len
-n
, "%s(): ", funcname
);
83 n
+= vsnprintf(buf
+n
,buf_len
-n
,format
,ap
);
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).
95 logv(int severity
, const char *funcname
, const char *format
, va_list ap
)
102 for (lf
= logfiles
; lf
; lf
= lf
->next
) {
103 if (severity
< lf
->loglevel
|| severity
> lf
->max_loglevel
)
109 format_msg(buf
, 10024, severity
, funcname
, format
, ap
);
112 if(fputs(buf
, lf
->file
) == EOF
) { /* error */
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
, ...)
127 logv(severity
, NULL
, format
, 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
, ...)
136 logv(severity
, fn
, format
, ap
);
140 /** Close all open log files. */
146 logfiles
= logfiles
->next
;
147 if (victim
->needs_close
)
148 fclose(victim
->file
);
149 tor_free(victim
->filename
);
154 /** Close and re-open all log files; used to rotate logs on SIGHUP. */
158 for (lf
= logfiles
; lf
; lf
= lf
->next
) {
159 if (lf
->needs_close
) {
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
)
171 lf
= tor_malloc(sizeof(logfile_t
));
172 lf
->filename
= tor_strdup(name
);
174 lf
->loglevel
= loglevelMin
;
175 lf
->max_loglevel
= loglevelMax
;
178 lf
->is_temporary
= 0;
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)
194 for (p
= &logfiles
; *p
; ) {
195 if ((*p
)->is_temporary
) {
200 tor_free(lf
->filename
);
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
213 int add_file_log(int loglevelMin
, int loglevelMax
, const char *filename
)
216 f
= fopen(filename
, "a");
218 add_stream_log(loglevelMin
, loglevelMax
, filename
, f
);
219 logfiles
->needs_close
= 1;
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"))
228 else if (!strcasecmp(level
, "notice"))
230 else if (!strcasecmp(level
, "info"))
232 else if (!strcasecmp(level
, "debug"))
238 int get_min_log_level(void)
242 for (lf
= logfiles
; lf
; lf
= lf
->next
) {
243 if (lf
->loglevel
< min
)