From d3d37cc289628b8ea11549d41a7fb35f51902dd6 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 14 Jun 2024 14:02:53 +0200 Subject: [PATCH] metrics-probe/filterx: implement update_metric() Signed-off-by: Attila Szakacs --- .../filterx/func-update-metric.c | 193 ++++++++++++++++++ modules/metrics-probe/metrics-probe-plugin.c | 5 +- 2 files changed, 197 insertions(+), 1 deletion(-) diff --git a/modules/metrics-probe/filterx/func-update-metric.c b/modules/metrics-probe/filterx/func-update-metric.c index 57dcac8401..9f2c0d93a7 100644 --- a/modules/metrics-probe/filterx/func-update-metric.c +++ b/modules/metrics-probe/filterx/func-update-metric.c @@ -22,3 +22,196 @@ */ #include "func-update-metric.h" +#include "filterx/filterx-metrics.h" +#include "filterx/expr-literal.h" +#include "filterx/filterx-eval.h" +#include "filterx/object-primitive.h" +#include "stats/stats.h" + +#define FILTERX_FUNC_UPDATE_METRIC_USAGE "update_metric(\"key\", labels={\"key\": \"value\"}, increment=1, level=0)" + +typedef struct FilterXFunctionUpdateMetric_ +{ + FilterXFunction super; + FilterXMetrics *metrics; + gint level; + + struct + { + FilterXExpr *expr; + gint64 value; + } increment; +} FilterXFunctionUpdateMetric; + +static gboolean +_get_increment(FilterXFunctionUpdateMetric *self, gint64 *increment) +{ + if (!self->increment.expr) + { + *increment = self->increment.value; + return TRUE; + } + + FilterXObject *increment_obj = filterx_expr_eval_typed(self->increment.expr); + if (!increment_obj) + return FALSE; + + gboolean success = filterx_integer_unwrap(increment_obj, increment); + if (!success) + filterx_eval_push_error("metric increment must be an integer", self->increment.expr, increment_obj); + + filterx_object_unref(increment_obj); + return success; +} + +static FilterXObject * +_eval(FilterXExpr *s) +{ + FilterXFunctionUpdateMetric *self = (FilterXFunctionUpdateMetric *) s; + + gboolean success = FALSE; + + gint64 increment; + if (!_get_increment(self, &increment)) + goto exit; + + StatsCounterItem *counter = filterx_metrics_get_stats_counter(self->metrics); + if (!counter) + goto exit; + + stats_counter_add(counter, increment); + success = TRUE; + +exit: + if (!success) + { + msg_error("FilterX: Failed to process update_metric()", filterx_format_last_error()); + filterx_eval_clear_errors(); + } + + return filterx_boolean_new(TRUE); +} + +static void +_free(FilterXExpr *s) +{ + FilterXFunctionUpdateMetric *self = (FilterXFunctionUpdateMetric *) s; + + if (self->metrics) + filterx_metrics_free(self->metrics); + filterx_expr_unref(self->increment.expr); + + filterx_function_free_method(&self->super); +} + +static gboolean +_extract_increment_arg(FilterXFunctionUpdateMetric *self, FilterXFunctionArgs *args, GError **error) +{ + self->increment.value = 1; + self->increment.expr = filterx_function_args_get_named_expr(args, "increment"); + + if (self->increment.expr && filterx_expr_is_literal(self->increment.expr)) + { + FilterXObject *increment_obj = filterx_expr_eval_typed(self->increment.expr); + if (!increment_obj) + { + g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL, + "failed to evaluate increment. " FILTERX_FUNC_UPDATE_METRIC_USAGE); + return FALSE; + } + + gboolean success = filterx_integer_unwrap(increment_obj, &self->increment.value); + filterx_object_unref(increment_obj); + if (!success) + { + g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL, + "failed to set increment, increment must be integer. " FILTERX_FUNC_UPDATE_METRIC_USAGE); + return FALSE; + } + + filterx_expr_unref(self->increment.expr); + self->increment.expr = NULL; + } + + return TRUE; +} + +static gboolean +_extract_level_arg(FilterXFunctionUpdateMetric *self, FilterXFunctionArgs *args, GError **error) +{ + gboolean exists; + gboolean arg_error; + self->level = filterx_function_args_get_named_literal_integer(args, "level", &exists, &arg_error); + + if (arg_error) + { + g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL, + "failed to set level, level must be a literal integer. " FILTERX_FUNC_UPDATE_METRIC_USAGE); + return FALSE; + } + + if (!exists) + self->level = STATS_LEVEL0; + + return TRUE; +} + +static gboolean +_init_metrics(FilterXFunctionUpdateMetric *self, FilterXFunctionArgs *args, GError **error) +{ + FilterXExpr *key = filterx_function_args_get_expr(args, 0); + FilterXExpr *labels = filterx_function_args_get_named_expr(args, "labels"); + + self->metrics = filterx_metrics_new(0, key, labels); + + filterx_expr_unref(key); + filterx_expr_unref(labels); + + return !!self->metrics; +} + +static gboolean +_extract_args(FilterXFunctionUpdateMetric *self, FilterXFunctionArgs *args, GError **error) +{ + if (filterx_function_args_len(args) != 1) + { + g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL, + "invalid number of arguments. " FILTERX_FUNC_UPDATE_METRIC_USAGE); + return FALSE; + } + + if (!_extract_increment_arg(self, args, error)) + return FALSE; + + if (!_extract_level_arg(self, args, error)) + return FALSE; + + if (!_init_metrics(self, args, error)) + return FALSE; + + return TRUE; +} + +FilterXFunction * +filterx_function_update_metric_new(const gchar *function_name, FilterXFunctionArgs *args, GError **error) +{ + FilterXFunctionUpdateMetric *self = g_new0(FilterXFunctionUpdateMetric, 1); + filterx_function_init_instance(&self->super, function_name); + + self->super.super.eval = _eval; + self->super.super.free_fn = _free; + + if (!_extract_args(self, args, error) || + !filterx_function_args_check(args, error)) + goto error; + + filterx_function_args_free(args); + return &self->super; + +error: + filterx_function_args_free(args); + filterx_expr_unref(&self->super.super); + return NULL; +} + +FILTERX_FUNCTION(update_metric, filterx_function_update_metric_new); diff --git a/modules/metrics-probe/metrics-probe-plugin.c b/modules/metrics-probe/metrics-probe-plugin.c index 4a85481137..f4a8a9b384 100644 --- a/modules/metrics-probe/metrics-probe-plugin.c +++ b/modules/metrics-probe/metrics-probe-plugin.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2023 Attila Szakacs + * Copyright (c) 2024 Axoflow + * Copyright (c) 2023-2024 Attila Szakacs * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -23,6 +24,7 @@ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" +#include "filterx/func-update-metric.h" extern CfgParser metrics_probe_parser; @@ -33,6 +35,7 @@ static Plugin metrics_probe_plugins[] = .name = "metrics-probe", .parser = &metrics_probe_parser, }, + FILTERX_FUNCTION_PLUGIN(update_metric), }; gboolean