diff options
author | Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> | 2022-04-12 08:18:40 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-12 08:18:40 +0300 |
commit | fedab0d7fa6f3b42cfc6e7c65ed13a32b7b907b5 (patch) | |
tree | 97feefebfb4aa91227476427b58d16d46f16c623 | |
parent | d5ad2681bb5ce1456ea5caa9b956617b36c2bd6a (diff) |
Add a chart label filter parameter in context data queries (#12652)
* Add function to filter chart labels
* Add new parameter to filter chart labels on context queries
* Change swagger
* Better formatting for swagger
-rw-r--r-- | collectors/plugins.d/plugins_d.c | 2 | ||||
-rw-r--r-- | collectors/plugins.d/plugins_d.h | 1 | ||||
-rw-r--r-- | database/rrd.h | 1 | ||||
-rw-r--r-- | database/rrdset.c | 36 | ||||
-rw-r--r-- | web/api/netdata-swagger.json | 22 | ||||
-rw-r--r-- | web/api/netdata-swagger.yaml | 18 | ||||
-rw-r--r-- | web/api/web_api_v1.c | 13 | ||||
-rw-r--r-- | web/api/web_api_v1.h | 1 |
8 files changed, 90 insertions, 4 deletions
diff --git a/collectors/plugins.d/plugins_d.c b/collectors/plugins.d/plugins_d.c index 42889fa8ca..614e43d584 100644 --- a/collectors/plugins.d/plugins_d.c +++ b/collectors/plugins.d/plugins_d.c @@ -36,7 +36,7 @@ inline int config_isspace(char c) } // split a text into words, respecting quotes -static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char), char *recover_input, char **recover_location, int max_recover) +inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char), char *recover_input, char **recover_location, int max_recover) { char *s = str, quote = 0; int i = 0, j, rec = 0; diff --git a/collectors/plugins.d/plugins_d.h b/collectors/plugins.d/plugins_d.h index 8f0b028578..e0b8ac5700 100644 --- a/collectors/plugins.d/plugins_d.h +++ b/collectors/plugins.d/plugins_d.h @@ -66,5 +66,6 @@ extern int pluginsd_initialize_plugin_directories(); extern int config_isspace(char c); extern int pluginsd_space(char c); +int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char), char *recover_input, char **recover_location, int max_recover); #endif /* NETDATA_PLUGINS_D_H */ diff --git a/database/rrd.h b/database/rrd.h index a305d8b4d3..071e1d0389 100644 --- a/database/rrd.h +++ b/database/rrd.h @@ -240,6 +240,7 @@ extern void rrdset_add_label_to_new_list(RRDSET *st, char *key, char *value, LAB extern void rrdset_finalize_labels(RRDSET *st); extern void rrdset_update_labels(RRDSET *st, struct label *labels); extern int rrdset_contains_label_keylist(RRDSET *st, char *key); +extern int rrdset_matches_label_keys(RRDSET *st, char *key, char *words[], uint32_t *hash_key_list, int *word_count, int size); extern struct label *rrdset_lookup_label_key(RRDSET *st, char *key, uint32_t key_hash); // ---------------------------------------------------------------------------- diff --git a/database/rrdset.c b/database/rrdset.c index 846b40d8ac..f8e471be7e 100644 --- a/database/rrdset.c +++ b/database/rrdset.c @@ -2043,3 +2043,39 @@ struct label *rrdset_lookup_label_key(RRDSET *st, char *key, uint32_t key_hash) } return ret; } + +static inline int k8s_space(char c) { + switch(c) { + case ':': + case ',': + return 1; + default: + return 0; + } +} + +int rrdset_matches_label_keys(RRDSET *st, char *keylist, char *words[], uint32_t *hash_key_list, int *word_count, int size) +{ + struct label_index *labels = &st->state->labels; + + if (!labels->head) + return 0; + + struct label *one_label; + + if (!*word_count) { + *word_count = quoted_strings_splitter(keylist, words, size, k8s_space, NULL, NULL, 0); + for (int i = 0; i < *word_count - 1; i += 2) { + hash_key_list[i] = simple_hash(words[i]); + } + } + + int ret = 1; + netdata_rwlock_rdlock(&labels->labels_rwlock); + for (int i = 0; ret && i < *word_count - 1; i += 2) { + one_label = label_list_lookup_key(labels->head, words[i], hash_key_list[i]); + ret = (one_label && !strcmp(one_label->value, words[i + 1])); + } + netdata_rwlock_unlock(&labels->labels_rwlock); + return ret; +} diff --git a/web/api/netdata-swagger.json b/web/api/netdata-swagger.json index 64c3a95bcf..4952e6116a 100644 --- a/web/api/netdata-swagger.json +++ b/web/api/netdata-swagger.json @@ -200,6 +200,28 @@ } }, { + "name": "chart_label_key", + "in": "query", + "description": "Specify the chart label keys that need to match for context queries as comma separated values. At least one matching key is needed to match the corresponding chart.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "string", + "format": "key1,key2,key3" + } + }, + { + "name": "chart_labels_filter", + "in": "query", + "description": "Specify the chart label keys and values to match for context queries. All keys/values need to match for the chart to be included in the query. The labels are specified as key1:value1,key2:value2", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "string", + "format": "key1:value1,key2:value2,key3:value3" + } + }, + { "name": "group", "in": "query", "description": "The grouping method. If multiple collected values are to be grouped in order to return fewer points, this parameters defines the method of grouping. methods supported \"min\", \"max\", \"average\", \"sum\", \"incremental-sum\". \"max\" is actually calculated on the absolute value collected (so it works for both positive and negative dimensions to return the most extreme value in either direction).", diff --git a/web/api/netdata-swagger.yaml b/web/api/netdata-swagger.yaml index a03180ea08..1e20ad0f5b 100644 --- a/web/api/netdata-swagger.yaml +++ b/web/api/netdata-swagger.yaml @@ -170,6 +170,24 @@ paths: type: number format: integer default: 20 + - name: chart_label_key + in: query + description: Specify the chart label keys that need to match for context queries as comma separated values. + At least one matching key is needed to match the corresponding chart. + required: false + allowEmptyValue: false + schema: + type: string + format: key1,key2,key3 + - name: chart_labels_filter + in: query + description: Specify the chart label keys and values to match for context queries. All keys/values need to + match for the chart to be included in the query. The labels are specified as key1:value1,key2:value2 + required: false + allowEmptyValue: false + schema: + type: string + format: key1:value1,key2:value2,key3:value3 - name: group in: query description: The grouping method. If multiple collected values are to be grouped diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 20318a1318..8cf89d38d5 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -419,6 +419,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c char *max_anomaly_rates_str = NULL; char *context = NULL; char *chart_label_key = NULL; + char *chart_labels_filter = NULL; int group = RRDR_GROUPING_AVERAGE; uint32_t format = DATASOURCE_JSON; @@ -439,6 +440,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c if(!strcmp(name, "context")) context = value; else if(!strcmp(name, "chart_label_key")) chart_label_key = value; + else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value; else if(!strcmp(name, "chart")) chart = value; else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) { if(!dimensions) dimensions = buffer_create(100); @@ -522,16 +524,21 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c uint32_t context_hash = simple_hash(context); rrdhost_rdlock(host); + char *words[MAX_CHART_LABELS_FILTER]; + uint32_t hash_key_list[MAX_CHART_LABELS_FILTER]; + int word_count = 0; rrdset_foreach_read(st1, host) { if (st1->hash_context == context_hash && !strcmp(st1->context, context) && - (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key))) - build_context_param_list(&context_param_list, st1); + (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key)) && + (!chart_labels_filter || + rrdset_matches_label_keys(st1, chart_labels_filter, words, hash_key_list, &word_count, MAX_CHART_LABELS_FILTER))) + build_context_param_list(&context_param_list, st1); } rrdhost_unlock(host); if (likely(context_param_list && context_param_list->rd)) // Just set the first one st = context_param_list->rd->rrdset; else { - if (!chart_label_key) + if (!chart_label_key && !chart_labels_filter) sql_build_context_param_list(&context_param_list, host, context, NULL); } } diff --git a/web/api/web_api_v1.h b/web/api/web_api_v1.h index 445b0e4a5c..a88c511ad8 100644 --- a/web/api/web_api_v1.h +++ b/web/api/web_api_v1.h @@ -8,6 +8,7 @@ #include "web/api/formatters/rrd2json.h" #include "web/api/health/health_cmdapi.h" +#define MAX_CHART_LABELS_FILTER (32) extern uint32_t web_client_api_request_v1_data_options(char *o); extern uint32_t web_client_api_request_v1_data_format(char *name); extern uint32_t web_client_api_request_v1_data_google_format(char *name); |