diff --git a/plugins/filter_log_to_metrics/log_to_metrics.c b/plugins/filter_log_to_metrics/log_to_metrics.c index 87231f66392..178d462f100 100644 --- a/plugins/filter_log_to_metrics/log_to_metrics.c +++ b/plugins/filter_log_to_metrics/log_to_metrics.c @@ -639,13 +639,14 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, snprintf(metric_description, sizeof(metric_description) - 1, "%s", ctx->metric_description); - /* Value field only needed for modes gauge and histogram */ - if (ctx->mode > 0) { - if (ctx->value_field == NULL || strlen(ctx->value_field) == 0) { - flb_plg_error(f_ins, "value_field is not set"); - log_to_metrics_destroy(ctx); - return -1; + if (ctx->value_field == NULL || strlen(ctx->value_field) == 0) { + /* require value field for modes gauge and histogram */ + if (ctx->mode > 0) { + flb_plg_error(f_ins, "value_field is not set"); + log_to_metrics_destroy(ctx); + return -1; } + } else { snprintf(value_field, sizeof(value_field) - 1, "%s", ctx->value_field); } @@ -825,6 +826,7 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, char **label_values = NULL; int label_count = 0; int i; + double counter_value = 0; double gauge_value = 0; double histogram_value = 0; char kubernetes_label_values @@ -901,8 +903,50 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, /* Calculating and setting metric depending on the mode */ switch (ctx->mode) { case FLB_LOG_TO_METRICS_COUNTER: - ret = cmt_counter_inc(ctx->c, ts, label_count, - label_values); + + // If value_field is not set, increment counter by 1 + if (ctx->value_field == NULL || strlen(ctx->value_field) == 0) { + ret = cmt_counter_inc(ctx->c, ts, label_count, + label_values); + break; + } + // If value_field is set, increment counter by value + ra = flb_ra_create(ctx->value_field, FLB_TRUE); + if (!ra) { + flb_plg_error(ctx->ins, "invalid record accessor key, aborting"); + break; + } + + rval = flb_ra_get_value_object(ra, map); + + if (!rval) { + flb_warn("given value field is empty or not existent"); + break; + } + if (rval->type == FLB_RA_STRING) { + sscanf(rval->val.string, "%lf", &counter_value); + } + else if (rval->type == FLB_RA_FLOAT) { + counter_value = rval->val.f64; + } + else if (rval->type == FLB_RA_INT) { + counter_value = (double)rval->val.i64; + } + else { + flb_plg_error(f_ins, + "cannot convert given value to metric"); + break; + } + ret = cmt_counter_add(ctx->c, ts, counter_value, + label_count, label_values); + if (rval) { + flb_ra_key_value_destroy(rval); + rval = NULL; + } + if (ra) { + flb_ra_destroy(ra); + ra = NULL; + } break; case FLB_LOG_TO_METRICS_GAUGE: @@ -1066,7 +1110,7 @@ static struct flb_config_map config_map[] = { { FLB_CONFIG_MAP_STR, "value_field", NULL, 0, FLB_TRUE, offsetof(struct log_to_metrics_ctx, value_field), - "Numeric field to use for gauge or histogram" + "Numeric field to use for gauge, histogram or counter" }, { FLB_CONFIG_MAP_STR, "metric_name", "a", diff --git a/tests/runtime/filter_log_to_metrics.c b/tests/runtime/filter_log_to_metrics.c index a68007b0885..6327605b2ee 100644 --- a/tests/runtime/filter_log_to_metrics.c +++ b/tests/runtime/filter_log_to_metrics.c @@ -57,6 +57,7 @@ /* Test functions */ void flb_test_log_to_metrics_counter_k8s(void); void flb_test_log_to_metrics_counter(void); +void flb_test_log_to_metrics_counter_value_field(void); void flb_test_log_to_metrics_counter_k8s_two_tuples(void); void flb_test_log_to_metrics_gauge(void); void flb_test_log_to_metrics_histogram(void); @@ -118,6 +119,7 @@ void flb_test_log_to_metrics_label(void); TEST_LIST = { {"counter_k8s", flb_test_log_to_metrics_counter_k8s }, {"counter", flb_test_log_to_metrics_counter }, + {"counter_value_field", flb_test_log_to_metrics_counter_value_field }, {"counter_k8s_two_tuples", flb_test_log_to_metrics_counter_k8s_two_tuples }, {"gauge", flb_test_log_to_metrics_gauge }, {"histogram", flb_test_log_to_metrics_histogram }, @@ -321,6 +323,74 @@ void flb_test_log_to_metrics_counter(void) } +void flb_test_log_to_metrics_counter_value_field(void) +{ + int ret; + int i; + flb_ctx_t *ctx; + int in_ffd; + int filter_ffd; + int out_ffd; + char *result = NULL; + struct flb_lib_out_cb cb_data; + char *input = JSON_MSG1; + char finalString[32768] = ""; + const char *expected = "\"value\":100.0,\"labels\":[\"red\",\"right\"]"; + const char *expected2 = "{\"ns\":\"myns\",\"ss\":\"subsystem\"," + "\"name\":\"test\",\"desc\":\"Counts durations\"}"; + + ctx = flb_create(); + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + "error", NULL); + + cb_data.cb = callback_test; + cb_data.data = NULL; + + in_ffd = flb_input(ctx, (char *) "lib", NULL); + TEST_CHECK(in_ffd >= 0); + flb_input_set(ctx, in_ffd, "tag", "test", NULL); + + filter_ffd = flb_filter(ctx, (char *) "log_to_metrics", NULL); + TEST_CHECK(filter_ffd >= 0); + ret = flb_filter_set(ctx, filter_ffd, + "Match", "*", + "Tag", "test_metric", + "metric_mode", "counter", + "metric_name", "test", + "metric_description", "Counts durations", + "metric_subsystem", "subsystem", + "metric_namespace", "myns", + "kubernetes_mode", "off", + "label_field", "color", + "label_field", "direction", + "value_field", "duration", + NULL); + + out_ffd = flb_output(ctx, (char *) "lib", (void *)&cb_data); + TEST_CHECK(out_ffd >= 0); + flb_output_set(ctx, out_ffd, + "match", "*", + "format", "json", + NULL); + ret = flb_start(ctx); + TEST_CHECK(ret == 0); + + for (i = 0; i < 5; i++){ + flb_lib_push(ctx, in_ffd, input, strlen(input)); + } + wait_with_timeout(2000, finalString); + result = strstr(finalString, expected); + if (!TEST_CHECK(result != NULL)) { + TEST_MSG("expected substring:\n%s\ngot:\n%s\n", expected, finalString); + } + result = strstr(finalString, expected2); + if (!TEST_CHECK(result != NULL)) { + TEST_MSG("expected substring:\n%s\ngot:\n%s\n", expected, finalString); + } + filter_test_destroy(ctx); + +} + void flb_test_log_to_metrics_counter_k8s_two_tuples(void) { int ret;