summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStelios Fragkakis <52996999+stelfrag@users.noreply.github.com>2021-01-14 18:50:33 +0200
committerGitHub <noreply@github.com>2021-01-14 18:50:33 +0200
commitcd443de780118c46dd8f02530086667d00948373 (patch)
treee29f21e28eb9eeb1d11539216a9e623ac225d3de
parentde6035c543296de179e359a415664106d66c3878 (diff)
Support multiple chart label keys in data queries (#10483)
-rw-r--r--database/rrd.h4
-rw-r--r--database/rrdlabels.c22
-rw-r--r--database/rrdset.c4
-rw-r--r--libnetdata/simple_pattern/simple_pattern.c9
-rw-r--r--libnetdata/simple_pattern/simple_pattern.h1
-rw-r--r--web/api/formatters/json_wrapper.c64
-rw-r--r--web/api/web_api_v1.c6
7 files changed, 74 insertions, 36 deletions
diff --git a/database/rrd.h b/database/rrd.h
index 20891409d4..86f4226348 100644
--- a/database/rrd.h
+++ b/database/rrd.h
@@ -211,6 +211,8 @@ extern int is_valid_label_value(char *value);
extern int is_valid_label_key(char *key);
extern void free_label_list(struct label *labels);
extern struct label *label_list_lookup_key(struct label *head, char *key, uint32_t key_hash);
+extern struct label *label_list_lookup_keylist(struct label *head, char *keylist);
+extern int label_list_contains_keylist(struct label *head, char *keylist);
extern int label_list_contains_key(struct label *head, char *key, uint32_t key_hash);
extern int label_list_contains(struct label *head, struct label *check);
extern struct label *merge_label_lists(struct label *lo_pri, struct label *hi_pri);
@@ -223,7 +225,7 @@ void reload_host_labels(void);
extern void rrdset_add_label_to_new_list(RRDSET *st, char *key, char *value, LABEL_SOURCE source);
extern void rrdset_finalize_labels(RRDSET *st);
extern void rrdset_update_labels(RRDSET *st, struct label *labels);
-extern int rrdset_contains_label_key(RRDSET *st, char *key, uint32_t key_hash);
+extern int rrdset_contains_label_keylist(RRDSET *st, char *key);
extern struct label *rrdset_lookup_label_key(RRDSET *st, char *key, uint32_t key_hash);
// ----------------------------------------------------------------------------
diff --git a/database/rrdlabels.c b/database/rrdlabels.c
index b423f422a4..f9583769d5 100644
--- a/database/rrdlabels.c
+++ b/database/rrdlabels.c
@@ -159,6 +159,28 @@ int label_list_contains(struct label *head, struct label *check)
return label_list_contains_key(head, check->key, check->key_hash);
}
+struct label *label_list_lookup_keylist(struct label *head, char *key)
+{
+ SIMPLE_PATTERN *pattern = NULL;
+
+ pattern = simple_pattern_create(key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+
+ while (head != NULL)
+ {
+ if (simple_pattern_matches(pattern, head->key))
+ break;
+ head = head->next;
+ }
+ simple_pattern_free(pattern);
+ return head;
+}
+
+int label_list_contains_keylist(struct label *head, char *keylist)
+{
+ return (label_list_lookup_keylist(head, keylist) != NULL);
+}
+
+
/* Create a list with entries from both lists.
If any entry in the low priority list is masked by an entry in the high priority list then delete it.
*/
diff --git a/database/rrdset.c b/database/rrdset.c
index 163fbb0715..760f401184 100644
--- a/database/rrdset.c
+++ b/database/rrdset.c
@@ -1949,7 +1949,7 @@ void rrdset_update_labels(RRDSET *st, struct label *labels)
rrdset_finalize_labels(st);
}
-int rrdset_contains_label_key(RRDSET *st, char *key, uint32_t key_hash)
+int rrdset_contains_label_keylist(RRDSET *st, char *keylist)
{
struct label_index *labels = &st->state->labels;
int ret;
@@ -1958,7 +1958,7 @@ int rrdset_contains_label_key(RRDSET *st, char *key, uint32_t key_hash)
return 0;
netdata_rwlock_rdlock(&labels->labels_rwlock);
- ret = label_list_contains_key(labels->head, key, key_hash);
+ ret = label_list_contains_keylist(labels->head, keylist);
netdata_rwlock_unlock(&labels->labels_rwlock);
return ret;
diff --git a/libnetdata/simple_pattern/simple_pattern.c b/libnetdata/simple_pattern/simple_pattern.c
index 44fa42a629..70b06a22bc 100644
--- a/libnetdata/simple_pattern/simple_pattern.c
+++ b/libnetdata/simple_pattern/simple_pattern.c
@@ -354,3 +354,12 @@ char *simple_pattern_trim_around_equal(char *src) {
return store;
}
+
+char *simple_pattern_iterate(SIMPLE_PATTERN **p)
+{
+ struct simple_pattern *root = (struct simple_pattern *) *p;
+ struct simple_pattern **Proot = (struct simple_pattern **)p;
+
+ (*Proot) = (*Proot)->next;
+ return (char *) root->match;
+}
diff --git a/libnetdata/simple_pattern/simple_pattern.h b/libnetdata/simple_pattern/simple_pattern.h
index ec6b535879..36fbbde7df 100644
--- a/libnetdata/simple_pattern/simple_pattern.h
+++ b/libnetdata/simple_pattern/simple_pattern.h
@@ -32,6 +32,7 @@ extern void simple_pattern_free(SIMPLE_PATTERN *list);
extern void simple_pattern_dump(uint64_t debug_type, SIMPLE_PATTERN *p) ;
extern int simple_pattern_is_potential_name(SIMPLE_PATTERN *p) ;
+extern char *simple_pattern_iterate(SIMPLE_PATTERN **p);
//Auxiliary function to create a pattern
char *simple_pattern_trim_around_equal(char *src);
diff --git a/web/api/formatters/json_wrapper.c b/web/api/formatters/json_wrapper.c
index 72967375d7..cf4f1099a2 100644
--- a/web/api/formatters/json_wrapper.c
+++ b/web/api/formatters/json_wrapper.c
@@ -116,43 +116,51 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
}
buffer_strcat(wb, "],\n");
if (chart_label_key) {
- uint32_t key_hash = simple_hash(chart_label_key);
- struct label *current_label;
+ buffer_sprintf(wb, " %schart_labels%s: { ", kq, kq);
- buffer_sprintf(
- wb,
- " %schart_labels%s: { %s%s%s : [",
- kq, kq, kq, chart_label_key, kq);
+ SIMPLE_PATTERN *pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ SIMPLE_PATTERN *original_pattern = pattern;
+ char *label_key = NULL;
+ int keys = 0;
+ while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
+ uint32_t key_hash = simple_hash(label_key);
+ struct label *current_label;
- for (c = 0, i = 0, rd = temp_rd; rd && c < r->d; c++, rd = rd->next) {
- if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
- continue;
- if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
- continue;
-
- if (i)
+ if (keys)
buffer_strcat(wb, ", ");
-
- current_label = rrdset_lookup_label_key(rd->rrdset, chart_label_key, key_hash);
- if (current_label) {
+ buffer_sprintf(wb, "%s%s%s : [", kq, label_key, kq);
+ keys++;
+
+ for (c = 0, i = 0, rd = temp_rd; rd && c < r->d; c++, rd = rd->next) {
+ if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
+ continue;
+ if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
+ continue;
+ if (i)
+ buffer_strcat(wb, ", ");
+
+ current_label = rrdset_lookup_label_key(rd->rrdset, label_key, key_hash);
+ if (current_label) {
+ buffer_strcat(wb, sq);
+ buffer_strcat(wb, current_label->value);
+ buffer_strcat(wb, sq);
+ } else
+ buffer_strcat(wb, "null");
+ i++;
+ }
+ if (!i) {
+ rows = 0;
buffer_strcat(wb, sq);
- buffer_strcat(wb, current_label->value);
+ buffer_strcat(wb, "no data");
buffer_strcat(wb, sq);
- } else
- buffer_strcat(wb, "null");
- i++;
+ }
+ buffer_strcat(wb, "]");
}
- if (!i) {
- rows = 0;
- buffer_strcat(wb, sq);
- buffer_strcat(wb, "no data");
- buffer_strcat(wb, sq);
- }
- buffer_strcat(wb, "] },\n");
+ buffer_strcat(wb, "},\n");
+ simple_pattern_free(original_pattern);
}
}
-
buffer_sprintf(wb, " %slatest_values%s: ["
, kq, kq);
diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c
index cbfeee9a5c..4287675418 100644
--- a/web/api/web_api_v1.c
+++ b/web/api/web_api_v1.c
@@ -501,15 +501,11 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
if (context && !chart) {
RRDSET *st1;
uint32_t context_hash = simple_hash(context);
- uint32_t key_hash;
-
- if (chart_label_key)
- key_hash = simple_hash(chart_label_key);
rrdhost_rdlock(host);
rrdset_foreach_read(st1, host) {
if (st1->hash_context == context_hash && !strcmp(st1->context, context) &&
- (!chart_label_key || rrdset_contains_label_key(st1, chart_label_key, key_hash)))
+ (!chart_label_key || rrdset_contains_label_keylist(st1, chart_label_key)))
build_context_param_list(&context_param_list, st1);
}
rrdhost_unlock(host);