bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "lib.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "str.h"
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#include "stats-dist.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "strescape.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "connection.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "ostream.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "master-service.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "stats-metrics.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen#include "client-reader.h"
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstruct reader_client {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen struct connection conn;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen struct stats_metrics *metrics;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen};
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstatic struct connection_list *reader_clients = NULL;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenvoid client_reader_create(int fd, struct stats_metrics *metrics)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen struct reader_client *client;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen client = i_new(struct reader_client, 1);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen client->metrics = metrics;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen connection_init_server(reader_clients, &client->conn,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen "stats-reader", fd, fd);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstatic void reader_client_destroy(struct connection *conn)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen connection_deinit(conn);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen i_free(conn);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen master_service_client_connection_destroyed(master_service);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenstatic void reader_client_dump_stats(string_t *str, struct stats_dist *stats,
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen const char *const *fields)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen for (unsigned int i = 0; fields[i] != NULL; i++) {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen const char *field = fields[i];
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen str_append_c(str, '\t');
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen if (strcmp(field, "count") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%u", stats_dist_get_count(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else if (strcmp(field, "sum") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%"PRIu64, stats_dist_get_sum(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else if (strcmp(field, "min") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%"PRIu64, stats_dist_get_min(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else if (strcmp(field, "max") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%"PRIu64, stats_dist_get_max(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else if (strcmp(field, "avg") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%"PRIu64, stats_dist_get_avg(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else if (strcmp(field, "median") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%"PRIu64, stats_dist_get_median(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else if (strcmp(field, "%95") == 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen str_printfa(str, "%"PRIu64, stats_dist_get_95th(stats));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen else {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen /* return unknown fields as empty */
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen }
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen }
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstatic int
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenreader_client_input_dump(struct reader_client *client, const char *const *args)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen struct stats_metrics_iter *iter;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen const struct metric *metric;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen string_t *str = t_str_new(128);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen o_stream_cork(client->conn.output);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen iter = stats_metrics_iterate_init(client->metrics);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen while ((metric = stats_metrics_iterate(iter)) != NULL) {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen str_truncate(str, 0);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen str_append_tabescaped(str, metric->name);
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen reader_client_dump_stats(str, metric->duration_stats, args);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen for (unsigned int i = 0; i < metric->fields_count; i++) {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen str_append_c(str, '\t');
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen str_append_tabescaped(str, metric->fields[i].field_key);
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen reader_client_dump_stats(str, metric->fields[i].stats, args);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen }
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen str_append_c(str, '\n');
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen o_stream_nsend(client->conn.output, str_data(str), str_len(str));
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen }
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen o_stream_nsend(client->conn.output, "\n", 1);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen stats_metrics_iterate_deinit(&iter);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen o_stream_uncork(client->conn.output);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen return 1;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainenstatic int
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainenreader_client_input_dump_reset(struct reader_client *client,
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen const char *const *args)
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen{
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen (void)reader_client_input_dump(client, args);
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen stats_metrics_reset(client->metrics);
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen return 1;
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen}
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstatic int
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenreader_client_input_args(struct connection *conn, const char *const *args)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen struct reader_client *client = (struct reader_client *)conn;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen const char *cmd = args[0];
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen if (cmd == NULL) {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen i_error("Client sent empty line");
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen return 1;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen }
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen args++;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen if (strcmp(cmd, "DUMP") == 0)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen return reader_client_input_dump(client, args);
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen else if (strcmp(cmd, "DUMP-RESET") == 0)
9c675f5e259c19f9fdc40808439479131b32421eTimo Sirainen return reader_client_input_dump_reset(client, args);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen return 1;
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstatic struct connection_settings client_set = {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .service_name_in = "stats-reader-client",
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .service_name_out = "stats-reader-server",
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .major_version = 2,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .minor_version = 0,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .input_max_size = 1024,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .output_max_size = (size_t)-1,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .client = FALSE,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen};
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenstatic const struct connection_vfuncs client_vfuncs = {
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .destroy = reader_client_destroy,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen .input_args = reader_client_input_args,
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen};
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenvoid client_readers_init(void)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen reader_clients = connection_list_init(&client_set, &client_vfuncs);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainenvoid client_readers_deinit(void)
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen{
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen connection_list_deinit(&reader_clients);
e9068f1c3326de0265d0ef542a0d7723f5f01bc8Timo Sirainen}