Added context parameter to the data endpoint (#9931)
Added functionality to support composite charts
Stelios Fragkakis committed
Sep 15, 2020 at 19:41 UTC
8f6f1baf9a5686fbd06273ed081d4e40d51bdc74
16 files changed
+244
-91
daemon/unit_test.c
+2
-2
@@ -1673,7 +1673,7 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
1673
update_every = REGION_UPDATE_EVERY[current_region];
1674
long points = (time_end - time_start) / update_every - 1;
1675
for (i = 0 ; i < CHARTS ; ++i) {
1676
- RRDR *r = rrd2rrdr(st[i], points, time_start + update_every, time_end, RRDR_GROUPING_AVERAGE, 0, 0, NULL);
1676
+ RRDR *r = rrd2rrdr(st[i], points, time_start + update_every, time_end, RRDR_GROUPING_AVERAGE, 0, 0, NULL, NULL);
1677
if (!r) {
1678
fprintf(stderr, " DB-engine unittest %s: empty RRDR ### E R R O R ###\n", st[i]->name);
1679
return ++errors;
@@ -1792,7 +1792,7 @@ int test_dbengine(void)
1792
long points = (time_end[REGIONS - 1] - time_start[0]) / update_every - 1; // cover all time regions with RRDR
1793
long point_offset = (time_start[current_region] - time_start[0]) / update_every;
1794
for (i = 0 ; i < CHARTS ; ++i) {
1795
- RRDR *r = rrd2rrdr(st[i], points, time_start[0] + update_every, time_end[REGIONS - 1], RRDR_GROUPING_AVERAGE, 0, 0, NULL);
1795
+ RRDR *r = rrd2rrdr(st[i], points, time_start[0] + update_every, time_end[REGIONS - 1], RRDR_GROUPING_AVERAGE, 0, 0, NULL, NULL);
1796
if (!r) {
1797
fprintf(stderr, " DB-engine unittest %s: empty RRDR ### E R R O R ###\n", st[i]->name);
1798
++errors;
database/engine/rrdengineapi.c
+2
-2
@@ -376,7 +376,7 @@ static inline uint32_t *pginfo_to_points(struct rrdeng_page_info *page_info)
376
* @return number of regions with different data collection intervals.
377
*/
378
unsigned rrdeng_variable_step_boundaries(RRDSET *st, time_t start_time, time_t end_time,
379
- struct rrdeng_region_info **region_info_arrayp, unsigned *max_intervalp)
379
+ struct rrdeng_region_info **region_info_arrayp, unsigned *max_intervalp, RRDDIM *temp_rd)
380
{
381
struct pg_cache_page_index *page_index;
382
struct rrdengine_instance *ctx;
@@ -397,7 +397,7 @@ unsigned rrdeng_variable_step_boundaries(RRDSET *st, time_t start_time, time_t e
397
page_info_array = NULL;
398
399
rrdset_rdlock(st);
400
- for(rd_iter = st->dimensions, rd = NULL, min_time = (usec_t)-1 ; rd_iter ; rd_iter = rd_iter->next) {
400
+ for(rd_iter = temp_rd?temp_rd:st->dimensions, rd = NULL, min_time = (usec_t)-1 ; rd_iter ; rd_iter = rd_iter->next) {
401
/*
402
* Choose oldest dimension as reference. This is not equivalent to the union of all dimensions
403
* but it is a best effort approximation with a bias towards older metrics in a chart. It
database/engine/rrdengineapi.h
+1
-1
@@ -43,7 +43,7 @@ extern void rrdeng_store_metric_next(RRDDIM *rd, usec_t point_in_time, storage_n
43
extern int rrdeng_store_metric_finalize(RRDDIM *rd);
44
extern unsigned
45
rrdeng_variable_step_boundaries(RRDSET *st, time_t start_time, time_t end_time,
46
- struct rrdeng_region_info **region_info_arrayp, unsigned *max_intervalp);
46
+ struct rrdeng_region_info **region_info_arrayp, unsigned *max_intervalp, RRDDIM *temp_rd);
47
extern void rrdeng_load_metric_init(RRDDIM *rd, struct rrddim_query_handle *rrdimm_handle,
48
time_t start_time, time_t end_time);
49
extern storage_number rrdeng_load_metric_next(struct rrddim_query_handle *rrdimm_handle, time_t *current_time);
database/rrd.h
+13
@@ -1053,6 +1053,19 @@ static inline time_t rrdset_first_entry_t(RRDSET *st) {
1053
}
1054
}
1055
1056
+// get the timestamp of the last entry in the round robin database
1057
+static inline time_t rrddim_last_entry_t(RRDDIM *rd) {
1058
+ if (rd->rrdset->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
1059
+ return rd->state->query_ops.latest_time(rd);
1060
+ return (time_t)rd->rrdset->last_updated.tv_sec;
1061
+}
1062
+
1063
+static inline time_t rrddim_first_entry_t(RRDDIM *rd) {
1064
+ if (rd->rrdset->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
1065
+ return rd->state->query_ops.oldest_time(rd);
1066
+ return (time_t)(rd->rrdset->last_updated.tv_sec - rrdset_duration(rd->rrdset));
1067
+}
1068
+
1069
time_t rrdhost_last_entry_t(RRDHOST *h);
1070
1071
// get the last slot updated in the round robin database
web/api/formatters/csv/csv.c
+5
-5
@@ -3,7 +3,7 @@
3
#include "libnetdata/libnetdata.h"
4
#include "csv.h"
5
6
-void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const char *startline, const char *separator, const char *endline, const char *betweenlines) {
6
+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) {
7
rrdset_check_rdlock(r->st);
8
9
//info("RRD2CSV(): %s: BEGIN", r->st->id);
@@ -11,7 +11,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
11
RRDDIM *d;
12
13
// print the csv header
14
- for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
14
+ for(c = 0, i = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
15
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
16
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
17
@@ -31,7 +31,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
31
32
if(format == DATASOURCE_CSV_MARKDOWN) {
33
// print the --- line after header
34
- for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
34
+ for(c = 0, i = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
35
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
36
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
37
@@ -89,7 +89,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
89
int set_min_max = 0;
90
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
91
total = 0;
92
- for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
92
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
93
calculated_number n = cn[c];
94
95
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
103
}
104
105
// for each dimension
106
- for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
106
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
107
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
108
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
109
web/api/formatters/csv/csv.h
+1
-1
@@ -5,7 +5,7 @@
5
6
#include "web/api/queries/rrdr.h"
7
8
-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);
8
+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);
9
10
#include "../rrd2json.h"
11
web/api/formatters/json/json.c
+7
-5
@@ -5,7 +5,7 @@
5
#define JSON_DATES_JS 1
6
#define JSON_DATES_TIMESTAMP 2
7
8
-void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
8
+void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, RRDDIM *temp_rd) {
9
rrdset_check_rdlock(r->st);
10
11
//info("RRD2JSON(): %s: BEGIN", r->st->id);
@@ -94,12 +94,14 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
94
RRDDIM *rd;
95
96
// print the header lines
97
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
97
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
98
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
99
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
100
101
buffer_strcat(wb, pre_label);
102
buffer_strcat(wb, rd->name);
103
+// buffer_strcat(wb, ".");
104
+// buffer_strcat(wb, rd->rrdset->name);
105
buffer_strcat(wb, post_label);
106
i++;
107
}
@@ -154,7 +156,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
156
if(row_annotations) {
157
// google supports one annotation per row
158
int annotation_found = 0;
157
- for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
159
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd ;c++, rd = rd->next) {
160
if(unlikely(!(r->od[c] & RRDR_DIMENSION_SELECTED))) continue;
161
162
if(co[c] & RRDR_VALUE_RESET) {
@@ -185,7 +187,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
187
int set_min_max = 0;
188
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
189
total = 0;
188
- for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
190
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
191
calculated_number n = cn[c];
192
193
if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
@@ -199,7 +201,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
201
}
202
203
// for each dimension
202
- for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
204
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
205
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
206
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
207
web/api/formatters/json/json.h
+1
-1
@@ -5,6 +5,6 @@
5
6
#include "../rrd2json.h"
7
8
-extern void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable);
8
+extern void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, RRDDIM *temp_rd);
9
10
#endif //NETDATA_API_FORMATTER_JSON_H
web/api/formatters/json_wrapper.c
+38
-8
@@ -2,7 +2,7 @@
2
3
#include "json_wrapper.h"
4
5
-void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value) {
5
+void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd) {
6
rrdset_check_rdlock(r->st);
7
8
long rows = rrdr_rows(r);
@@ -34,8 +34,8 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
34
" %safter%s: %u,\n"
35
" %sdimension_names%s: ["
36
, kq, kq
37
- , kq, kq, sq, r->st->id, sq
38
- , kq, kq, sq, r->st->name, sq
37
+ , kq, kq, sq, temp_rd?r->st->context:r->st->id, sq
38
+ , kq, kq, sq, temp_rd?r->st->context:r->st->name, sq
39
, kq, kq, r->update_every
40
, kq, kq, r->st->update_every
41
, 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
44
, kq, kq, (uint32_t)r->after
45
, kq, kq);
46
47
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
47
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
48
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
49
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
50
@@ -68,7 +68,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
68
" %sdimension_ids%s: ["
69
, kq, kq);
70
71
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
71
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
72
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
73
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
74
@@ -85,11 +85,41 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
85
buffer_strcat(wb, sq);
86
}
87
88
+ // Composite charts
89
+ if (temp_rd) {
90
+ buffer_sprintf(
91
+ wb,
92
+ "],\n"
93
+ " %schart_ids%s: [",
94
+ kq, kq);
95
+
96
+ for (c = 0, i = 0, rd = temp_rd ; rd && c < r->d; c++, rd = rd->next) {
97
+ if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
98
+ continue;
99
+ if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
100
+ continue;
101
+
102
+ if (i)
103
+ buffer_strcat(wb, ", ");
104
+ buffer_strcat(wb, sq);
105
+ buffer_strcat(wb, rd->rrdset->name);
106
+ buffer_strcat(wb, sq);
107
+ i++;
108
+ }
109
+ if (!i) {
110
+ rows = 0;
111
+ buffer_strcat(wb, sq);
112
+ buffer_strcat(wb, "no data");
113
+ buffer_strcat(wb, sq);
114
+ }
115
+ }
116
+
117
+
118
buffer_sprintf(wb, "],\n"
119
" %slatest_values%s: ["
120
, kq, kq);
121
92
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
122
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
123
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
124
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
125
@@ -125,7 +155,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
155
156
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
157
total = 0;
128
- for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
158
+ for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
159
calculated_number *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
160
calculated_number n = cn[c];
161
@@ -138,7 +168,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
168
if(total == 0) total = 1;
169
}
170
141
- for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
171
+ for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
172
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
173
if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
174
web/api/formatters/json_wrapper.h
+1
-1
@@ -5,7 +5,7 @@
5
6
#include "rrd2json.h"
7
8
-extern void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value);
8
+extern void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value, RRDDIM *temp_rd);
9
extern void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value);
10
11
#endif //NETDATA_API_FORMATTER_JSON_WRAPPER_H
web/api/formatters/rrd2json.c
+90
-28
@@ -2,6 +2,26 @@
2
3
#include "web/api/web_api_v1.h"
4
5
+static inline void free_temp_rrddim(RRDDIM *temp_rd)
6
+{
7
+ if (unlikely(!temp_rd))
8
+ return;
9
+
10
+ RRDDIM *t;
11
+ while (temp_rd) {
12
+ t = temp_rd->next;
13
+ freez((char *)temp_rd->id);
14
+ freez((char *)temp_rd->name);
15
+#ifdef ENABLE_DBENGINE
16
+ if (temp_rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
17
+ freez(temp_rd->state->metric_uuid);
18
+#endif
19
+ freez(temp_rd->state);
20
+ freez(temp_rd);
21
+ temp_rd = t;
22
+ }
23
+}
24
+
25
void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
26
rrdset2json(st, wb, NULL, NULL, 0);
27
}
@@ -69,7 +89,10 @@ int rrdset2value_api_v1(
89
, time_t *db_before
90
, int *value_is_null
91
) {
72
- RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions);
92
+ RRDDIM *temp_rd = NULL;
93
+
94
+ RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions, temp_rd);
95
+
96
if(!r) {
97
if(value_is_null) *value_is_null = 1;
98
return HTTP_RESP_INTERNAL_SERVER_ERROR;
@@ -98,6 +121,8 @@ int rrdset2value_api_v1(
121
long i = (!(options & RRDR_OPTION_REVERSED))?rrdr_rows(r) - 1:0;
122
*n = rrdr2value(r, i, options, value_is_null);
123
124
+ free_temp_rrddim(temp_rd);
125
+
126
rrdr_free(r);
127
return HTTP_RESP_OK;
128
}
@@ -114,10 +139,45 @@ int rrdset2anything_api_v1(
139
, long group_time
140
, uint32_t options
141
, time_t *latest_timestamp
142
+ , char *context
143
) {
144
st->last_accessed_time = now_realtime_sec();
145
120
- RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL);
146
+ RRDDIM *temp_rd = NULL;
147
+
148
+ if (context) {
149
+ rrdhost_rdlock(st->rrdhost);
150
+ RRDSET *st1;
151
+ rrdset_foreach_read(st1, st->rrdhost) {
152
+ if (strcmp(st1->context, context) == 0) {
153
+ // Loop the dimensions of the chart
154
+ RRDDIM *rd1;
155
+ rrdset_rdlock(st1);
156
+ rrddim_foreach_read(rd1, st1) {
157
+ RRDDIM *rd = mallocz(rd1->memsize);
158
+ memcpy(rd, rd1, rd1->memsize);
159
+ rd->id = strdupz(rd1->id);
160
+ rd->name = strdupz(rd1->name);
161
+ rd->state = mallocz(sizeof(*rd->state));
162
+ memcpy(rd->state, rd1->state, sizeof(*rd->state));
163
+ memcpy(&rd->state->collect_ops, &rd1->state->collect_ops, sizeof(struct rrddim_collect_ops));
164
+ memcpy(&rd->state->query_ops, &rd1->state->query_ops, sizeof(struct rrddim_query_ops));
165
+#ifdef ENABLE_DBENGINE
166
+ if (rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
167
+ rd->state->metric_uuid = mallocz(sizeof(uuid_t));
168
+ uuid_copy(*rd->state->metric_uuid, *rd1->state->metric_uuid);
169
+ }
170
+#endif
171
+ rd->next = temp_rd;
172
+ temp_rd = rd;
173
+ }
174
+ rrdset_unlock(st1);
175
+ }
176
+ }
177
+ rrdhost_unlock(st->rrdhost);
178
+ }
179
+
180
+ RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, options, dimensions?buffer_tostring(dimensions):NULL, temp_rd);
181
if(!r) {
182
buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
183
return HTTP_RESP_INTERNAL_SERVER_ERROR;
@@ -135,7 +195,7 @@ int rrdset2anything_api_v1(
195
case DATASOURCE_SSV:
196
if(options & RRDR_OPTION_JSON_WRAP) {
197
wb->contenttype = CT_APPLICATION_JSON;
138
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
198
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
199
rrdr2ssv(r, wb, options, "", " ", "");
200
rrdr_json_wrapper_end(r, wb, format, options, 1);
201
}
@@ -148,7 +208,7 @@ int rrdset2anything_api_v1(
208
case DATASOURCE_SSV_COMMA:
209
if(options & RRDR_OPTION_JSON_WRAP) {
210
wb->contenttype = CT_APPLICATION_JSON;
151
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
211
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
212
rrdr2ssv(r, wb, options, "", ",", "");
213
rrdr_json_wrapper_end(r, wb, format, options, 1);
214
}
@@ -161,7 +221,7 @@ int rrdset2anything_api_v1(
221
case DATASOURCE_JS_ARRAY:
222
if(options & RRDR_OPTION_JSON_WRAP) {
223
wb->contenttype = CT_APPLICATION_JSON;
164
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
224
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
225
rrdr2ssv(r, wb, options, "[", ",", "]");
226
rrdr_json_wrapper_end(r, wb, format, options, 0);
227
}
@@ -174,42 +234,42 @@ int rrdset2anything_api_v1(
234
case DATASOURCE_CSV:
235
if(options & RRDR_OPTION_JSON_WRAP) {
236
wb->contenttype = CT_APPLICATION_JSON;
177
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
178
- rrdr2csv(r, wb, format, options, "", ",", "\\n", "");
237
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
238
+ rrdr2csv(r, wb, format, options, "", ",", "\\n", "", temp_rd);
239
rrdr_json_wrapper_end(r, wb, format, options, 1);
240
}
241
else {
242
wb->contenttype = CT_TEXT_PLAIN;
183
- rrdr2csv(r, wb, format, options, "", ",", "\r\n", "");
243
+ rrdr2csv(r, wb, format, options, "", ",", "\r\n", "", temp_rd);
244
}
245
break;
246
247
case DATASOURCE_CSV_MARKDOWN:
248
if(options & RRDR_OPTION_JSON_WRAP) {
249
wb->contenttype = CT_APPLICATION_JSON;
190
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
191
- rrdr2csv(r, wb, format, options, "", "|", "\\n", "");
250
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
251
+ rrdr2csv(r, wb, format, options, "", "|", "\\n", "", temp_rd);
252
rrdr_json_wrapper_end(r, wb, format, options, 1);
253
}
254
else {
255
wb->contenttype = CT_TEXT_PLAIN;
196
- rrdr2csv(r, wb, format, options, "", "|", "\r\n", "");
256
+ rrdr2csv(r, wb, format, options, "", "|", "\r\n", "", temp_rd);
257
}
258
break;
259
260
case DATASOURCE_CSV_JSON_ARRAY:
261
wb->contenttype = CT_APPLICATION_JSON;
262
if(options & RRDR_OPTION_JSON_WRAP) {
203
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
263
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
264
buffer_strcat(wb, "[\n");
205
- rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
265
+ rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd);
266
buffer_strcat(wb, "\n]");
267
rrdr_json_wrapper_end(r, wb, format, options, 0);
268
}
269
else {
270
wb->contenttype = CT_APPLICATION_JSON;
271
buffer_strcat(wb, "[\n");
212
- rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
272
+ rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd);
273
buffer_strcat(wb, "\n]");
274
}
275
break;
@@ -217,29 +277,29 @@ int rrdset2anything_api_v1(
277
case DATASOURCE_TSV:
278
if(options & RRDR_OPTION_JSON_WRAP) {
279
wb->contenttype = CT_APPLICATION_JSON;
220
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
221
- rrdr2csv(r, wb, format, options, "", "\t", "\\n", "");
280
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
281
+ rrdr2csv(r, wb, format, options, "", "\t", "\\n", "", temp_rd);
282
rrdr_json_wrapper_end(r, wb, format, options, 1);
283
}
284
else {
285
wb->contenttype = CT_TEXT_PLAIN;
226
- rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "");
286
+ rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "", temp_rd);
287
}
288
break;
289
290
case DATASOURCE_HTML:
291
if(options & RRDR_OPTION_JSON_WRAP) {
292
wb->contenttype = CT_APPLICATION_JSON;
233
- rrdr_json_wrapper_begin(r, wb, format, options, 1);
293
+ rrdr_json_wrapper_begin(r, wb, format, options, 1, temp_rd);
294
buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
235
- rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
295
+ rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "", temp_rd);
296
buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
297
rrdr_json_wrapper_end(r, wb, format, options, 1);
298
}
299
else {
300
wb->contenttype = CT_TEXT_HTML;
301
buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
242
- rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
302
+ rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\n", "", temp_rd);
303
buffer_strcat(wb, "</table>\n</center>\n</html>\n");
304
}
305
break;
@@ -248,9 +308,9 @@ int rrdset2anything_api_v1(
308
wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
309
310
if(options & RRDR_OPTION_JSON_WRAP)
251
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
311
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
312
253
- rrdr2json(r, wb, options, 1);
313
+ rrdr2json(r, wb, options, 1, temp_rd);
314
315
if(options & RRDR_OPTION_JSON_WRAP)
316
rrdr_json_wrapper_end(r, wb, format, options, 0);
@@ -260,9 +320,9 @@ int rrdset2anything_api_v1(
320
wb->contenttype = CT_APPLICATION_JSON;
321
322
if(options & RRDR_OPTION_JSON_WRAP)
263
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
323
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
324
265
- rrdr2json(r, wb, options, 1);
325
+ rrdr2json(r, wb, options, 1, temp_rd);
326
327
if(options & RRDR_OPTION_JSON_WRAP)
328
rrdr_json_wrapper_end(r, wb, format, options, 0);
@@ -271,9 +331,9 @@ int rrdset2anything_api_v1(
331
case DATASOURCE_JSONP:
332
wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
333
if(options & RRDR_OPTION_JSON_WRAP)
274
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
334
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
335
276
- rrdr2json(r, wb, options, 0);
336
+ rrdr2json(r, wb, options, 0, temp_rd);
337
338
if(options & RRDR_OPTION_JSON_WRAP)
339
rrdr_json_wrapper_end(r, wb, format, options, 0);
@@ -284,15 +344,17 @@ int rrdset2anything_api_v1(
344
wb->contenttype = CT_APPLICATION_JSON;
345
346
if(options & RRDR_OPTION_JSON_WRAP)
287
- rrdr_json_wrapper_begin(r, wb, format, options, 0);
347
+ rrdr_json_wrapper_begin(r, wb, format, options, 0, temp_rd);
348
289
- rrdr2json(r, wb, options, 0);
349
+ rrdr2json(r, wb, options, 0, temp_rd);
350
351
if(options & RRDR_OPTION_JSON_WRAP)
352
rrdr_json_wrapper_end(r, wb, format, options, 0);
353
break;
354
}
355
356
+ free_temp_rrddim(temp_rd);
357
+
358
rrdr_free(r);
359
return HTTP_RESP_OK;
360
}
web/api/formatters/rrd2json.h
+1
@@ -65,6 +65,7 @@ extern int rrdset2anything_api_v1(
65
, long group_time
66
, uint32_t options
67
, time_t *latest_timestamp
68
+ , char *context
69
);
70
71
extern int rrdset2value_api_v1(
web/api/queries/query.c
+33
-21
@@ -281,7 +281,7 @@ RRDR_GROUPING web_client_api_request_v1_data_group(const char *name, RRDR_GROUPI
281
282
// ----------------------------------------------------------------------------
283
284
-static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options, const char *dims) {
284
+static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options, const char *dims, RRDDIM *temp_rd) {
285
rrdset_check_rdlock(r->st);
286
287
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,
300
301
RRDDIM *d;
302
long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
303
- for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
303
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d ;c++, d = d->next) {
304
if( (match_ids && simple_pattern_matches(pattern, d->id))
305
|| (match_names && simple_pattern_matches(pattern, d->name))
306
) {
@@ -332,7 +332,7 @@ static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options,
332
// but they are all zero
333
// enable the selected ones
334
// to avoid returning an empty chart
335
- for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
335
+ for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d ;c++, d = d->next)
336
if(unlikely(r->od[c] & RRDR_DIMENSION_SELECTED))
337
r->od[c] |= RRDR_DIMENSION_NONZERO;
338
}
@@ -815,7 +815,8 @@ static RRDR *rrd2rrdr_fixedstep(
815
, int update_every
816
, time_t first_entry_t
817
, time_t last_entry_t
818
- , int absolute_period_requested
818
+ , int absolute_period_requested,
819
+ RRDDIM *temp_rd
820
) {
821
int aligned = !(options & RRDR_OPTION_NOT_ALIGNED);
822
@@ -824,7 +825,7 @@ static RRDR *rrd2rrdr_fixedstep(
825
long available_points = duration / update_every;
826
827
if(duration <= 0 || available_points <= 0)
827
- return rrdr_create(st, 1);
828
+ return rrdr_create(st, 1, temp_rd);
829
830
// check the number of wanted points in the result
831
if(unlikely(points_requested < 0)) points_requested = -points_requested;
@@ -982,7 +983,7 @@ static RRDR *rrd2rrdr_fixedstep(
983
// initialize our result set
984
// this also locks the chart for us
985
985
- RRDR *r = rrdr_create(st, points_wanted);
986
+ RRDR *r = rrdr_create(st, points_wanted, temp_rd);
987
if(unlikely(!r)) {
988
#ifdef NETDATA_INTERNAL_CHECKS
989
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(
1056
rrdset_check_rdlock(st);
1057
1058
if(dimensions)
1058
- rrdr_disable_not_selected_dimensions(r, options, dimensions);
1059
+ rrdr_disable_not_selected_dimensions(r, options, dimensions, temp_rd);
1060
1061
1062
// -------------------------------------------------------------------------
@@ -1066,7 +1067,7 @@ static RRDR *rrd2rrdr_fixedstep(
1067
1068
RRDDIM *rd;
1069
long c, dimensions_used = 0, dimensions_nonzero = 0;
1069
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1070
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1071
1072
// if we need a percentage, we need to calculate all dimensions
1073
if(unlikely(!(options & RRDR_OPTION_PERCENTAGE) && (r->od[c] & RRDR_DIMENSION_HIDDEN))) {
@@ -1159,7 +1160,7 @@ static RRDR *rrd2rrdr_fixedstep(
1160
if(unlikely(options & RRDR_OPTION_NONZERO && !dimensions_nonzero)) {
1161
// all the dimensions are zero
1162
// mark them as NONZERO to send them all
1162
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1163
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1164
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
1165
r->od[c] |= RRDR_DIMENSION_NONZERO;
1166
}
@@ -1184,6 +1185,7 @@ static RRDR *rrd2rrdr_variablestep(
1185
, time_t last_entry_t
1186
, int absolute_period_requested
1187
, struct rrdeng_region_info *region_info_array
1188
+ , RRDDIM *temp_rd
1189
) {
1190
int aligned = !(options & RRDR_OPTION_NOT_ALIGNED);
1191
@@ -1193,7 +1195,7 @@ static RRDR *rrd2rrdr_variablestep(
1195
1196
if(duration <= 0 || available_points <= 0) {
1197
freez(region_info_array);
1196
- return rrdr_create(st, 1);
1198
+ return rrdr_create(st, 1, temp_rd);
1199
}
1200
1201
// check the number of wanted points in the result
@@ -1352,7 +1354,7 @@ static RRDR *rrd2rrdr_variablestep(
1354
// initialize our result set
1355
// this also locks the chart for us
1356
1355
- RRDR *r = rrdr_create(st, points_wanted);
1357
+ RRDR *r = rrdr_create(st, points_wanted, temp_rd);
1358
if(unlikely(!r)) {
1359
#ifdef NETDATA_INTERNAL_CHECKS
1360
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(
1430
rrdset_check_rdlock(st);
1431
1432
if(dimensions)
1431
- rrdr_disable_not_selected_dimensions(r, options, dimensions);
1433
+ rrdr_disable_not_selected_dimensions(r, options, dimensions, temp_rd);
1434
1435
1436
// -------------------------------------------------------------------------
@@ -1439,7 +1441,7 @@ static RRDR *rrd2rrdr_variablestep(
1441
1442
RRDDIM *rd;
1443
long c, dimensions_used = 0, dimensions_nonzero = 0;
1442
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1444
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1445
1446
// if we need a percentage, we need to calculate all dimensions
1447
if(unlikely(!(options & RRDR_OPTION_PERCENTAGE) && (r->od[c] & RRDR_DIMENSION_HIDDEN))) {
@@ -1533,7 +1535,7 @@ static RRDR *rrd2rrdr_variablestep(
1535
if(unlikely(options & RRDR_OPTION_NONZERO && !dimensions_nonzero)) {
1536
// all the dimensions are zero
1537
// mark them as NONZERO to send them all
1536
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1538
+ for(rd = temp_rd?temp_rd:st->dimensions, c = 0 ; rd && c < dimensions_count ; rd = rd->next, c++) {
1539
if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
1540
r->od[c] |= RRDR_DIMENSION_NONZERO;
1541
}
@@ -1554,11 +1556,21 @@ RRDR *rrd2rrdr(
1556
, long resampling_time_requested
1557
, RRDR_OPTIONS options
1558
, const char *dimensions
1557
-) {
1559
+ , RRDDIM *temp_rd
1560
+)
1561
+{
1562
int rrd_update_every;
1563
int absolute_period_requested;
1560
- time_t first_entry_t = rrdset_first_entry_t(st);
1561
- time_t last_entry_t = rrdset_last_entry_t(st);
1564
+
1565
+ time_t first_entry_t;
1566
+ time_t last_entry_t;
1567
+ if (temp_rd) {
1568
+ first_entry_t = rrddim_first_entry_t(temp_rd);
1569
+ last_entry_t = rrddim_last_entry_t(temp_rd);
1570
+ } else {
1571
+ first_entry_t = rrdset_first_entry_t(st);
1572
+ last_entry_t = rrdset_last_entry_t(st);
1573
+ }
1574
1575
rrd_update_every = st->update_every;
1576
absolute_period_requested = rrdr_convert_before_after_to_absolute(&after_requested, &before_requested,
@@ -1571,7 +1583,7 @@ RRDR *rrd2rrdr(
1583
1584
/* This call takes the chart read-lock */
1585
regions = rrdeng_variable_step_boundaries(st, after_requested, before_requested,
1574
- ®ion_info_array, &max_interval);
1586
+ ®ion_info_array, &max_interval, temp_rd);
1587
if (1 == regions) {
1588
if (region_info_array) {
1589
if (rrd_update_every != region_info_array[0].update_every) {
@@ -1585,7 +1597,7 @@ RRDR *rrd2rrdr(
1597
}
1598
return rrd2rrdr_fixedstep(st, points_requested, after_requested, before_requested, group_method,
1599
resampling_time_requested, options, dimensions, rrd_update_every,
1588
- first_entry_t, last_entry_t, absolute_period_requested);
1600
+ first_entry_t, last_entry_t, absolute_period_requested, temp_rd);
1601
} else {
1602
if (rrd_update_every != (uint16_t)max_interval) {
1603
rrd_update_every = (uint16_t) max_interval;
@@ -1596,11 +1608,11 @@ RRDR *rrd2rrdr(
1608
}
1609
return rrd2rrdr_variablestep(st, points_requested, after_requested, before_requested, group_method,
1610
resampling_time_requested, options, dimensions, rrd_update_every,
1599
- first_entry_t, last_entry_t, absolute_period_requested, region_info_array);
1611
+ first_entry_t, last_entry_t, absolute_period_requested, region_info_array, temp_rd);
1612
}
1613
}
1614
#endif
1615
return rrd2rrdr_fixedstep(st, points_requested, after_requested, before_requested, group_method,
1616
resampling_time_requested, options, dimensions,
1605
- rrd_update_every, first_entry_t, last_entry_t, absolute_period_requested);
1617
+ rrd_update_every, first_entry_t, last_entry_t, absolute_period_requested, temp_rd);
1618
}
\ No newline at end of file
web/api/queries/rrdr.c
+10
-3
@@ -98,7 +98,7 @@ inline void rrdr_free(RRDR *r)
98
freez(r);
99
}
100
101
-RRDR *rrdr_create(RRDSET *st, long n)
101
+RRDR *rrdr_create(struct rrdset *st, long n, struct rrddim *temp_rd)
102
{
103
if(unlikely(!st)) {
104
error("NULL value given!");
@@ -111,7 +111,14 @@ RRDR *rrdr_create(RRDSET *st, long n)
111
rrdr_lock_rrdset(r);
112
113
RRDDIM *rd;
114
- rrddim_foreach_read(rd, st) r->d++;
114
+ if (temp_rd) {
115
+ RRDDIM *t = temp_rd;
116
+ while (t) {
117
+ r->d++;
118
+ t = t->next;
119
+ }
120
+ } else
121
+ rrddim_foreach_read(rd, st) r->d++;
122
123
r->n = n;
124
@@ -122,7 +129,7 @@ RRDR *rrdr_create(RRDSET *st, long n)
129
130
// set the hidden flag on hidden dimensions
131
int c;
125
- for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
132
+ for(c = 0, rd = temp_rd?temp_rd:st->dimensions ; rd ; c++, rd = rd->next) {
133
if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)))
134
r->od[c] = RRDR_DIMENSION_HIDDEN;
135
else
web/api/queries/rrdr.h
+3
-2
@@ -97,13 +97,14 @@ typedef struct rrdresult {
97
98
#define rrdr_rows(r) ((r)->rows)
99
100
+#include "../../../database/rrd.h"
101
extern void rrdr_free(RRDR *r);
101
-extern RRDR *rrdr_create(struct rrdset *st, long n);
102
+extern RRDR *rrdr_create(struct rrdset *st, long n, struct rrddim *id);
103
104
#include "../web_api_v1.h"
105
#include "web/api/queries/query.h"
106
106
-extern RRDR *rrd2rrdr(RRDSET *st, long points_requested, long long after_requested, long long before_requested, RRDR_GROUPING group_method, long resampling_time_requested, RRDR_OPTIONS options, const char *dimensions);
107
+extern RRDR *rrd2rrdr(RRDSET *st, long points_requested, long long after_requested, long long before_requested, RRDR_GROUPING group_method, long resampling_time_requested, RRDR_OPTIONS options, const char *dimensions, RRDDIM *temp_rd);
108
109
#include "query.h"
110
web/api/web_api_v1.c
+36
-11
@@ -397,7 +397,8 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
397
, *before_str = NULL
398
, *after_str = NULL
399
, *group_time_str = NULL
400
- , *points_str = NULL;
400
+ , *points_str = NULL
401
+ , *context = NULL;
402
403
int group = RRDR_GROUPING_AVERAGE;
404
uint32_t format = DATASOURCE_JSON;
@@ -416,7 +417,8 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
417
// name and value are now the parameters
418
// they are not null and not empty
419
419
- if(!strcmp(name, "chart")) chart = value;
420
+ if(!strcmp(name, "context")) context = value;
421
+ else if(!strcmp(name, "chart")) chart = value;
422
else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
423
if(!dimensions) dimensions = buffer_create(100);
424
buffer_strcat(dimensions, "|");
@@ -482,18 +484,41 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
484
fix_google_param(responseHandler);
485
fix_google_param(outFileName);
486
485
- if(!chart || !*chart) {
487
+ RRDSET *st = NULL;
488
+
489
+ if((!chart || !*chart) && (!context)) {
490
buffer_sprintf(w->response.data, "No chart id is given at the request.");
491
goto cleanup;
492
}
493
490
- RRDSET *st = rrdset_find(host, chart);
491
- if(!st) st = rrdset_find_byname(host, chart);
492
- if(!st) {
493
- buffer_strcat(w->response.data, "Chart is not found: ");
494
- buffer_strcat_htmlescape(w->response.data, chart);
495
- ret = HTTP_RESP_NOT_FOUND;
496
- goto cleanup;
494
+ if (context) {
495
+ st = NULL;
496
+ // TODO: Scan all charts of host
497
+ rrdhost_rdlock(localhost);
498
+ RRDSET *st1;
499
+ rrdset_foreach_read(st1, localhost) {
500
+ if (strcmp(st1->context, context) == 0) {
501
+ st = st1;
502
+ break;
503
+ }
504
+ }
505
+ rrdhost_unlock(localhost);
506
+ }
507
+
508
+ if (!st) {
509
+ if (!chart || !*chart) {
510
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
511
+ goto cleanup;
512
+ }
513
+ st = rrdset_find(host, chart);
514
+ if (!st)
515
+ st = rrdset_find_byname(host, chart);
516
+ if (!st) {
517
+ buffer_strcat(w->response.data, "Chart is not found: ");
518
+ buffer_strcat_htmlescape(w->response.data, chart);
519
+ ret = HTTP_RESP_NOT_FOUND;
520
+ goto cleanup;
521
+ }
522
}
523
st->last_accessed_time = now_realtime_sec();
524
@@ -540,7 +565,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
565
}
566
567
ret = rrdset2anything_api_v1(st, w->response.data, dimensions, format, points, after, before, group, group_time
543
- , options, &last_timestamp_in_data);
568
+ , options, &last_timestamp_in_data, context);
569
570
if(format == DATASOURCE_DATATABLE_JSONP) {
571
if(google_timestamp < last_timestamp_in_data)