dovecot-2.1: log: Keep track of last 1000 errors/warnings. "dove...

dovecot at dovecot.org dovecot at dovecot.org
Mon Feb 6 19:30:24 EET 2012


details:   http://hg.dovecot.org/dovecot-2.1/rev/66f875b5102b
changeset: 14065:66f875b5102b
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Feb 06 19:30:12 2012 +0200
description:
log: Keep track of last 1000 errors/warnings. "doveadm log errors" shows them.

diffstat:

 src/doveadm/doveadm-log.c |  57 +++++++++++++++++++++++++++++++++++++++++++-
 src/log/Makefile.am       |   6 +++-
 src/log/log-connection.c  |  60 ++++++++++++++++++++++++++++++++++++----------
 src/log/log-connection.h  |   3 +-
 src/log/log-settings.c    |  19 +++++++++++++-
 src/log/main.c            |  16 +++++++++++-
 6 files changed, 140 insertions(+), 21 deletions(-)

diffs (truncated from 352 to 300 lines):

diff -r 0d224f2c3152 -r 66f875b5102b src/doveadm/doveadm-log.c
--- a/src/doveadm/doveadm-log.c	Mon Feb 06 19:28:40 2012 +0200
+++ b/src/doveadm/doveadm-log.c	Mon Feb 06 19:30:12 2012 +0200
@@ -2,9 +2,11 @@
 
 #include "lib.h"
 #include "ioloop.h"
+#include "istream.h"
 #include "hash.h"
 #include "str.h"
-#include "istream.h"
+#include "strescape.h"
+#include "time-util.h"
 #include "master-service-private.h"
 #include "master-service-settings.h"
 #include "doveadm.h"
@@ -18,6 +20,8 @@
 
 #define LAST_LOG_TYPE LOG_TYPE_PANIC
 #define TEST_LOG_MSG_PREFIX "This is Dovecot's "
+#define LOG_ERRORS_FNAME "log-errors"
+#define LOG_TIMESTAMP_FORMAT "%b %d %H:%M:%S"
 
 static void cmd_log_test(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
 {
@@ -274,10 +278,59 @@
 	}
 }
 
