From dc2539081d86a0c33d52a536c46d3af521722177 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 16 Aug 2018 12:17:38 +0300 Subject: [PATCH] lib: Add event_field_clear() to allow clearing parent event's fields --- src/lib/Makefile.am | 1 + src/lib/event-filter.c | 4 +++ src/lib/lib-event.c | 5 ++++ src/lib/lib-event.h | 10 +++++++- src/lib/test-event-filter.c | 50 +++++++++++++++++++++++++++++++++++++ src/lib/test-lib.inc | 1 + 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/lib/test-event-filter.c diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 17254a9d4e..51954d4a92 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -345,6 +345,7 @@ test_lib_SOURCES = \ test-crc32.c \ test-data-stack.c \ test-event-log.c \ + test-event-filter.c \ test-failures.c \ test-file-create-locked.c \ test-guid.c \ diff --git a/src/lib/event-filter.c b/src/lib/event-filter.c index 76585a4f9a..37aa3465b8 100644 --- a/src/lib/event-filter.c +++ b/src/lib/event-filter.c @@ -450,6 +450,10 @@ event_match_field(struct event *event, const struct event_field *wanted_field) } switch (field->value_type) { case EVENT_FIELD_VALUE_TYPE_STR: + if (field->value.str[0] == '\0') { + /* field was removed */ + return FALSE; + } return wildcard_match_icase(field->value.str, wanted_field->value.str); case EVENT_FIELD_VALUE_TYPE_INTMAX: return field->value.intmax == wanted_field->value.intmax; diff --git a/src/lib/lib-event.c b/src/lib/lib-event.c index 2a9fbbeb12..8f2b65fe42 100644 --- a/src/lib/lib-event.c +++ b/src/lib/lib-event.c @@ -529,6 +529,11 @@ event_add_fields(struct event *event, return event; } +void event_field_clear(struct event *event, const char *key) +{ + event_add_str(event, key, ""); +} + struct event *event_get_parent(struct event *event) { return event->parent; diff --git a/src/lib/lib-event.h b/src/lib/lib-event.h index 7e055d7b1e..c77732750f 100644 --- a/src/lib/lib-event.h +++ b/src/lib/lib-event.h @@ -177,7 +177,9 @@ event_add_category(struct event *event, struct event_category *category); /* Add key=value field to the event. If a key already exists, it's replaced. Child events automatically inherit key=values from their parents at the time the event is sent. So changing a key in parent will change the values - in the child events as well. Returns the event parameter. */ + in the child events as well, unless the key has been overwritten in the + child event. Setting the value to "" is the same as event_field_clear(). + Returns the event parameter. */ struct event * event_add_str(struct event *event, const char *key, const char *value); struct event * @@ -193,6 +195,12 @@ event_add_timeval(struct event *event, const char *key, terminates with key=NULL. Returns the event parameter. */ struct event * event_add_fields(struct event *event, const struct event_add_field *fields); +/* Mark a field as nonexistent. If a parent event has the field set, this + allows removing it from the child event. Using an event filter with e.g. + "key=*" won't match this field anymore, although it's still visible in + event_find_field*() and event_get_fields(). This is the same as using + event_add_str() with value="". */ +void event_field_clear(struct event *event, const char *key); /* Returns the parent event, or NULL if it doesn't exist. */ struct event *event_get_parent(struct event *event); diff --git a/src/lib/test-event-filter.c b/src/lib/test-event-filter.c new file mode 100644 index 0000000000..eb9621a96e --- /dev/null +++ b/src/lib/test-event-filter.c @@ -0,0 +1,50 @@ +/* Copyright (c) 2018 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "ioloop.h" +#include "event-filter.h" + +static void test_event_filter_clear_parent_fields(void) +{ + struct event_filter *filter; + struct event_filter_field filter_fields[] = { + { .key = "", .value = "*" }, + { .key = NULL, .value = NULL } + }; + const struct event_filter_query query = { + .fields = filter_fields, + }; + const struct failure_context failure_ctx = { + .type = LOG_TYPE_DEBUG + }; + const char *keys[] = { "str", "int" }; + + test_begin("event filter: clear parent fields"); + + struct event *parent = event_create(NULL); + event_add_str(parent, "str", "parent_str"); + event_add_int(parent, "int", 0); + + struct event *child = event_create(NULL); + event_field_clear(child, "str"); + event_field_clear(child, "int"); + + for (unsigned int i = 0; i < N_ELEMENTS(keys); i++) { + filter_fields[0].key = keys[i]; + filter = event_filter_create(); + event_filter_add(filter, &query); + + test_assert_idx(event_filter_match(filter, parent, &failure_ctx), i); + test_assert_idx(!event_filter_match(filter, child, &failure_ctx), i); + event_filter_unref(&filter); + } + + event_unref(&parent); + event_unref(&child); + test_end(); +} + +void test_event_filter(void) +{ + test_event_filter_clear_parent_fields(); +} diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index ce3544c2b8..b0f43cc1f3 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -16,6 +16,7 @@ TEST(test_crc32) TEST(test_data_stack) FATAL(fatal_data_stack) TEST(test_event_log) +TEST(test_event_filter) TEST(test_failures) TEST(test_file_create_locked) TEST(test_guid)