2
0
Fork 0
lighttpd2/src/log.c

359 lines
7.9 KiB
C
Raw Normal View History

2008-06-24 19:19:20 +00:00
#include "log.h"
#include "plugin_core.h"
2008-06-24 19:19:20 +00:00
#include <stdarg.h>
#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
int log_write(server* UNUSED_PARAM(srv), connection* UNUSED_PARAM(con), const char *fmt, ...) {
va_list ap;
GString *logline;
logline = g_string_sized_new(0);
va_start(ap, fmt);
g_string_vprintf(logline, fmt, ap);
va_end(ap);
g_string_append_len(logline, CONST_STR_LEN("\r\n"));
write(STDERR_FILENO, logline->str, logline->len);
g_string_free(logline, TRUE);
return 0;
}
2008-07-18 23:33:12 +00:00
gboolean log_write_(server *srv, connection *con, log_level_t log_level, const gchar *fmt, ...) {
va_list ap;
GString *log_line;
2008-07-18 20:16:30 +00:00
log_t *log;
2008-07-18 22:11:08 +00:00
log_entry_t *log_entry;
2008-07-18 22:38:33 +00:00
log_level_t log_level_want;
if (con != NULL) {
if (!srv) srv = con->srv;
2008-07-18 20:16:30 +00:00
/* get log index from connection */
log = CORE_OPTION(CORE_OPTION_LOG_TARGET) ? CORE_OPTION(CORE_OPTION_LOG_TARGET) : srv->log_stderr;
log_level_want = (log_level_t) CORE_OPTION(CORE_OPTION_LOG_LEVEL);
}
2008-07-18 22:38:33 +00:00
else {
2008-07-19 20:13:32 +00:00
log = srv->log_stderr;
2008-07-18 22:38:33 +00:00
log_level_want = LOG_LEVEL_DEBUG;
}
/* ingore messages we are not interested in */
2008-07-19 13:12:32 +00:00
if (log_level < log_level_want)
2008-07-18 22:38:33 +00:00
return TRUE;
2008-07-18 20:16:30 +00:00
log_ref(srv, log);
2008-07-20 14:35:04 +00:00
log_line = g_string_sized_new(0);
va_start(ap, fmt);
g_string_vprintf(log_line, fmt, ap);
va_end(ap);
2008-07-18 20:16:30 +00:00
/* check if last message for this log was the same */
2008-07-19 20:13:32 +00:00
if (g_string_equal(log->lastmsg, log_line)) {
2008-07-18 20:16:30 +00:00
log->lastmsg_count++;
2008-07-20 14:35:04 +00:00
log_unref(srv, log);
g_string_free(log_line, TRUE);
2008-07-18 20:16:30 +00:00
return TRUE;
}
else {
if (log->lastmsg_count > 0) {
2008-07-19 13:12:32 +00:00
guint count = log->lastmsg_count;
log->lastmsg_count = 0;
log_write_(srv, con, log_level, "last message repeated %d times", count);
2008-07-18 20:16:30 +00:00
}
}
log->lastmsg = g_string_assign(log->lastmsg, log_line->str);
2008-07-19 13:12:32 +00:00
g_string_append_len(log_line, CONST_STR_LEN("\r\n"));
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-07-18 22:11:08 +00:00
g_async_queue_push(srv->log_queue, log_entry);
2008-07-22 14:00:31 +00:00
/* on critical error, exit */
if (log_level == LOG_LEVEL_ERROR) {
g_atomic_int_set(&srv->exiting, TRUE);
log_thread_wakeup(srv); /* just in case the logging thread is sleeping at this point */
}
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;
queue = srv->log_queue;
while (TRUE) {
2008-08-02 20:56:07 +00:00
/* do we need to rotate logs? */
if (g_atomic_int_get(&srv->rotate_logs)) {
g_atomic_int_set(&srv->rotate_logs, FALSE);
2008-07-20 14:35:04 +00:00
g_mutex_lock(srv->log_mutex);
g_hash_table_foreach(srv->logs, (GHFunc) log_rotate, srv);
g_mutex_unlock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
}
2008-07-18 22:11:08 +00:00
2008-07-20 14:35:04 +00:00
log_entry = g_async_queue_pop(srv->log_queue);
if (log_entry->log == NULL) {
g_slice_free(log_entry_t, log_entry);
2008-08-02 20:56:07 +00:00
/* lighty is exiting, end logging thread */
if (g_atomic_int_get(&srv->exiting) && g_async_queue_length(srv->log_queue) == 0)
break;
2008-07-18 22:11:08 +00:00
continue;
}
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:
/* 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) {
g_atomic_int_set(&srv->rotate_logs, TRUE);
}
2008-07-19 20:13:32 +00:00
void log_ref(server *srv, log_t *log) {
g_mutex_lock(srv->log_mutex);
log->refcount++;
g_mutex_unlock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
}
void log_unref(server *srv, log_t *log) {
g_mutex_lock(srv->log_mutex);
if (g_atomic_int_dec_and_test(&log->refcount))
log_free_unlocked(srv, log);
g_mutex_unlock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
}
log_type_t log_type_from_path(GString *path) {
if (path->len == 0)
return LOG_TYPE_STDERR;
/* 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, "message"))
return LOG_LEVEL_MESSAGE;
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_MESSAGE: return "message";
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;
gint fd = -1;
2008-07-19 20:13:32 +00:00
2008-07-20 14:35:04 +00:00
g_mutex_lock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
log = g_hash_table_lookup(srv->logs, path->str);
/* log already open, inc refcount */
if (log != NULL)
{
log->refcount++;
g_mutex_unlock(srv->log_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:
/* TODO */
2008-08-08 23:55:07 +00:00
fd = -1;
2008-07-19 20:13:32 +00:00
assert(NULL);
}
if (fd == -1) {
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;
log->path = path;
log->refcount = 1;
2008-07-20 14:35:04 +00:00
g_mutex_unlock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
return log;
}
/* only call this if srv->log_mutex is NOT locked */
2008-07-19 20:13:32 +00:00
void log_free(server *srv, log_t *log) {
2008-07-20 14:35:04 +00:00
g_mutex_lock(srv->log_mutex);
log_free_unlocked(srv, log);
g_mutex_unlock(srv->log_mutex);
}
/* only call this if srv->log_mutex IS locked */
void log_free_unlocked(server *srv, log_t *log) {
g_mutex_lock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
if (log->type == LOG_TYPE_FILE || log->type == LOG_TYPE_PIPE)
close(log->fd);
g_hash_table_remove(srv->logs, log->path);
g_string_free(log->path, TRUE);
g_string_free(log->lastmsg, TRUE);
g_slice_free(log_t, log);
2008-07-20 14:35:04 +00:00
g_mutex_unlock(srv->log_mutex);
2008-07-19 20:13:32 +00:00
}
void log_init(server *srv) {
GString *str;
2008-08-03 20:26:37 +00:00
srv->logs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
2008-07-19 20:13:32 +00:00
srv->log_queue = g_async_queue_new();
2008-07-20 14:35:04 +00:00
srv->log_mutex = g_mutex_new();
2008-07-18 22:11:08 +00:00
2008-07-19 13:12:32 +00:00
/* first entry in srv->logs is the plain good old stderr */
2008-07-19 20:13:32 +00:00
str = g_string_new_len(CONST_STR_LEN("stderr"));
srv->log_stderr = log_new(srv, LOG_TYPE_STDERR, str);
srv->log_syslog = NULL;
}
void log_thread_start(server *srv) {
GError *err = NULL;
2008-07-19 13:12:32 +00:00
2008-07-18 22:11:08 +00:00
srv->log_thread = g_thread_create((GThreadFunc)log_thread, srv, TRUE, &err);
if (srv->log_thread == NULL) {
g_printerr("could not create loggin thread: %s\n", err->message);
assert(NULL);
}
}
void log_thread_wakeup(server *srv) {
log_entry_t *e;
2008-07-19 20:13:32 +00:00
e = g_slice_new(log_entry_t);
e->log = NULL;
e->msg = NULL;
2008-07-19 20:13:32 +00:00
g_async_queue_push(srv->log_queue, e);
2008-07-19 20:13:32 +00:00
}
2008-07-18 22:11:08 +00:00