]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Rewrite doveadm stats dump command to allow reuse code in other commands.
authorsergey.kitov <sergey.kitov@open-xchange.com>
Wed, 9 Jun 2021 14:22:39 +0000 (17:22 +0300)
committersergey.kitov <sergey.kitov@open-xchange.com>
Fri, 3 Sep 2021 12:44:32 +0000 (15:44 +0300)
src/doveadm/doveadm-stats.c

index f389d220a6b86c175cc8550cc8645cfd3d8e85b2..360c73fe0f2d6151979262b96f8212f8f1d74d4f 100644 (file)
@@ -20,6 +20,87 @@ enum doveadm_dump_field_type {
        DOVEADM_DUMP_FIELD_TYPE_STDDEV,
 };
 
+struct stats_cmd_context {
+       string_t *cmd;
+       struct doveadm_cmd_context *cctx;
+       struct istream *input;
+       const char *path;
+       void *data;
+};
+
+struct dump_data {
+       const char **fields;
+       unsigned int field_count;
+       enum doveadm_dump_field_type *field_types;
+};
+
+struct stats_cmd_vfuncs {
+       int (*build_cmd)(struct stats_cmd_context *ctx, const char **error_r);
+       void (*process_response)(struct stats_cmd_context *ctx);
+};
+
+static int build_stats_dump_cmd(struct stats_cmd_context *ctx, const char **error_r);
+
+static void stats_dump_process_response(struct stats_cmd_context *ctx);
+
+static void stats_send_cmd(struct stats_cmd_context *ctx);
+
+static struct stats_cmd_vfuncs dump_vfuncs = {
+       .build_cmd = build_stats_dump_cmd,
+       .process_response = stats_dump_process_response
+};
+
+
+static string_t *init_stats_cmd(void)
+{
+       string_t *cmd = t_str_new(128);
+       str_append(cmd, "VERSION\tstats-reader-client\t2\t0\n");
+       return cmd;
+}
+
+static void stats_exec_cmd(struct doveadm_cmd_context *cctx,
+                          struct stats_cmd_vfuncs *vfuncs)
+{
+       struct stats_cmd_context ctx;
+       const char *build_cmd_error;
+       ctx.cctx = cctx;
+       if (vfuncs->build_cmd(&ctx, &build_cmd_error) < 0) {
+               i_error("%s", build_cmd_error);
+               return;
+       }
+       stats_send_cmd(&ctx);
+       vfuncs->process_response(&ctx);
+       i_stream_destroy(&ctx.input);
+}
+
+static void handle_disconnection(struct stats_cmd_context *ctx)
+{
+       i_error("read(%s) failed: %s", ctx->path,
+               i_stream_get_disconnect_reason(ctx->input));
+}
+
+static void stats_send_cmd(struct stats_cmd_context *ctx)
+{
+       int fd;
+       const char *line;
+       if (!doveadm_cmd_param_str(ctx->cctx, "socket-path", &ctx->path))
+               ctx->path = t_strconcat(doveadm_settings->base_dir,
+                                       "/stats-reader", NULL);
+
+       fd = doveadm_connect(ctx->path);
+       net_set_nonblock(fd, FALSE);
+       if (write_full(fd, str_data(ctx->cmd), str_len(ctx->cmd)) < 0)
+               i_fatal("write(%s) failed %m", ctx->path);
+       ctx->input = i_stream_create_fd_autoclose(&fd, SIZE_MAX);
+
+       if ((line = i_stream_read_next_line(ctx->input)) == NULL)
+               i_fatal("%s: Failed to read VERSION line", ctx->path);
+       else if (!version_string_verify(line, "stats-reader-server", 2)) {
+               i_fatal_status(EX_PROTOCOL,
+                       "%s is not a compatible stats-reader socket", ctx->path);
+       }
+}
+
 static void dump_timing(const char *const **args,
                        const enum doveadm_dump_field_type field_types[],
                        unsigned int fields_count)
@@ -45,47 +126,55 @@ static void dump_timing(const char *const **args,
        *args += args_count;
 }
 
