]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: event-log - Add support for appending part of the log message to a string buffer...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 30 Jun 2019 09:45:16 +0000 (11:45 +0200)
committerStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 9 Jul 2019 19:42:49 +0000 (21:42 +0200)
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.

src/lib/event-log.c
src/lib/event-log.h
src/lib/lib-event.h

index eb672ed1cb27d9ec2b2b7da1eeac93d6bca0bd37..b8ce28735df2d4b90359a3315d6526116926ad1c 100644 (file)
@@ -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);
index 6b0427b56f67adebec56b0433e7f8a4c5c2baf9e..e38ce9ff23355b05e63d35684ee3ca6340d5b3a3 100644 (file)
@@ -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,
index a1c6820f0f49415d82910d30fc331eacd243cbef..4a62e1a00c7b904c98e25fc7a37c90b99809e7aa 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/time.h>
 
 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