client-reader.c revision 9c675f5e259c19f9fdc40808439479131b32421e
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "lib.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "str.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "timing.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "strescape.h"
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek#include "connection.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "ostream.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "master-service.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "stats-metrics.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "client-reader.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozekstruct reader_client {
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek struct connection conn;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher struct stats_metrics *metrics;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek};
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagherstatic struct connection_list *reader_clients = NULL;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanvoid client_reader_create(int fd, struct stats_metrics *metrics)
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher{
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher struct reader_client *client;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan client = i_new(struct reader_client, 1);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher client->metrics = metrics;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher connection_init_server(reader_clients, &client->conn,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher "stats-reader", fd, fd);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekstatic void reader_client_destroy(struct connection *conn)
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek connection_deinit(conn);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher i_free(conn);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan master_service_client_connection_destroyed(master_service);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void reader_client_dump_timing(string_t *str, struct timing *timing,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *const *fields)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (unsigned int i = 0; fields[i] != NULL; i++) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher const char *field = fields[i];
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher str_append_c(str, '\t');
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (strcmp(field, "count") == 0)
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher str_printfa(str, "%u", timing_get_count(timing));
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek else if (strcmp(field, "sum") == 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_printfa(str, "%"PRIu64, timing_get_sum(timing));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan else if (strcmp(field, "min") == 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_printfa(str, "%"PRIu64, timing_get_min(timing));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher else if (strcmp(field, "max") == 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_printfa(str, "%"PRIu64, timing_get_max(timing));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan else if (strcmp(field, "avg") == 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_printfa(str, "%"PRIu64, timing_get_avg(timing));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan else if (strcmp(field, "median") == 0)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher str_printfa(str, "%"PRIu64, timing_get_median(timing));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan else if (strcmp(field, "%95") == 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_printfa(str, "%"PRIu64, timing_get_95th(timing));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher else {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher /* return unknown fields as empty */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic int
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanreader_client_input_dump(struct reader_client *client, const char *const *args)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek struct stats_metrics_iter *iter;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher const struct metric *metric;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek string_t *str = t_str_new(128);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek o_stream_cork(client->conn.output);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek iter = stats_metrics_iterate_init(client->metrics);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek while ((metric = stats_metrics_iterate(iter)) != NULL) {
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher str_truncate(str, 0);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_append_tabescaped(str, metric->name);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan reader_client_dump_timing(str, metric->duration_timing, args);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (unsigned int i = 0; i < metric->fields_count; i++) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher str_append_c(str, '\t');
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_append_tabescaped(str, metric->fields[i].field_key);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan reader_client_dump_timing(str, metric->fields[i].timing, args);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan str_append_c(str, '\n');
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan o_stream_nsend(client->conn.output, str_data(str), str_len(str));
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan }
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan o_stream_nsend(client->conn.output, "\n", 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan stats_metrics_iterate_deinit(&iter);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher o_stream_uncork(client->conn.output);
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek return 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekstatic int
ea929f1b022fc2cb77dec89b0e12accef983ec85Jakub Hrozekreader_client_input_dump_reset(struct reader_client *client,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *const *args)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan (void)reader_client_input_dump(client, args);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher stats_metrics_reset(client->metrics);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic int
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanreader_client_input_args(struct connection *conn, const char *const *args)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher{
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher struct reader_client *client = (struct reader_client *)conn;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *cmd = args[0];
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (cmd == NULL) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_error("Client sent empty line");
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher args++;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (strcmp(cmd, "DUMP") == 0)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher return reader_client_input_dump(client, args);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher else if (strcmp(cmd, "DUMP-RESET") == 0)
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan return reader_client_input_dump_reset(client, args);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic struct connection_settings client_set = {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher .service_name_in = "stats-reader-client",
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher .service_name_out = "stats-reader-server",
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan .major_version = 2,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher .minor_version = 0,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan .input_max_size = 1024,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher .output_max_size = (size_t)-1,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan .client = FALSE,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan};
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic const struct connection_vfuncs client_vfuncs = {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan .destroy = reader_client_destroy,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher .input_args = reader_client_input_args,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher};
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallaghervoid client_readers_init(void)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan reader_clients = connection_list_init(&client_set, &client_vfuncs);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallaghervoid client_readers_deinit(void)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek connection_list_deinit(&reader_clients);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan