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);