Add stderr log support in mod_fastcgi (split lines from backend in log.c)

personal/stbuehler/wip
Stefan Bühler 14 years ago
parent 159a03f19b
commit 5c797977c6
  1. 20
      include/lighttpd/log.h
  2. 36
      src/log.c
  3. 54
      src/modules/mod_fastcgi.c
  4. 2
      src/plugin_core.c

@ -34,7 +34,9 @@ LI_API const char *remove_path(const char *path);
#define _DEBUG(srv, vr, fmt, ...) \
log_write_(srv, vr, LOG_LEVEL_INFO, LOG_FLAG_TIMESTAMP, "(debug) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
#define _BACKEND(srv, vr, fmt, ...) \
log_write_(srv, vr, LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP)
log_write_(srv, vr, LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, "(backend) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
#define _BACKEND_LINES(srv, vr, txt, fmt, ...) \
log_split_lines_(srv, vr, LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, txt, "(backend) %s.%d: "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
#define VR_SEGFAULT(vr, fmt, ...) _SEGFAULT(vr->con->srv, vr, fmt, __VA_ARGS__)
@ -42,21 +44,20 @@ LI_API const char *remove_path(const char *path);
#define VR_WARNING(vr, fmt, ...) _WARNING(vr->con->srv, vr, fmt, __VA_ARGS__)
#define VR_INFO(vr, fmt, ...) _INFO(vr->con->srv, vr, fmt, __VA_ARGS__)
#define VR_DEBUG(vr, fmt, ...) _DEBUG(vr->con->srv, vr, fmt, __VA_ARGS__)
#define VR_BACKEND(vr, fmt, ...) _BACKEND(vr->con->srv, vr, fmt, __VA_ARGS__)
#define VR_BACKEND(vr, fmt, ...) _BACKEND(vr->con->srv, vr, fmt, __VA_ARGS__)
#define VR_BACKEND_LINES(vr, txt, fmt, ...) _BACKEND_LINES(vr->con->srv, vr, txt, fmt, __VA_ARGS__)
#define SEGFAULT(srv, fmt, ...) _SEGFAULT(srv, NULL, fmt, __VA_ARGS__)
#define ERROR(srv, fmt, ...) _ERROR(srv, NULL, fmt, __VA_ARGS__)
#define WARNING(srv, fmt, ...) _WARNING(srv, NULL, fmt, __VA_ARGS__)
#define INFO(srv, fmt, ...) _INFO(srv, NULL, fmt, __VA_ARGS__)
#define DEBUG(srv, fmt, ...) _DEBUG(srv, NULL, fmt, __VA_ARGS__)
#define BACKEND(srv, fmt, ...) _BACKEND(srv, NULL, fmt, __VA_ARGS__)
#define BACKEND(srv, fmt, ...) _BACKEND(srv, NULL, fmt, __VA_ARGS__)
/* TODO: perhaps make portable (detect if cc supports) */
#define __ATTRIBUTE_PRINTF_FORMAT(fmt, arg) __attribute__ ((__format__ (__printf__, fmt, arg)))
/*LI_API int log_write(server *srv, connection *con, const char *fmt, ...) __ATTRIBUTE_PRINTF_FORMAT(3, 4);*/
struct log_t;
typedef struct log_t log_t;
@ -152,7 +153,12 @@ LI_API void log_write(server *srv, log_t *log, GString *msg);
/* log_write_ is used to write to the errorlog */
LI_API gboolean log_write_(server *srv, vrequest *vr, log_level_t log_level, guint flags, const gchar *fmt, ...) __ATTRIBUTE_PRINTF_FORMAT(5, 6);
log_timestamp_t *log_timestamp_new(server *srv, GString *format);
gboolean log_timestamp_free(server *srv, log_timestamp_t *ts);
LI_API log_timestamp_t *log_timestamp_new(server *srv, GString *format);
LI_API gboolean log_timestamp_free(server *srv, log_timestamp_t *ts);
/* replaces '\r' and '\n' with '\0' */
LI_API void log_split_lines(server *srv, vrequest *vr, log_level_t log_level, guint flags, gchar *txt, const gchar *prefix);
LI_API void log_split_lines_(server *srv, vrequest *vr, log_level_t log_level, guint flags, gchar *txt, const gchar *fmt, ...) __ATTRIBUTE_PRINTF_FORMAT(6, 7);
#endif

@ -535,3 +535,39 @@ gboolean log_timestamp_free(server *srv, log_timestamp_t *ts) {
return FALSE;
}
void log_split_lines(server *srv, vrequest *vr, log_level_t log_level, guint flags, gchar *txt, const gchar *prefix) {
gchar *start;
start = txt;
while ('\0' != *txt) {
if ('\r' == *txt || '\n' == *txt) {
*txt = '\0';
if (txt - start > 1) { /* skip empty lines*/
log_write_(srv, vr, log_level, flags, "%s%s", prefix, start);
}
txt++;
while (*txt == '\n' || *txt == '\r') txt++;
start = txt;
} else {
txt++;
}
}
if (txt - start > 1) { /* skip empty lines*/
log_write_(srv, vr, log_level, flags, "%s%s", prefix, start);
}
}
void log_split_lines_(server *srv, vrequest *vr, log_level_t log_level, guint flags, gchar *txt, const gchar *fmt, ...) {
va_list ap;
GString *prefix;
prefix = g_string_sized_new(0);
va_start(ap, fmt);
g_string_vprintf(prefix, fmt, ap);
va_end(ap);
log_split_lines(srv, vr, log_level, flags, txt, prefix->str);
g_string_free(prefix, TRUE);
}

@ -1,7 +1,42 @@
/*
* mod_fastcgi - connect to fastcgi backends for generating content
*
* Description:
* mod_fastcgi connects to a backend over tcp oder unix sockets
*
* Setups:
* none
* Options:
* fastcgi.log_plain_errors <value> - whether to prepend timestamp and other info to
* fastcgi stderr lines in the "backend" log.
* type: boolean
* Actions:
* fastcgi <socket> - connect to backend at <socket>
* socket: string, either "ip:port" or "unix:/path"
*
* Example config:
* fastcgi "127.0.0.1:9090"
*
* Todo:
* - reuse fastcgi connections (keepalive)
* - send more infos to backend (http headers, auth info)
* - option for alternative doc-root?
*
* Author:
* Copyright (c) 2009 Stefan Bühler
*/
#include <lighttpd/base.h>
#include <lighttpd/plugin_core.h>
enum fastcgi_options_t {
FASTCGI_OPTION_LOG_PLAIN_ERRORS = 0,
};
#define FASTCGI_OPTION(idx) _FASTCGI_OPTION(vr, idx)
#define _FASTCGI_OPTION(vr, idx) _OPTION_ABS(vr, p->opt_base_index + idx)
LI_API gboolean mod_fastcgi_init(modules *mods, module *mod);
LI_API gboolean mod_fastcgi_free(modules *mods, module *mod);
@ -401,12 +436,14 @@ static gboolean fastcgi_get_packet(fastcgi_connection *fcon) {
}
static gboolean fastcgi_parse_response(fastcgi_connection *fcon) {
vrequest *vr = fcon->vr;
plugin *p = fcon->ctx->plugin;
while (fastcgi_get_packet(fcon)) {
if (fcon->fcgi_in_record.version != FCGI_VERSION_1) {
VR_ERROR(fcon->vr, "Unknown fastcgi protocol version %i", (gint) fcon->fcgi_in_record.version);
VR_ERROR(vr, "Unknown fastcgi protocol version %i", (gint) fcon->fcgi_in_record.version);
close(fcon->fd);
fcon->fd = -1;
vrequest_error(fcon->vr);
vrequest_error(vr);
return FALSE;
}
chunkqueue_skip(fcon->fcgi_in, FCGI_HEADER_LEN);
@ -422,8 +459,17 @@ static gboolean fastcgi_parse_response(fastcgi_connection *fcon) {
chunkqueue_steal_len(fcon->stdout, fcon->fcgi_in, fcon->fcgi_in_record.contentLength);
}
break;
case FCGI_STDERR:
chunkqueue_extract_to(vr, fcon->fcgi_in, fcon->fcgi_in_record.contentLength, vr->con->wrk->tmp_str);
if (FASTCGI_OPTION(FASTCGI_OPTION_LOG_PLAIN_ERRORS).boolean) {
log_split_lines(vr->con->srv, vr, LOG_LEVEL_BACKEND, 0, vr->con->wrk->tmp_str->str, "");
} else {
VR_BACKEND_LINES(vr, vr->con->wrk->tmp_str->str, "%s", "(fcgi-stderr) ");
}
chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.contentLength);
break;
default:
VR_WARNING(fcon->vr, "Unhandled fastcgi record type %i", (gint) fcon->fcgi_in_record.type);
VR_WARNING(vr, "Unhandled fastcgi record type %i", (gint) fcon->fcgi_in_record.type);
chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.contentLength);
break;
}
@ -645,6 +691,8 @@ static action* fastcgi_create(server *srv, plugin* p, value *val) {
}
static const plugin_option options[] = {
{ "fastcgi.log_plain_errors", VALUE_BOOLEAN, GINT_TO_POINTER(FALSE), NULL, NULL },
{ NULL, 0, NULL, NULL, NULL }
};

@ -941,7 +941,7 @@ static action* core_physical_is_dir(server *srv, plugin* p, value *val) {
}
static const plugin_option options[] = {
{ "debug.log_request_handling", VALUE_BOOLEAN, NULL, NULL, NULL },
{ "debug.log_request_handling", VALUE_BOOLEAN, GINT_TO_POINTER(FALSE), NULL, NULL },
{ "log.timestamp", VALUE_STRING, NULL, core_option_log_timestamp_parse, core_option_log_timestamp_free },
{ "log", VALUE_HASH, NULL, core_option_log_parse, core_option_log_free },

Loading…
Cancel
Save