[doc] NEWS
[lighttpd.git] / src / log.c
blobb10bebe18e565bf827b67e7efd7bafd219a83d1a
1 #include "first.h"
3 #include "base.h"
4 #include "log.h"
5 #include "array.h"
7 #include <sys/types.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <time.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <stdio.h>
19 #ifdef HAVE_SYSLOG_H
20 # include <syslog.h>
21 #endif
23 #ifdef HAVE_VALGRIND_VALGRIND_H
24 # include <valgrind/valgrind.h>
25 #endif
27 #ifndef O_LARGEFILE
28 # define O_LARGEFILE 0
29 #endif
31 /* retry write on EINTR or when not all data was written */
32 ssize_t write_all(int fd, const void* buf, size_t count) {
33 ssize_t written = 0;
35 while (count > 0) {
36 ssize_t r = write(fd, buf, count);
37 if (r < 0) {
38 switch (errno) {
39 case EINTR:
40 /* try again */
41 break;
42 default:
43 /* fail - repeating probably won't help */
44 return -1;
46 } else if (0 == r) {
47 /* really shouldn't happen... */
48 errno = EIO;
49 return -1;
50 } else {
51 force_assert(r <= (ssize_t) count);
52 written += r;
53 buf = r + (char const*) buf;
54 count -= r;
58 return written;
61 /* Close fd and _try_ to get a /dev/null for it instead.
62 * close() alone may trigger some bugs when a
63 * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO
64 * and later tries to just print on stdout/stderr
66 * Returns 0 on success and -1 on failure (fd gets closed in all cases)
68 int openDevNull(int fd) {
69 int tmpfd;
70 close(fd);
71 #if defined(__WIN32)
72 /* Cygwin should work with /dev/null */
73 tmpfd = open("nul", O_RDWR);
74 #else
75 tmpfd = open("/dev/null", O_RDWR);
76 #endif
77 if (tmpfd != -1 && tmpfd != fd) {
78 dup2(tmpfd, fd);
79 close(tmpfd);
81 return (tmpfd != -1) ? 0 : -1;
84 int open_logfile_or_pipe(server *srv, const char* logfile) {
85 int fd;
87 if (logfile[0] == '|') {
88 #ifdef HAVE_FORK
89 /* create write pipe and spawn process */
91 int to_log_fds[2];
93 if (pipe(to_log_fds)) {
94 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
95 return -1;
98 /* fork, execve */
99 switch (fork()) {
100 case 0:
101 /* child */
102 close(STDIN_FILENO);
104 /* dup the filehandle to STDIN */
105 if (to_log_fds[0] != STDIN_FILENO) {
106 if (STDIN_FILENO != dup2(to_log_fds[0], STDIN_FILENO)) {
107 log_error_write(srv, __FILE__, __LINE__, "ss",
108 "dup2 failed: ", strerror(errno));
109 exit(-1);
111 close(to_log_fds[0]);
113 close(to_log_fds[1]);
115 #ifndef FD_CLOEXEC
117 int i;
118 /* we don't need the client socket */
119 for (i = 3; i < 256; i++) {
120 close(i);
123 #endif
125 /* close old stderr */
126 openDevNull(STDERR_FILENO);
128 /* exec the log-process (skip the | ) */
129 execl("/bin/sh", "sh", "-c", logfile + 1, NULL);
130 log_error_write(srv, __FILE__, __LINE__, "sss",
131 "spawning log process failed: ", strerror(errno),
132 logfile + 1);
134 exit(-1);
135 break;
136 case -1:
137 /* error */
138 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
139 return -1;
140 default:
141 close(to_log_fds[0]);
142 fd = to_log_fds[1];
143 break;
146 #else
147 return -1;
148 #endif
149 } else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
150 log_error_write(srv, __FILE__, __LINE__, "SSSS",
151 "opening errorlog '", logfile,
152 "' failed: ", strerror(errno));
154 return -1;
157 fd_close_on_exec(fd);
159 return fd;
164 * open the errorlog
166 * we have 4 possibilities:
167 * - stderr (default)
168 * - syslog
169 * - logfile
170 * - pipe
172 * if the open failed, report to the user and die
176 int log_error_open(server *srv) {
177 #ifdef HAVE_SYSLOG_H
178 /* perhaps someone wants to use syslog() */
179 openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
180 #endif
182 srv->errorlog_mode = ERRORLOG_FD;
183 srv->errorlog_fd = STDERR_FILENO;
185 if (srv->srvconf.errorlog_use_syslog) {
186 srv->errorlog_mode = ERRORLOG_SYSLOG;
187 } else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) {
188 const char *logfile = srv->srvconf.errorlog_file->ptr;
190 if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
191 return -1;
193 srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
196 log_error_write(srv, __FILE__, __LINE__, "s", "server started");
198 if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
199 /* We can only log to stderr in dont-daemonize mode;
200 * if we do daemonize and no errorlog file is specified, we log into /dev/null
202 srv->errorlog_fd = -1;
205 if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) {
206 int breakage_fd;
207 const char *logfile = srv->srvconf.breakagelog_file->ptr;
209 if (srv->errorlog_mode == ERRORLOG_FD) {
210 srv->errorlog_fd = dup(STDERR_FILENO);
211 fd_close_on_exec(srv->errorlog_fd);
214 if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
215 return -1;
218 if (STDERR_FILENO != breakage_fd) {
219 dup2(breakage_fd, STDERR_FILENO);
220 close(breakage_fd);
222 } else if (!srv->srvconf.dont_daemonize) {
223 /* move stderr to /dev/null */
224 openDevNull(STDERR_FILENO);
226 return 0;
230 * open the errorlog
232 * if the open failed, report to the user and die
233 * if no filename is given, use syslog instead
237 int log_error_cycle(server *srv) {
238 /* only cycle if the error log is a file */
240 if (srv->errorlog_mode == ERRORLOG_FILE) {
241 const char *logfile = srv->srvconf.errorlog_file->ptr;
242 /* already check of opening time */
244 int new_fd;
246 if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
247 /* write to old log */
248 log_error_write(srv, __FILE__, __LINE__, "SSSSS",
249 "cycling errorlog '", logfile,
250 "' failed: ", strerror(errno),
251 ", falling back to syslog()");
253 close(srv->errorlog_fd);
254 srv->errorlog_fd = -1;
255 #ifdef HAVE_SYSLOG_H
256 srv->errorlog_mode = ERRORLOG_SYSLOG;
257 #endif
258 } else {
259 /* ok, new log is open, close the old one */
260 close(srv->errorlog_fd);
261 srv->errorlog_fd = new_fd;
262 fd_close_on_exec(srv->errorlog_fd);
266 return 0;
269 int log_error_close(server *srv) {
270 switch(srv->errorlog_mode) {
271 case ERRORLOG_PIPE:
272 case ERRORLOG_FILE:
273 case ERRORLOG_FD:
274 if (-1 != srv->errorlog_fd) {
275 /* don't close STDERR */
276 if (STDERR_FILENO != srv->errorlog_fd)
277 close(srv->errorlog_fd);
278 srv->errorlog_fd = -1;
280 break;
281 case ERRORLOG_SYSLOG:
282 #ifdef HAVE_SYSLOG_H
283 closelog();
284 #endif
285 break;
288 return 0;
291 /* lowercase: append space, uppercase: don't */
292 static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
293 for(; *fmt; fmt++) {
294 int d;
295 char *s;
296 buffer *b;
297 off_t o;
299 switch(*fmt) {
300 case 's': /* string */
301 s = va_arg(ap, char *);
302 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
303 buffer_append_string_len(out, CONST_STR_LEN(" "));
304 break;
305 case 'b': /* buffer */
306 b = va_arg(ap, buffer *);
307 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
308 buffer_append_string_len(out, CONST_STR_LEN(" "));
309 break;
310 case 'd': /* int */
311 d = va_arg(ap, int);
312 buffer_append_int(out, d);
313 buffer_append_string_len(out, CONST_STR_LEN(" "));
314 break;
315 case 'o': /* off_t */
316 o = va_arg(ap, off_t);
317 buffer_append_int(out, o);
318 buffer_append_string_len(out, CONST_STR_LEN(" "));
319 break;
320 case 'x': /* int (hex) */
321 d = va_arg(ap, int);
322 buffer_append_string_len(out, CONST_STR_LEN("0x"));
323 buffer_append_uint_hex(out, d);
324 buffer_append_string_len(out, CONST_STR_LEN(" "));
325 break;
326 case 'S': /* string */
327 s = va_arg(ap, char *);
328 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
329 break;
330 case 'B': /* buffer */
331 b = va_arg(ap, buffer *);
332 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
333 break;
334 case 'D': /* int */
335 d = va_arg(ap, int);
336 buffer_append_int(out, d);
337 break;
338 case 'O': /* off_t */
339 o = va_arg(ap, off_t);
340 buffer_append_int(out, o);
341 break;
342 case 'X': /* int (hex) */
343 d = va_arg(ap, int);
344 buffer_append_string_len(out, CONST_STR_LEN("0x"));
345 buffer_append_uint_hex(out, d);
346 break;
347 case '(':
348 case ')':
349 case '<':
350 case '>':
351 case ',':
352 case ' ':
353 buffer_append_string_len(out, fmt, 1);
354 break;
359 static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
360 switch(srv->errorlog_mode) {
361 case ERRORLOG_PIPE:
362 case ERRORLOG_FILE:
363 case ERRORLOG_FD:
364 if (-1 == srv->errorlog_fd) return -1;
365 /* cache the generated timestamp */
366 if (srv->cur_ts != srv->last_generated_debug_ts) {
367 buffer_string_prepare_copy(srv->ts_debug_str, 255);
368 buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
370 srv->last_generated_debug_ts = srv->cur_ts;
373 buffer_copy_buffer(b, srv->ts_debug_str);
374 buffer_append_string_len(b, CONST_STR_LEN(": ("));
375 break;
376 case ERRORLOG_SYSLOG:
377 /* syslog is generating its own timestamps */
378 buffer_copy_string_len(b, CONST_STR_LEN("("));
379 break;
382 buffer_append_string(b, filename);
383 buffer_append_string_len(b, CONST_STR_LEN("."));
384 buffer_append_int(b, line);
385 buffer_append_string_len(b, CONST_STR_LEN(") "));
387 return 0;
390 static void log_write(server *srv, buffer *b) {
391 switch(srv->errorlog_mode) {
392 case ERRORLOG_PIPE:
393 case ERRORLOG_FILE:
394 case ERRORLOG_FD:
395 buffer_append_string_len(b, CONST_STR_LEN("\n"));
396 write_all(srv->errorlog_fd, CONST_BUF_LEN(b));
397 break;
398 case ERRORLOG_SYSLOG:
399 syslog(LOG_ERR, "%s", b->ptr);
400 break;
404 int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
405 va_list ap;
407 if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
409 va_start(ap, fmt);
410 log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
411 va_end(ap);
413 log_write(srv, srv->errorlog_buf);
415 return 0;
418 int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
419 va_list ap;
420 size_t prefix_len;
421 buffer *b = srv->errorlog_buf;
422 char *pos, *end, *current_line;
424 if (buffer_string_is_empty(multiline)) return 0;
426 if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
428 va_start(ap, fmt);
429 log_buffer_append_printf(b, fmt, ap);
430 va_end(ap);
432 prefix_len = buffer_string_length(b);
434 current_line = pos = multiline->ptr;
435 end = multiline->ptr + buffer_string_length(multiline);
437 for ( ; pos <= end ; ++pos) {
438 switch (*pos) {
439 case '\n':
440 case '\r':
441 case '\0': /* handles end of string */
442 if (current_line < pos) {
443 /* truncate to prefix */
444 buffer_string_set_length(b, prefix_len);
446 buffer_append_string_len(b, current_line, pos - current_line);
447 log_write(srv, b);
449 current_line = pos + 1;
450 break;
451 default:
452 break;
456 return 0;