Browse Source

[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

personal/stbuehler/wip
Stefan Bühler 10 years ago
parent
commit
5d48ae7102
  1. 81
      include/lighttpd/log.h
  2. 4
      include/lighttpd/plugin_core.h
  3. 5
      include/lighttpd/typedefs.h
  4. 2
      include/lighttpd/virtualrequest.h
  5. 87
      src/main/log.c
  6. 116
      src/main/plugin_core.c
  7. 3
      src/main/virtualrequest.c
  8. 2
      src/modules/mod_fastcgi.c

81
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

4
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,

5
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,

2
include/lighttpd/virtualrequest.h

@ -94,6 +94,8 @@ struct liVRequest {
liOptionValue *options;
liOptionPtrValue **optionptrs;
liLogContext log_context;
liVRequestState state;
ev_tstamp ts_started;

87
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);
}

116
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 }

3
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) {

2
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);
}

Loading…
Cancel
Save