summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorIlya Mashchenko <ilya@netdata.cloud>2020-12-14 17:27:55 +0300
committerGitHub <noreply@github.com>2020-12-14 17:27:55 +0300
commit0f8175dd3060691394e263cdab01c8f940b1b5d3 (patch)
tree4b14cd6b7e6ba7797eeec4c74b4c4c35cdad4494 /web
parent7bfa8c8eba72a109d940b1fa5c7acaed9cd7a52c (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.c43
-rw-r--r--web/api/formatters/json_wrapper.h2
-rw-r--r--web/api/formatters/rrd2json.c25
-rw-r--r--web/api/formatters/rrd2json.h1
-rw-r--r--web/api/formatters/rrdset2json.c34
-rw-r--r--web/api/web_api_v1.c32
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);
}