summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorStelios Fragkakis <52996999+stelfrag@users.noreply.github.com>2020-09-15 19:41:39 +0300
committerGitHub <noreply@github.com>2020-09-15 19:41:39 +0300
commit8f6f1baf9a5686fbd06273ed081d4e40d51bdc74 (patch)
treea0bade47cb44b8ee4c8e2009bd3ee5ee6f3f1c09 /web
parent59a2aec9c8fb2dfbcfe80668571c39cc08af770c (diff)
Added context parameter to the data endpoint (#9931)
Added functionality to support composite charts
Diffstat (limited to 'web')
-rw-r--r--web/api/formatters/csv/csv.c10
-rw-r--r--web/api/formatters/csv/csv.h2
-rw-r--r--web/api/formatters/json/json.c12
-rw-r--r--web/api/formatters/json/json.h2
-rw-r--r--web/api/formatters/json_wrapper.c46
-rw-r--r--web/api/formatters/json_wrapper.h2
-rw-r--r--web/api/formatters/rrd2json.c118
-rw-r--r--web/api/formatters/rrd2json.h1
-rw-r--r--web/api/queries/query.c54
-rw-r--r--web/api/queries/rrdr.c13
-rw-r--r--web/api/queries/rrdr.h5
-rw-r--r--web/api/web_api_v1.c47
12 files changed, 226 insertions, 86 deletions
diff --git a/web/api/formatters/csv/csv.c b/web/api/formatters/csv/csv.c
index 53bf29828e..da0a6b5837 100644
--- a/web/api/formatters/csv/csv.c
+++ b/web/api/formatters/csv/csv.c
@@ -3,7 +3,7 @@
#include "libnetdata/libnetdata.h"
#include "csv.h"
-void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const char *startline, const char *separator, const char *endline, const char *betweenlines) {
+void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const char *startline, const char *separator, const char *endline, const char *betweenlines, RRDDIM *temp_rd) {
rrdset_check_rdlock(r->st);
//info("RRD2CSV(): %s: BEGIN", r->st->id);
@@ -11,7 +11,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
RRDDIM *d;
// print the csv header
- for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+ for(c = 0, i = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
@@ -31,7 +31,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
if(format == DATASOURCE_CSV_MARKDOWN) {
// print the --- line after header
- for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+ for(c = 0, i = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
@@ -89,7 +89,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
int set_min_max = 0;
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
total = 0;
- for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
calculated_number n = cn[c];
if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
@@ -103,7 +103,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
}
// for each dimension
- for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
diff --git a/web/api/formatters/csv/csv.h b/web/api/formatters/csv/csv.h
index a89742d346..cf6020de4d 100644
--- a/web/api/formatters/csv/csv.h
+++ b/web/api/formatters/csv/csv.h
@@ -5,7 +5,7 @@
#include "web/api/queries/rrdr.h"
-extern void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const char *startline, const char *separator, const char *endline, const char *betweenlines);
+extern void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const char *startline, const char *separator, const char *endline, const char *betweenlines, RRDDIM *temp_rd);
#include "../rrd2json.h"
diff --git a/web/api/formatters/json/json.c b/web/api/formatters/json/json.c
index 66b3b9c837..f28eb5738b 100644
--- a/web/api/formatters/json/json.c
+++ b/web/api/formatters/json/json.c
@@ -5,7 +5,7 @@
#define JSON_DATES_JS 1
#define JSON_DATES_TIMESTAMP 2
-void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
+void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, RRDDIM *temp_rd) {
rrdset_check_rdlock(r->st);
//info("RRD2JSON(): %s: BEGIN", r->st->id);
@@ -94,12 +94,14 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
RRDDIM *rd;
// print the header lines
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; 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;
buffer_strcat(wb, pre_label);
buffer_strcat(wb, rd->name);
+// buffer_strcat(wb, ".");
+// buffer_strcat(wb, rd->rrdset->name);
buffer_strcat(wb, post_label);
i++;
}
@@ -154,7 +156,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
if(row_annotations) {
// google supports one annotation per row
int annotation_found = 0;
- for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd ;c++, rd = rd->next) {
if(unlikely(!(r->od[c] & RRDR_DIMENSION_SELECTED))) continue;
if(co[c] & RRDR_VALUE_RESET) {
@@ -185,7 +187,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
int set_min_max = 0;
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
total = 0;
- for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
calculated_number n = cn[c];
if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
@@ -199,7 +201,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
}
// for each dimension
- for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; 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;
diff --git a/web/api/formatters/json/json.h b/web/api/formatters/json/json.h
index 01363ce014..6d73a3ffe4 100644
--- a/web/api/formatters/json/json.h
+++ b/web/api/formatters/json/json.h
@@ -5,6 +5,6 @@
#include "../rrd2json.h"
-extern void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable);
+extern void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, RRDDIM *temp_rd);
#endif //NETDATA_API_FORMATTER_JSON_H
diff --git a/web/api/formatters/json_wrapper.c b/web/api/formatters/json_wrapper.c
index 5ef2caf101..e838a969f8 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) {
+void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd) {
rrdset_check_rdlock(r->st);
long rows = rrdr_rows(r);
@@ -34,8 +34,8 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
" %safter%s: %u,\n"
" %sdimension_names%s: ["
, kq, kq
- , kq, kq, sq, r->st->id, sq
- , kq, kq, sq, r->st->name, sq
+ , kq, kq, sq, temp_rd?r->st->context:r->st->id, sq
+ , kq, kq, sq, temp_rd?r->st->context:r->st->name, sq
, kq, kq, r->update_every
, kq, kq, r->st->update_every
, kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
@@ -44,7 +44,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
, kq, kq, (uint32_t)r->after
, kq, kq);
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; 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;
@@ -68,7 +68,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
" %sdimension_ids%s: ["
, kq, kq);
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; 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;
@@ -85,11 +85,41 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
buffer_strcat(wb, sq);
}
+ // Composite charts
+ if (temp_rd) {
+ buffer_sprintf(
+ wb,
+ "],\n"
+ " %schart_ids%s: [",
+ kq, 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, ", ");
+ buffer_strcat(wb, sq);
+ buffer_strcat(wb, rd->rrdset->name);
+ buffer_strcat(wb, sq);
+ i++;
+ }
+ if (!i) {
+ rows = 0;
+ buffer_strcat(wb, sq);
+ buffer_strcat(wb, "no data");
+ buffer_strcat(wb, sq);
+ }
+ }
+
+
buffer_sprintf(wb, "],\n"
" %slatest_values%s: ["
, kq, kq);
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; 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;
@@ -125,7 +155,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
total = 0;
- for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
calculated_number *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
calculated_number n = cn[c];
@@ -138,7 +168,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
if(total == 0) total = 1;
}
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; 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;
diff --git a/web/api/formatters/json_wrapper.h b/web/api/formatters/json_wrapper.h
index 7cb7d34530..b502f02862 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);
+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_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 5672c69521..7b07d398ed 100644
--- a/web/api/formatters/rrd2json.c
+++ b/web/api/formatters/rrd2json.c
@@ -2,6 +2,26 @@
#include "web/api/web_api_v1.h"
+static inline void free_temp_rrddim(RRDDIM *temp_rd)
+{
+ if (unlikely(!temp_rd))
+ return;
+
+ RRDDIM *t;
+ while (temp_rd) {
+ t = temp_rd->next;
+ freez((char *)temp_rd->id);
+ freez((char *)temp_rd->name);
+#ifdef ENABLE_DBENGINE
+ if (temp_rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
+ freez(temp_rd->state->metric_uuid);
+#endif
+ freez(temp_rd->state);
+ freez(temp_rd);
+ temp_rd = t;
+ }
+}
+
void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
rrdset2json(st, wb, NULL, NULL, 0);
}
@@ -69,7 +89,10 @@ int rrdset2value_api_v1(
, time_t *db_before
, int *value_is_null
) {
- RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions);
+ RRDDIM *temp_rd = NULL;
+
+ RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions, temp_rd);
+
if(!r) {
if(value_is_null) *value_is_null = 1;
return HTTP_RESP_INTERNAL_SERVER_ERROR;
@@ -98,6 +121,8 @@ int rrdset2value_api_v1(
long i = (!(options & RRDR_OPTION_REVERSED))?rrdr_rows(r) - 1:0;
*n = rrdr2value(r, i, options, value_is_null);
+ free_temp_rrddim(temp_rd);
+
rrdr_free(r);
return HTTP_RESP_OK;
}
@@ -114,10 +139,45 @@ int rrdset2anything_api_v1(
, long group_time
, uint32_t options
, time_t *latest_timestamp
+ , char *context
) {
st->last_accessed_time = now_realtime_sec();
- RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL);
+ RRDDIM *temp_rd = NULL;
+
+ if (context) {
+ rrdhost_rdlock(st->rrdhost);
+ RRDSET *st1;
+ rrdset_foreach_read(st1, st->rrdhost) {
+ if (strcmp(st1->context, context) == 0) {
+ // Loop the dimensions of the chart
+ RRDDIM *rd1;
+ rrdset_rdlock(st1);
+ rrddim_foreach_read(rd1, st1) {
+ RRDDIM *rd = mallocz(rd1->memsize);
+ memcpy(rd, rd1, rd1->memsize);
+ rd->id = strdupz(rd1->id);
+ rd->name = strdupz(rd1->name);
+ rd->state = mallocz(sizeof(*rd->state));
+ memcpy(rd->state, rd1->state, sizeof(*rd->state));
+ memcpy(&rd->state->collect_ops, &rd1->state->collect_ops, sizeof(struct rrddim_collect_ops));
+ memcpy(&rd->state->query_ops, &rd1->state->query_ops, sizeof(struct rrddim_query_ops));
+#ifdef ENABLE_DBENGINE
+ if (rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
+ rd->state->metric_uuid = mallocz(sizeof(uuid_t));
+ uuid_copy(*rd->state->metric_uuid, *rd1->state->metric_uuid);
+ }
+#endif
+ rd->next = temp_rd;
+ temp_rd = rd;
+ }
+ rrdset_unlock(st1);
+ }
+ }
+ rrdhost_unlock(st->rrdhost);
+ }
+
+ RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL, temp_rd);
if(!r) {
buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
return HTTP_RESP_INTERNAL_SERVER_ERROR;
@@ -135,7 +195,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);
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
rrdr2ssv(r, wb, options, "", " ", "");
rrdr_json_wrapper_end(r, wb, format, options, 1);
}
@@ -148,7 +208,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);
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
rrdr2ssv(r, wb, options, "", ",", "");
rrdr_json_wrapper_end(r, wb, format, options, 1);
}
@@ -161,7 +221,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);
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
rrdr2ssv(r, wb, options, "[", ",", "]");
rrdr_json_wrapper_end(r, wb, format, options, 0);
}
@@ -174,42 +234,42 @@ 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);
- rrdr2csv(r, wb, format, options, "", ",", "\\n", "");
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
+ rrdr2csv(r, wb, format, options, "", ",", "\\n", "", temp_rd);
rrdr_json_wrapper_end(r, wb, format, options, 1);
}
else {
wb->contenttype = CT_TEXT_PLAIN;
- rrdr2csv(r, wb, format, options, "", ",", "\r\n", "");
+ rrdr2csv(r, wb, format, options, "", ",", "\r\n", "", temp_rd);
}
break;
case DATASOURCE_CSV_MARKDOWN:
if(options & RRDR_OPTION_JSON_WRAP) {
wb->contenttype = CT_APPLICATION_JSON;
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
- rrdr2csv(r, wb, format, options, "", "|", "\\n", "");
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
+ rrdr2csv(r, wb, format, options, "", "|", "\\n", "", temp_rd);
rrdr_json_wrapper_end(r, wb, format, options, 1);
}
else {
wb->contenttype = CT_TEXT_PLAIN;
- rrdr2csv(r, wb, format, options, "", "|", "\r\n", "");
+ rrdr2csv(r, wb, format, options, "", "|", "\r\n", "", temp_rd);
}
break;
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);
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
buffer_strcat(wb, "[\n");
- rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
+ rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd);
buffer_strcat(wb, "\n]");
rrdr_json_wrapper_end(r, wb, format, options, 0);
}
else {
wb->contenttype = CT_APPLICATION_JSON;
buffer_strcat(wb, "[\n");
- rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
+ rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd);
buffer_strcat(wb, "\n]");
}
break;
@@ -217,29 +277,29 @@ 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);
- rrdr2csv(r, wb, format, options, "", "\t", "\\n", "");
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
+ rrdr2csv(r, wb, format, options, "", "\t", "\\n", "", temp_rd);
rrdr_json_wrapper_end(r, wb, format, options, 1);
}
else {
wb->contenttype = CT_TEXT_PLAIN;
- rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "");
+ rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "", temp_rd);
}
break;
case DATASOURCE_HTML:
if(options & RRDR_OPTION_JSON_WRAP) {
wb->contenttype = CT_APPLICATION_JSON;
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
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", "");
+ rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "", temp_rd);
buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
rrdr_json_wrapper_end(r, wb, format, options, 1);
}
else {
wb->contenttype = CT_TEXT_HTML;
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", "");
+ rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\n", "", temp_rd);
buffer_strcat(wb, "</table>\n</center>\n</html>\n");
}
break;
@@ -248,9 +308,9 @@ 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);
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
- rrdr2json(r, wb, options, 1);
+ rrdr2json(r, wb, options, 1, temp_rd);
if(options & RRDR_OPTION_JSON_WRAP)
rrdr_json_wrapper_end(r, wb, format, options, 0);
@@ -260,9 +320,9 @@ int rrdset2anything_api_v1(
wb->contenttype = CT_APPLICATION_JSON;
if(options & RRDR_OPTION_JSON_WRAP)
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
- rrdr2json(r, wb, options, 1);
+ rrdr2json(r, wb, options, 1, temp_rd);
if(options & RRDR_OPTION_JSON_WRAP)
rrdr_json_wrapper_end(r, wb, format, options, 0);
@@ -271,9 +331,9 @@ 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);
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
- rrdr2json(r, wb, options, 0);
+ rrdr2json(r, wb, options, 0, temp_rd);
if(options & RRDR_OPTION_JSON_WRAP)
rrdr_json_wrapper_end(r, wb, format, options, 0);
@@ -284,15 +344,17 @@ int rrdset2anything_api_v1(
wb->contenttype = CT_APPLICATION_JSON;
if(options & RRDR_OPTION_JSON_WRAP)
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
- rrdr2json(r, wb, options, 0);
+ rrdr2json(r, wb, options, 0, temp_rd);
if(options & RRDR_OPTION_JSON_WRAP)
rrdr_json_wrapper_end(r, wb, format, options, 0);
break;
}
+ free_temp_rrddim(temp_rd);
+
rrdr_free(r);
return HTTP_RESP_OK;
}
diff --git a/web/api/formatters/rrd2json.h b/web/api/formatters/rrd2json.h
index 8fce4ef7b4..f235113480 100644
--- a/web/api/formatters/rrd2json.h
+++ b/web/api/formatters/rrd2json.h
@@ -65,6 +65,7 @@ extern int rrdset2anything_api_v1(
, long group_time
, uint32_t options
, time_t *latest_timestamp
+ , char *context
);
extern int rrdset2value_api_v1(
diff --git a/web/api/queries/query.c b/web/api/queries/query.c
index 68b3525715..6b46cc6bd2 100644
--- a/web/api/queries/query.c
+++ b/web/api/queries/query.c
@@ -281,7 +281,7 @@ RRDR_GROUPING web_client_api_request_v1_data_group(const char *name, RRDR_GROUPI
// ----------------------------------------------------------------------------
-static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options, const char *dims) {
+static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options, const char *dims, RRDDIM *temp_rd) {
rrdset_check_rdlock(r->st);
if(unlikely(!dims || !*dims || (dims[0] == '*' && dims[1] == '\0'))) return;
@@ -300,7 +300,7 @@ static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options,
RRDDIM *d;
long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
- for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d ;c++, d = d->next) {
if( (match_ids && simple_pattern_matches(pattern, d->id))
|| (match_names && simple_pattern_matches(pattern, d->name))
) {
@@ -332,7 +332,7 @@ static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options,
// but they are all zero
// enable the selected ones
// to avoid returning an empty chart
- for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d ;c++, d = d->next)
if(unlikely(r->od[c] & RRDR_DIMENSION_SELECTED))
r->od[c] |= RRDR_DIMENSION_NONZERO;
}
@@ -815,7 +815,8 @@ static RRDR *rrd2rrdr_fixedstep(
, int update_every
, time_t first_entry_t
, time_t last_entry_t
- , int absolute_period_requested
+ , int absolute_period_requested,
+ RRDDIM *temp_rd
) {
int aligned = !(options & RRDR_OPTION_NOT_ALIGNED);
@@ -824,7 +825,7 @@ static RRDR *rrd2rrdr_fixedstep(
long available_points = duration / update_every;
if(duration <= 0 || available_points <= 0)
- return rrdr_create(st, 1);
+ return rrdr_create(st, 1, temp_rd);
// check the number of wanted points in the result
if(unlikely(points_requested < 0)) points_requested = -points_requested;
@@ -982,7 +983,7 @@ static RRDR *rrd2rrdr_fixedstep(
// initialize our result set
// this also locks the chart for us
- RRDR *r = rrdr_create(st, points_wanted);
+ RRDR *r = rrdr_create(st, points_wanted, temp_rd);
if(unlikely(!r)) {
#ifdef NETDATA_INTERNAL_CHECKS
error("INTERNAL CHECK: Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after_wanted, (uint32_t)before_wanted, (uint32_t)duration, points_wanted);
@@ -1055,7 +1056,7 @@ static RRDR *rrd2rrdr_fixedstep(
rrdset_check_rdlock(st);
if(dimensions)
- rrdr_disable_not_selected_dimensions(r, options, dimensions);
+ rrdr_disable_not_selected_dimensions(r, options, dimensions, temp_rd);
// -------------------------------------------------------------------------
@@ -1066,7 +1067,7 @@ static RRDR *rrd2rrdr_fixedstep(
RRDDIM *rd;
long c, dimensions_used = 0, dimensions_nonzero = 0;
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
// if we need a percentage, we need to calculate all dimensions
if(unlikely(!(options & RRDR_OPTION_PERCENTAGE) && (r->od[c] & RRDR_DIMENSION_HIDDEN))) {
@@ -1159,7 +1160,7 @@ static RRDR *rrd2rrdr_fixedstep(
if(unlikely(options & RRDR_OPTION_NONZERO && !dimensions_nonzero)) {
// all the dimensions are zero
// mark them as NONZERO to send them all
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
r->od[c] |= RRDR_DIMENSION_NONZERO;
}
@@ -1184,6 +1185,7 @@ static RRDR *rrd2rrdr_variablestep(
, time_t last_entry_t
, int absolute_period_requested
, struct rrdeng_region_info *region_info_array
+ , RRDDIM *temp_rd
) {
int aligned = !(options & RRDR_OPTION_NOT_ALIGNED);
@@ -1193,7 +1195,7 @@ static RRDR *rrd2rrdr_variablestep(
if(duration <= 0 || available_points <= 0) {
freez(region_info_array);
- return rrdr_create(st, 1);
+ return rrdr_create(st, 1, temp_rd);
}
// check the number of wanted points in the result
@@ -1352,7 +1354,7 @@ static RRDR *rrd2rrdr_variablestep(
// initialize our result set
// this also locks the chart for us
- RRDR *r = rrdr_create(st, points_wanted);
+ RRDR *r = rrdr_create(st, points_wanted, temp_rd);
if(unlikely(!r)) {
#ifdef NETDATA_INTERNAL_CHECKS
error("INTERNAL CHECK: Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after_wanted, (uint32_t)before_wanted, (uint32_t)duration, points_wanted);
@@ -1428,7 +1430,7 @@ static RRDR *rrd2rrdr_variablestep(
rrdset_check_rdlock(st);
if(dimensions)
- rrdr_disable_not_selected_dimensions(r, options, dimensions);
+ rrdr_disable_not_selected_dimensions(r, options, dimensions, temp_rd);
// -------------------------------------------------------------------------
@@ -1439,7 +1441,7 @@ static RRDR *rrd2rrdr_variablestep(
RRDDIM *rd;
long c, dimensions_used = 0, dimensions_nonzero = 0;
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
// if we need a percentage, we need to calculate all dimensions
if(unlikely(!(options & RRDR_OPTION_PERCENTAGE) && (r->od[c] & RRDR_DIMENSION_HIDDEN))) {
@@ -1533,7 +1535,7 @@ static RRDR *rrd2rrdr_variablestep(
if(unlikely(options & RRDR_OPTION_NONZERO && !dimensions_nonzero)) {
// all the dimensions are zero
// mark them as NONZERO to send them all
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
r->od[c] |= RRDR_DIMENSION_NONZERO;
}
@@ -1554,11 +1556,21 @@ RRDR *rrd2rrdr(
, long resampling_time_requested
, RRDR_OPTIONS options
, const char *dimensions
-) {
+ , RRDDIM *temp_rd
+)
+{
int rrd_update_every;
int absolute_period_requested;
- time_t first_entry_t = rrdset_first_entry_t(st);
- time_t last_entry_t = rrdset_last_entry_t(st);
+
+ time_t first_entry_t;
+ time_t last_entry_t;
+ if (temp_rd) {
+ first_entry_t = rrddim_first_entry_t(temp_rd);
+ last_entry_t = rrddim_last_entry_t(temp_rd);
+ } else {
+ first_entry_t = rrdset_first_entry_t(st);
+ last_entry_t = rrdset_last_entry_t(st);
+ }
rrd_update_every = st->update_every;
absolute_period_requested = rrdr_convert_before_after_to_absolute(&after_requested, &before_requested,
@@ -1571,7 +1583,7 @@ RRDR *rrd2rrdr(
/* This call takes the chart read-lock */
regions = rrdeng_variable_step_boundaries(st, after_requested, before_requested,
- &region_info_array, &max_interval);
+ &region_info_array, &max_interval, temp_rd);
if (1 == regions) {
if (region_info_array) {
if (rrd_update_every != region_info_array[0].update_every) {
@@ -1585,7 +1597,7 @@ RRDR *rrd2rrdr(
}
return rrd2rrdr_fixedstep(st, points_requested, after_requested, before_requested, group_method,
resampling_time_requested, options, dimensions, rrd_update_every,
- first_entry_t, last_entry_t, absolute_period_requested);
+ first_entry_t, last_entry_t, absolute_period_requested, temp_rd);
} else {
if (rrd_update_every != (uint16_t)max_interval) {
rrd_update_every = (uint16_t) max_interval;
@@ -1596,11 +1608,11 @@ RRDR *rrd2r