else if (strcmp(cmd, "DUMP-RESET") == 0)
return reader_client_input_dump_reset(client, args);
else if (strcmp(cmd, "REOPEN") == 0) {
- event_exporter_transports_reopen();
+ event_exporters_reopen();
o_stream_nsend(client->conn.output, "+\n", 2);
}
return 1;
#include <fcntl.h>
struct file_event_exporter {
- struct file_event_exporter *next;
+ struct event_exporter exporter;
+
char *fname;
struct ostream *output;
int fd;
#define EXPORTER_LAST_ERROR_DELAY 60
-static struct file_event_exporter *exporter_file_list_head = NULL;
-
static void exporter_file_close(struct file_event_exporter *node)
{
+ if (node->fd == -1)
+ return;
if (o_stream_finish(node->output) < 0) {
i_error("write(%s) failed: %s", node->fname,
o_stream_get_error(node->output));
i_close_fd(&node->fd);
}
-static void exporter_file_destroy(struct file_event_exporter **_node)
+static void event_exporter_file_deinit(struct event_exporter *_exporter)
{
- struct file_event_exporter *node = *_node;
- if (node == NULL)
- return;
- *_node = NULL;
+ struct file_event_exporter *node =
+ container_of(_exporter, struct file_event_exporter, exporter);
exporter_file_close(node);
i_free(node->fname);
- i_free(node);
}
-static void event_exporter_file_deinit(void)
+static void
+exporter_file_init(struct file_event_exporter *node, bool unix_socket)
{
- struct file_event_exporter *node, *next = exporter_file_list_head;
- exporter_file_list_head = NULL;
- while (next != NULL) {
- node = next;
- next = node->next;
- exporter_file_destroy(&node);
- }
+ node->fname = i_strdup(t_strcut(node->exporter.transport_args, ' '));
+ node->fd = -1;
+ node->unix_socket = unix_socket;
+ node->connect_timeout_msecs = node->exporter.transport_timeout;
}
-static struct file_event_exporter *
-exporter_file_init(const struct event_exporter *exporter, bool unix_socket)
+static int
+event_exporter_file_init(pool_t pool, struct event *event ATTR_UNUSED,
+ struct event_exporter **exporter_r,
+ const char **error_r ATTR_UNUSED)
{
- struct file_event_exporter *node;
- node = i_new(struct file_event_exporter, 1);
- node->fname = i_strdup(t_strcut(exporter->transport_args, ' '));
- node->fd = -1;
- node->unix_socket = unix_socket;
- node->connect_timeout_msecs = exporter->transport_timeout;
- node->next = exporter_file_list_head;
- exporter_file_list_head = node;
- event_export_transport_assign_context(exporter, node);
- return node;
+ struct file_event_exporter *node =
+ p_new(pool, struct file_event_exporter, 1);
+ *exporter_r = &node->exporter;
+ return 0;
}
static void exporter_file_open_error(struct file_event_exporter *node, const char *func)
}
static void
-event_exporter_file_send(struct event_exporter *exporter, const buffer_t *buf)
+event_exporter_file_send(struct event_exporter *_exporter, const buffer_t *buf)
{
- struct file_event_exporter *node = exporter->transport_context;
- if (node == NULL)
- node = exporter_file_init(exporter, FALSE);
+ struct file_event_exporter *node =
+ container_of(_exporter, struct file_event_exporter, exporter);
+ if (node->fname == NULL)
+ exporter_file_init(node, FALSE);
if (!exporter_file_open(node))
return;
event_exporter_file_write(node, buf);
}
static void
-event_exporter_unix_send(struct event_exporter *exporter, const buffer_t *buf)
+event_exporter_unix_send(struct event_exporter *_exporter,
+ const buffer_t *buf)
{
- struct file_event_exporter *node = exporter->transport_context;
- if (node == NULL)
- node = exporter_file_init(exporter, TRUE);
+ struct file_event_exporter *node =
+ container_of(_exporter, struct file_event_exporter, exporter);
+ if (node->fname == NULL)
+ exporter_file_init(node, TRUE);
if (!exporter_file_open(node))
return;
event_exporter_file_write(node, buf);
}
-static void event_exporter_file_reopen(void)
+static void event_exporter_file_reopen(struct event_exporter *_exporter)
{
- /* close all files, but not unix sockets */
- struct file_event_exporter *node = exporter_file_list_head;
- while (node != NULL) {
- if (!node->unix_socket)
- exporter_file_close(node);
- node = node->next;
- }
+ struct file_event_exporter *node =
+ container_of(_exporter, struct file_event_exporter, exporter);
+ exporter_file_close(node);
}
const struct event_exporter_transport event_exporter_transport_file = {
.name = "file",
+ .init = event_exporter_file_init,
.send = event_exporter_file_send,
.reopen = event_exporter_file_reopen,
};
const struct event_exporter_transport event_exporter_transport_unix = {
.name = "unix",
+ .init = event_exporter_file_init,
.deinit = event_exporter_file_deinit,
.send = event_exporter_unix_send,
- .reopen = event_exporter_file_reopen,
};
/* the http client used to export all events with exporter=http-post */
static struct http_client *exporter_http_client;
-static void event_exporter_http_post_deinit(void)
+static void
+event_exporter_http_post_deinit(struct event_exporter *exporter ATTR_UNUSED)
{
if (exporter_http_client != NULL)
http_client_deinit(&exporter_http_client);
#include "str.h"
#include "event-exporter.h"
+#define LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN 1000
+
+static int event_exporter_log_init(pool_t pool, struct event *event ATTR_UNUSED,
+ struct event_exporter **exporter_r,
+ const char **error_r ATTR_UNUSED)
+{
+ struct event_exporter *exporter = p_new(pool, struct event_exporter, 1);
+ exporter->format_max_field_len =
+ LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN;
+ *exporter_r = exporter;
+ return 0;
+}
+
static void
event_exporter_log_send(struct event_exporter *exporter ATTR_UNUSED,
const buffer_t *buf)
const struct event_exporter_transport event_exporter_transport_log = {
.name = "log",
+ .init = event_exporter_log_init,
.send = event_exporter_log_send,
};
/* Copyright (c) 2024 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
+#include "array.h"
#include "event-exporter.h"
static const struct event_exporter_transport *event_exporter_transports[] = {
&event_exporter_transport_log,
};
+static ARRAY(struct event_exporter *) event_exporters;
+
const struct event_exporter_transport *
event_exporter_transport_find(const char *name)
{
return NULL;
}
-void event_exporter_transports_reopen(void)
+void event_exporters_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();
+ struct event_exporter *exporter;
+
+ array_foreach_elem(&event_exporters, exporter) {
+ if (exporter->transport->reopen != NULL)
+ exporter->transport->reopen(exporter);
}
}
-void event_exporter_transports_deinit(void)
+void event_exporters_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();
+ struct event_exporter *exporter;
+
+ if (!array_is_created(&event_exporters))
+ return;
+
+ array_foreach_elem(&event_exporters, exporter) {
+ if (exporter->transport->deinit != NULL)
+ exporter->transport->deinit(exporter);
}
}
+
+int event_exporter_init(const struct event_exporter_transport *transport,
+ pool_t pool, struct event *event,
+ struct event_exporter **exporter_r,
+ const char **error_r)
+{
+ struct event_exporter *exporter;
+
+ if (transport->init == NULL)
+ exporter = p_new(pool, struct event_exporter, 1);
+ else if (transport->init(pool, event, &exporter, error_r) < 0)
+ return -1;
+
+ if (!array_is_created(&event_exporters))
+ i_array_init(&event_exporters, 4);
+ array_push_back(&event_exporters, &exporter);
+ *exporter_r = exporter;
+ return 0;
+}
struct event_exporter_transport {
const char *name;
- void (*deinit)(void);
+ int (*init)(pool_t pool, struct event *event,
+ struct event_exporter **exporter_r, const char **error_r);
+ void (*deinit)(struct event_exporter *exporter);
/* function to send the event */
void (*send)(struct event_exporter *exporter, const buffer_t *buf);
- void (*reopen)(void);
+ void (*reopen)(struct event_exporter *exporter);
};
extern const struct event_exporter_transport event_exporter_transport_drop;
const struct event_exporter_transport *
event_exporter_transport_find(const char *name);
-void event_exporter_transports_reopen(void);
-void event_exporter_transports_deinit(void);
+
+void event_exporters_reopen(void);
+void event_exporters_deinit(void);
+
+int event_exporter_init(const struct event_exporter_transport *transport,
+ pool_t pool, struct event *event,
+ struct event_exporter **exporter_r,
+ const char **error_r);
/* fmt functions */
void event_export_fmt_json(const struct metric *metric, struct event *event, buffer_t *dest);
void (*append)(string_t *, const char *),
const char *separator);
-/* assign transport context to a event exporter */
-void event_export_transport_assign_context(const struct event_exporter *exporter,
- void *context);
-
#endif
#include <ctype.h>
-#define LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN 1000
#define STATS_SUB_METRIC_MAX_LENGTH 256
struct stats_metrics {
stats_metric_sub_metric_alloc(struct metric *metric, const char *name, pool_t pool);
static void stats_metric_free(struct metric *metric);
-static void stats_exporters_add_set(struct stats_metrics *metrics,
- const struct stats_exporter_settings *set)
+static int stats_exporters_add_set(struct stats_metrics *metrics,
+ struct event *event,
+ const struct stats_exporter_settings *set,
+ const char **error_r)
{
+ const struct event_exporter_transport *transport =
+ set->parsed_transport;
struct event_exporter *exporter;
- exporter = p_new(metrics->pool, struct event_exporter, 1);
+ if (event_exporter_init(transport, metrics->pool, event,
+ &exporter, error_r) < 0)
+ return -1;
exporter->name = p_strdup(metrics->pool, set->name);
exporter->transport_args = p_strdup(metrics->pool, set->transport_args);
exporter->transport_timeout = set->transport_timeout;
i_unreached();
}
- if (strcmp(set->parsed_transport->name, "log") == 0) {
- exporter->format_max_field_len =
- LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN;
- }
- exporter->transport = set->parsed_transport;
+ exporter->transport = transport;
exporter->transport_args = set->transport_args;
array_push_back(&metrics->exporters, &exporter);
-}
-
-void event_export_transport_assign_context(const struct event_exporter *exporter,
- void *context)
-{
- struct event_exporter *ptr = (struct event_exporter *)exporter;
- ptr->transport_context = context;
+ return 0;
}
static int stats_exporters_add_filter(struct stats_metrics *metrics,
*error_r = "Exporter name can't be empty";
ret = -1;
} else {
- stats_exporters_add_set(metrics, set);
+ struct event *event = event_create(metrics->event);
+ event_set_ptr(event, SETTINGS_EVENT_FILTER_NAME,
+ p_strdup_printf(event_get_pool(event),
+ "event_exporter/%s", filter_name));
+ ret = stats_exporters_add_set(metrics, event, set, error_r);
+ event_unref(&event);
}
settings_free(set);
return ret;
*_metrics = NULL;
- event_exporter_transports_deinit();
+ event_exporters_deinit();
array_foreach_elem(&metrics->metrics, metric)
stats_metric_free(metric);
*/
const char *transport_args;
unsigned int transport_timeout;
- void *transport_context;
const struct event_exporter_transport *transport;
};