From 0e48ef6acb8ed3b239096527408293989fcb870a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Mon, 25 Mar 2013 17:22:32 +0000 Subject: [PATCH] [mod_fastcgi,log] support multi line logging (fixes #2252) git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2866 152afb58-edef-0310-8abb-c4023f1b3aa9 --- NEWS | 1 + src/log.c | 166 +++++++++++++++++++++++++++++++--------------- src/log.h | 1 + src/mod_fastcgi.c | 4 +- 4 files changed, 115 insertions(+), 57 deletions(-) diff --git a/NEWS b/NEWS index 3eed4a36..ab7c732b 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ NEWS * mod_fastcgi: fix mix up of "mode" => "authorizer" in other fastcgi configs (fixes #2465, thx peex) * fix handling of If-Modified-Since if If-None-Match is present (don't return 412 for date parsing errors); follow current draft for HTTP/1.1, which tells us to ignore If-Modified-Since if we have matching etags. + * [mod_fastcgi,log] support multi line logging (fixes #2252) - 1.4.32 - 2012-11-21 * Code cleanup with clang/sparse (fixes #2437, thx kibi) diff --git a/src/log.c b/src/log.c index 10db6354..4778ee8f 100644 --- a/src/log.c +++ b/src/log.c @@ -263,39 +263,9 @@ int log_error_close(server *srv) { return 0; } -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) { - va_list ap; - - switch(srv->errorlog_mode) { - case ERRORLOG_PIPE: - case ERRORLOG_FILE: - case ERRORLOG_FD: - if (-1 == srv->errorlog_fd) return 0; - /* cache the generated timestamp */ - if (srv->cur_ts != srv->last_generated_debug_ts) { - buffer_prepare_copy(srv->ts_debug_str, 255); - strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts))); - srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1; - - srv->last_generated_debug_ts = srv->cur_ts; - } - - buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(": (")); - break; - case ERRORLOG_SYSLOG: - /* syslog is generating its own timestamps */ - buffer_copy_string_len(srv->errorlog_buf, CONST_STR_LEN("(")); - break; - } - - buffer_append_string(srv->errorlog_buf, filename); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(".")); - buffer_append_long(srv->errorlog_buf, line); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(") ")); - - - for(va_start(ap, fmt); *fmt; fmt++) { +/* lowercase: append space, uppercase: don't */ +static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) { + for(; *fmt; fmt++) { int d; char *s; buffer *b; @@ -304,50 +274,50 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const switch(*fmt) { case 's': /* string */ s = va_arg(ap, char *); - buffer_append_string(srv->errorlog_buf, s); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); + buffer_append_string(out, s); + buffer_append_string_len(out, CONST_STR_LEN(" ")); break; case 'b': /* buffer */ b = va_arg(ap, buffer *); - buffer_append_string_buffer(srv->errorlog_buf, b); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); + buffer_append_string_buffer(out, b); + buffer_append_string_len(out, CONST_STR_LEN(" ")); break; case 'd': /* int */ d = va_arg(ap, int); - buffer_append_long(srv->errorlog_buf, d); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); + buffer_append_long(out, d); + buffer_append_string_len(out, CONST_STR_LEN(" ")); break; case 'o': /* off_t */ o = va_arg(ap, off_t); - buffer_append_off_t(srv->errorlog_buf, o); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); + buffer_append_off_t(out, o); + buffer_append_string_len(out, CONST_STR_LEN(" ")); break; case 'x': /* int (hex) */ d = va_arg(ap, int); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("0x")); - buffer_append_long_hex(srv->errorlog_buf, d); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); + buffer_append_string_len(out, CONST_STR_LEN("0x")); + buffer_append_long_hex(out, d); + buffer_append_string_len(out, CONST_STR_LEN(" ")); break; case 'S': /* string */ s = va_arg(ap, char *); - buffer_append_string(srv->errorlog_buf, s); + buffer_append_string(out, s); break; case 'B': /* buffer */ b = va_arg(ap, buffer *); - buffer_append_string_buffer(srv->errorlog_buf, b); + buffer_append_string_buffer(out, b); break; case 'D': /* int */ d = va_arg(ap, int); - buffer_append_long(srv->errorlog_buf, d); + buffer_append_long(out, d); break; case 'O': /* off_t */ o = va_arg(ap, off_t); - buffer_append_off_t(srv->errorlog_buf, o); + buffer_append_off_t(out, o); break; case 'X': /* int (hex) */ d = va_arg(ap, int); - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("0x")); - buffer_append_long_hex(srv->errorlog_buf, d); + buffer_append_string_len(out, CONST_STR_LEN("0x")); + buffer_append_long_hex(out, d); break; case '(': case ')': @@ -355,24 +325,110 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const case '>': case ',': case ' ': - buffer_append_string_len(srv->errorlog_buf, fmt, 1); + buffer_append_string_len(out, fmt, 1); break; } } - va_end(ap); +} +static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) { switch(srv->errorlog_mode) { case ERRORLOG_PIPE: case ERRORLOG_FILE: case ERRORLOG_FD: - buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("\n")); - write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1); + if (-1 == srv->errorlog_fd) return -1; + /* cache the generated timestamp */ + if (srv->cur_ts != srv->last_generated_debug_ts) { + buffer_prepare_copy(srv->ts_debug_str, 255); + strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts))); + srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1; + + srv->last_generated_debug_ts = srv->cur_ts; + } + + buffer_copy_string_buffer(b, srv->ts_debug_str); + buffer_append_string_len(b, CONST_STR_LEN(": (")); break; case ERRORLOG_SYSLOG: - syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr); + /* syslog is generating its own timestamps */ + buffer_copy_string_len(b, CONST_STR_LEN("(")); break; } + buffer_append_string(b, filename); + buffer_append_string_len(b, CONST_STR_LEN(".")); + buffer_append_long(b, line); + buffer_append_string_len(b, CONST_STR_LEN(") ")); + return 0; } +static void log_write(server *srv, buffer *b) { + switch(srv->errorlog_mode) { + case ERRORLOG_PIPE: + case ERRORLOG_FILE: + case ERRORLOG_FD: + buffer_append_string_len(b, CONST_STR_LEN("\n")); + write(srv->errorlog_fd, b->ptr, b->used - 1); + break; + case ERRORLOG_SYSLOG: + syslog(LOG_ERR, "%s", b->ptr); + break; + } +} + +int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) { + va_list ap; + + if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0; + + va_start(ap, fmt); + log_buffer_append_printf(srv->errorlog_buf, fmt, ap); + va_end(ap); + + log_write(srv, srv->errorlog_buf); + + return 0; +} + +int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) { + va_list ap; + size_t prefix_used; + buffer *b = srv->errorlog_buf; + char *pos, *end, *current_line; + + if (multiline->used < 2) return 0; + + if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0; + + va_start(ap, fmt); + log_buffer_append_printf(b, fmt, ap); + va_end(ap); + + prefix_used = b->used; + + current_line = pos = multiline->ptr; + end = multiline->ptr + multiline->used; + + for ( ; pos < end ; ++pos) { + switch (*pos) { + case '\n': + case '\r': + case '\0': /* handles end of string */ + if (current_line < pos) { + /* truncate to prefix */ + b->used = prefix_used; + b->ptr[b->used - 1] = '\0'; + + buffer_append_string_len(b, current_line, pos - current_line); + log_write(srv, b); + } + current_line = pos + 1; + break; + default: + break; + } + } + + return 0; +} diff --git a/src/log.h b/src/log.h index 583288b6..b19f6b36 100644 --- a/src/log.h +++ b/src/log.h @@ -15,6 +15,7 @@ int open_logfile_or_pipe(server *srv, const char* logfile); int log_error_open(server *srv); int log_error_close(server *srv); int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...); +int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...); int log_error_cycle(server *srv); #endif diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index f7f643e9..f0e87b6f 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -2674,8 +2674,8 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { case FCGI_STDERR: if (packet.len == 0) break; - log_error_write(srv, __FILE__, __LINE__, "sb", - "FastCGI-stderr:", packet.b); + log_error_write_multiline_buffer(srv, __FILE__, __LINE__, packet.b, "s", + "FastCGI-stderr:"); break; case FCGI_END_REQUEST: