]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
stats: Change event exporter transports to be extensible
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 29 Aug 2024 09:49:36 +0000 (12:49 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:39:59 +0000 (10:39 +0200)
12 files changed:
src/stats/Makefile.am
src/stats/client-reader.c
src/stats/event-exporter-transport-drop.c
src/stats/event-exporter-transport-file.c
src/stats/event-exporter-transport-http-post.c
src/stats/event-exporter-transport-log.c
src/stats/event-exporter.c [new file with mode: 0644]
src/stats/event-exporter.h
src/stats/stats-metrics.c
src/stats/stats-metrics.h
src/stats/stats-settings.c
src/stats/stats-settings.h

index a6b0da348327a787395e317f0bd6230cfac5f6aa..2415bceb57a4d49e77eff66a92ad84da750ace6d 100644 (file)
@@ -36,6 +36,7 @@ libstats_local_la_SOURCES = \
        client-reader.c \
        client-writer.c \
        client-http.c \
+       event-exporter.c \
        event-exporter-fmt.c \
        event-exporter-fmt-json.c \
        event-exporter-fmt-none.c \
index e73ea982e1a6219bc74aaae0b2f6543296a1c541..59d81c85ba797807baa4fc1deb6069ca0e7fab78 100644 (file)
@@ -12,6 +12,7 @@
 #include "master-service.h"
 #include "stats-metrics.h"
 #include "stats-settings.h"
+#include "event-exporter.h"
 #include "client-reader.h"
 #include "client-writer.h"
 #include "event-exporter.h"
@@ -257,7 +258,7 @@ reader_client_input_args(struct connection *conn, const char *const *args)
        else if (strcmp(cmd, "DUMP-RESET") == 0)
                return reader_client_input_dump_reset(client, args);
        else if (strcmp(cmd, "REOPEN") == 0) {
-               event_export_transport_file_reopen();
+               event_exporter_transports_reopen();
                o_stream_nsend(client->conn.output, "+\n", 2);
        }
        return 1;
index 943f30579f52e6a892dab566b34957d4b3ffed3a..06663e25f1cb6abd58ba92d0aa409ea088ba6dc5 100644 (file)
@@ -3,7 +3,14 @@
 #include "lib.h"
 #include "event-exporter.h"
 
-void event_export_transport_drop(const struct exporter *exporter ATTR_UNUSED,
-                                const buffer_t *buf ATTR_UNUSED)
+static void
+event_exporter_drop_send(struct exporter *exporter ATTR_UNUSED,
+                        const buffer_t *buf ATTR_UNUSED)
 {
 }
+
+const struct event_exporter_transport event_exporter_transport_drop = {
+       .name = "drop",
+
+       .send = event_exporter_drop_send,
+};
index 9f44cf1de9c5e1e71e8a28215c139c1440f01b25..e2640ef7eb2d820dbb1076e3ed01765bb895b2d7 100644 (file)
@@ -50,7 +50,7 @@ static void exporter_file_destroy(struct exporter_file **_node)
        i_free(node);
 }
 
-void event_export_transport_file_deinit(void)
+static void event_exporter_file_deinit(void)
 {
        struct exporter_file *node, *next = exporter_file_list_head;
        exporter_file_list_head = NULL;
@@ -125,8 +125,8 @@ static bool exporter_file_open(struct exporter_file *node)
        return TRUE;
 }
 
-static void event_export_transport_file_write(struct exporter_file *node,
-                                             const buffer_t *buf)
+static void event_exporter_file_write(struct exporter_file *node,
+                                     const buffer_t *buf)
 {
        const struct const_iovec vec[] = {
                { .iov_base = buf->data, .iov_len = buf->used },
@@ -142,29 +142,29 @@ static void event_export_transport_file_write(struct exporter_file *node,
        }
 }
 
-void event_export_transport_file(const struct exporter *exporter,
-                                const buffer_t *buf)
+static void
+event_exporter_file_send(struct exporter *exporter, const buffer_t *buf)
 {
        struct exporter_file *node = exporter->transport_context;
        if (node == NULL)
                node = exporter_file_init(exporter, FALSE);
        if (!exporter_file_open(node))
                return;
-       event_export_transport_file_write(node, buf);
+       event_exporter_file_write(node, buf);
 }
 
-void event_export_transport_unix(const struct exporter *exporter,
-                                const buffer_t *buf)
+static void
+event_exporter_unix_send(struct exporter *exporter, const buffer_t *buf)
 {
        struct exporter_file *node = exporter->transport_context;
        if (node == NULL)
                node = exporter_file_init(exporter, TRUE);
        if (!exporter_file_open(node))
                return;
-       event_export_transport_file_write(node, buf);
+       event_exporter_file_write(node, buf);
 }
 
-void event_export_transport_file_reopen(void)
+static void event_exporter_file_reopen(void)
 {
        /* close all files, but not unix sockets */
        struct exporter_file *node = exporter_file_list_head;
@@ -174,3 +174,18 @@ void event_export_transport_file_reopen(void)
                node = node->next;
        }
 }
+
+const struct event_exporter_transport event_exporter_transport_file = {
+       .name = "file",
+
+       .send = event_exporter_file_send,
+       .reopen = event_exporter_file_reopen,
+};
+
+const struct event_exporter_transport event_exporter_transport_unix = {
+       .name = "unix",
+
+       .deinit = event_exporter_file_deinit,
+       .send = event_exporter_unix_send,
+       .reopen = event_exporter_file_reopen,
+};
index 9ab6ccee804d017d21b33b769e15df508d03431c..9a5fc47233356298455abd705bfd9db3687e7ec6 100644 (file)
@@ -14,7 +14,7 @@
 /* the http client used to export all events with exporter=http-post */
 static struct http_client *exporter_http_client;
 
-void event_export_transport_http_post_deinit(void)
+static void event_exporter_http_post_deinit(void)
 {
        if (exporter_http_client != NULL)
                http_client_deinit(&exporter_http_client);
@@ -45,8 +45,8 @@ static void response_fxn(const struct http_response *response,
        suppressed = 0;
 }
 
-void event_export_transport_http_post(const struct exporter *exporter,
-                                     const buffer_t *buf)
+static void
+event_exporter_http_post_send(struct exporter *exporter, const buffer_t *buf)
 {
        struct http_client_request *req;
 
@@ -66,3 +66,10 @@ void event_export_transport_http_post(const struct exporter *exporter,
        http_client_request_set_timeout_msecs(req, exporter->transport_timeout);
        http_client_request_submit(req);
 }
+
+const struct event_exporter_transport event_exporter_transport_http_post = {
+       .name = "http-post",
+
+       .deinit = event_exporter_http_post_deinit,
+       .send = event_exporter_http_post_send,
+};
index a0cf67fcf13e41064f10838e4b155f2ea6858102..3adceb2793d2876a2afeec2e1d0471c2745da5fc 100644 (file)
@@ -5,8 +5,15 @@
 #include "str.h"
 #include "event-exporter.h"
 
-void event_export_transport_log(const struct exporter *exporter ATTR_UNUSED,
-                               const buffer_t *buf)
+static void
+event_exporter_log_send(struct exporter *exporter ATTR_UNUSED,
+                       const buffer_t *buf)
 {
        i_info("%.*s", (int)buf->used, (const char *)buf->data);
 }
+
+const struct event_exporter_transport event_exporter_transport_log = {
+       .name = "log",
+
+       .send = event_exporter_log_send,
+};
diff --git a/src/stats/event-exporter.c b/src/stats/event-exporter.c
new file mode 100644 (file)
index 0000000..0fda420
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (c) 2024 Dovecot authors, see the included COPYING file */
+
+#include "stats-common.h"
+#include "event-exporter.h"
+
+static const struct event_exporter_transport *event_exporter_transports[] = {
+       &event_exporter_transport_drop,
+       &event_exporter_transport_file,
+       &event_exporter_transport_unix,
+       &event_exporter_transport_http_post,
+       &event_exporter_transport_log,
+};
+
+const struct event_exporter_transport *
+event_exporter_transport_find(const char *name)
+{
+       for (unsigned int i = 0; i < N_ELEMENTS(event_exporter_transports); i++) {
+               if (strcmp(event_exporter_transports[i]->name, name) == 0)
+                       return event_exporter_transports[i];
+       }
+       return NULL;
+}
+
+void event_exporter_transports_reopen(void)
+{
+       for (unsigned int i = 0; i < N_ELEMENTS(event_exporter_transports); i++) {
+               if (event_exporter_transports[i]->reopen != NULL)
+                       event_exporter_transports[i]->reopen();
+       }
+}
+
+void event_exporter_transports_deinit(void)
+{
+       for (unsigned int i = 0; i < N_ELEMENTS(event_exporter_transports); i++) {
+               if (event_exporter_transports[i]->reopen != NULL)
+                       event_exporter_transports[i]->deinit();
+       }
+}
index 704f0bffa62ec28c3c2a65124862eb52778a0d73..9003fb5876ae8365dbe9f5ec2f9b3d91b92aa54e 100644 (file)
@@ -3,21 +3,33 @@
 
 #include "stats-metrics.h"
 
+struct event_exporter_transport {
+       const char *name;
+
+       void (*deinit)(void);
+
+       /* function to send the event */
+       void (*send)(struct exporter *exporter, const buffer_t *buf);
+
+       void (*reopen)(void);
+};
+
+extern const struct event_exporter_transport event_exporter_transport_drop;
+extern const struct event_exporter_transport event_exporter_transport_file;
+extern const struct event_exporter_transport event_exporter_transport_unix;
+extern const struct event_exporter_transport event_exporter_transport_http_post;
+extern const struct event_exporter_transport event_exporter_transport_log;
+
+const struct event_exporter_transport *
+event_exporter_transport_find(const char *name);
+void event_exporter_transports_reopen(void);
+void event_exporter_transports_deinit(void);
+
 /* fmt functions */
 void event_export_fmt_json(const struct metric *metric, struct event *event, buffer_t *dest);
 void event_export_fmt_none(const struct metric *metric, struct event *event, buffer_t *dest);
 void event_export_fmt_tabescaped_text(const struct metric *metric, struct event *event, buffer_t *dest);
 
-/* transport functions */
-void event_export_transport_drop(const struct exporter *exporter, const buffer_t *buf);
-void event_export_transport_http_post(const struct exporter *exporter, const buffer_t *buf);
-void event_export_transport_http_post_deinit(void);
-void event_export_transport_log(const struct exporter *exporter, const buffer_t *buf);
-void event_export_transport_file(const struct exporter *exporter, const buffer_t *buf);
-void event_export_transport_unix(const struct exporter *exporter, const buffer_t *buf);
-void event_export_transport_file_reopen(void);
-void event_export_transport_file_deinit(void);
-
 /* append a microsecond resolution RFC3339 UTC timestamp */
 void event_export_helper_fmt_rfc3339_time(string_t *dest, const struct timeval *time);
 /* append a microsecond resolution unix timestamp in seconds (i.e., %u.%06u) */
index 12336994b475934a1a94bdfd49b92bfd5836d4c4..e19c63aff832c8b800e1056a3c2e8460890506b5 100644 (file)
@@ -61,27 +61,11 @@ static void stats_exporters_add_set(struct stats_metrics *metrics,
                i_unreached();
        }
 
-       /* TODO: The following should be plugable.
-        *
-        * Note: Make sure to mirror any changes to the below code in
-        * stats_exporter_settings_check().
-        */
-       if (strcmp(set->driver, "drop") == 0) {
-               exporter->transport = event_export_transport_drop;
-       } else if (strcmp(set->driver, "http-post") == 0) {
-               exporter->transport = event_export_transport_http_post;
-       } else if (strcmp(set->driver, "log") == 0) {
-               exporter->transport = event_export_transport_log;
+       if (strcmp(set->parsed_transport->name, "log") == 0) {
                exporter->format_max_field_len =
                        LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN;
-       } else if (strcmp(set->driver, "file") == 0) {
-               exporter->transport = event_export_transport_file;
-       } else if (strcmp(set->driver, "unix") == 0) {
-               exporter->transport = event_export_transport_unix;
-       } else {
-               i_unreached();
        }
-
+       exporter->transport = set->parsed_transport;
        exporter->transport_args = set->transport_args;
 
        array_push_back(&metrics->exporters, &exporter);
@@ -380,14 +364,6 @@ static void stats_metric_free(struct metric *metric)
                stats_metric_free(sub_metric);
 }
 
-static void stats_export_deinit(void)
-{
-       /* no need for event_export_transport_drop_deinit() - no-op */
-       event_export_transport_http_post_deinit();
-       /* no need for event_export_transport_log_deinit() - no-op */
-       event_export_transport_file_deinit();
-}
-
 void stats_metrics_deinit(struct stats_metrics **_metrics)
 {
        struct stats_metrics *metrics = *_metrics;
@@ -395,7 +371,7 @@ void stats_metrics_deinit(struct stats_metrics **_metrics)
 
        *_metrics = NULL;
 
-       stats_export_deinit();
+       event_exporter_transports_deinit();
 
        array_foreach_elem(&metrics->metrics, metric)
                stats_metric_free(metric);
@@ -818,7 +794,7 @@ static void
 stats_export_event(struct metric *metric, struct event *oldevent)
 {
        const struct metric_export_info *info = &metric->export_info;
-       const struct exporter *exporter = info->exporter;
+       struct exporter *exporter = info->exporter;
        struct event *event;
 
        i_assert(exporter != NULL);
@@ -831,7 +807,7 @@ stats_export_event(struct metric *metric, struct event *oldevent)
                buf = t_buffer_create(128);
 
                exporter->format(metric, event, buf);
-               exporter->transport(exporter, buf);
+               exporter->transport->send(exporter, buf);
        } T_END;
 
        event_unref(&event);
index e2b43acc1c4e385c1baf651aee4e139630a233e8..a9968c035bbeb69fddfd89ceb2a3b9ae34d19cbd 100644 (file)
@@ -37,12 +37,11 @@ struct exporter {
        unsigned int transport_timeout;
        void *transport_context;
 
-       /* function to send the event */
-       void (*transport)(const struct exporter *, const buffer_t *);
+       const struct event_exporter_transport *transport;
 };
 
 struct metric_export_info {
-       const struct exporter *exporter;
+       struct exporter *exporter;
 
        enum event_exporter_includes {
                EVENT_EXPORTER_INCL_NONE       = 0,
index 2051f897bc7f395e84ce020b2ad637a6274ea5a9..d9600bb2d3d34ba23089515004d5f265bf7d7d62 100644 (file)
@@ -5,6 +5,7 @@
 #include "settings.h"
 #include "service-settings.h"
 #include "stats-settings.h"
+#include "event-exporter.h"
 #include "array.h"
 #include "str.h"
 #include "var-expand.h"
@@ -260,24 +261,16 @@ static bool stats_exporter_settings_check(void *_set, pool_t pool ATTR_UNUSED,
                return FALSE;
        }
 
-       /* TODO: The following should be plugable.
-        *
-        * Note: Make sure to mirror any changes to the below code in
-        * stats_exporters_add_set().
-        */
        if (set->driver[0] == '\0')
                set->driver = set->name;
-       if (strcmp(set->driver, "drop") == 0 ||
-           strcmp(set->driver, "http-post") == 0 ||
-           strcmp(set->driver, "log") == 0 ||
-           strcmp(set->driver, "file") == 0 ||
-           strcmp(set->driver, "unix") == 0) {
-               /* no-op */
-       } else {
+#ifndef CONFIG_BINARY
+       set->parsed_transport = event_exporter_transport_find(set->driver);
+       if (set->parsed_transport == NULL) {
                *error_r = t_strdup_printf("Unknown evente_exporter_driver: %s",
                                           set->driver);
                return FALSE;
        }
+#endif
 
        if (!parse_format_args(set, error_r))
                return FALSE;
index f74a8c4c11f5e7acf159cf67ad4e619eefca7676..b5590b5760910a38822f83949118f8a9e3dc9016 100644 (file)
@@ -74,6 +74,7 @@ struct stats_exporter_settings {
 
        /* parsed values */
        enum event_exporter_time_fmt parsed_time_format;
+       const struct event_exporter_transport *parsed_transport;
 };
 
 /* <settings checks> */