@cryptotaxi247 / netdata-1 / commits / fedab0d7f

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

Stelios Fragkakis committed Apr 12, 2022 at 08:18 UTC fedab0d7fa6f3b42cfc6e7c65ed13a32b7b907b5
8 files changed +90 -4
collectors/plugins.d/plugins_d.c
+1 -1
@@ -36,7 +36,7 @@ inline int config_isspace(char c)
36 }
37
38 // split a text into words, respecting quotes
39 -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)
39 +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)
40 {
41 char *s = str, quote = 0;
42 int i = 0, j, rec = 0;
collectors/plugins.d/plugins_d.h
+1
@@ -66,5 +66,6 @@ extern int pluginsd_initialize_plugin_directories();
66
67 extern int config_isspace(char c);
68 extern int pluginsd_space(char c);
69 +int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char), char *recover_input, char **recover_location, int max_recover);
70
71 #endif /* NETDATA_PLUGINS_D_H */
database/rrd.h
+1
@@ -240,6 +240,7 @@ extern void rrdset_add_label_to_new_list(RRDSET *st, char *key, char *value, LAB
240 extern void rrdset_finalize_labels(RRDSET *st);
241 extern void rrdset_update_labels(RRDSET *st, struct label *labels);
242 extern int rrdset_contains_label_keylist(RRDSET *st, char *key);
243 +extern int rrdset_matches_label_keys(RRDSET *st, char *key, char *words[], uint32_t *hash_key_list, int *word_count, int size);
244 extern struct label *rrdset_lookup_label_key(RRDSET *st, char *key, uint32_t key_hash);
245
246 // ----------------------------------------------------------------------------
database/rrdset.c
+36
@@ -2043,3 +2043,39 @@ struct label *rrdset_lookup_label_key(RRDSET *st, char *key, uint32_t key_hash)
2043 }
2044 return ret;
2045 }
2046 +
2047 +static inline int k8s_space(char c) {
2048 + switch(c) {
2049 + case ':':
2050 + case ',':
2051 + return 1;
2052 + default:
2053 + return 0;
2054 + }
2055 +}
2056 +
2057 +int rrdset_matches_label_keys(RRDSET *st, char *keylist, char *words[], uint32_t *hash_key_list, int *word_count, int size)
2058 +{
2059 + struct label_index *labels = &st->state->labels;
2060 +
2061 + if (!labels->head)
2062 + return 0;
2063 +
2064 + struct label *one_label;
2065 +
2066 + if (!*word_count) {
2067 + *word_count = quoted_strings_splitter(keylist, words, size, k8s_space, NULL, NULL, 0);
2068 + for (int i = 0; i < *word_count - 1; i += 2) {
2069 + hash_key_list[i] = simple_hash(words[i]);
2070 + }
2071 + }
2072 +
2073 + int ret = 1;
2074 + netdata_rwlock_rdlock(&labels->labels_rwlock);
2075 + for (int i = 0; ret && i < *word_count - 1; i += 2) {
2076 + one_label = label_list_lookup_key(labels->head, words[i], hash_key_list[i]);
2077 + ret = (one_label && !strcmp(one_label->value, words[i + 1]));
2078 + }
2079 + netdata_rwlock_unlock(&labels->labels_rwlock);
2080 + return ret;
2081 +}
web/api/netdata-swagger.json
+22
@@ -199,6 +199,28 @@
199 "default": 20
200 }
201 },
202 + {
203 + "name": "chart_label_key",
204 + "in": "query",
205 + "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.",
206 + "required": false,
207 + "allowEmptyValue": false,
208 + "schema": {
209 + "type": "string",
210 + "format": "key1,key2,key3"
211 + }
212 + },
213 + {
214 + "name": "chart_labels_filter",
215 + "in": "query",
216 + "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",
217 + "required": false,
218 + "allowEmptyValue": false,
219 + "schema": {
220 + "type": "string",
221 + "format": "key1:value1,key2:value2,key3:value3"
222 + }
223 + },
224 {
225 "name": "group",
226 "in": "query",
web/api/netdata-swagger.yaml
+18
@@ -170,6 +170,24 @@ paths:
170 type: number
171 format: integer
172 default: 20
173 + - name: chart_label_key
174 + in: query
175 + description: Specify the chart label keys that need to match for context queries as comma separated values.
176 + At least one matching key is needed to match the corresponding chart.
177 + required: false
178 + allowEmptyValue: false
179 + schema:
180 + type: string
181 + format: key1,key2,key3
182 + - name: chart_labels_filter
183 + in: query
184 + description: Specify the chart label keys and values to match for context queries. All keys/values need to
185 + match for the chart to be included in the query. The labels are specified as key1:value1,key2:value2
186 + required: false
187 + allowEmptyValue: false
188 + schema:
189 + type: string
190 + format: key1:value1,key2:value2,key3:value3
191 - name: group
192 in: query
193 description: The grouping method. If multiple collected values are to be grouped
web/api/web_api_v1.c
+10 -3
@@ -419,6 +419,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
419 char *max_anomaly_rates_str = NULL;
420 char *context = NULL;
421 char *chart_label_key = NULL;
422 + char *chart_labels_filter = NULL;
423
424 int group = RRDR_GROUPING_AVERAGE;
425 uint32_t format = DATASOURCE_JSON;
@@ -439,6 +440,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
440
441 if(!strcmp(name, "context")) context = value;
442 else if(!strcmp(name, "chart_label_key")) chart_label_key = value;
443 + else if(!strcmp(name, "chart_labels_filter")) chart_labels_filter = value;
444 else if(!strcmp(name, "chart")) chart = value;
445 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
446 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
524 uint32_t context_hash = simple_hash(context);
525
526 rrdhost_rdlock(host);
527 + char *words[MAX_CHART_LABELS_FILTER];
528 + uint32_t hash_key_list[MAX_CHART_LABELS_FILTER];
529 + int word_count = 0;
530 rrdset_foreach_read(st1, host) {
531 if (st1->hash_context == context_hash && !strcmp(st1->context, context) &&
527 - (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key)))
528 - build_context_param_list(&context_param_list, st1);
532 + (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key)) &&
533 + (!chart_labels_filter ||
534 + rrdset_matches_label_keys(st1, chart_labels_filter, words, hash_key_list, &word_count, MAX_CHART_LABELS_FILTER)))
535 + build_context_param_list(&context_param_list, st1);
536 }
537 rrdhost_unlock(host);
538 if (likely(context_param_list && context_param_list->rd)) // Just set the first one
539 st = context_param_list->rd->rrdset;
540 else {
534 - if (!chart_label_key)
541 + if (!chart_label_key && !chart_labels_filter)
542 sql_build_context_param_list(&context_param_list, host, context, NULL);
543 }
544 }
web/api/web_api_v1.h
+1
@@ -8,6 +8,7 @@
8 #include "web/api/formatters/rrd2json.h"
9 #include "web/api/health/health_cmdapi.h"
10
11 +#define MAX_CHART_LABELS_FILTER (32)
12 extern uint32_t web_client_api_request_v1_data_options(char *o);
13 extern uint32_t web_client_api_request_v1_data_format(char *name);
14 extern uint32_t web_client_api_request_v1_data_google_format(char *name);