From: Timo Sirainen Date: Sat, 14 Jan 2023 21:42:40 +0000 (+0200) Subject: master: Track the last 1000 errors in a buffer X-Git-Tag: 2.4.0~3174 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=961be3379258f08cae69ad9192498fbd62ea1a20;p=thirdparty%2Fdovecot%2Fcore.git master: Track the last 1000 errors in a buffer This is the same as what the log process does. The master process errors aren't sent to the log process though. --- diff --git a/src/master/common.h b/src/master/common.h index 36bda94d71..f88a496910 100644 --- a/src/master/common.h +++ b/src/master/common.h @@ -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; diff --git a/src/master/main.c b/src/master/main.c index 6c95510aaf..4cd561c900 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -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(); diff --git a/src/master/master-client.c b/src/master/master-client.c index 6294b28112..014d21eed8 100644 --- a/src/master/master-client.c +++ b/src/master/master-client.c @@ -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);