From 5d48ae71026320aac780a8e63e5e425dc84cf395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Sat, 17 Mar 2012 15:52:19 +0100 Subject: [PATCH] [log] Add changable log contexts (i.e. references to the real one), so a pointer to such context can be used over a longer period of time --- include/lighttpd/log.h | 81 +++++++++++---------- include/lighttpd/plugin_core.h | 4 +- include/lighttpd/typedefs.h | 5 +- include/lighttpd/virtualrequest.h | 2 + src/main/log.c | 87 +++++++++++++--------- src/main/plugin_core.c | 116 +++++++++++++++++++++--------- src/main/virtualrequest.c | 3 + src/modules/mod_fastcgi.c | 2 +- 8 files changed, 193 insertions(+), 107 deletions(-) diff --git a/include/lighttpd/log.h b/include/lighttpd/log.h index e58d6a0..9884fba 100644 --- a/include/lighttpd/log.h +++ b/include/lighttpd/log.h @@ -26,44 +26,44 @@ abort();\ } while(0) -#define _ERROR(srv, wrk, log_map, fmt, ...) \ - li_log_write(srv, wrk, log_map, LI_LOG_LEVEL_ERROR, LOG_FLAG_TIMESTAMP, "(error) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define _ERROR(srv, wrk, ctx, fmt, ...) \ + li_log_write(srv, wrk, ctx, LI_LOG_LEVEL_ERROR, LOG_FLAG_TIMESTAMP, "(error) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) -#define _WARNING(srv, wrk, log_map, fmt, ...) \ - li_log_write(srv, wrk, log_map, LI_LOG_LEVEL_WARNING, LOG_FLAG_TIMESTAMP, "(warning) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define _WARNING(srv, wrk, ctx, fmt, ...) \ + li_log_write(srv, wrk, ctx, LI_LOG_LEVEL_WARNING, LOG_FLAG_TIMESTAMP, "(warning) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) -#define _INFO(srv, wrk, log_map, fmt, ...) \ - li_log_write(srv, wrk, log_map, LI_LOG_LEVEL_INFO, LOG_FLAG_TIMESTAMP, "(info) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define _INFO(srv, wrk, ctx, fmt, ...) \ + li_log_write(srv, wrk, ctx, LI_LOG_LEVEL_INFO, LOG_FLAG_TIMESTAMP, "(info) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) -#define _DEBUG(srv, wrk, log_map, fmt, ...) \ - li_log_write(srv, wrk, log_map, LI_LOG_LEVEL_DEBUG, LOG_FLAG_TIMESTAMP, "(debug) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define _DEBUG(srv, wrk, ctx, fmt, ...) \ + li_log_write(srv, wrk, ctx, LI_LOG_LEVEL_DEBUG, LOG_FLAG_TIMESTAMP, "(debug) %s.%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) -#define _BACKEND(srv, wrk, log_map, fmt, ...) \ - li_log_write(srv, wrk, log_map, LI_LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, fmt, __VA_ARGS__) -#define _BACKEND_LINES(srv, wrk, log_map, txt, fmt, ...) \ - li_log_split_lines_(srv, wrk, log_map, LI_LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, txt, fmt, __VA_ARGS__) +#define _BACKEND(srv, wrk, ctx, fmt, ...) \ + li_log_write(srv, wrk, ctx, LI_LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, fmt, __VA_ARGS__) +#define _BACKEND_LINES(srv, wrk, ctx, txt, fmt, ...) \ + li_log_split_lines_(srv, wrk, ctx, LI_LOG_LEVEL_BACKEND, LOG_FLAG_TIMESTAMP, txt, fmt, __VA_ARGS__) -#define _GERROR(srv, wrk, log_map, error, fmt, ...) \ - li_log_write(srv, wrk, log_map, LI_LOG_LEVEL_ERROR, LOG_FLAG_TIMESTAMP, "(error) %s.%d: " fmt "\n %s", LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__, error ? error->message : "Empty GError") +#define _GERROR(srv, wrk, ctx, error, fmt, ...) \ + li_log_write(srv, wrk, ctx, LI_LOG_LEVEL_ERROR, LOG_FLAG_TIMESTAMP, "(error) %s.%d: " fmt "\n %s", LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__, error ? error->message : "Empty GError") -#define VR_SEGFAULT(vr, fmt, ...) _SEGFAULT(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define VR_ERROR(vr, fmt, ...) _ERROR(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define VR_WARNING(vr, fmt, ...) _WARNING(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define VR_INFO(vr, fmt, ...) _INFO(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define VR_DEBUG(vr, fmt, ...) _DEBUG(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define VR_BACKEND(vr, fmt, ...) _BACKEND(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define VR_BACKEND_LINES(vr, txt, fmt, ...) _BACKEND_LINES(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), txt, fmt, __VA_ARGS__) -#define VR_GERROR(vr, error, fmt, ...) _GERROR(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), error, fmt, __VA_ARGS__) +#define VR_SEGFAULT(vr, fmt, ...) _SEGFAULT(vr->wrk->srv, vr->wrk, &vr->log_context, fmt, __VA_ARGS__) +#define VR_ERROR(vr, fmt, ...) _ERROR(vr->wrk->srv, vr->wrk, &vr->log_context, fmt, __VA_ARGS__) +#define VR_WARNING(vr, fmt, ...) _WARNING(vr->wrk->srv, vr->wrk, &vr->log_context, fmt, __VA_ARGS__) +#define VR_INFO(vr, fmt, ...) _INFO(vr->wrk->srv, vr->wrk, &vr->log_context, fmt, __VA_ARGS__) +#define VR_DEBUG(vr, fmt, ...) _DEBUG(vr->wrk->srv, vr->wrk, &vr->log_context, fmt, __VA_ARGS__) +#define VR_BACKEND(vr, fmt, ...) _BACKEND(vr->wrk->srv, vr->wrk, &vr->log_context, fmt, __VA_ARGS__) +#define VR_BACKEND_LINES(vr, txt, fmt, ...) _BACKEND_LINES(vr->wrk->srv, vr->wrk, &vr->log_context, txt, fmt, __VA_ARGS__) +#define VR_GERROR(vr, error, fmt, ...) _GERROR(vr->wrk->srv, vr->wrk, &vr->log_context, error, fmt, __VA_ARGS__) /* vr may be NULL; if vr is NULL, srv must NOT be NULL */ -#define _VR_SEGFAULT(srv, vr, fmt, ...) _SEGFAULT(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define _VR_ERROR(srv, vr, fmt, ...) _ERROR(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define _VR_WARNING(srv, vr, fmt, ...) _WARNING(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define _VR_INFO(srv, vr, fmt, ...) _INFO(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define _VR_DEBUG(srv, vr, fmt, ...) _DEBUG(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define _VR_BACKEND(srv, vr, fmt, ...) _BACKEND(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), fmt, __VA_ARGS__) -#define _VR_BACKEND_LINES(srv, vr, txt, fmt, ...) _BACKEND_LINES(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), txt, fmt, __VA_ARGS__) -#define _VR_GERROR(srv, vr, error, fmt, ...) _GERROR(srv, NULL != vr ? vr->wrk : NULL, li_log_vr_map(vr), error, fmt, __VA_ARGS__) +#define _VR_SEGFAULT(srv, vr, fmt, ...) _SEGFAULT(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, fmt, __VA_ARGS__) +#define _VR_ERROR(srv, vr, fmt, ...) _ERROR(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, fmt, __VA_ARGS__) +#define _VR_WARNING(srv, vr, fmt, ...) _WARNING(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, fmt, __VA_ARGS__) +#define _VR_INFO(srv, vr, fmt, ...) _INFO(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, fmt, __VA_ARGS__) +#define _VR_DEBUG(srv, vr, fmt, ...) _DEBUG(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, fmt, __VA_ARGS__) +#define _VR_BACKEND(srv, vr, fmt, ...) _BACKEND(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, fmt, __VA_ARGS__) +#define _VR_BACKEND_LINES(srv, vr, txt, fmt, ...) _BACKEND_LINES(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, txt, fmt, __VA_ARGS__) +#define _VR_GERROR(srv, vr, error, fmt, ...) _GERROR(srv, NULL != vr ? vr->wrk : NULL, &vr->log_context, error, fmt, __VA_ARGS__) #define SEGFAULT(srv, fmt, ...) _SEGFAULT(srv, NULL, NULL, fmt, __VA_ARGS__) #define ERROR(srv, fmt, ...) _ERROR(srv, NULL, NULL, fmt, __VA_ARGS__) @@ -78,6 +78,11 @@ #define LOG_FLAG_TIMESTAMP (0x1) /* prepend a timestamp to the log message */ #define LOG_FLAG_NOLOCK (0x1 << 1) /* for internal use only */ +/* embed this into structures that should have their own log context, like liVRequest and liServer.logs */ +struct liLogContext { + liLogMap *log_map; +}; + struct liLogTarget { liLogType type; GString *path; @@ -111,6 +116,8 @@ struct liLogServerData { GString *format; GString *cached; } timestamp; + + liLogContext log_context; }; struct liLogWorkerData { @@ -119,7 +126,7 @@ struct liLogWorkerData { struct liLogMap { int refcount; - GArray *arr; + GString* targets[LI_LOG_LEVEL_COUNT]; }; /* determines the type of a log target by the path given. /absolute/path = file; |app = pipe; stderr = stderr; syslog = syslog; @@ -128,7 +135,8 @@ struct liLogMap { */ LI_API liLogType li_log_type_from_path(GString *path, gchar **param); -LI_API liLogLevel li_log_level_from_string(GString *str); +/* returns -1 for invalid names */ +LI_API int li_log_level_from_string(GString *str); LI_API gchar* li_log_level_str(liLogLevel log_level); /* log_new is used to create a new log target, if a log with the same path already exists, it is referenced instead */ @@ -143,18 +151,19 @@ LI_API void li_log_init(liServer *srv); LI_API void li_log_cleanup(liServer *srv); LI_API liLogMap* li_log_map_new(void); +LI_API liLogMap* li_log_map_new_default(void); LI_API void li_log_map_acquire(liLogMap *log_map); LI_API void li_log_map_release(liLogMap *log_map); -LI_API liLogMap* li_log_vr_map(liVRequest *vr); +LI_API void li_log_context_set(liLogContext *context, liLogMap *log_map); LI_API gboolean li_log_write_direct(liServer *srv, liWorker *wrk, GString *path, GString *msg); /* li_log_write is used to write to the errorlog */ -LI_API gboolean li_log_write(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLevel log_level, guint flags, const gchar *fmt, ...) G_GNUC_PRINTF(6, 7); +LI_API gboolean li_log_write(liServer *srv, liWorker *wrk, liLogContext* context, liLogLevel log_level, guint flags, const gchar *fmt, ...) G_GNUC_PRINTF(6, 7); /* replaces '\r' and '\n' with '\0' */ -LI_API void li_log_split_lines(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLevel log_level, guint flags, gchar *txt, const gchar *prefix); -LI_API void li_log_split_lines_(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLevel log_level, guint flags, gchar *txt, const gchar *fmt, ...) G_GNUC_PRINTF(7, 8); +LI_API void li_log_split_lines(liServer *srv, liWorker *wrk, liLogContext* context, liLogLevel log_level, guint flags, gchar *txt, const gchar *prefix); +LI_API void li_log_split_lines_(liServer *srv, liWorker *wrk, liLogContext* context, liLogLevel log_level, guint flags, gchar *txt, const gchar *fmt, ...) G_GNUC_PRINTF(7, 8); #endif diff --git a/include/lighttpd/plugin_core.h b/include/lighttpd/plugin_core.h index 304be3e..5f5b8af 100644 --- a/include/lighttpd/plugin_core.h +++ b/include/lighttpd/plugin_core.h @@ -19,9 +19,7 @@ enum liCoreOptions { }; enum liCoreOptionPtrs { - LI_CORE_OPTION_LOG = 0, - - LI_CORE_OPTION_STATIC_FILE_EXCLUDE_EXTENSIONS, + LI_CORE_OPTION_STATIC_FILE_EXCLUDE_EXTENSIONS = 0, LI_CORE_OPTION_SERVER_NAME, LI_CORE_OPTION_SERVER_TAG, diff --git a/include/lighttpd/typedefs.h b/include/lighttpd/typedefs.h index 56d1226..f7451aa 100644 --- a/include/lighttpd/typedefs.h +++ b/include/lighttpd/typedefs.h @@ -97,9 +97,10 @@ typedef struct liLogEntry liLogEntry; typedef struct liLogServerData liLogServerData; typedef struct liLogWorkerData liLogWorkerData; typedef struct liLogMap liLogMap; +typedef struct liLogContext liLogContext; typedef enum { - LI_LOG_LEVEL_DEBUG, + LI_LOG_LEVEL_DEBUG = 0, LI_LOG_LEVEL_INFO, LI_LOG_LEVEL_WARNING, LI_LOG_LEVEL_ERROR, @@ -107,6 +108,8 @@ typedef enum { LI_LOG_LEVEL_BACKEND } liLogLevel; +#define LI_LOG_LEVEL_COUNT (1 + (unsigned int) LI_LOG_LEVEL_BACKEND) + typedef enum { LI_LOG_TYPE_STDERR, LI_LOG_TYPE_FILE, diff --git a/include/lighttpd/virtualrequest.h b/include/lighttpd/virtualrequest.h index 9154fe9..e614724 100644 --- a/include/lighttpd/virtualrequest.h +++ b/include/lighttpd/virtualrequest.h @@ -94,6 +94,8 @@ struct liVRequest { liOptionValue *options; liOptionPtrValue **optionptrs; + liLogContext log_context; + liVRequestState state; ev_tstamp ts_started; diff --git a/src/main/log.c b/src/main/log.c index d8ef0b8..48a3d3a 100644 --- a/src/main/log.c +++ b/src/main/log.c @@ -121,6 +121,7 @@ void li_log_init(liServer *srv) { srv->logs.thread_alive = FALSE; g_queue_init(&srv->logs.write_queue); g_static_mutex_init(&srv->logs.write_queue_mutex); + srv->logs.log_context.log_map = li_log_map_new_default(); } void li_log_cleanup(liServer *srv) { @@ -137,40 +138,59 @@ void li_log_cleanup(liServer *srv) { g_string_free(srv->logs.timestamp.cached, TRUE); ev_loop_destroy(srv->logs.loop); + + li_log_context_set(&srv->logs.log_context, NULL); } -LI_API liLogMap* li_log_map_new(void) { +liLogMap* li_log_map_new(void) { liLogMap *log_map = g_slice_new0(liLogMap); log_map->refcount = 1; - log_map->arr = g_array_sized_new(FALSE, TRUE, sizeof(GString*), 6); - g_array_set_size(log_map->arr, 6); return log_map; } -LI_API void li_log_map_acquire(liLogMap *log_map) { +liLogMap* li_log_map_new_default(void) { + liLogMap *log_map = li_log_map_new(); + + /* default: log LI_LOG_LEVEL_WARNING, LI_LOG_LEVEL_ERROR and LI_LOG_LEVEL_BACKEND to stderr */ + log_map->targets[LI_LOG_LEVEL_WARNING] = g_string_new_len(CONST_STR_LEN("stderr")); + log_map->targets[LI_LOG_LEVEL_ERROR] = g_string_new_len(CONST_STR_LEN("stderr")); + log_map->targets[LI_LOG_LEVEL_BACKEND] = g_string_new_len(CONST_STR_LEN("stderr")); + + return log_map; +} + +void li_log_map_acquire(liLogMap *log_map) { assert(g_atomic_int_get(&log_map->refcount) > 0); g_atomic_int_inc(&log_map->refcount); } -LI_API void li_log_map_release(liLogMap *log_map) { +void li_log_map_release(liLogMap *log_map) { if (!log_map) return; assert(g_atomic_int_get(&log_map->refcount) > 0); if (g_atomic_int_dec_and_test(&log_map->refcount)) { - for (guint i = 0; i < log_map->arr->len; i++) { - if (NULL != g_array_index(log_map->arr, GString*, i)) - g_string_free(g_array_index(log_map->arr, GString*, i), TRUE); + for (guint i = 0; i < LI_LOG_LEVEL_COUNT; ++i) { + if (NULL != log_map->targets[i]) { + g_string_free(log_map->targets[i], TRUE); + } } - g_array_free(log_map->arr, TRUE); g_slice_free(liLogMap, log_map); } } -liLogMap* li_log_vr_map(liVRequest *vr) { - return (NULL != vr) ? CORE_OPTIONPTR(LI_CORE_OPTION_LOG).ptr : NULL; +void li_log_context_set(liLogContext *context, liLogMap *log_map) { + if (NULL == context || context->log_map == log_map) return; + + li_log_map_release(context->log_map); + if (NULL != log_map) { + li_log_map_acquire(log_map); + context->log_map = log_map; + } else { + context->log_map = NULL; + } } gboolean li_log_write_direct(liServer *srv, liWorker *wrk, GString *path, GString *msg) { @@ -199,23 +219,20 @@ gboolean li_log_write_direct(liServer *srv, liWorker *wrk, GString *path, GStrin return TRUE; } -gboolean li_log_write(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLevel log_level, guint flags, const gchar *fmt, ...) { +gboolean li_log_write(liServer *srv, liWorker *wrk, liLogContext *context, liLogLevel log_level, guint flags, const gchar *fmt, ...) { va_list ap; GString *log_line; liLogEntry *log_entry; + liLogMap *log_map = NULL; GString *path; if (!srv) srv = wrk->srv; - if (NULL == log_map) { - if (0 + LI_CORE_OPTION_LOG < srv->optionptr_def_values->len) { - liOptionPtrValue *oval = g_array_index(srv->optionptr_def_values, liOptionPtrValue*, 0 + LI_CORE_OPTION_LOG); - if (NULL != oval) log_map = oval->data.ptr; - } - } + if (NULL != context) log_map = context->log_map; + if (NULL == log_map) log_map = srv->logs.log_context.log_map; - if (log_map != NULL && log_level < log_map->arr->len) { - path = g_array_index(log_map->arr, GString*, log_level); + if (log_map != NULL && log_level < LI_LOG_LEVEL_COUNT) { + path = log_map->targets[log_level]; } else { return FALSE; } @@ -428,7 +445,7 @@ liLogType li_log_type_from_path(GString *path, gchar **param) { #undef RET_PAR #undef TRY_SCHEME -liLogLevel li_log_level_from_string(GString *str) { +int li_log_level_from_string(GString *str) { if (g_str_equal(str->str, "debug")) return LI_LOG_LEVEL_DEBUG; if (g_str_equal(str->str, "info")) @@ -437,22 +454,24 @@ liLogLevel li_log_level_from_string(GString *str) { return LI_LOG_LEVEL_WARNING; if (g_str_equal(str->str, "error")) return LI_LOG_LEVEL_ERROR; + if (g_str_equal(str->str, "abort")) + return LI_LOG_LEVEL_ABORT; if (g_str_equal(str->str, "backend")) return LI_LOG_LEVEL_BACKEND; - /* fall back to debug level */ - return LI_LOG_LEVEL_DEBUG; + return -1; } gchar* li_log_level_str(liLogLevel log_level) { switch (log_level) { - case LI_LOG_LEVEL_DEBUG: return "debug"; - case LI_LOG_LEVEL_INFO: return "info"; - case LI_LOG_LEVEL_WARNING: return "warning"; - case LI_LOG_LEVEL_ERROR: return "error"; - case LI_LOG_LEVEL_BACKEND: return "backend"; - default: return "unknown"; + case LI_LOG_LEVEL_DEBUG: return "debug"; + case LI_LOG_LEVEL_INFO: return "info"; + case LI_LOG_LEVEL_WARNING: return "warning"; + case LI_LOG_LEVEL_ERROR: return "error"; + case LI_LOG_LEVEL_ABORT: return "abort"; + case LI_LOG_LEVEL_BACKEND: return "backend"; } + return "unknown"; } void li_log_thread_start(liServer *srv) { @@ -492,7 +511,7 @@ void li_log_thread_wakeup(liServer *srv) { ev_async_send(srv->logs.loop, &srv->logs.watcher); } -void li_log_split_lines(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLevel log_level, guint flags, gchar *txt, const gchar *prefix) { +void li_log_split_lines(liServer *srv, liWorker *wrk, liLogContext *context, liLogLevel log_level, guint flags, gchar *txt, const gchar *prefix) { gchar *start; start = txt; @@ -500,7 +519,7 @@ void li_log_split_lines(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLe if ('\r' == *txt || '\n' == *txt) { *txt = '\0'; if (txt - start > 1) { /* skip empty lines*/ - li_log_write(srv, wrk, log_map, log_level, flags, "%s%s", prefix, start); + li_log_write(srv, wrk, context, log_level, flags, "%s%s", prefix, start); } txt++; while (*txt == '\n' || *txt == '\r') txt++; @@ -510,11 +529,11 @@ void li_log_split_lines(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLe } } if (txt - start > 1) { /* skip empty lines*/ - li_log_write(srv, wrk, log_map, log_level, flags, "%s%s", prefix, start); + li_log_write(srv, wrk, context, log_level, flags, "%s%s", prefix, start); } } -void li_log_split_lines_(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogLevel log_level, guint flags, gchar *txt, const gchar *fmt, ...) { +void li_log_split_lines_(liServer *srv, liWorker *wrk, liLogContext *context, liLogLevel log_level, guint flags, gchar *txt, const gchar *fmt, ...) { va_list ap; GString *prefix; @@ -523,7 +542,7 @@ void li_log_split_lines_(liServer *srv, liWorker *wrk, liLogMap* log_map, liLogL g_string_vprintf(prefix, fmt, ap); va_end(ap); - li_log_split_lines(srv, wrk, log_map, log_level, flags, txt, prefix->str); + li_log_split_lines(srv, wrk, context, log_level, flags, txt, prefix->str); g_string_free(prefix, TRUE); } diff --git a/src/main/plugin_core.c b/src/main/plugin_core.c index 29c626b..7460d91 100644 --- a/src/main/plugin_core.c +++ b/src/main/plugin_core.c @@ -1317,68 +1317,120 @@ static gboolean core_tasklet_pool_threads(liServer *srv, liPlugin* p, liValue *v * OPTIONS */ -static gboolean core_option_log_parse(liServer *srv, liWorker *wrk, liPlugin *p, size_t ndx, liValue *val, gpointer *oval) { +static liLogMap* logmap_from_value(liServer *srv, liValue *val) { + liLogMap *log_map; GHashTableIter iter; gpointer k, v; - liLogLevel level; + int level; GString *path; GString *level_str; - liLogMap *logmap = li_log_map_new(); - UNUSED(wrk); - UNUSED(p); - UNUSED(ndx); - - *oval = logmap; - /* default value */ - if (!val) { - /* default: log LI_LOG_LEVEL_WARNING, LI_LOG_LEVEL_ERROR and LI_LOG_LEVEL_BACKEND to stderr */ - g_array_index(logmap->arr, GString*, LI_LOG_LEVEL_WARNING) = g_string_new_len(CONST_STR_LEN("stderr")); - g_array_index(logmap->arr, GString*, LI_LOG_LEVEL_ERROR) = g_string_new_len(CONST_STR_LEN("stderr")); - g_array_index(logmap->arr, GString*, LI_LOG_LEVEL_BACKEND) = g_string_new_len(CONST_STR_LEN("stderr")); - return TRUE; + if (NULL == val) { + return li_log_map_new_default(); } + if (val->type != LI_VALUE_HASH) return NULL; + + log_map = li_log_map_new(); + g_hash_table_iter_init(&iter, val->data.hash); while (g_hash_table_iter_next(&iter, &k, &v)) { if (((liValue*)v)->type != LI_VALUE_STRING) { ERROR(srv, "log expects a hashtable with string values, %s given", li_value_type_string(((liValue*)v)->type)); - li_log_map_release(logmap); - return FALSE; + li_log_map_release(log_map); + return NULL; } path = ((liValue*)v)->data.string; level_str = (GString*)k; if (g_str_equal(level_str->str, "*")) { - for (guint i = 0; i < logmap->arr->len; i++) { + for (guint i = 0; i < LI_LOG_LEVEL_COUNT; i++) { /* overwrite old path */ - if (NULL != g_array_index(logmap->arr, GString*, i)) { - g_string_free(g_array_index(logmap->arr, GString*, i), TRUE); + if (NULL != log_map->targets[i]) { + g_string_free(log_map->targets[i], TRUE); } - g_array_index(logmap->arr, GString*, i) = g_string_new_len(GSTR_LEN(path)); + log_map->targets[i] = g_string_new_len(GSTR_LEN(path)); } } else { level = li_log_level_from_string(level_str); - if (NULL != g_array_index(logmap->arr, GString*, level)) { - g_string_free(g_array_index(logmap->arr, GString*, level), TRUE); + if (-1 == level) { + ERROR(srv, "unknown log level '%s'", level_str->str); + li_log_map_release(log_map); + return NULL; + } + if (NULL != log_map->targets[level]) { + g_string_free(log_map->targets[level], TRUE); } - g_array_index(logmap->arr, GString*, level) = li_value_extract_string(v); + log_map->targets[level] = li_value_extract_string(v); } } - return TRUE; + return log_map; } -static void core_option_log_free(liServer *srv, liPlugin *p, size_t ndx, gpointer oval) { - liLogMap *logmap = oval; +static void core_log_free(liServer *srv, gpointer param) { + liLogMap *log_map = param; UNUSED(srv); - UNUSED(p); - UNUSED(ndx); - li_log_map_release(logmap); + li_log_map_release(log_map); +} + +static liHandlerResult core_handle_log(liVRequest *vr, gpointer param, gpointer *context) { + liLogMap *log_map = param; + + UNUSED(context); + + li_log_context_set(&vr->log_context, log_map); + + return LI_HANDLER_GO_ON; +} + +static liAction* core_log(liServer *srv, liWorker *wrk, liPlugin* p, liValue *val, gpointer userdata) { + liLogMap *log_map; + + UNUSED(wrk); UNUSED(p); UNUSED(userdata); + + if (!val) { + return li_action_new_function(core_handle_log, NULL, core_log_free, NULL); + } + + if (val->type != LI_VALUE_HASH) { + ERROR(srv, "%s", "log expects a hashtable with string values"); + return NULL; + } + + log_map = logmap_from_value(srv, val); + if (NULL == log_map) return NULL; + + return li_action_new_function(core_handle_log, NULL, core_log_free, log_map); +} + +static gboolean core_setup_log(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) { + liLogMap *log_map; + UNUSED(p); UNUSED(userdata); + + if (!val) { + log_map = li_log_map_new_default(); + li_log_context_set(&srv->logs.log_context, log_map); + li_log_map_release(log_map); + return TRUE; + } + + if (val->type != LI_VALUE_HASH) { + ERROR(srv, "%s", "log expects a hashtable with string values"); + return FALSE; + } + + log_map = logmap_from_value(srv, val); + if (NULL == log_map) return FALSE; + + li_log_context_set(&srv->logs.log_context, log_map); + li_log_map_release(log_map); + + return TRUE; } static gboolean core_setup_log_timestamp(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) { @@ -2019,8 +2071,6 @@ static const liPluginOption options[] = { }; static const liPluginOptionPtr optionptrs[] = { - { "log", LI_VALUE_HASH, NULL, core_option_log_parse, core_option_log_free }, - { "static.exclude_extensions", LI_VALUE_LIST, NULL, core_option_static_exclude_exts_parse, NULL }, { "server.name", LI_VALUE_STRING, NULL, NULL, NULL }, @@ -2045,6 +2095,7 @@ static const liPluginAction actions[] = { { "set_status", core_status, NULL }, + { "log", core_log, NULL }, { "log.write", core_log_write, NULL }, { "respond", core_respond, NULL }, @@ -2079,6 +2130,7 @@ static const liPluginSetup setups[] = { { "io.timeout", core_io_timeout, NULL }, { "stat_cache.ttl", core_stat_cache_ttl, NULL }, { "tasklet_pool.threads", core_tasklet_pool_threads, NULL }, + { "log", core_setup_log, NULL }, { "log.timestamp", core_setup_log_timestamp, NULL }, { NULL, NULL, NULL } diff --git a/src/main/virtualrequest.c b/src/main/virtualrequest.c index 49a70eb..9e73ec2 100644 --- a/src/main/virtualrequest.c +++ b/src/main/virtualrequest.c @@ -227,6 +227,7 @@ void li_vrequest_free(liVRequest* vr) { } g_slice_free1(srv->optionptr_def_values->len * sizeof(liOptionPtrValue*), vr->optionptrs); + li_log_context_set(&vr->log_context, NULL); while (vr->stat_cache_entries->len > 0 ) { liStatCacheEntry *sce = g_ptr_array_index(vr->stat_cache_entries, 0); @@ -293,6 +294,8 @@ void li_vrequest_reset(liVRequest *vr, gboolean keepalive) { } } } + + li_log_context_set(&vr->log_context, NULL); } void li_vrequest_error(liVRequest *vr) { diff --git a/src/modules/mod_fastcgi.c b/src/modules/mod_fastcgi.c index 4c79f66..d785624 100644 --- a/src/modules/mod_fastcgi.c +++ b/src/modules/mod_fastcgi.c @@ -533,7 +533,7 @@ static gboolean fastcgi_parse_response(fastcgi_connection *fcon) { len = fastcgi_available(fcon); li_chunkqueue_extract_to(fcon->fcgi_in, len, vr->wrk->tmp_str, NULL); if (OPTION(FASTCGI_OPTION_LOG_PLAIN_ERRORS).boolean) { - li_log_split_lines(vr->wrk->srv, vr->wrk, li_log_vr_map(vr), LI_LOG_LEVEL_BACKEND, 0, vr->wrk->tmp_str->str, ""); + li_log_split_lines(vr->wrk->srv, vr->wrk, &vr->log_context, LI_LOG_LEVEL_BACKEND, 0, vr->wrk->tmp_str->str, ""); } else { VR_BACKEND_LINES(vr, vr->wrk->tmp_str->str, "(fcgi-stderr %s) ", fcon->ctx->socket_str->str); }