+static void cmd_log_error_write(const char *const *args)
+{
+	/* <type> <timestamp> <prefix> <text> */
+	const char *type_prefix = "?";
+	unsigned int type;
+	time_t t;
+
+	/* find type's prefix */
+	for (type = 0; type < LOG_TYPE_COUNT; type++) {
+		if (strcmp(args[0], failure_log_type_names[type]) == 0) {
+			type_prefix = failure_log_type_prefixes[type];
+			break;
+		}
+	}
+
+	if (str_to_time(args[1], &t) < 0) {
+		i_error("Invalid timestamp: %s", args[1]);
+		t = 0;
+	}
+
+	printf("%s %s%s%s\n", t_strflocaltime(LOG_TIMESTAMP_FORMAT, t),
+	       args[2], type_prefix, args[3]);
+}
+
+static void cmd_log_errors(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
+{
+	struct istream *input;
+	const char *path, *line, *const *args;
+	int fd;
+
+	path = t_strconcat(doveadm_settings->base_dir,
+			   "/"LOG_ERRORS_FNAME, NULL);
+	fd = net_connect_unix(path);
+	if (fd == -1)
+		i_fatal("net_connect_unix(%s) failed: %m", path);
+	net_set_nonblock(fd, FALSE);
+
+	input = i_stream_create_fd(fd, (size_t)-1, TRUE);
+	while ((line = i_stream_read_next_line(input)) != NULL) T_BEGIN {
+		args = t_strsplit_tabescaped(line);
+		if (str_array_length(args) == 4)
+			cmd_log_error_write(args);
+		else
+			i_error("Invalid input from log: %s", line);
+	} T_END;
+	i_stream_destroy(&input);
+}
+
 struct doveadm_cmd doveadm_cmd_log[] = {
 	{ cmd_log_test, "log test", "" },
 	{ cmd_log_reopen, "log reopen", "" },
-	{ cmd_log_find, "log find", "[<dir>]" }
+	{ cmd_log_find, "log find", "[<dir>]" },
+	{ cmd_log_errors, "log errors", "" }
 };
 
 void doveadm_register_log_commands(void)
diff -r 0d224f2c3152 -r 66f875b5102b src/log/Makefile.am
--- a/src/log/Makefile.am	Mon Feb 06 19:28:40 2012 +0200
+++ b/src/log/Makefile.am	Mon Feb 06 19:30:12 2012 +0200
@@ -11,9 +11,13 @@
 log_DEPENDENCIES = $(LIBDOVECOT_DEPS)
 
 log_SOURCES = \
+	doveadm-connection.c \
 	log-connection.c \
+	log-error-buffer.c \
 	log-settings.c \
 	main.c
 
 noinst_HEADERS = \
-	log-connection.h
+	doveadm-connection.h \
+	log-connection.h \
+	log-error-buffer.h
diff -r 0d224f2c3152 -r 66f875b5102b src/log/log-connection.c
--- a/src/log/log-connection.c	Mon Feb 06 19:28:40 2012 +0200
+++ b/src/log/log-connection.c	Mon Feb 06 19:30:12 2012 +0200
@@ -8,6 +8,7 @@
 #include "hash.h"
 #include "master-interface.h"
 #include "master-service.h"
+#include "log-error-buffer.h"
 #include "log-connection.h"
 
 #include <stdio.h>
@@ -25,6 +26,7 @@
 struct log_connection {
 	struct log_connection *prev, *next;
 
+	struct log_error_buffer *errorbuf;
 	int fd;
 	int listen_fd;
 	struct io *io;
@@ -77,8 +79,38 @@
 }
 
 static void
+client_log_ctx(struct log_connection *log,
+	       const struct failure_context *ctx, time_t log_time,
+	       const char *prefix, const char *text)
+{
+	struct log_error err;
+
+	switch (ctx->type) {
+	case LOG_TYPE_DEBUG:
+	case LOG_TYPE_INFO:
+	case LOG_TYPE_COUNT:
+	case LOG_TYPE_OPTION:
+		break;
+	case LOG_TYPE_WARNING:
+	case LOG_TYPE_ERROR:
+	case LOG_TYPE_FATAL:
+	case LOG_TYPE_PANIC:
+		memset(&err, 0, sizeof(err));
+		err.type = ctx->type;
+		err.timestamp = log_time;
+		err.prefix = prefix;
+		err.text = text;
+		log_error_buffer_add(log->errorbuf, &err);
+		break;
+	}
+	i_set_failure_prefix(prefix);
+	i_log_type(ctx, "%s", text);
+	i_set_failure_prefix("log: ");
+}
+
+static void
 client_log_fatal(struct log_connection *log, struct log_client *client,
-		 const char *line, const struct tm *tm)
+		 const char *line, time_t log_time, const struct tm *tm)
 {
 	struct failure_context failure_ctx;
 	const char *prefix = log->default_prefix;
@@ -95,13 +127,12 @@
 					       line, net_ip2addr(&client->ip));
 		}
 	}
-	i_set_failure_prefix(prefix);
-	i_log_type(&failure_ctx, "master: %s", line);
-	i_set_failure_prefix("log: ");
+	client_log_ctx(log, &failure_ctx, log_time, prefix,
+		       t_strconcat("master: ", line, NULL));
 }
 
 static void
-log_parse_master_line(const char *line, const struct tm *tm)
+log_parse_master_line(const char *line, time_t log_time, const struct tm *tm)
 {
 	struct log_connection *const *logs, *log;
 	struct log_client *client;
@@ -136,19 +167,20 @@
 		}
 		log_client_free(log, client, pid);
 	} else if (strncmp(line, "FATAL ", 6) == 0) {
-		client_log_fatal(log, client, line + 6, tm);
+		client_log_fatal(log, client, line + 6, log_time, tm);
 	} else if (strncmp(line, "DEFAULT-FATAL ", 14) == 0) {
 		/* If the client has logged a fatal/panic, don't log this
 		   message. */
 		if (client == NULL || !client->fatal_logged)
-			client_log_fatal(log, client, line + 14, tm);
+			client_log_fatal(log, client, line + 14, log_time, tm);
 	} else {
 		i_error("Received unknown command from master: %s", line);
 	}
 }
 
 static void