-static void stats_dump(const char *path, const char *const *fields, bool reset)
+static int build_stats_dump_cmd(struct stats_cmd_context *ctx,
+                               const char **error_r ATTR_UNUSED)
 {
-       struct istream *input;
-       string_t *cmd = t_str_new(128);
-       unsigned int i, fields_count = str_array_length(fields);
-       enum doveadm_dump_field_type field_types[fields_count];
-       char *line;
-       int fd;
-
-       fd = doveadm_connect(path);
-       net_set_nonblock(fd, FALSE);
-       str_append(cmd, "VERSION\tstats-reader-client\t2\t0\n");
-       str_append(cmd, reset ? "DUMP-RESET" : "DUMP");
+       bool reset;
+       struct dump_data *data = t_new(struct dump_data, 1);
+       const char *fields_raw;
+       const char **fields;
+       if (!doveadm_cmd_param_bool(ctx->cctx, "reset", &reset))
+               reset = FALSE;
+       if (!doveadm_cmd_param_str(ctx->cctx, "fields", &fields_raw))
+               fields_raw = DOVEADM_DUMP_DEFAULT_FIELDS;
+
+       fields = t_strsplit_spaces(fields_raw, ", ");
+       data->fields = fields;
+       data->field_count = str_array_length(fields);
+       enum doveadm_dump_field_type field_types[data->field_count];
+       ctx->data = data;
+       ctx->cmd = init_stats_cmd();
+       str_append(ctx->cmd, reset ? "DUMP-RESET" : "DUMP");
        i_zero(&field_types);
-       for (i = 0; i < fields_count; i++) {
-               str_append_c(cmd, '\t');
+       unsigned int i;
+       for (i = 0; i < data->field_count; i++) {
+               str_append_c(ctx->cmd, '\t');
                if (strcmp(fields[i], "stddev") == 0) {
                        field_types[i] = DOVEADM_DUMP_FIELD_TYPE_STDDEV;
-                       str_append(cmd, "variance");
+                       str_append(ctx->cmd, "variance");
                } else {
-                       str_append_tabescaped(cmd, fields[i]);
+                       str_append_tabescaped(ctx->cmd, fields[i]);
                }
        }
-       str_append_c(cmd, '\n');
-       if (write_full(fd, str_data(cmd), str_len(cmd)) < 0)
-               i_fatal("write(%s) failed: %m", path);
+       str_append_c(ctx->cmd, '\n');
+       data->field_types = field_types;
+       return 0;
+}
 
-       input = i_stream_create_fd_autoclose(&fd, SIZE_MAX);
-       if ((line = i_stream_read_next_line(input)) == NULL)
-               i_fatal("%s: Failed to read VERSION line", path);
-       else if (!version_string_verify(line, "stats-reader-server", 2)) {
-               i_fatal_status(EX_PROTOCOL,
-                       "%s is not a compatible stats-reader socket", path);
-       }
+static void stats_dump_process_response(struct stats_cmd_context *ctx)
+{
+       unsigned int i;
+       char *line;
+       struct dump_data *data = ctx->data;
 
+       doveadm_print_init(DOVEADM_PRINT_TYPE_TAB);
        doveadm_print_header_simple("metric_name");
        doveadm_print_header_simple("field");
-       for (i = 0; i < fields_count; i++)
-               doveadm_print_header(fields[i], fields[i], DOVEADM_PRINT_HEADER_FLAG_NUMBER);
+       for (i = 0; i < data->field_count; i++)
+               doveadm_print_header(data->fields[i], data->fields[i],
+                                    DOVEADM_PRINT_HEADER_FLAG_NUMBER);
 
-       while ((line = i_stream_read_next_line(input)) != NULL) {
+       while ((line = i_stream_read_next_line(ctx->input)) != NULL) {
                if (line[0] == '\0')
                        break;
                T_BEGIN {
@@ -95,37 +184,21 @@ static void stats_dump(const char *path, const char *const *fields, bool reset)
                        const char *metric_name = args[0];
                        doveadm_print(metric_name); args++;
                        doveadm_print("duration");
-                       dump_timing(&args, field_types, fields_count);
+                       dump_timing(&args, data->field_types, data->field_count);
                        while (*args != NULL) {
                                doveadm_print(metric_name);
                                doveadm_print(*args); args++;
-                               dump_timing(&args, field_types, fields_count);
+                               dump_timing(&args, data->field_types, data->field_count);
                        }
                } T_END;
        }
-
-       if (input->stream_errno != 0)
-               i_fatal("read(%s) failed: %s", path, i_stream_get_error(input));
-       i_stream_destroy(&input);
+       if (line == NULL)
+               handle_disconnection(ctx);
 }
 
-static void
-doveadm_cmd_stats_dump(struct doveadm_cmd_context *cctx)
+static void doveadm_cmd_stats_dump(struct doveadm_cmd_context *cctx)
 {
-       const char *path, *fields;
-       bool reset;
-
-       if (!doveadm_cmd_param_str(cctx, "socket-path", &path))
-               path = t_strconcat(doveadm_settings->base_dir, "/stats-reader", NULL);
-       if (!doveadm_cmd_param_bool(cctx, "reset", &reset))
-               reset = FALSE;
-
-       if (!doveadm_cmd_param_str(cctx, "fields", &fields))
-               fields = DOVEADM_DUMP_DEFAULT_FIELDS;
-
-       doveadm_print_init(DOVEADM_PRINT_TYPE_TAB);
-       stats_dump(path, t_strsplit_spaces(fields, ", "), reset);
-       return;
+       stats_exec_cmd(cctx, &dump_vfuncs);
 }
 
 struct doveadm_cmd_ver2 doveadm_cmd_stats_dump_ver2 = {