2008-06-24 19:19:20 +00:00
|
|
|
|
2008-11-16 20:33:53 +00:00
|
|
|
#include <lighttpd/base.h>
|
|
|
|
#include <lighttpd/plugin_core.h>
|
2008-09-18 07:14:57 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2008-06-24 19:19:20 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
/* from server.h */
|
|
|
|
|
2008-06-24 19:19:20 +00:00
|
|
|
#if REMOVE_PATH_FROM_FILE
|
|
|
|
const char *remove_path(const char *path) {
|
|
|
|
char *p = strrchr(path, DIR_SEPERATOR);
|
|
|
|
if (NULL != p && *(p) != '\0') {
|
|
|
|
return (p + 1);
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-12-02 14:58:06 +00:00
|
|
|
void log_write(server *srv, log_t *log, GString *msg) {
|
|
|
|
log_entry_t *log_entry;
|
2008-06-24 19:19:20 +00:00
|
|
|
|
2008-12-20 15:25:02 +00:00
|
|
|
if (g_atomic_int_get(&srv->state) == SERVER_STARTING) {
|
|
|
|
angel_log(srv, msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-12-02 14:58:06 +00:00
|
|
|
log_ref(srv, log);
|
2008-06-24 19:19:20 +00:00
|
|
|
|
2008-12-02 14:58:06 +00:00
|
|
|
log_entry = g_slice_new(log_entry_t);
|
|
|
|
log_entry->log = log;
|
|
|
|
log_entry->msg = msg;
|
2008-06-24 19:19:20 +00:00
|
|
|
|
2008-12-02 14:58:06 +00:00
|
|
|
g_async_queue_push(srv->logs.queue, log_entry);
|
2008-06-24 19:19:20 +00:00
|
|
|
}
|
|
|
|
|
2008-12-30 13:24:33 +00:00
|
|
|
gboolean log_write_(server *srv, vrequest *vr, log_level_t log_level, guint flags, const gchar *fmt, ...) {
|
2008-07-18 18:23:05 +00:00
|
|
|
va_list ap;
|
|
|
|
GString *log_line;
|
2008-09-24 21:43:22 +00:00
|
|
|
log_t *log = NULL;
|
2008-07-18 22:11:08 +00:00
|
|
|
log_entry_t *log_entry;
|
2008-09-24 21:43:22 +00:00
|
|
|
log_timestamp_t *ts = NULL;
|
2008-07-18 18:23:05 +00:00
|
|
|
|
2008-12-30 13:24:33 +00:00
|
|
|
if (vr != NULL) {
|
2008-09-24 21:43:22 +00:00
|
|
|
|
2008-12-30 13:24:33 +00:00
|
|
|
if (!srv) srv = vr->con->srv;
|
2008-09-24 21:43:22 +00:00
|
|
|
/* get log from connection */
|
2008-09-26 14:11:08 +00:00
|
|
|
log = g_array_index(CORE_OPTION(CORE_OPTION_LOG).list, log_t*, log_level);
|
2008-09-24 21:43:22 +00:00
|
|
|
if (log == NULL)
|
|
|
|
return TRUE;
|
2008-09-26 14:11:08 +00:00
|
|
|
ts = CORE_OPTION(CORE_OPTION_LOG_TS_FORMAT).ptr;
|
2008-09-24 21:43:22 +00:00
|
|
|
if (!ts)
|
2008-09-26 22:09:12 +00:00
|
|
|
ts = g_array_index(srv->logs.timestamps, log_timestamp_t*, 0);
|
2008-07-18 18:23:05 +00:00
|
|
|
}
|
2008-07-18 22:38:33 +00:00
|
|
|
else {
|
2008-09-24 21:43:22 +00:00
|
|
|
log = srv->logs.stderr;
|
2008-09-26 22:09:12 +00:00
|
|
|
ts = g_array_index(srv->logs.timestamps, log_timestamp_t*, 0);
|
2008-07-18 22:38:33 +00:00
|
|
|
}
|
|
|
|
|
2008-08-06 21:48:39 +00:00
|
|
|
log_ref(srv, log);
|
2008-07-18 18:23:05 +00:00
|
|
|
log_line = g_string_sized_new(0);
|
|
|
|
va_start(ap, fmt);
|
|
|
|
g_string_vprintf(log_line, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
if (!(flags & LOG_FLAG_NOLOCK))
|
|
|
|
log_lock(log);
|
|
|
|
|
|
|
|
if (!(flags & LOG_FLAG_ALLOW_REPEAT)) {
|
|
|
|
|
|
|
|
/* check if last message for this log was the same */
|
|
|
|
if (g_string_equal(log->lastmsg, log_line)) {
|
|
|
|
log->lastmsg_count++;
|
|
|
|
if (!(flags & LOG_FLAG_NOLOCK))
|
|
|
|
log_unlock(log);
|
|
|
|
log_unref(srv, log);
|
|
|
|
g_string_free(log_line, TRUE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (log->lastmsg_count > 0) {
|
|
|
|
guint count = log->lastmsg_count;
|
|
|
|
log->lastmsg_count = 0;
|
2008-12-30 13:24:33 +00:00
|
|
|
log_write_(srv, vr, log_level, flags | LOG_FLAG_NOLOCK | LOG_FLAG_ALLOW_REPEAT, "last message repeated %d times", count);
|
2008-09-24 21:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-18 20:16:30 +00:00
|
|
|
}
|
2008-09-24 21:43:22 +00:00
|
|
|
|
|
|
|
g_string_assign(log->lastmsg, log_line->str);
|
|
|
|
|
|
|
|
/* for normal error messages, we prepend a timestamp */
|
|
|
|
if (flags & LOG_FLAG_TIMETAMP) {
|
|
|
|
time_t cur_ts;
|
|
|
|
|
|
|
|
g_mutex_lock(srv->logs.mutex);
|
|
|
|
|
|
|
|
/* if we have a worker context, we can use its timestamp to save us a call to time() */
|
2008-12-30 13:24:33 +00:00
|
|
|
if (vr != NULL)
|
|
|
|
cur_ts = (time_t)CUR_TS(vr->con->wrk);
|
2008-09-24 21:43:22 +00:00
|
|
|
else
|
|
|
|
cur_ts = time(NULL);
|
|
|
|
|
|
|
|
if (cur_ts != ts->last_ts) {
|
|
|
|
gsize s;
|
|
|
|
g_string_set_size(ts->cached, 255);
|
|
|
|
s = strftime(ts->cached->str, ts->cached->allocated_len,
|
|
|
|
ts->format->str, localtime(&cur_ts));
|
|
|
|
|
|
|
|
g_string_set_size(ts->cached, s);
|
|
|
|
|
|
|
|
ts->last_ts = cur_ts;
|
2008-07-18 20:16:30 +00:00
|
|
|
}
|
2008-09-24 21:43:22 +00:00
|
|
|
|
|
|
|
g_string_prepend_c(log_line, ' ');
|
|
|
|
g_string_prepend_len(log_line, GSTR_LEN(ts->cached));
|
|
|
|
|
|
|
|
g_mutex_unlock(srv->logs.mutex);
|
2008-07-18 20:16:30 +00:00
|
|
|
}
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
if (!(flags & LOG_FLAG_NOLOCK))
|
|
|
|
log_unlock(log);
|
2008-07-19 13:12:32 +00:00
|
|
|
|
2008-07-18 18:23:05 +00:00
|
|
|
g_string_append_len(log_line, CONST_STR_LEN("\r\n"));
|
|
|
|
|
2008-12-20 15:25:02 +00:00
|
|
|
if (g_atomic_int_get(&srv->state) == SERVER_STARTING) {
|
|
|
|
log_unref(srv, log);
|
|
|
|
return angel_log(srv, log_line);
|
|
|
|
}
|
2008-07-18 22:11:08 +00:00
|
|
|
log_entry = g_slice_new(log_entry_t);
|
2008-07-19 20:13:32 +00:00
|
|
|
log_entry->log = log;
|
2008-07-18 22:11:08 +00:00
|
|
|
log_entry->msg = log_line;
|
2008-07-22 14:00:31 +00:00
|
|
|
log_entry->level = log_level;
|
2008-07-19 20:13:32 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
g_async_queue_push(srv->logs.queue, log_entry);
|
2008-07-18 18:23:05 +00:00
|
|
|
|
2008-07-22 14:00:31 +00:00
|
|
|
/* on critical error, exit */
|
2008-09-24 21:43:22 +00:00
|
|
|
if (log_level == LOG_LEVEL_ABORT) {
|
2008-09-26 22:09:12 +00:00
|
|
|
log_thread_stop(srv);
|
2008-07-22 14:00:31 +00:00
|
|
|
g_atomic_int_set(&srv->exiting, TRUE);
|
|
|
|
}
|
|
|
|
|
2008-07-18 18:23:05 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2008-07-18 20:16:30 +00:00
|
|
|
|
2008-07-18 22:11:08 +00:00
|
|
|
|
|
|
|
gpointer log_thread(server *srv) {
|
|
|
|
GAsyncQueue *queue;
|
2008-07-19 20:13:32 +00:00
|
|
|
log_t *log;
|
2008-07-18 22:11:08 +00:00
|
|
|
log_entry_t *log_entry;
|
2008-07-19 20:13:32 +00:00
|
|
|
GString *msg;
|
2008-07-18 22:11:08 +00:00
|
|
|
gssize bytes_written;
|
|
|
|
gssize write_res;
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
queue = srv->logs.queue;
|
2008-07-18 22:11:08 +00:00
|
|
|
|
|
|
|
while (TRUE) {
|
2008-08-02 20:56:07 +00:00
|
|
|
/* do we need to rotate logs? */
|
2008-09-24 21:43:22 +00:00
|
|
|
/*
|
2008-07-20 16:28:58 +00:00
|
|
|
if (g_atomic_int_get(&srv->rotate_logs)) {
|
|
|
|
g_atomic_int_set(&srv->rotate_logs, FALSE);
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_lock(srv->logs.mutex);
|
|
|
|
g_hash_table_foreach(srv->logs.targets, (GHFunc) log_rotate, srv);
|
|
|
|
g_mutex_unlock(srv->logs.mutex);
|
2008-07-19 20:13:32 +00:00
|
|
|
}
|
2008-09-24 21:43:22 +00:00
|
|
|
*/
|
2008-07-18 22:11:08 +00:00
|
|
|
|
2008-09-26 22:09:12 +00:00
|
|
|
if (g_atomic_int_get(&srv->logs.thread_stop) == TRUE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (g_atomic_int_get(&srv->logs.thread_finish) == TRUE && g_async_queue_length(srv->logs.queue) == 0)
|
|
|
|
break;
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
log_entry = g_async_queue_pop(srv->logs.queue);
|
2008-07-20 14:35:04 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
/* if log_entry->log is NULL, it means that the logger thread has been woken up probably because it should exit */
|
2008-07-20 15:12:17 +00:00
|
|
|
if (log_entry->log == NULL) {
|
|
|
|
g_slice_free(log_entry_t, log_entry);
|
2008-07-18 22:11:08 +00:00
|
|
|
continue;
|
2008-07-20 15:12:17 +00:00
|
|
|
}
|
2008-07-18 22:11:08 +00:00
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
log = log_entry->log;
|
|
|
|
msg = log_entry->msg;
|
|
|
|
|
2008-07-19 13:12:32 +00:00
|
|
|
bytes_written = 0;
|
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
while (bytes_written < (gssize)msg->len) {
|
|
|
|
write_res = write(log->fd, msg->str + bytes_written, msg->len - bytes_written);
|
2008-07-18 22:11:08 +00:00
|
|
|
|
|
|
|
/* write() failed, check why */
|
|
|
|
if (write_res == -1) {
|
|
|
|
switch (errno) {
|
|
|
|
case EAGAIN:
|
|
|
|
case EINTR:
|
|
|
|
continue;
|
|
|
|
}
|
2008-07-19 13:12:32 +00:00
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
g_printerr("could not write to log: %s\n", msg->str);
|
2008-07-20 14:35:04 +00:00
|
|
|
break;
|
2008-07-18 22:11:08 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
bytes_written += write_res;
|
2008-07-19 20:13:32 +00:00
|
|
|
assert(bytes_written <= (gssize) msg->len);
|
2008-07-18 22:11:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
g_string_free(msg, TRUE);
|
2008-07-18 22:11:08 +00:00
|
|
|
g_slice_free(log_entry_t, log_entry);
|
2008-07-19 20:13:32 +00:00
|
|
|
log_unref(srv, log);
|
2008-07-18 22:11:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-07-20 14:35:04 +00:00
|
|
|
void log_rotate(gchar * path, log_t *log, server * UNUSED_PARAM(srv)) {
|
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
switch (log->type) {
|
|
|
|
case LOG_TYPE_FILE:
|
|
|
|
close(log->fd);
|
|
|
|
log->fd = open(log->path->str, O_RDWR | O_CREAT | O_APPEND, 0660);
|
|
|
|
if (log->fd == -1) {
|
|
|
|
g_printerr("failed to reopen log: %s\n", path);
|
|
|
|
assert(NULL); /* TODO */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOG_TYPE_STDERR:
|
|
|
|
break;
|
|
|
|
case LOG_TYPE_PIPE:
|
|
|
|
case LOG_TYPE_SYSLOG:
|
2008-11-12 16:38:32 +00:00
|
|
|
case LOG_TYPE_NONE:
|
2008-07-19 20:13:32 +00:00
|
|
|
/* TODO */
|
|
|
|
assert(NULL);
|
|
|
|
}
|
2008-07-20 14:35:04 +00:00
|
|
|
|
|
|
|
g_string_truncate(log->lastmsg, 0);
|
|
|
|
log->lastmsg_count = 0;
|
2008-07-19 20:13:32 +00:00
|
|
|
}
|
|
|
|
|
2008-07-22 14:00:31 +00:00
|
|
|
void log_rotate_logs(server *srv) {
|
2008-09-24 21:43:22 +00:00
|
|
|
UNUSED(srv);
|
|
|
|
|
|
|
|
/*g_atomic_int_set(&srv->rotate_logs, TRUE);*/
|
2008-07-22 14:00:31 +00:00
|
|
|
}
|
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
|
2008-08-06 21:48:39 +00:00
|
|
|
void log_ref(server *srv, log_t *log) {
|
2008-09-09 14:41:02 +00:00
|
|
|
UNUSED(srv);
|
|
|
|
g_atomic_int_inc(&log->refcount);
|
2008-07-19 20:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void log_unref(server *srv, log_t *log) {
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_lock(srv->logs.mutex);
|
2008-08-06 21:48:39 +00:00
|
|
|
|
2008-07-20 16:28:58 +00:00
|
|
|
if (g_atomic_int_dec_and_test(&log->refcount))
|
2008-08-06 21:48:39 +00:00
|
|
|
log_free_unlocked(srv, log);
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_unlock(srv->logs.mutex);
|
2008-07-19 20:13:32 +00:00
|
|
|
}
|
|
|
|
|
2008-08-13 17:57:19 +00:00
|
|
|
log_type_t log_type_from_path(GString *path) {
|
|
|
|
if (path->len == 0)
|
2008-11-12 16:38:32 +00:00
|
|
|
return LOG_TYPE_NONE;
|
2008-08-13 17:57:19 +00:00
|
|
|
|
|
|
|
/* targets starting with a slash are absolute paths and therefor file targets */
|
|
|
|
if (*path->str == '/')
|
|
|
|
return LOG_TYPE_FILE;
|
|
|
|
|
|
|
|
/* targets starting with a pipe are ... pipes! */
|
|
|
|
if (*path->str == '|')
|
|
|
|
return LOG_TYPE_PIPE;
|
|
|
|
|
|
|
|
if (g_str_equal(path->str, "stderr"))
|
|
|
|
return LOG_TYPE_STDERR;
|
|
|
|
|
|
|
|
if (g_str_equal(path->str, "syslog"))
|
|
|
|
return LOG_TYPE_SYSLOG;
|
|
|
|
|
|
|
|
/* fall back to stderr */
|
|
|
|
return LOG_TYPE_STDERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_level_t log_level_from_string(GString *str) {
|
|
|
|
if (g_str_equal(str->str, "debug"))
|
|
|
|
return LOG_LEVEL_DEBUG;
|
|
|
|
if (g_str_equal(str->str, "info"))
|
|
|
|
return LOG_LEVEL_INFO;
|
|
|
|
if (g_str_equal(str->str, "warning"))
|
|
|
|
return LOG_LEVEL_WARNING;
|
|
|
|
if (g_str_equal(str->str, "error"))
|
|
|
|
return LOG_LEVEL_ERROR;
|
|
|
|
|
|
|
|
/* fall back to debug level */
|
|
|
|
return LOG_LEVEL_DEBUG;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar* log_level_str(log_level_t log_level) {
|
|
|
|
switch (log_level) {
|
|
|
|
case LOG_LEVEL_DEBUG: return "debug";
|
|
|
|
case LOG_LEVEL_INFO: return "info";
|
|
|
|
case LOG_LEVEL_WARNING: return "warning";
|
|
|
|
case LOG_LEVEL_ERROR: return "error";
|
|
|
|
default: return "unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
log_t *log_new(server *srv, log_type_t type, GString *path) {
|
2008-07-18 22:51:17 +00:00
|
|
|
log_t *log;
|
2008-08-12 17:34:11 +00:00
|
|
|
gint fd = -1;
|
2008-07-19 20:13:32 +00:00
|
|
|
|
2008-11-12 16:38:32 +00:00
|
|
|
if (type == LOG_TYPE_NONE)
|
|
|
|
return NULL;
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_lock(srv->logs.mutex);
|
|
|
|
log = g_hash_table_lookup(srv->logs.targets, path->str);
|
2008-07-19 20:13:32 +00:00
|
|
|
|
|
|
|
/* log already open, inc refcount */
|
|
|
|
if (log != NULL)
|
|
|
|
{
|
2008-09-09 14:41:02 +00:00
|
|
|
g_atomic_int_inc(&log->refcount);
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_unlock(srv->logs.mutex);
|
2008-07-19 20:13:32 +00:00
|
|
|
return log;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case LOG_TYPE_STDERR:
|
|
|
|
fd = STDERR_FILENO;
|
|
|
|
break;
|
|
|
|
case LOG_TYPE_FILE:
|
|
|
|
fd = open(path->str, O_RDWR | O_CREAT | O_APPEND, 0660);
|
|
|
|
break;
|
|
|
|
case LOG_TYPE_PIPE:
|
|
|
|
case LOG_TYPE_SYSLOG:
|
2008-11-12 16:38:32 +00:00
|
|
|
case LOG_TYPE_NONE:
|
2008-07-19 20:13:32 +00:00
|
|
|
/* TODO */
|
2008-08-08 23:55:07 +00:00
|
|
|
fd = -1;
|
2008-07-19 20:13:32 +00:00
|
|
|
assert(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd == -1) {
|
2008-08-13 19:50:07 +00:00
|
|
|
g_printerr("failed to open log: %s", g_strerror(errno));
|
2008-07-19 20:13:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
log = g_slice_new0(log_t);
|
|
|
|
log->lastmsg = g_string_sized_new(0);
|
|
|
|
log->fd = fd;
|
2008-10-17 16:07:38 +00:00
|
|
|
log->path = g_string_new_len(GSTR_LEN(path));
|
2008-07-19 20:13:32 +00:00
|
|
|
log->refcount = 1;
|
2008-09-24 21:43:22 +00:00
|
|
|
log->mutex = g_mutex_new();
|
2008-07-19 20:13:32 +00:00
|
|
|
|
2008-10-17 16:07:38 +00:00
|
|
|
g_hash_table_insert(srv->logs.targets, log->path->str, log);
|
2008-09-09 22:07:42 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_unlock(srv->logs.mutex);
|
2008-07-19 20:13:32 +00:00
|
|
|
|
|
|
|
return log;
|
|
|
|
}
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
/* only call this if srv->logs.mutex is NOT locked */
|
2008-07-19 20:13:32 +00:00
|
|
|
void log_free(server *srv, log_t *log) {
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_lock(srv->logs.mutex);
|
2008-08-06 21:48:39 +00:00
|
|
|
log_free_unlocked(srv, log);
|
2008-09-24 21:43:22 +00:00
|
|
|
g_mutex_unlock(srv->logs.mutex);
|
2008-08-06 21:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* only call this if srv->log_mutex IS locked */
|
|
|
|
void log_free_unlocked(server *srv, log_t *log) {
|
2008-07-19 20:13:32 +00:00
|
|
|
if (log->type == LOG_TYPE_FILE || log->type == LOG_TYPE_PIPE)
|
|
|
|
close(log->fd);
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
g_hash_table_remove(srv->logs.targets, log->path);
|
2008-07-19 20:13:32 +00:00
|
|
|
g_string_free(log->path, TRUE);
|
|
|
|
g_string_free(log->lastmsg, TRUE);
|
2008-09-24 21:43:22 +00:00
|
|
|
|
|
|
|
g_mutex_free(log->mutex);
|
|
|
|
|
2008-07-19 20:13:32 +00:00
|
|
|
g_slice_free(log_t, log);
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_init(server *srv) {
|
|
|
|
GString *str;
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
srv->logs.targets = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
|
|
|
|
srv->logs.queue = g_async_queue_new();
|
|
|
|
srv->logs.mutex = g_mutex_new();
|
2008-09-26 22:09:12 +00:00
|
|
|
srv->logs.timestamps = g_array_new(FALSE, FALSE, sizeof(log_timestamp_t*));
|
|
|
|
srv->logs.thread_alive = FALSE;
|
2008-09-24 21:43:22 +00:00
|
|
|
|
|
|
|
/* first entry in srv->logs.timestamps is the default timestamp */
|
|
|
|
log_timestamp_new(srv, g_string_new_len(CONST_STR_LEN("%d/%b/%Y %T %Z")));
|
2008-07-18 22:11:08 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
/* first entry in srv->logs.targets is the plain good old stderr */
|
2008-07-19 20:13:32 +00:00
|
|
|
str = g_string_new_len(CONST_STR_LEN("stderr"));
|
2008-09-24 21:43:22 +00:00
|
|
|
srv->logs.stderr = log_new(srv, LOG_TYPE_STDERR, str);
|
2008-10-17 16:07:38 +00:00
|
|
|
g_string_free(str, TRUE);
|
2008-07-20 15:12:17 +00:00
|
|
|
}
|
|
|
|
|
2008-09-26 22:09:12 +00:00
|
|
|
void log_cleanup(server *srv) {
|
|
|
|
guint i;
|
|
|
|
/* wait for logging thread to exit */
|
|
|
|
if (g_atomic_int_get(&srv->logs.thread_alive) == TRUE)
|
|
|
|
{
|
|
|
|
log_thread_finish(srv);
|
|
|
|
g_thread_join(srv->logs.thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_free(srv, srv->logs.stderr);
|
|
|
|
|
|
|
|
g_hash_table_destroy(srv->logs.targets);
|
|
|
|
g_mutex_free(srv->logs.mutex);
|
|
|
|
g_async_queue_unref(srv->logs.queue);
|
|
|
|
|
|
|
|
log_timestamp_t *ts;
|
|
|
|
for (i = 0; i < srv->logs.timestamps->len; i++) {
|
|
|
|
ts = g_array_index(srv->logs.timestamps, log_timestamp_t*, i);
|
|
|
|
g_print("ts #%d refcount: %d\n", i, ts->refcount);
|
|
|
|
/*if (g_atomic_int_dec_and_test(&ts->refcount)) {
|
|
|
|
g_string_free(ts->cached, TRUE);
|
|
|
|
g_string_free(ts->format, TRUE);
|
|
|
|
g_slice_free(log_timestamp_t, ts);
|
|
|
|
g_array_remove_index_fast(srv->logs.timestamps, i);
|
|
|
|
i--;
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
log_timestamp_free(srv, g_array_index(srv->logs.timestamps, log_timestamp_t*, 0));
|
|
|
|
|
|
|
|
g_array_free(srv->logs.timestamps, TRUE);
|
|
|
|
}
|
|
|
|
|
2008-07-20 15:12:17 +00:00
|
|
|
void log_thread_start(server *srv) {
|
|
|
|
GError *err = NULL;
|
2008-07-19 13:12:32 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
srv->logs.thread = g_thread_create((GThreadFunc)log_thread, srv, TRUE, &err);
|
2008-09-26 22:09:12 +00:00
|
|
|
g_atomic_int_set(&srv->logs.thread_alive, TRUE);
|
2008-07-18 22:11:08 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
if (srv->logs.thread == NULL) {
|
2008-07-18 22:11:08 +00:00
|
|
|
g_printerr("could not create loggin thread: %s\n", err->message);
|
2008-09-24 21:43:22 +00:00
|
|
|
g_error_free(err);
|
|
|
|
abort();
|
2008-07-18 22:11:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-26 22:09:12 +00:00
|
|
|
void log_thread_stop(server *srv) {
|
|
|
|
if (g_atomic_int_get(&srv->logs.thread_alive) == TRUE) {
|
|
|
|
g_atomic_int_set(&srv->logs.thread_stop, TRUE);
|
|
|
|
log_thread_wakeup(srv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_thread_finish(server *srv) {
|
|
|
|
if (g_atomic_int_get(&srv->logs.thread_alive) == TRUE) {
|
|
|
|
g_atomic_int_set(&srv->logs.thread_finish, TRUE);
|
|
|
|
log_thread_wakeup(srv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-20 15:12:17 +00:00
|
|
|
void log_thread_wakeup(server *srv) {
|
2008-09-27 15:06:43 +00:00
|
|
|
if (!g_atomic_int_get(&srv->logs.thread_alive))
|
|
|
|
log_thread_start(srv);
|
2008-07-20 15:12:17 +00:00
|
|
|
log_entry_t *e;
|
2008-07-19 20:13:32 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
e = g_slice_new0(log_entry_t);
|
|
|
|
|
|
|
|
g_async_queue_push(srv->logs.queue, e);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void log_lock(log_t *log) {
|
|
|
|
g_mutex_lock(log->mutex);
|
|
|
|
}
|
2008-07-19 20:13:32 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
void log_unlock(log_t *log) {
|
|
|
|
g_mutex_unlock(log->mutex);
|
2008-07-19 20:13:32 +00:00
|
|
|
}
|
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
log_timestamp_t *log_timestamp_new(server *srv, GString *format) {
|
|
|
|
log_timestamp_t *ts;
|
2008-07-18 22:11:08 +00:00
|
|
|
|
2008-09-24 21:43:22 +00:00
|
|
|
/* check if there already exists a timestamp entry with the same format */
|
|
|
|
for (guint i = 0; i < srv->logs.timestamps->len; i++) {
|
2008-09-26 22:09:12 +00:00
|
|
|
ts = g_array_index(srv->logs.timestamps, log_timestamp_t*, i);
|
2008-09-24 21:43:22 +00:00
|
|
|
if (g_string_equal(ts->format, format)) {
|
|
|
|
g_atomic_int_inc(&(ts->refcount));
|
2008-09-26 22:09:12 +00:00
|
|
|
g_string_free(format, TRUE);
|
2008-09-24 21:43:22 +00:00
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ts = g_slice_new(log_timestamp_t);
|
|
|
|
|
|
|
|
ts->cached = g_string_sized_new(0);
|
|
|
|
ts->last_ts = 0;
|
|
|
|
ts->refcount = 1;
|
|
|
|
ts->format = format;
|
|
|
|
|
2008-09-26 22:09:12 +00:00
|
|
|
g_array_append_val(srv->logs.timestamps, ts);
|
2008-09-24 21:43:22 +00:00
|
|
|
|
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
2008-09-26 22:09:12 +00:00
|
|
|
gboolean log_timestamp_free(server *srv, log_timestamp_t *ts) {
|
2008-09-24 21:43:22 +00:00
|
|
|
if (g_atomic_int_dec_and_test(&(ts->refcount))) {
|
|
|
|
for (guint i = 0; i < srv->logs.timestamps->len; i++) {
|
2008-09-26 22:09:12 +00:00
|
|
|
if (g_string_equal(g_array_index(srv->logs.timestamps, log_timestamp_t*, i)->format, ts->format)) {
|
2008-09-24 21:43:22 +00:00
|
|
|
g_array_remove_index_fast(srv->logs.timestamps, i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-09-26 22:09:12 +00:00
|
|
|
g_string_free(ts->cached, TRUE);
|
|
|
|
g_string_free(ts->format, TRUE);
|
2008-09-24 21:43:22 +00:00
|
|
|
g_slice_free(log_timestamp_t, ts);
|
2008-09-26 22:09:12 +00:00
|
|
|
return TRUE;
|
2008-09-24 21:43:22 +00:00
|
|
|
}
|
2008-09-26 22:09:12 +00:00
|
|
|
|
|
|
|
return FALSE;
|
2008-09-24 21:43:22 +00:00
|
|
|
}
|