|
|
|
@ -8,8 +8,7 @@
|
|
|
|
|
|
|
|
|
|
#include <lighttpd/base.h> |
|
|
|
|
#include <lighttpd/plugin_core.h> |
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
|
#include <stdarg.h> |
|
|
|
|
|
|
|
|
|
#define LOG_DEFAULT_TS_FORMAT "%d/%b/%Y %T %Z" |
|
|
|
@ -47,35 +46,32 @@ static liLog *log_open(liServer *srv, GString *path) {
|
|
|
|
|
else |
|
|
|
|
log = NULL; |
|
|
|
|
|
|
|
|
|
if (!log) { |
|
|
|
|
if (NULL == log) { |
|
|
|
|
/* log not open */ |
|
|
|
|
gint fd = -1; |
|
|
|
|
liLogType type = li_log_type_from_path(path); |
|
|
|
|
gchar *param = NULL; |
|
|
|
|
liLogType type = li_log_type_from_path(path, ¶m); |
|
|
|
|
GString sparam = { param, (param != NULL ? path->len - (param - path->str) : 0), 0 }; |
|
|
|
|
|
|
|
|
|
switch (type) { |
|
|
|
|
case LI_LOG_TYPE_STDERR: |
|
|
|
|
fd = STDERR_FILENO; |
|
|
|
|
break; |
|
|
|
|
case LI_LOG_TYPE_FILE: |
|
|
|
|
/* todo: open via angel */ |
|
|
|
|
fd = open(path->str, O_RDWR | O_CREAT | O_APPEND, 0660); |
|
|
|
|
if (fd == -1) { |
|
|
|
|
int err = errno; |
|
|
|
|
GString *str = g_string_sized_new(255); |
|
|
|
|
g_string_append_printf(str, "(error) %s.%d: failed to open log file '%s': %s", LI_REMOVE_PATH(__FILE__), __LINE__, path->str, g_strerror(err)); |
|
|
|
|
/* li_log_write_stderr(srv, str->str, TRUE); */ |
|
|
|
|
g_string_free(str, TRUE); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
/* TODO: open via angel */ |
|
|
|
|
fd = li_angel_fake_log_open_file(srv, &sparam); |
|
|
|
|
break; |
|
|
|
|
case LI_LOG_TYPE_PIPE: |
|
|
|
|
ERROR(srv, "%s", "pipe logging not supported yet"); |
|
|
|
|
break; |
|
|
|
|
case LI_LOG_TYPE_SYSLOG: |
|
|
|
|
/* todo */ |
|
|
|
|
assert(NULL); |
|
|
|
|
ERROR(srv, "%s", "syslog not supported yet"); |
|
|
|
|
break; |
|
|
|
|
case LI_LOG_TYPE_NONE: |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Even if -1 == fd we create an entry, so we don't throw an error every time */ |
|
|
|
|
log = g_slice_new0(liLog); |
|
|
|
|
log->type = type; |
|
|
|
|
log->path = g_string_new_len(GSTR_LEN(path)); |
|
|
|
@ -95,7 +91,7 @@ static void log_close(liServer *srv, liLog *log) {
|
|
|
|
|
li_waitqueue_remove(&srv->logs.close_queue, &log->wqelem); |
|
|
|
|
|
|
|
|
|
if (log->type == LI_LOG_TYPE_FILE || log->type == LI_LOG_TYPE_PIPE) { |
|
|
|
|
close(log->fd); |
|
|
|
|
if (-1 != log->fd) close(log->fd); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*g_print("log_close(\"%s\")\n", log->path->str);*/ |
|
|
|
@ -297,12 +293,7 @@ static GString *log_timestamp_format(liServer *srv, liLogTimestamp *ts) {
|
|
|
|
|
|
|
|
|
|
static void log_watcher_cb(struct ev_loop *loop, ev_async *w, int revents) { |
|
|
|
|
liServer *srv = (liServer*) w->data; |
|
|
|
|
liLog *log; |
|
|
|
|
liLogEntry *log_entry; |
|
|
|
|
GList *queue_link, *queue_link_next; |
|
|
|
|
GString *msg; |
|
|
|
|
gssize bytes_written; |
|
|
|
|
gssize write_res; |
|
|
|
|
|
|
|
|
|
UNUSED(loop); |
|
|
|
|
UNUSED(revents); |
|
|
|
@ -325,15 +316,11 @@ static void log_watcher_cb(struct ev_loop *loop, ev_async *w, int revents) {
|
|
|
|
|
g_static_mutex_unlock(&srv->logs.write_queue_mutex); |
|
|
|
|
|
|
|
|
|
while (queue_link) { |
|
|
|
|
log_entry = queue_link->data; |
|
|
|
|
log = log_open(srv, log_entry->path); |
|
|
|
|
msg = log_entry->msg; |
|
|
|
|
bytes_written = 0; |
|
|
|
|
|
|
|
|
|
if (!log) { |
|
|
|
|
li_log_write_stderr(srv, log_entry->msg->str, TRUE); |
|
|
|
|
goto next; |
|
|
|
|
} |
|
|
|
|
liLog *log; |
|
|
|
|
liLogEntry *log_entry = queue_link->data; |
|
|
|
|
GString *msg = log_entry->msg; |
|
|
|
|
gssize bytes_written = 0; |
|
|
|
|
gssize write_res; |
|
|
|
|
|
|
|
|
|
if (log_entry->flags & LOG_FLAG_TIMESTAMP) { |
|
|
|
|
log_timestamp_format(srv, log_entry->ts); |
|
|
|
@ -343,6 +330,13 @@ static void log_watcher_cb(struct ev_loop *loop, ev_async *w, int revents) {
|
|
|
|
|
|
|
|
|
|
g_string_append_len(msg, CONST_STR_LEN("\n")); |
|
|
|
|
|
|
|
|
|
log = log_open(srv, log_entry->path); |
|
|
|
|
|
|
|
|
|
if (NULL == log || -1 == log->fd) { |
|
|
|
|
li_log_write_stderr(srv, msg->str, TRUE); |
|
|
|
|
goto next; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* todo: support for other logtargets than files */ |
|
|
|
|
while (bytes_written < (gssize)msg->len) { |
|
|
|
|
write_res = write(log->fd, msg->str + bytes_written, msg->len - bytes_written); |
|
|
|
@ -371,7 +365,7 @@ static void log_watcher_cb(struct ev_loop *loop, ev_async *w, int revents) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
next: |
|
|
|
|
next: |
|
|
|
|
queue_link_next = queue_link->next; |
|
|
|
|
g_string_free(log_entry->path, TRUE); |
|
|
|
|
g_string_free(log_entry->msg, TRUE); |
|
|
|
@ -393,37 +387,42 @@ static void log_watcher_cb(struct ev_loop *loop, ev_async *w, int revents) {
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
liLogType li_log_type_from_path(GString *path) { |
|
|
|
|
#define RET(type, offset) do { if (NULL != param) *param = path->str + offset; return type; } while(0) |
|
|
|
|
#define RET_PAR(type, par) do { if (NULL != param) *param = par; return type; } while(0) |
|
|
|
|
#define TRY_SCHEME(scheme, type) do { if (g_str_has_prefix(path->str, scheme)) RET(type, sizeof(scheme)-1); } while(0) |
|
|
|
|
liLogType li_log_type_from_path(GString *path, gchar **param) { |
|
|
|
|
if (path->len == 0) |
|
|
|
|
return LI_LOG_TYPE_NONE; |
|
|
|
|
|
|
|
|
|
/* look for scheme:// paths */ |
|
|
|
|
if (g_str_has_prefix(path->str, "file://")) |
|
|
|
|
return LI_LOG_TYPE_FILE; |
|
|
|
|
if (g_str_has_prefix(path->str, "pipe://")) |
|
|
|
|
return LI_LOG_TYPE_PIPE; |
|
|
|
|
if (g_str_has_prefix(path->str, "stderr://")) |
|
|
|
|
return LI_LOG_TYPE_STDERR; |
|
|
|
|
if (g_str_has_prefix(path->str, "syslog://")) |
|
|
|
|
return LI_LOG_TYPE_SYSLOG; |
|
|
|
|
/* look for scheme: paths */ |
|
|
|
|
TRY_SCHEME("file:", LI_LOG_TYPE_FILE); |
|
|
|
|
TRY_SCHEME("pipe:", LI_LOG_TYPE_PIPE); |
|
|
|
|
TRY_SCHEME("stderr:", LI_LOG_TYPE_STDERR); |
|
|
|
|
TRY_SCHEME("syslog:", LI_LOG_TYPE_SYSLOG); |
|
|
|
|
|
|
|
|
|
/* targets starting with a slash are absolute paths and therefor file targets */ |
|
|
|
|
if (*path->str == '/') |
|
|
|
|
return LI_LOG_TYPE_FILE; |
|
|
|
|
RET(LI_LOG_TYPE_FILE, 0); |
|
|
|
|
|
|
|
|
|
/* targets starting with a pipe are ... pipes! */ |
|
|
|
|
if (*path->str == '|') |
|
|
|
|
return LI_LOG_TYPE_PIPE; |
|
|
|
|
if (*path->str == '|') { |
|
|
|
|
guint i = 1; |
|
|
|
|
while (path->str[i] == ' ') i++; /* skip spaces */ |
|
|
|
|
RET(LI_LOG_TYPE_PIPE, i); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (g_str_equal(path->str, "stderr")) |
|
|
|
|
return LI_LOG_TYPE_STDERR; |
|
|
|
|
RET_PAR(LI_LOG_TYPE_STDERR, NULL); |
|
|
|
|
|
|
|
|
|
if (g_str_equal(path->str, "syslog")) |
|
|
|
|
return LI_LOG_TYPE_SYSLOG; |
|
|
|
|
RET_PAR(LI_LOG_TYPE_SYSLOG, NULL); |
|
|
|
|
|
|
|
|
|
/* fall back to stderr */ |
|
|
|
|
return LI_LOG_TYPE_STDERR; |
|
|
|
|
RET_PAR(LI_LOG_TYPE_STDERR, NULL); |
|
|
|
|
} |
|
|
|
|
#undef RET |
|
|
|
|
#undef RET_PAR |
|
|
|
|
#undef TRY_SCHEME |
|
|
|
|
|
|
|
|
|
liLogLevel li_log_level_from_string(GString *str) { |
|
|
|
|
if (g_str_equal(str->str, "debug")) |
|
|
|
|