From f6770eff3aad1e135f62eebeeb1963b882b0af1c Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 26 Apr 2024 19:27:51 +0900 Subject: [PATCH] filter: Implement label key-value filtering Signed-off-by: Hiroshi Hatake --- include/cmetrics/cmt_filter.h | 4 + src/cmt_filter.c | 327 ++++++++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+) diff --git a/include/cmetrics/cmt_filter.h b/include/cmetrics/cmt_filter.h index 7676cbf..0ecf2d2 100644 --- a/include/cmetrics/cmt_filter.h +++ b/include/cmetrics/cmt_filter.h @@ -38,4 +38,8 @@ int cmt_filter(struct cmt *dst, struct cmt *src, void *compare_ctx, int (*compare)(void *compare_ctx, const char *str, size_t slen), int flags); +int cmt_filter_with_label_pair(struct cmt *dst, struct cmt *src, + const char *label_key, + const char *label_value); + #endif diff --git a/src/cmt_filter.c b/src/cmt_filter.c index 586802c..cdba2a0 100644 --- a/src/cmt_filter.c +++ b/src/cmt_filter.c @@ -162,6 +162,300 @@ static int filter_context_label_key(struct cmt *dst, struct cmt *src, return CMT_FILTER_SUCCESS; } +static int filter_get_label_index(struct cmt_map *src, const char *label_key) +{ + struct cfl_list *head; + struct cmt_map_label *label; + size_t index = 0; + + cfl_list_foreach(head, &src->label_keys) { + label = cfl_list_entry(head, struct cmt_map_label, _head); + if (strcasecmp(label->name, label_key) == 0) { + return index; + } + + index++; + } + + return -1; +} + +int metrics_check_label_value_existence(struct cmt_metric *metric, + size_t label_index, + const char *label_value) +{ + struct cfl_list *iterator; + size_t index; + struct cmt_map_label *label = NULL; + + index = 0; + + cfl_list_foreach(iterator, &metric->labels) { + label = cfl_list_entry(iterator, struct cmt_map_label, _head); + + if (label_index == index) { + break; + } + + index++; + } + + if (label_index != index) { + return CMT_FALSE; + } + + if (label == NULL) { + return CMT_FALSE; + } + + if (label->name == NULL) { + return CMT_FALSE; + } + + if (strncasecmp(label->name, label_value, strlen(label->name)) == 0) { + return CMT_TRUE; + } + + return CMT_FALSE; +} + +static int metrics_map_drop_label_value_pairs(struct cmt_map *map, + size_t label_index, + const char *label_value) +{ + struct cfl_list *head; + struct cmt_metric *metric; + int result; + + result = CMT_FALSE; + + cfl_list_foreach(head, &map->metrics) { + metric = cfl_list_entry(head, struct cmt_metric, _head); + + result = metrics_check_label_value_existence(metric, + label_index, + label_value); + + if (result == CMT_TRUE) { + result = CMT_TRUE; + break; + } + } + + if (result == CMT_TRUE) { + cmt_map_metric_destroy(metric); + } + + return result; +} + +static int filter_context_label_key_value(struct cmt *dst, struct cmt *src, + const char *label_key, const char *label_value) +{ + int ret; + char **labels = NULL; + struct cfl_list *head; + struct cmt_map *map; + struct cmt_counter *counter; + struct cmt_gauge *gauge; + struct cmt_untyped *untyped; + struct cmt_histogram *histogram; + struct cmt_summary *summary; + size_t index = 0; + + /* Counters */ + cfl_list_foreach(head, &src->counters) { + counter = cfl_list_entry(head, struct cmt_counter, _head); + + ret = cmt_cat_copy_label_keys(counter->map, (char **) &labels); + if (ret == -1) { + return -1; + } + + map = cmt_map_create(CMT_COUNTER, &counter->opts, + counter->map->label_count, + labels, (void *) counter); + free(labels); + if (!map) { + cmt_log_error(src, "unable to allocate map for counter"); + return -1; + } + + ret = cmt_cat_copy_map(&counter->opts, map, counter->map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + index = filter_get_label_index(map, label_key); + if (index != -1) { + metrics_map_drop_label_value_pairs(map, index, label_value); + } + + ret = cmt_cat_counter(dst, counter, map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + cmt_map_destroy(map); + } + + /* Gauges */ + cfl_list_foreach(head, &src->gauges) { + gauge = cfl_list_entry(head, struct cmt_gauge, _head); + + ret = cmt_cat_copy_label_keys(gauge->map, (char **) &labels); + if (ret == -1) { + return -1; + } + + map = cmt_map_create(CMT_GAUGE, &gauge->opts, + gauge->map->label_count, + labels, (void *) gauge); + free(labels); + if (!map) { + cmt_log_error(src, "unable to allocate map for gauge"); + return -1; + } + + ret = cmt_cat_copy_map(&gauge->opts, map, gauge->map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + index = filter_get_label_index(map, label_key); + if (index != -1) { + metrics_map_drop_label_value_pairs(map, index, label_value); + } + + ret = cmt_cat_gauge(dst, gauge, map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + cmt_map_destroy(map); + } + + /* Untyped */ + cfl_list_foreach(head, &src->untypeds) { + untyped = cfl_list_entry(head, struct cmt_untyped, _head); + + ret = cmt_cat_copy_label_keys(untyped->map, (char **) &labels); + if (ret == -1) { + return -1; + } + + map = cmt_map_create(CMT_UNTYPED, &gauge->opts, + untyped->map->label_count, + labels, (void *) untyped); + free(labels); + if (!map) { + cmt_log_error(src, "unable to allocate map for untyped"); + return -1; + } + + ret = cmt_cat_copy_map(&untyped->opts, map, untyped->map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + index = filter_get_label_index(map, label_key); + if (index != -1) { + metrics_map_drop_label_value_pairs(map, index, label_value); + } + + ret = cmt_cat_untyped(dst, untyped, map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + cmt_map_destroy(map); + } + + /* Histogram */ + cfl_list_foreach(head, &src->histograms) { + histogram = cfl_list_entry(head, struct cmt_histogram, _head); + + ret = cmt_cat_copy_label_keys(histogram->map, (char **) &labels); + if (ret == -1) { + return -1; + } + + map = cmt_map_create(CMT_HISTOGRAM, &histogram->opts, + histogram->map->label_count, + labels, (void *) histogram); + free(labels); + if (!map) { + cmt_log_error(src, "unable to allocate map for histogram"); + return -1; + } + + ret = cmt_cat_copy_map(&histogram->opts, map, histogram->map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + index = filter_get_label_index(map, label_key); + if (index != -1) { + metrics_map_drop_label_value_pairs(map, index, label_value); + } + + ret = cmt_cat_histogram(dst, histogram, map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + cmt_map_destroy(map); + } + + /* Summary */ + cfl_list_foreach(head, &src->summaries) { + summary = cfl_list_entry(head, struct cmt_summary, _head); + + ret = cmt_cat_copy_label_keys(summary->map, (char **) &labels); + if (ret == -1) { + return -1; + } + + map = cmt_map_create(CMT_SUMMARY, &summary->opts, + summary->map->label_count, + labels, (void *) summary); + free(labels); + if (!map) { + cmt_log_error(src, "unable to allocate map for summary"); + return -1; + } + + ret = cmt_cat_copy_map(&summary->opts, map, summary->map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + index = filter_get_label_index(map, label_key); + if (index != -1) { + metrics_map_drop_label_value_pairs(map, index, label_value); + } + + ret = cmt_cat_summary(dst, summary, map); + if (ret == -1) { + cmt_map_destroy(map); + return -1; + } + + cmt_map_destroy(map); + } + + return CMT_FILTER_SUCCESS; +} + static int compare_fqname(struct cmt_opts *src, const char *fqname, void *compare_ctx, int (*compare)(void *compare_ctx, const char *str, size_t slen), int flags) @@ -287,6 +581,39 @@ static int filter_context_fqname(struct cmt *dst, struct cmt *src, return CMT_FILTER_SUCCESS; } +int cmt_filter_with_label_pair(struct cmt *dst, struct cmt *src, + const char *label_key, + const char *label_value) +{ + int ret = CMT_FILTER_SUCCESS; + + if (!dst) { + return CMT_FILTER_INVALID_ARGUMENT; + } + + if (!src) { + return CMT_FILTER_INVALID_ARGUMENT; + } + + if (label_key == NULL) { + return CMT_FILTER_INVALID_ARGUMENT; + } + + if (label_value == NULL) { + return CMT_FILTER_INVALID_ARGUMENT; + } + + if (label_key != NULL && label_value != NULL) { + ret = filter_context_label_key_value(dst, src, label_key, label_value); + } + + if (ret != CMT_FILTER_SUCCESS) { + return CMT_FILTER_FAILED_OPERATION; + } + + return ret; +} + int cmt_filter(struct cmt *dst, struct cmt *src, const char *fqname, const char *label_key, void *compare_ctx, int (*compare)(void *compare_ctx, const char *str, size_t slen),