-log_it(struct log_connection *log, const char *line, const struct tm *tm)
+log_it(struct log_connection *log, const char *line,
+       time_t log_time, const struct tm *tm)
 {
 	struct failure_line failure;
 	struct failure_context failure_ctx;
@@ -157,7 +189,7 @@
 
 	if (log->master) {
 		T_BEGIN {
-			log_parse_master_line(line, tm);
+			log_parse_master_line(line, log_time, tm);
 		} T_END;
 		return;
 	}
@@ -185,9 +217,7 @@
 
 	prefix = client != NULL && client->prefix != NULL ?
 		client->prefix : log->default_prefix;
-	i_set_failure_prefix(prefix);
-	i_log_type(&failure_ctx, "%s", failure.text);
-	i_set_failure_prefix("log: ");
+	client_log_ctx(log, &failure_ctx, log_time, prefix, failure.text);
 }
 
 static int log_connection_handshake(struct log_connection *log)
@@ -256,7 +286,7 @@
 		tm = *localtime(&now);
 
 		while ((line = i_stream_next_line(log->input)) != NULL)
-			log_it(log, line, &tm);
+			log_it(log, line, now, &tm);
 	}
 
 	if (log->input->eof)
@@ -269,11 +299,13 @@
 	}
 }
 
-struct log_connection *log_connection_create(int fd, int listen_fd)
+struct log_connection *
+log_connection_create(struct log_error_buffer *errorbuf, int fd, int listen_fd)
 {
 	struct log_connection *log;
 
 	log = i_new(struct log_connection, 1);
+	log->errorbuf = errorbuf;
 	log->fd = fd;
 	log->listen_fd = listen_fd;
 	log->io = io_add(fd, IO_READ, log_connection_input, log);
diff -r 0d224f2c3152 -r 66f875b5102b src/log/log-connection.h
--- a/src/log/log-connection.h	Mon Feb 06 19:28:40 2012 +0200
+++ b/src/log/log-connection.h	Mon Feb 06 19:30:12 2012 +0200
@@ -1,7 +1,8 @@
 #ifndef LOG_CONNECTION_H
 #define LOG_CONNECTION_H
 
-struct log_connection *log_connection_create(int fd, int listen_fd);
+struct log_connection *
+log_connection_create(struct log_error_buffer *errorbuf, int fd, int listen_fd);
 void log_connection_destroy(struct log_connection *log);
 
 void log_connections_init(void);
diff -r 0d224f2c3152 -r 66f875b5102b src/log/log-settings.c
--- a/src/log/log-settings.c	Mon Feb 06 19:28:40 2012 +0200
+++ b/src/log/log-settings.c	Mon Feb 06 19:30:12 2012 +0200
@@ -1,11 +1,25 @@
 /* Copyright (c) 2009-2011 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "buffer.h"
 #include "settings-parser.h"
 #include "service-settings.h"
 
 #include <stddef.h>
 
+/* <settings checks> */
+static struct file_listener_settings log_unix_listeners_array[] = {
+	{ "log-errors", 0600, "", "" }
+};
+static struct file_listener_settings *log_unix_listeners[] = {
+	&log_unix_listeners_array[0]
+};
+static buffer_t log_unix_listeners_buf = {
+	log_unix_listeners,
+	sizeof(log_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
 struct service_settings log_service_settings = {
 	.name = "log",
 	.protocol = "",
@@ -23,10 +37,11 @@
 	.process_limit = 1,
 	.client_limit = 0,
 	.service_count = 0,
-	.idle_kill = 0,
+	.idle_kill = -1U,
 	.vsz_limit = (uoff_t)-1,
 
-	.unix_listeners = ARRAY_INIT,
+	.unix_listeners = { { &log_unix_listeners_buf,


More information about the dovecot-cvs mailing list