diff options
Diffstat (limited to 'src/stats/event-exporter-fmt-tab-text.c')
-rw-r--r-- | src/stats/event-exporter-fmt-tab-text.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/stats/event-exporter-fmt-tab-text.c b/src/stats/event-exporter-fmt-tab-text.c new file mode 100644 index 0000000..49a065b --- /dev/null +++ b/src/stats/event-exporter-fmt-tab-text.c @@ -0,0 +1,212 @@ +/* Copyright (c) 2019 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "array.h" +#include "lib-event-private.h" +#include "event-exporter.h" +#include "str.h" +#include "strescape.h" +#include "hostpid.h" + +static void append_strlist(string_t *dest, const ARRAY_TYPE(const_string) *strlist) +{ + string_t *str = t_str_new(64); + const char *value; + bool first = TRUE; + + /* append the strings first escaped into a temporary string */ + array_foreach_elem(strlist, value) { + if (first) + first = FALSE; + else + str_append_c(str, '\t'); + str_append_tabescaped(str, value); + } + /* append the temporary string (double-)escaped as the value */ + str_append_tabescaped(dest, str_c(str)); +} + +static void append_int(string_t *dest, intmax_t val) +{ + str_printfa(dest, "%jd", val); +} + +static void append_time(string_t *dest, const struct timeval *time, + enum event_exporter_time_fmt fmt) +{ + switch (fmt) { + case EVENT_EXPORTER_TIME_FMT_NATIVE: + i_panic("tab-text format does not have a native date/time type"); + case EVENT_EXPORTER_TIME_FMT_UNIX: + event_export_helper_fmt_unix_time(dest, time); + break; + case EVENT_EXPORTER_TIME_FMT_RFC3339: + event_export_helper_fmt_rfc3339_time(dest, time); + break; + } +} + +static void append_field_str(string_t *dest, const char *str, + const struct metric_export_info *info) +{ + if (info->exporter->format_max_field_len == 0) + str_append_tabescaped(dest, str); + else { + size_t len = strlen(str); + str_append_tabescaped_n(dest, (const unsigned char *)str, + I_MIN(len, info->exporter->format_max_field_len)); + if (len > info->exporter->format_max_field_len) + str_append(dest, "..."); + } +} + +static void append_field_value(string_t *dest, const struct event_field *field, + const struct metric_export_info *info) +{ + switch (field->value_type) { + case EVENT_FIELD_VALUE_TYPE_STR: + append_field_str(dest, field->value.str, info); + break; + case EVENT_FIELD_VALUE_TYPE_INTMAX: + append_int(dest, field->value.intmax); + break; + case EVENT_FIELD_VALUE_TYPE_TIMEVAL: + append_time(dest, &field->value.timeval, + info->exporter->time_format); + break; + case EVENT_FIELD_VALUE_TYPE_STRLIST: + append_strlist(dest, &field->value.strlist); + break; + } +} + +static void tabtext_export_name(string_t *dest, struct event *event, + const struct metric_export_info *info) +{ + if ((info->include & EVENT_EXPORTER_INCL_NAME) == 0) + return; + + str_append(dest, "event:"); + str_append_tabescaped(dest, event->sending_name); + str_append_c(dest, '\t'); +} + +static void tabtext_export_hostname(string_t *dest, + const struct metric_export_info *info) +{ + if ((info->include & EVENT_EXPORTER_INCL_HOSTNAME) == 0) + return; + + str_append(dest, "hostname:"); + str_append_tabescaped(dest, my_hostname); + str_append_c(dest, '\t'); +} + +static void tabtext_export_timestamps(string_t *dest, struct event *event, + const struct metric_export_info *info) +{ + if ((info->include & EVENT_EXPORTER_INCL_TIMESTAMPS) == 0) + return; + + str_append(dest, "start_time:"); + append_time(dest, &event->tv_created, info->exporter->time_format); + str_append(dest, "\tend_time:"); + append_time(dest, &ioloop_timeval, info->exporter->time_format); + str_append_c(dest, '\t'); +} + +static void append_category(string_t *dest, const char *cat) +{ + str_append(dest, "category:"); + str_append_tabescaped(dest, cat); +} + +static void tabtext_export_categories(string_t *dest, struct event *event, + const struct metric_export_info *info) +{ + struct event_category *const *cats; + unsigned int count; + + if ((info->include & EVENT_EXPORTER_INCL_CATEGORIES) == 0) + return; + + cats = event_get_categories(event, &count); + event_export_helper_fmt_categories(dest, cats, count, + append_category, "\t"); + + str_append_c(dest, '\t'); /* extra \t to have something to remove later */ +} + +static void tabtext_export_fields(string_t *dest, struct event *event, + const struct metric_export_info *info, + const unsigned int fields_count, + const struct metric_field *fields) +{ + if ((info->include & EVENT_EXPORTER_INCL_FIELDS) == 0) + return; + + if (fields_count == 0) { + /* include all fields */ + const struct event_field *fields; + unsigned int count; + + fields = event_get_fields(event, &count); + + for (unsigned int i = 0; i < count; i++) { + const struct event_field *field = &fields[i]; + + str_append(dest, "field:"); + str_append_tabescaped(dest, field->key); + str_append_c(dest, '='); + append_field_value(dest, field, info); + str_append_c(dest, '\t'); + } + } else { + for (unsigned int i = 0; i < fields_count; i++) { + const char *name = fields[i].field_key; + const struct event_field *field; + + field = event_find_field_recursive(event, name); + if (field == NULL) + continue; /* doesn't exist, skip it */ + + str_append(dest, "field:"); + str_append_tabescaped(dest, name); + str_append_c(dest, '='); + append_field_value(dest, field, info); + str_append_c(dest, '\t'); + } + } +} + +/* + * Serialize the event as tab delimited collection of the following: + * + * event:<event name> + * hostname:<tab escaped hostname> + * start_time:<event creation timestamp> + * end_time:<event export timestamp> + * category:<category> + * field:<name>=<tab escaped value> + * + * Note: cat and field can occur multiple times. + */ +void event_export_fmt_tabescaped_text(const struct metric *metric, + struct event *event, buffer_t *dest) +{ + const struct metric_export_info *info = &metric->export_info; + + if (info->include == EVENT_EXPORTER_INCL_NONE) + return; + + tabtext_export_name(dest, event, info); + tabtext_export_hostname(dest, info); + tabtext_export_timestamps(dest, event, info); + tabtext_export_categories(dest, event, info); + tabtext_export_fields(dest, event, info, metric->fields_count, + metric->fields); + + /* remove trailing tab */ + str_truncate(dest, str_len(dest) - 1); +} |