]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: Track the last 1000 errors in a buffer
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 14 Jan 2023 21:42:40 +0000 (23:42 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Mon, 23 Jan 2023 07:04:36 +0000 (07:04 +0000)
This is the same as what the log process does. The master process errors
aren't sent to the log process though.

src/master/common.h
src/master/main.c
src/master/master-client.c

index 36bda94d71643dc5eb999789a86891fdf662464a..f88a496910e34f373fb2b6a6437103535f073fb5 100644 (file)
@@ -15,6 +15,7 @@ extern bool have_proc_fs_suid_dumpable;
 extern bool have_proc_sys_kernel_core_pattern;
 extern const char *ssl_manual_key_password;
 extern int global_master_dead_pipe_fd[2];
+extern struct log_error_buffer *log_error_buffer;
 extern struct service_list *services;
 extern bool startup_finished;
 
index 6c95510aaf4b46c14460f9bc271106be14687d8a..4cd561c900fed3b389776e02308072d297271cbf 100644 (file)
@@ -16,6 +16,7 @@
 #include "master-instance.h"
 #include "master-service-private.h"
 #include "master-service-settings.h"
+#include "log-error-buffer.h"
 #include "askpass.h"
 #include "capabilities.h"
 #include "master-client.h"
@@ -60,6 +61,7 @@ bool have_proc_fs_suid_dumpable;
 bool have_proc_sys_kernel_core_pattern;
 const char *ssl_manual_key_password;
 int global_master_dead_pipe_fd[2];
+struct log_error_buffer *log_error_buffer;
 struct service_list *services;
 bool startup_finished = FALSE;
 
@@ -143,6 +145,25 @@ int get_gid(const char *group, gid_t *gid_r, const char **error_r)
        }
 }
 
+static void ATTR_FORMAT(2, 0)
+master_error_handler(const struct failure_context *ctx,
+                    const char *fmt, va_list args)
+{
+       va_list args2;
+
+       VA_COPY(args2, args);
+       struct log_error error = {
+               .type = ctx->type,
+               .timestamp = ioloop_timeval,
+               .prefix = ctx->log_prefix != NULL ? ctx->log_prefix : "",
+               .text = t_strdup_vprintf(fmt, args2),
+       };
+       log_error_buffer_add(log_error_buffer, &error);
+       va_end(args2);
+
+       orig_error_callback(ctx, fmt, args);
+}
+
 static void ATTR_NORETURN ATTR_FORMAT(2, 0)
 master_fatal_callback(const struct failure_context *ctx,
                      const char *format, va_list args)
@@ -594,6 +615,9 @@ static void main_deinit(void)
        service_pids_deinit();
        /* notify systemd that we are done */
        i_sd_notify(0, "STATUS=Dovecot stopped");
+
+       i_set_error_handler(orig_error_callback);
+       log_error_buffer_deinit(&log_error_buffer);
 }
 
 static const char *get_full_config_path(struct service_list *list)
@@ -909,8 +933,9 @@ int main(int argc, char *argv[])
        if (chdir(set->base_dir) < 0)
                i_fatal("chdir(%s) failed: %m", set->base_dir);
 
+       log_error_buffer = log_error_buffer_init();
        i_set_fatal_handler(master_fatal_callback);
-       i_set_error_handler(orig_error_callback);
+       i_set_error_handler(master_error_handler);
 
        if (!foreground)
                daemonize();
index 6294b281128c8a9484a4ea7273a3a5820ba2e02f..014d21eed88f66dfaac5e24e0dd8c4a2e239b8ef 100644 (file)
@@ -6,6 +6,7 @@
 #include "strescape.h"
 #include "ostream.h"
 #include "connection.h"
+#include "log-error-buffer.h"
 #include "service.h"
 #include "service-process.h"
 #include "service-monitor.h"
@@ -83,6 +84,35 @@ master_client_process_status(struct master_client *client,
        return 1;
 }
 
+static int master_client_send_errors(struct master_client *client)
+{
+       struct log_error_buffer_iter *iter;
+       const struct log_error *error;
+       string_t *str = t_str_new(256);
+       int ret = 0;
+
+       iter = log_error_buffer_iter_init(log_error_buffer);
+       while ((error = log_error_buffer_iter_next(iter)) != NULL) {
+               str_truncate(str, 0);
+               str_printfa(str, "%s\t%"PRIdTIME_T".%06u\t",
+                           failure_log_type_names[error->type],
+                           error->timestamp.tv_sec,
+                           (unsigned int)error->timestamp.tv_usec);
+               str_append_tabescaped(str, error->prefix);
+               str_append_c(str, '\t');
+               str_append_tabescaped(str, error->text);
+               str_append_c(str, '\n');
+               if (o_stream_send(client->conn.output,
+                                 str_data(str), str_len(str)) < 0) {
+                       ret = -1;
+                       break;
+               }
+       }
+       log_error_buffer_iter_deinit(&iter);
+       o_stream_nsend_str(client->conn.output, "\n");
+       return ret;
+}
+
 static int
 master_client_stop(struct master_client *client, const char *const *args)
 {
@@ -118,6 +148,8 @@ master_client_input_args(struct connection *conn, const char *const *args)
                return master_client_service_status(client);
        if (strcmp(cmd, "PROCESS-STATUS") == 0)
                return master_client_process_status(client, args);
+       if (strcmp(cmd, "ERROR-LOG") == 0)
+               return master_client_send_errors(client);
        if (strcmp(cmd, "STOP") == 0)
                return master_client_stop(client, args);
        e_error(conn->event, "Unknown command: %s", cmd);