diff options
author | Ilya Mashchenko <ilya@netdata.cloud> | 2020-12-14 17:27:55 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-14 17:27:55 +0300 |
commit | 0f8175dd3060691394e263cdab01c8f940b1b5d3 (patch) | |
tree | 4b14cd6b7e6ba7797eeec4c74b4c4c35cdad4494 /web | |
parent | 7bfa8c8eba72a109d940b1fa5c7acaed9cd7a52c (diff) |
Kubernetes labels (#10107)
Co-authored-by: Markos Fountoulakis <markos.fountoulakis.senior@gmail.com>
Co-authored-by: Vladimir Kobal <vlad@prokk.net>
Diffstat (limited to 'web')
-rw-r--r-- | web/api/formatters/json_wrapper.c | 43 | ||||
-rw-r--r-- | web/api/formatters/json_wrapper.h | 2 | ||||
-rw-r--r-- | web/api/formatters/rrd2json.c | 25 | ||||
-rw-r--r-- | web/api/formatters/rrd2json.h | 1 | ||||
-rw-r--r-- | web/api/formatters/rrdset2json.c | 34 | ||||
-rw-r--r-- | web/api/web_api_v1.c | 32 |
6 files changed, 112 insertions, 25 deletions
diff --git a/web/api/formatters/json_wrapper.c b/web/api/formatters/json_wrapper.c index bfe172cfce..72967375d7 100644 --- a/web/api/formatters/json_wrapper.c +++ b/web/api/formatters/json_wrapper.c @@ -2,7 +2,7 @@ #include "json_wrapper.h" -void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd) { +void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd, char *chart_label_key) { rrdset_check_rdlock(r->st); long rows = rrdr_rows(r); @@ -86,12 +86,12 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS buffer_strcat(wb, "no data"); buffer_strcat(wb, sq); } + buffer_strcat(wb, "],\n"); // Composite charts if (temp_rd) { buffer_sprintf( wb, - "],\n" " %schart_ids%s: [", kq, kq); @@ -114,11 +114,46 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS buffer_strcat(wb, "no data"); buffer_strcat(wb, sq); } + 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: { %s%s%s : [", + kq, kq, kq, chart_label_key, kq); + + 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, chart_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, "no data"); + buffer_strcat(wb, sq); + } + buffer_strcat(wb, "] },\n"); + } } - buffer_sprintf(wb, "],\n" - " %slatest_values%s: [" + buffer_sprintf(wb, " %slatest_values%s: [" , kq, kq); for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { diff --git a/web/api/formatters/json_wrapper.h b/web/api/formatters/json_wrapper.h index b502f02862..d48d5d1ae8 100644 --- a/web/api/formatters/json_wrapper.h +++ b/web/api/formatters/json_wrapper.h @@ -5,7 +5,7 @@ #include "rrd2json.h" -extern void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd); +extern void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd, char *chart_key); extern void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value); #endif //NETDATA_API_FORMATTER_JSON_WRAPPER_H diff --git a/web/api/formatters/rrd2json.c b/web/api/formatters/rrd2json.c index 390659061c..9168f76eb1 100644 --- a/web/api/formatters/rrd2json.c +++ b/web/api/formatters/rrd2json.c @@ -188,6 +188,7 @@ int rrdset2anything_api_v1( , uint32_t options , time_t *latest_timestamp , struct context_param *context_param_list + , char *chart_label_key ) { time_t last_accessed_time = now_realtime_sec(); st->last_accessed_time = last_accessed_time; @@ -212,7 +213,7 @@ int rrdset2anything_api_v1( case DATASOURCE_SSV: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); rrdr2ssv(r, wb, options, "", " ", ""); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -225,7 +226,7 @@ int rrdset2anything_api_v1( case DATASOURCE_SSV_COMMA: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); rrdr2ssv(r, wb, options, "", ",", ""); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -238,7 +239,7 @@ int rrdset2anything_api_v1( case DATASOURCE_JS_ARRAY: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); rrdr2ssv(r, wb, options, "[", ",", "]"); rrdr_json_wrapper_end(r, wb, format, options, 0); } @@ -251,7 +252,7 @@ int rrdset2anything_api_v1( case DATASOURCE_CSV: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); rrdr2csv(r, wb, format, options, "", ",", "\\n", "", temp_rd); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -264,7 +265,7 @@ int rrdset2anything_api_v1( case DATASOURCE_CSV_MARKDOWN: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); rrdr2csv(r, wb, format, options, "", "|", "\\n", "", temp_rd); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -277,7 +278,7 @@ int rrdset2anything_api_v1( case DATASOURCE_CSV_JSON_ARRAY: wb->contenttype = CT_APPLICATION_JSON; if(options & RRDR_OPTION_JSON_WRAP) { - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); buffer_strcat(wb, "[\n"); rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd); buffer_strcat(wb, "\n]"); @@ -294,7 +295,7 @@ int rrdset2anything_api_v1( case DATASOURCE_TSV: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); rrdr2csv(r, wb, format, options, "", "\t", "\\n", "", temp_rd); rrdr_json_wrapper_end(r, wb, format, options, 1); } @@ -307,7 +308,7 @@ int rrdset2anything_api_v1( case DATASOURCE_HTML: if(options & RRDR_OPTION_JSON_WRAP) { wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd, chart_label_key); buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n"); rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "", temp_rd); buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n"); @@ -325,7 +326,7 @@ int rrdset2anything_api_v1( wb->contenttype = CT_APPLICATION_X_JAVASCRIPT; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); rrdr2json(r, wb, options, 1, temp_rd); @@ -337,7 +338,7 @@ int rrdset2anything_api_v1( wb->contenttype = CT_APPLICATION_JSON; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); rrdr2json(r, wb, options, 1, temp_rd); @@ -348,7 +349,7 @@ int rrdset2anything_api_v1( case DATASOURCE_JSONP: wb->contenttype = CT_APPLICATION_X_JAVASCRIPT; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); rrdr2json(r, wb, options, 0, temp_rd); @@ -361,7 +362,7 @@ int rrdset2anything_api_v1( wb->contenttype = CT_APPLICATION_JSON; if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd); + rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd, chart_label_key); rrdr2json(r, wb, options, 0, temp_rd); diff --git a/web/api/formatters/rrd2json.h b/web/api/formatters/rrd2json.h index fcae720f4f..1f929c4943 100644 --- a/web/api/formatters/rrd2json.h +++ b/web/api/formatters/rrd2json.h @@ -66,6 +66,7 @@ extern int rrdset2anything_api_v1( , uint32_t options , time_t *latest_timestamp , struct context_param *context_param_list + , char *chart_label_key ); extern int rrdset2value_api_v1( diff --git a/web/api/formatters/rrdset2json.c b/web/api/formatters/rrdset2json.c index 251395eff5..5482881e0c 100644 --- a/web/api/formatters/rrdset2json.c +++ b/web/api/formatters/rrdset2json.c @@ -2,6 +2,36 @@ #include "rrdset2json.h" +void chart_labels2json(RRDSET *st, BUFFER *wb, size_t indentation) +{ + char tabs[11]; + struct label_index *labels = &st->state->labels; + + if (indentation > 10) + indentation = 10; + + tabs[0] = '\0'; + while (indentation) { + strcat(tabs, "\t"); + indentation--; + } + + int count = 0; + netdata_rwlock_rdlock(&labels->labels_rwlock); + for (struct label *label = labels->head; label; label = label->next) { + if(count > 0) buffer_strcat(wb, ",\n"); + buffer_strcat(wb, tabs); + + char value[CONFIG_MAX_VALUE * 2 + 1]; + sanitize_json_string(value, label->value, CONFIG_MAX_VALUE * 2); + buffer_sprintf(wb, "\"%s\": \"%s\"", label->key, value); + + count++; + } + buffer_strcat(wb, "\n"); + netdata_rwlock_unlock(&labels->labels_rwlock); +} + // generate JSON for the /api/v1/chart API call void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used, int skip_volatile) { @@ -118,6 +148,10 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor "\n\t\t\t}" ); } + buffer_strcat(wb, ",\n\t\t\t\"chart_labels\": {\n"); + chart_labels2json(st, wb, 2); + buffer_strcat(wb, "\t\t\t}\n"); + buffer_sprintf(wb, "\n\t\t}" diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 71027552f2..cbfeee9a5c 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -402,7 +402,8 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c , *after_str = NULL , *group_time_str = NULL , *points_str = NULL - , *context = NULL; + , *context = NULL + , *chart_label_key = NULL; int group = RRDR_GROUPING_AVERAGE; uint32_t format = DATASOURCE_JSON; @@ -422,6 +423,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c // they are not null and not empty if(!strcmp(name, "context")) context = value; + else if(!strcmp(name, "chart_label_key")) chart_label_key = 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); @@ -499,9 +501,15 @@ 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)) + if (st1->hash_context == context_hash && !strcmp(st1->context, context) && + (!chart_label_key || rrdset_contains_label_key(st1, chart_label_key, key_hash))) build_context_param_list(&context_param_list, st1); } rrdhost_unlock(host); @@ -518,8 +526,16 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c if (!st && !context_param_list) { if (context && !chart) { - buffer_strcat(w->response.data, "Context is not found: "); - buffer_strcat_htmlescape(w->response.data, context); + if (!chart_label_key) { + buffer_strcat(w->response.data, "Context is not found: "); + buffer_strcat_htmlescape(w->response.data, context); + } else { + buffer_strcat(w->response.data, "Context: "); + buffer_strcat_htmlescape(w->response.data, context); + buffer_strcat(w->response.data, " or chart label key: "); + buffer_strcat_htmlescape(w->response.data, chart_label_key); + buffer_strcat(w->response.data, " not found"); + } } else { buffer_strcat(w->response.data, "Chart is not found: "); @@ -572,7 +588,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c } ret = rrdset2anything_api_v1(st, w->response.data, dimensions, format, points, after, before, group, group_time - , options, &last_timestamp_in_data, context_param_list); + , options, &last_timestamp_in_data, context_param_list, chart_label_key); free_context_param_list(&context_param_list); @@ -869,8 +885,8 @@ inline void host_labels2json(RRDHOST *host, BUFFER *wb, size_t indentation) { int count = 0; rrdhost_rdlock(host); - netdata_rwlock_rdlock(&host->labels_rwlock); - for (struct label *label = host->labels; label; label = label->next) { + netdata_rwlock_rdlock(&host->labels.labels_rwlock); + for (struct label *label = host->labels.head; label; label = label->next) { if(count > 0) buffer_strcat(wb, ",\n"); buffer_strcat(wb, tabs); @@ -881,7 +897,7 @@ inline void host_labels2json(RRDHOST *host, BUFFER *wb, size_t indentation) { count++; } buffer_strcat(wb, "\n"); - netdata_rwlock_unlock(&host->labels_rwlock); + netdata_rwlock_unlock(&host->labels.labels_rwlock); rrdhost_unlock(host); } |