From: Stephan Bosch Date: Sun, 30 Jun 2019 09:45:16 +0000 (+0200) Subject: lib: event-log - Add support for appending part of the log message to a string buffer... X-Git-Tag: 2.3.9~398 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d4aeac280a9f8d04f822627ec9a4daaf4e689060;p=thirdparty%2Fdovecot%2Fcore.git lib: event-log - Add support for appending part of the log message to a string buffer while sending the event. The message appended to the string buffer includes prefixes and message callback modifications by parent events up until a specified base event. The event is otherwise sent as normal with the full prefixes and all modifications up to the root event, so in that respect this new feature behaves just like event_log*(). This is primarily useful to mimic (part of) event logging in parallel logs that are visible to users. It is also possible to inhibit sending the event and only log to the string buffer. --- diff --git a/src/lib/event-log.c b/src/lib/event-log.c index eb672ed1cb..b8ce28735d 100644 --- a/src/lib/event-log.c +++ b/src/lib/event-log.c @@ -99,18 +99,59 @@ struct event_get_log_message_context { string_t *log_prefix; const char *message; - bool replace_prefix; unsigned int type_pos; + + bool replace_prefix:1; + bool str_out_done:1; }; +static inline void ATTR_FORMAT(2, 0) +event_get_log_message_str_out(struct event_get_log_message_context *glmctx, + const char *fmt, va_list args) +{ + const struct event_log_params *params = glmctx->params; + string_t *str_out = params->base_str_out; + + /* The message is appended once in full, rather than incremental during + the recursion. */ + + if (glmctx->str_out_done || str_out == NULL) + return; + + /* append the current log prefix to the string buffer */ + str_append_str(str_out, glmctx->log_prefix); + + if (glmctx->message != NULL) { + /* a child event already constructed a message */ + str_append(str_out, glmctx->message); + } else { + va_list args_copy; + + /* construct message from format and arguments */ + VA_COPY(args_copy, args); + str_vprintfa(str_out, fmt, args_copy); + va_end(args_copy); + } + + /* finished with the string buffer */ + glmctx->str_out_done = TRUE; +} + static bool ATTR_FORMAT(3, 0) event_get_log_message(struct event *event, struct event_get_log_message_context *glmctx, const char *fmt, va_list args) { + const struct event_log_params *params = glmctx->params; const char *prefix = event->log_prefix; bool ret = FALSE; + /* Reached the base event? */ + if (event == params->base_event) { + /* Append the message to the provided string buffer. */ + event_get_log_message_str_out(glmctx, fmt, args); + } + /* Call the message amendment callback for this event if there is one. */ if (event->log_message_callback != NULL) { @@ -143,16 +184,20 @@ event_get_log_message(struct event *event, prefix = event->log_prefix_callback( event->log_prefix_callback_context); } - if (prefix != NULL) { - str_insert(glmctx->log_prefix, 0, prefix); - ret = TRUE; - } - if (event->log_prefix_replace) { /* this event replaces all parent log prefixes */ glmctx->replace_prefix = TRUE; glmctx->type_pos = (prefix == NULL ? 0 : strlen(prefix)); - } else if (event->parent != NULL) { + event_get_log_message_str_out(glmctx, fmt, args); + } + if (prefix != NULL) { + str_insert(glmctx->log_prefix, 0, prefix); + ret = TRUE; + } + if (event->parent == NULL) { + event_get_log_message_str_out(glmctx, fmt, args); + } else if (!event->log_prefix_replace && + (!params->no_send || !glmctx->str_out_done)) { if (event_get_log_message(event->parent, glmctx, fmt, args)) ret = TRUE; } @@ -231,6 +276,8 @@ event_logv_params(struct event *event, const struct event_log_params *params, bool abort_after_event = FALSE; int old_errno = errno; + i_assert(!params->no_send || params->base_str_out != NULL); + if (global_core_log_filter != NULL && event_filter_match_source(global_core_log_filter, event, event->source_filename, @@ -242,7 +289,17 @@ event_logv_params(struct event *event, const struct event_log_params *params, glmctx.log_prefix = t_str_new(64); if (!event_get_log_message(event, &glmctx, fmt, args)) { /* keep log prefix as it is */ - event_vsend(event, &ctx, fmt, args); + if (params->base_str_out != NULL && !glmctx.str_out_done) { + va_list args_copy; + + VA_COPY(args_copy, args); + str_vprintfa(params->base_str_out, fmt, args_copy); + va_end(args_copy); + } + if (!params->no_send) + event_vsend(event, &ctx, fmt, args); + } else if (params->no_send) { + /* don't send the event */ } else if (glmctx.replace_prefix) { /* event overrides the log prefix (even if it's "") */ ctx.log_prefix = str_c(glmctx.log_prefix); diff --git a/src/lib/event-log.h b/src/lib/event-log.h index 6b0427b56f..e38ce9ff23 100644 --- a/src/lib/event-log.h +++ b/src/lib/event-log.h @@ -9,6 +9,22 @@ struct event_log_params { enum log_type log_type; const char *source_filename; unsigned int source_linenum; + + /* Base event used as a reference for base_* parameters (see below) */ + struct event *base_event; + + /* Append the event message to base_str_out in addition to emitting the + event as normal. The message appended to the string buffer includes + prefixes and message callback modifications by parent events up until + the base_event. The event is otherwise sent as normal with the full + prefixes and all modifications up to the root event (unless + no_send=TRUE). This is primarily useful to mimic (part of) event + logging in parallel logs that are visible to users. */ + string_t *base_str_out; + + /* Don't actually send the event; only append to the provided string + buffer (base_str_out must not be NULL). */ + bool no_send:1; }; void e_error(struct event *event, diff --git a/src/lib/lib-event.h b/src/lib/lib-event.h index a1c6820f0f..4a62e1a00c 100644 --- a/src/lib/lib-event.h +++ b/src/lib/lib-event.h @@ -5,6 +5,7 @@ #include struct event; +struct event_log_params; /* Hierarchical category of events. Each event can belong to multiple categories. For example [ lib-storage/maildir, syscall/io ]. The categories