summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStelios Fragkakis <52996999+stelfrag@users.noreply.github.com>2022-04-12 08:18:40 +0300
committerGitHub <noreply@github.com>2022-04-12 08:18:40 +0300
commitfedab0d7fa6f3b42cfc6e7c65ed13a32b7b907b5 (patch)
tree97feefebfb4aa91227476427b58d16d46f16c623
parentd5ad2681bb5ce1456ea5caa9b956617b36c2bd6a (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.c2
-rw-r--r--collectors/plugins.d/plugins_d.h1
-rw-r--r--database/rrd.h1
-rw-r--r--database/rrdset.c36
-rw-r--r--web/api/netdata-swagger.json22
-rw-r--r--web/api/netdata-swagger.yaml18
-rw-r--r--web/api/web_api_v1.c13
-rw-r--r--web/api/web_api_v1.h1
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);