bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* Pointer to the event_category. NULL if the category isn't
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen registered yet. If it becomes registered, this will be filled out
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen by the category register callback. */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen ARRAY(struct event_filter_query_internal) queries;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenstatic struct event_filter *event_filters = NULL;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen pool_t pool = pool_alloconly_create("event filter", 256);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid event_filter_ref(struct event_filter *filter)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid event_filter_unref(struct event_filter **_filter)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_add_categories(struct event_filter *filter,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen struct event_filter_query_internal *int_query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const char *const *categories)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen unsigned int categories_count = str_array_length(categories);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen unsigned int i;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* copy strings */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen cat = p_new(filter->pool, struct event_filter_category,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (i = 0; i < categories_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen cat[i].name = p_strdup(filter->pool, categories[i]);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen cat[i].category = event_category_find_registered(categories[i]);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_query->has_unregistered_categories = TRUE;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_query->categories_count = categories_count;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_add_fields(struct event_filter *filter,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen struct event_filter_query_internal *int_query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (count = 0; fields[count].key != NULL; count++) ;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_fields = p_new(filter->pool, struct event_field, count);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (i = 0; i < count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_fields[i].key = p_strdup(filter->pool, fields[i].key);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* Filter currently supports only comparing strings
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen and numbers. */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_fields[i].value.str = p_strdup(filter->pool, fields[i].value);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (str_to_intmax(fields[i].value, &int_fields[i].value.intmax) < 0) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* not a number - no problem */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid event_filter_add(struct event_filter *filter,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen struct event_filter_query_internal *int_query;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_query = array_append_space(&filter->queries);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_query->name = p_strdup(filter->pool, query->name);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen p_strdup_empty(filter->pool, query->source_filename);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen int_query->source_linenum = query->source_linenum;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_filter_add_categories(filter, int_query, query->categories);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_filter_add_fields(filter, int_query, query->fields);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid event_filter_merge(struct event_filter *dest,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const struct event_filter_query_internal *int_query;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen unsigned int i;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen array_foreach(&src->queries, int_query) T_BEGIN {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen query.source_filename = int_query->source_filename;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen query.source_linenum = int_query->source_linenum;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen t_array_init(&categories, int_query->categories_count);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (i = 0; i < int_query->categories_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen t_array_init(&fields, int_query->fields_count);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (i = 0; i < int_query->fields_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen field->key = p_strdup(dest->pool, int_query->fields[i].key);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen field->value = p_strdup(dest->pool, int_query->fields[i].value.str);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_export_query(const struct event_filter_query_internal *query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen unsigned int i;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen str_append_tabescaped(dest, query->source_filename);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen str_printfa(dest, "\t%u\t", query->source_linenum);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (i = 0; i < query->categories_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen str_append_c(dest, EVENT_FILTER_CODE_CATEGORY);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen str_append_tabescaped(dest, query->categories[i].name);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen str_append_tabescaped(dest, query->fields[i].key);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen str_append_tabescaped(dest, query->fields[i].value.str);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid event_filter_export(struct event_filter *filter, string_t *dest)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const struct event_filter_query_internal *query;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenbool event_filter_import(struct event_filter *filter, const char *str,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const char **error_r)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenbool event_filter_import_unescaped(struct event_filter *filter,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const char *const *args,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const char **error_r)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (unsigned int i = 0; args[i] != NULL; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* finish the query */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* start the next query */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (str_to_uint(args[i], &query.source_linenum) < 0) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_has_category(struct event *event, struct event_category *wanted_category)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* try also the parent events */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_query_match_categories(const struct event_filter_query_internal *query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* At least one of the categories in the filter hasn't even
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen been registered yet. This filter can't match. */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (unsigned int i = 0; i < query->categories_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (!event_has_category(event, query->categories[i].category))
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_match_field(struct event *event, const struct event_field *wanted_field)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* wanted_field has the value in all available formats */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen while ((field = event_find_field(event, wanted_field->key)) == NULL) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen return wildcard_match_icase(field->value.str, wanted_field->value.str);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen return field->value.intmax == wanted_field->value.intmax;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* there's no point to support matching exact timestamps */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_query_match_fields(const struct event_filter_query_internal *query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (unsigned int i = 0; i < query->fields_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (!event_match_field(event, &query->fields[i]))
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_query_match(const struct event_filter_query_internal *query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen struct event *event, const char *source_filename,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen strcmp(event->sending_name, query->name) != 0)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (source_linenum != query->source_linenum ||
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen strcmp(event->source_filename, query->source_filename) != 0)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (!event_filter_query_match_categories(query, event))
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (!event_filter_query_match_fields(query, event))
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_match_fastpath(struct event_filter *filter, struct event *event)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (filter->named_queries_only && event->sending_name == NULL) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen /* No debug logging is enabled. Only named events may be wanted
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for stats. This event doesn't have a name, so we don't need
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen to check any further. */
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenbool event_filter_match(struct event_filter *filter, struct event *event)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen return event_filter_match_source(filter, event, event->source_filename,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenbool event_filter_match_source(struct event_filter *filter, struct event *event,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const struct event_filter_query_internal *query;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (!event_filter_match_fastpath(filter, event))
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (event_filter_query_match(query, event, source_filename,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_match_iter_init(struct event_filter *filter, struct event *event)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen iter = i_new(struct event_filter_match_iter, 1);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (!event_filter_match_fastpath(filter, event))
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid *event_filter_match_iter_next(struct event_filter_match_iter *iter)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const struct event_filter_query_internal *queries;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen queries = array_get(&iter->filter->queries, &count);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen const struct event_filter_query_internal *query =
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenvoid event_filter_match_iter_deinit(struct event_filter_match_iter **_iter)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen struct event_filter_match_iter *iter = *_iter;
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_query_remove_category(struct event_filter_query_internal *query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (unsigned int i = 0; i < query->categories_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (query->categories[i].category == category) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_remove_category(struct event_filter *filter,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen array_foreach_modifiable(&filter->queries, query)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_filter_query_remove_category(query, category);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_query_add_missing_category(struct event_filter_query_internal *query,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (unsigned int i = 0; i < query->categories_count; i++) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen if (strcmp(query->categories[i].name, category->name) == 0)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenevent_filter_add_missing_category(struct event_filter *filter,
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen array_foreach_modifiable(&filter->queries, query)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_filter_query_add_missing_category(query, category);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainenstatic void event_filter_category_registered(struct event_category *category)
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen for (filter = event_filters; filter != NULL; filter = filter->next) {
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_filter_remove_category(filter, category);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_filter_add_missing_category(filter, category);
918384d458981e7db4aadc283212eb19912d5709Timo Sirainen event_category_register_callback(event_filter_category_registered);