Browse Source

Support multiple chart label keys in data queries (#10483)

Stelios Fragkakis 4 years ago
parent
commit
cd443de780

+ 3 - 1
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);
 
 // ----------------------------------------------------------------------------

+ 22 - 0
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.
 */

+ 2 - 2
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;

+ 9 - 0
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;
+}

+ 1 - 0
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);

+ 36 - 28
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);
 

+ 1 - 5
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);