2
3
#include "json_wrapper.h"
4
5
-struct value_output {
6
- int c;
7
- BUFFER *wb;
8
-};
9
-
10
-static int value_list_output_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) {
11
- struct value_output *ap = (struct value_output *)data;
12
- BUFFER *wb = ap->wb;
13
- char *output = (char *) entry;
14
- if(ap->c) buffer_strcat(wb, ",");
15
- buffer_strcat(wb, output);
16
- (ap->c)++;
17
- return 0;
18
-}
19
-
20
-static int fill_formatted_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
21
- (void)ls;
22
- DICTIONARY *dict = (DICTIONARY *)data;
23
- char n[RRD_ID_LENGTH_MAX * 2 + 2];
24
- char output[RRD_ID_LENGTH_MAX * 2 + 8];
25
- char v[RRD_ID_LENGTH_MAX * 2 + 1];
26
-
27
- sanitize_json_string(v, (char *)value, RRD_ID_LENGTH_MAX * 2);
28
- int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\", \"%s\"]", name, v);
29
- snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, v);
30
- dictionary_set(dict, n, output, len + 1);
31
-
32
- return 1;
33
-}
34
-
35
-void rrdr_show_plan(RRDR *r, BUFFER *wb, const char *kq, const char *sq __maybe_unused) {
5
+void jsonwrap_query_plan(RRDR *r, BUFFER *wb) {
6
QUERY_TARGET *qt = r->internal.qt;
7
38
- buffer_sprintf(wb, "\n\t%squery_plan%s: {", kq, kq);
39
-
8
+ buffer_json_member_add_object(wb, "query_plan");
9
for(size_t m = 0; m < qt->query.used; m++) {
10
QUERY_METRIC *qm = &qt->query.array[m];
11
43
- if(m)
44
- buffer_strcat(wb, ",");
45
-
46
- buffer_sprintf(wb, "\n\t\t%s%s%s: {", kq, string2str(qm->dimension.id), kq);
47
-
48
- buffer_sprintf(wb, "\n\t\t\t%splans%s: [", kq, kq);
49
- for(size_t p = 0; p < qm->plan.used ;p++) {
50
- QUERY_PLAN_ENTRY *qp = &qm->plan.array[p];
51
- if(p)
52
- buffer_strcat(wb, ",");
53
-
54
- buffer_strcat(wb, "\n\t\t\t\t{");
55
- buffer_sprintf(wb, "\n\t\t\t\t\t%stier%s: %zu,", kq, kq, qp->tier);
56
- buffer_sprintf(wb, "\n\t\t\t\t\t%safter%s: %ld,", kq, kq, qp->after);
57
- buffer_sprintf(wb, "\n\t\t\t\t\t%sbefore%s: %ld", kq, kq, qp->before);
58
- buffer_strcat(wb, "\n\t\t\t\t}");
59
- }
60
- buffer_strcat(wb, "\n\t\t\t],");
61
-
62
- buffer_sprintf(wb, "\n\t\t\t%stiers%s: [", kq, kq);
63
- for(size_t tier = 0; tier < storage_tiers ;tier++) {
64
- if(tier)
65
- buffer_strcat(wb, ",");
66
-
67
- buffer_strcat(wb, "\n\t\t\t\t{");
68
- buffer_sprintf(wb, "\n\t\t\t\t\t%stier%s: %zu,", kq, kq, tier);
69
- buffer_sprintf(wb, "\n\t\t\t\t\t%sdb_first_time%s: %ld,", kq, kq, qm->tiers[tier].db_first_time_s);
70
- buffer_sprintf(wb, "\n\t\t\t\t\t%sdb_last_time%s: %ld,", kq, kq, qm->tiers[tier].db_last_time_s);
71
- buffer_sprintf(wb, "\n\t\t\t\t\t%sweight%s: %ld", kq, kq, qm->tiers[tier].weight);
72
- buffer_strcat(wb, "\n\t\t\t\t}");
12
+ buffer_json_member_add_object(wb, string2str(qm->dimension.id));
13
+ {
14
+ buffer_json_member_add_array(wb, "plans");
15
+ for (size_t p = 0; p < qm->plan.used; p++) {
16
+ QUERY_PLAN_ENTRY *qp = &qm->plan.array[p];
17
+
18
+ buffer_json_add_array_item_object(wb);
19
+ buffer_json_member_add_uint64(wb, "tier", qp->tier);
20
+ buffer_json_member_add_time_t(wb, "after", qp->after);
21
+ buffer_json_member_add_time_t(wb, "before", qp->before);
22
+ buffer_json_object_close(wb);
23
+ }
24
+ buffer_json_array_close(wb);
25
+
26
+ buffer_json_member_add_array(wb, "tiers");
27
+ for (size_t tier = 0; tier < storage_tiers; tier++) {
28
+ buffer_json_add_array_item_object(wb);
29
+ buffer_json_member_add_uint64(wb, "tier", tier);
30
+ buffer_json_member_add_time_t(wb, "db_first_time", qm->tiers[tier].db_first_time_s);
31
+ buffer_json_member_add_time_t(wb, "db_last_time", qm->tiers[tier].db_last_time_s);
32
+ buffer_json_member_add_int64(wb, "weight", qm->tiers[tier].weight);
33
+ buffer_json_object_close(wb);
34
+ }
35
+ buffer_json_array_close(wb);
36
}
74
- buffer_strcat(wb, "\n\t\t\t]");
75
-
76
- buffer_strcat(wb, "\n\t\t}");
37
+ buffer_json_object_close(wb);
38
}
78
-
79
- buffer_strcat(wb, "\n\t},");
39
+ buffer_json_object_close(wb);
40
}
41
82
-void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
83
- RRDR_GROUPING group_method)
84
-{
42
+static inline long jsonwrap_dimension_names(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
43
QUERY_TARGET *qt = r->internal.qt;
86
-
87
- long rows = rrdr_rows(r);
88
- long c, i;
44
const long query_used = qt->query.used;
45
+ long c, i;
46
91
- //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
92
- char kq[2] = "", // key quote
93
- sq[2] = ""; // string quote
94
-
95
- if( options & RRDR_OPTION_GOOGLE_JSON ) {
96
- kq[0] = '\0';
97
- sq[0] = '\'';
98
- }
99
- else {
100
- kq[0] = '"';
101
- sq[0] = '"';
102
- }
103
-
104
- buffer_sprintf(wb, "{\n"
105
- " %sapi%s: 1,\n"
106
- " %sid%s: %s%s%s,\n"
107
- " %sname%s: %s%s%s,\n"
108
- " %sview_update_every%s: %lld,\n"
109
- " %supdate_every%s: %lld,\n"
110
- " %sfirst_entry%s: %lld,\n"
111
- " %slast_entry%s: %lld,\n"
112
- " %sbefore%s: %lld,\n"
113
- " %safter%s: %lld,\n"
114
- " %sgroup%s: %s%s%s,\n"
115
- " %soptions%s: %s"
116
- , kq, kq
117
- , kq, kq, sq, qt->id, sq
118
- , kq, kq, sq, qt->id, sq
119
- , kq, kq, (long long)r->update_every
120
- , kq, kq, (long long)qt->db.minimum_latest_update_every_s
121
- , kq, kq, (long long)qt->db.first_time_s
122
- , kq, kq, (long long)qt->db.last_time_s
123
- , kq, kq, (long long)r->before
124
- , kq, kq, (long long)r->after
125
- , kq, kq, sq, web_client_api_request_v1_data_group_to_string(group_method), sq
126
- , kq, kq, sq);
127
-
128
- web_client_api_request_v1_data_options_to_buffer(wb, r->internal.query_options);
129
-
130
- buffer_sprintf(wb, "%s,\n %sdimension_names%s: [", sq, kq, kq);
131
-
47
+ buffer_json_member_add_array(wb, key);
48
for(c = 0, i = 0; c < query_used ; c++) {
133
- if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
134
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
135
- if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
136
-
137
- if(i) buffer_strcat(wb, ", ");
138
- buffer_strcat(wb, sq);
139
- buffer_strcat(wb, string2str(qt->query.array[c].dimension.name));
140
- buffer_strcat(wb, sq);
49
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
50
+ continue;
51
+
52
+ buffer_json_add_array_item_string(wb, string2str(qt->query.array[c].dimension.name));
53
i++;
54
}
143
- if(!i) {
144
-#ifdef NETDATA_INTERNAL_CHECKS
145
- error("QUERY: '%s', RRDR is empty, %zu dimensions, options is 0x%08x", qt->id, r->d, options);
146
-#endif
147
- rows = 0;
148
- buffer_strcat(wb, sq);
149
- buffer_strcat(wb, "no data");
150
- buffer_strcat(wb, sq);
151
- }
55
+ buffer_json_array_close(wb);
56
153
- buffer_sprintf(wb, "],\n"
154
- " %sdimension_ids%s: ["
155
- , kq, kq);
57
+ return i;
58
+}
59
+
60
+static inline long jsonwrap_dimension_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
61
+ QUERY_TARGET *qt = r->internal.qt;
62
+ const long query_used = qt->query.used;
63
+ long c, i;
64
65
+ buffer_json_member_add_array(wb, key);
66
for(c = 0, i = 0; c < query_used ; c++) {
158
- if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
159
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
160
- if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
161
-
162
- if(i) buffer_strcat(wb, ", ");
163
- buffer_strcat(wb, sq);
164
- buffer_strcat(wb, string2str(qt->query.array[c].dimension.id));
165
- buffer_strcat(wb, sq);
67
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
68
+ continue;
69
+
70
+ buffer_json_add_array_item_string(wb, string2str(qt->query.array[c].dimension.id));
71
i++;
72
}
168
- if(!i) {
169
- rows = 0;
170
- buffer_strcat(wb, sq);
171
- buffer_strcat(wb, "no data");
172
- buffer_strcat(wb, sq);
173
- }
174
- buffer_strcat(wb, "],\n");
73
+ buffer_json_array_close(wb);
74
176
- if (r->internal.query_options & RRDR_OPTION_ALL_DIMENSIONS) {
177
- buffer_sprintf(wb, " %sfull_dimension_list%s: [", kq, kq);
75
+ return i;
76
+}
77
179
- char name[RRD_ID_LENGTH_MAX * 2 + 2];
180
- char output[RRD_ID_LENGTH_MAX * 2 + 8];
78
+static inline long jsonwrap_chart_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
79
+ QUERY_TARGET *qt = r->internal.qt;
80
+ const long query_used = qt->query.used;
81
+ long c, i;
82
182
- struct value_output co = {.c = 0, .wb = wb};
83
+ buffer_json_member_add_array(wb, key);
84
+ for (c = 0, i = 0; c < query_used; c++) {
85
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
86
+ continue;
87
184
- DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
185
- for (c = 0; c < (long)qt->metrics.used ;c++) {
186
- snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
187
- rrdmetric_acquired_id(qt->metrics.array[c]),
188
- rrdmetric_acquired_name(qt->metrics.array[c]));
88
+ QUERY_METRIC *qm = &qt->query.array[c];
89
+ buffer_json_add_array_item_string(wb, string2str(qm->chart.id));
90
+ i++;
91
+ }
92
+ buffer_json_array_close(wb);
93
190
- int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]",
191
- rrdmetric_acquired_id(qt->metrics.array[c]),
192
- rrdmetric_acquired_name(qt->metrics.array[c]));
94
+ return i;
95
+}
96
194
- dictionary_set(dict, name, output, len + 1);
195
- }
196
- dictionary_walkthrough_read(dict, value_list_output_callback, &co);
197
- dictionary_destroy(dict);
97
+struct rrdlabels_formatting_v2 {
98
+ BUFFER *wb;
99
+ DICTIONARY *dict;
100
+};
101
199
- co.c = 0;
200
- buffer_sprintf(wb, "],\n %sfull_chart_list%s: [", kq, kq);
201
- dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
202
- for (c = 0; c < (long)qt->instances.used ; c++) {
203
- RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
102
+static int rrdlabels_formatting_v2(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
103
+ struct rrdlabels_formatting_v2 *t = data;
104
+ BUFFER *wb = t->wb;
105
+ DICTIONARY *dict = t->dict;
106
205
- snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
206
- rrdinstance_acquired_id(ria),
207
- rrdinstance_acquired_name(ria));
107
+ char n[RRD_ID_LENGTH_MAX * 2 + 2];
108
+ snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, value);
109
+
110
+ bool existing = 0;
111
+ bool *set = dictionary_set(dict, n, &existing, sizeof(bool));
112
+ if(!*set) {
113
+ *set = true;
114
+ buffer_json_add_array_item_array(wb);
115
+ buffer_json_add_array_item_string(wb, name);
116
+ buffer_json_add_array_item_string(wb, value);
117
+ buffer_json_array_close(wb);
118
+ }
119
+
120
+ return 1;
121
+}
122
209
- int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]",
210
- rrdinstance_acquired_id(ria),
211
- rrdinstance_acquired_name(ria));
123
+static inline void jsonwrap_full_dimension_list(BUFFER *wb, RRDR *r) {
124
+ QUERY_TARGET *qt = r->internal.qt;
125
213
- dictionary_set(dict, name, output, len + 1);
126
+ char name[RRD_ID_LENGTH_MAX * 2 + 2];
127
+
128
+ buffer_json_member_add_array(wb, "full_dimension_list");
129
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
130
+ for (long c = 0; c < (long)qt->metrics.used ;c++) {
131
+ RRDMETRIC_ACQUIRED *rma = qt->metrics.array[c];
132
+
133
+ snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
134
+ rrdmetric_acquired_id(rma),
135
+ rrdmetric_acquired_name(rma));
136
+
137
+ bool existing = 0;
138
+ bool *set = dictionary_set(dict, name, &existing, sizeof(bool));
139
+ if(!*set) {
140
+ *set = true;
141
+ buffer_json_add_array_item_array(wb);
142
+ buffer_json_add_array_item_string(wb, rrdmetric_acquired_id(rma));
143
+ buffer_json_add_array_item_string(wb, rrdmetric_acquired_name(rma));
144
+ buffer_json_array_close(wb);
145
}
215
- dictionary_walkthrough_read(dict, value_list_output_callback, &co);
216
- dictionary_destroy(dict);
217
-
218
- co.c = 0;
219
- buffer_sprintf(wb, "],\n %sfull_chart_labels%s: [", kq, kq);
220
- dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
221
- for (c = 0; c < (long)qt->instances.used ; c++) {
222
- RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
223
- rrdlabels_walkthrough_read(rrdinstance_acquired_labels(ria), fill_formatted_callback, dict);
146
+ }
147
+ dictionary_destroy(dict);
148
+ buffer_json_array_close(wb);
149
+
150
+ buffer_json_member_add_array(wb, "full_chart_list");
151
+ dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
152
+ for (long c = 0; c < (long)qt->instances.used ; c++) {
153
+ RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
154
+
155
+ snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
156
+ rrdinstance_acquired_id(ria),
157
+ rrdinstance_acquired_name(ria));
158
+
159
+ bool existing = 0;
160
+ bool *set = dictionary_set(dict, name, &existing, sizeof(bool));
161
+ if(!*set) {
162
+ *set = true;
163
+ buffer_json_add_array_item_array(wb);
164
+ buffer_json_add_array_item_string(wb, rrdinstance_acquired_id(ria));
165
+ buffer_json_add_array_item_string(wb, rrdinstance_acquired_name(ria));
166
+ buffer_json_array_close(wb);
167
}
225
- dictionary_walkthrough_read(dict, value_list_output_callback, &co);
226
- dictionary_destroy(dict);
227
- buffer_strcat(wb, "],\n");
168
}
169
+ dictionary_destroy(dict);
170
+ buffer_json_array_close(wb);
171
+
172
+ buffer_json_member_add_array(wb, "full_chart_labels");
173
+ struct rrdlabels_formatting_v2 t = {
174
+ .wb = wb,
175
+ .dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE),
176
+ };
177
+ for (long c = 0; c < (long)qt->instances.used ; c++) {
178
+ RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
179
+ rrdlabels_walkthrough_read(rrdinstance_acquired_labels(ria), rrdlabels_formatting_v2, &t);
180
+ }
181
+ dictionary_destroy(t.dict);
182
+ buffer_json_array_close(wb);
183
+}
184
230
- // functions
231
- {
232
- DICTIONARY *funcs = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
233
- RRDINSTANCE_ACQUIRED *ria = NULL;
234
- for (c = 0; c < query_used ; c++) {
235
- QUERY_METRIC *qm = &qt->query.array[c];
236
- if(qm->link.ria == ria)
237
- continue;
185
+static inline void jsonwrap_functions(BUFFER *wb, const char *key, RRDR *r) {
186
+ QUERY_TARGET *qt = r->internal.qt;
187
+ const long query_used = qt->query.used;
188
239
- ria = qm->link.ria;
240
- chart_functions_to_dict(rrdinstance_acquired_functions(ria), funcs);
241
- }
189
+ DICTIONARY *funcs = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
190
+ RRDINSTANCE_ACQUIRED *ria = NULL;
191
+ for (long c = 0; c < query_used ; c++) {
192
+ QUERY_METRIC *qm = &qt->query.array[c];
193
+ if(qm->link.ria == ria)
194
+ continue;
195
243
- buffer_sprintf(wb, " %sfunctions%s: [", kq, kq);
244
- void *t; (void)t;
245
- dfe_start_read(funcs, t) {
246
- const char *comma = "";
247
- if(t_dfe.counter) comma = ", ";
248
- buffer_sprintf(wb, "%s%s%s%s", comma, sq, t_dfe.name, sq);
249
- }
250
- dfe_done(t);
251
- dictionary_destroy(funcs);
252
- buffer_strcat(wb, "],\n");
196
+ ria = qm->link.ria;
197
+ chart_functions_to_dict(rrdinstance_acquired_functions(ria), funcs);
198
}
199
255
- // context query
256
- if (!qt->request.st) {
257
- buffer_sprintf(
258
- wb,
259
- " %schart_ids%s: [",
260
- kq, kq);
200
+ buffer_json_member_add_array(wb, key);
201
+ void *t; (void)t;
202
+ dfe_start_read(funcs, t)
203
+ buffer_json_add_array_item_string(wb, t_dfe.name);
204
+ dfe_done(t);
205
+ dictionary_destroy(funcs);
206
+ buffer_json_array_close(wb);
207
+}
208
262
- for (c = 0, i = 0; c < query_used; c++) {
263
- QUERY_METRIC *qm = &qt->query.array[c];
209
+static inline long jsonwrap_chart_labels_filter(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
210
+ QUERY_TARGET *qt = r->internal.qt;
211
+ const long query_used = qt->query.used;
212
+ long c, i = 0;
213
+
214
+ buffer_json_member_add_object(wb, key);
215
265
- if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
266
- if (unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
267
- if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
216
+ SIMPLE_PATTERN *pattern = qt->instances.chart_label_key_pattern;
217
+ char *label_key = NULL;
218
+ while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
219
+ buffer_json_member_add_array(wb, label_key);
220
+
221
+ for (c = 0, i = 0; c < query_used; c++) {
222
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
223
continue;
224
270
- if (i)
271
- buffer_strcat(wb, ", ");
272
- buffer_strcat(wb, sq);
273
- buffer_strcat(wb, string2str(qm->chart.id));
274
- buffer_strcat(wb, sq);
225
+ QUERY_METRIC *qm = &qt->query.array[c];
226
+ rrdlabels_value_to_buffer_array_item_or_null(rrdinstance_acquired_labels(qm->link.ria), wb, label_key);
227
i++;
228
}
277
- if (!i) {
278
- rows = 0;
279
- buffer_strcat(wb, sq);
280
- buffer_strcat(wb, "no data");
281
- buffer_strcat(wb, sq);
282
- }
283
- buffer_strcat(wb, "],\n");
284
- if (qt->instances.chart_label_key_pattern) {
285
- buffer_sprintf(wb, " %schart_labels%s: { ", kq, kq);
286
-
287
- SIMPLE_PATTERN *pattern = qt->instances.chart_label_key_pattern;
288
- char *label_key = NULL;
289
- int keys = 0;
290
- while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
291
- if (keys)
292
- buffer_strcat(wb, ", ");
293
- buffer_sprintf(wb, "%s%s%s : [", kq, label_key, kq);
294
- keys++;
295
-
296
- for (c = 0, i = 0; c < query_used; c++) {
297
- QUERY_METRIC *qm = &qt->query.array[c];
298
-
299
- if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
300
- if (unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
301
- if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
302
- continue;
303
-
304
- if (i)
305
- buffer_strcat(wb, ", ");
306
- rrdlabels_get_value_to_buffer_or_null(rrdinstance_acquired_labels(qm->link.ria), wb, label_key, sq, "null");
307
- i++;
308
- }
309
- if (!i) {
310
- rows = 0;
311
- buffer_strcat(wb, sq);
312
- buffer_strcat(wb, "no data");
313
- buffer_strcat(wb, sq);
314
- }
315
- buffer_strcat(wb, "]");
316
- }
317
- buffer_strcat(wb, "},\n");
318
- }
229
+ buffer_json_array_close(wb);
230
}
231
321
- buffer_sprintf(wb, " %slatest_values%s: ["
322
- , kq, kq);
232
+ buffer_json_object_close(wb);
233
+
234
+ return i;
235
+}
236
+
237
+static inline long jsonwrap_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
238
+ QUERY_TARGET *qt = r->internal.qt;
239
+ const long query_used = qt->query.used;
240
+ long c, i;
241
+
242
+ buffer_json_member_add_array(wb, key);
243
244
for(c = 0, i = 0; c < query_used ;c++) {
245
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
246
+ continue;
247
+
248
QUERY_METRIC *qm = &qt->query.array[c];
249
+ buffer_json_add_array_item_double(wb, rrdmetric_acquired_last_stored_value(qm->link.rma));
250
+ i++;
251
+ }
252
327
- if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
328
- if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
253
+ buffer_json_array_close(wb);
254
330
- if(i) buffer_strcat(wb, ", ");
331
- i++;
255
+ return i;
256
+}
257
333
- NETDATA_DOUBLE value = rrdmetric_acquired_last_stored_value(qm->link.rma);
334
- if (NAN == value)
335
- buffer_strcat(wb, "null");
336
- else
337
- buffer_rrd_value(wb, value);
338
- }
339
- if(!i) {
340
- rows = 0;
341
- buffer_strcat(wb, "null");
342
- }
258
+static inline long jsonwrap_view_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
259
+ QUERY_TARGET *qt = r->internal.qt;
260
+ const long query_used = qt->query.used;
261
+ long c, i;
262
344
- buffer_sprintf(wb, "],\n"
345
- " %sview_latest_values%s: ["
346
- , kq, kq);
263
+ buffer_json_member_add_array(wb, key);
264
348
- i = 0;
349
- if(rows) {
350
- NETDATA_DOUBLE total = 1;
265
+ NETDATA_DOUBLE total = 1;
266
352
- if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
353
- total = 0;
354
- for(c = 0; c < query_used ;c++) {
355
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
267
+ if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
268
+ total = 0;
269
+ for(c = 0; c < query_used ;c++) {
270
+ if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
271
357
- NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
358
- NETDATA_DOUBLE n = cn[c];
272
+ NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
273
+ NETDATA_DOUBLE n = cn[c];
274
360
- if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
361
- n = -n;
275
+ if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
276
+ n = -n;
277
363
- total += n;
364
- }
365
- // prevent a division by zero
366
- if(total == 0) total = 1;
278
+ total += n;
279
}
280
+ // prevent a division by zero
281
+ if(total == 0) total = 1;
282
+ }
283
369
- for(c = 0, i = 0; c < query_used ;c++) {
370
- if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
371
- if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
372
- if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
284
+ for(c = 0, i = 0; c < query_used ;c++) {
285
+ if(!rrdr_dimension_should_be_exposed(r->od[c], options))
286
+ continue;
287
374
- if(i) buffer_strcat(wb, ", ");
375
- i++;
288
+ i++;
289
377
- NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
378
- RRDR_VALUE_FLAGS *co = &r->o[ (rrdr_rows(r) - 1) * r->d ];
379
- NETDATA_DOUBLE n = cn[c];
290
+ NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
291
+ RRDR_VALUE_FLAGS *co = &r->o[ (rrdr_rows(r) - 1) * r->d ];
292
+ NETDATA_DOUBLE n = cn[c];
293
381
- if(co[c] & RRDR_VALUE_EMPTY) {
382
- if(options & RRDR_OPTION_NULL2ZERO)
383
- buffer_strcat(wb, "0");
384
- else
385
- buffer_strcat(wb, "null");
386
- }
387
- else {
388
- if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
389
- n = -n;
294
+ if(co[c] & RRDR_VALUE_EMPTY) {
295
+ if(options & RRDR_OPTION_NULL2ZERO)
296
+ buffer_json_add_array_item_double(wb, 0.0);
297
+ else
298
+ buffer_json_add_array_item_double(wb, NAN);
299
+ }
300
+ else {
301
+ if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
302
+ n = -n;
303
391
- if(unlikely(options & RRDR_OPTION_PERCENTAGE))
392
- n = n * 100 / total;
304
+ if(unlikely(options & RRDR_OPTION_PERCENTAGE))
305
+ n = n * 100 / total;
306
394
- buffer_rrd_value(wb, n);
395
- }
307
+ buffer_json_add_array_item_double(wb, n);
308
}
309
}
398
- if(!i) {
399
- rows = 0;
400
- buffer_strcat(wb, "null");
310
+
311
+ buffer_json_array_close(wb);
312
+
313
+ return i;
314
+}
315
+
316
+void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
317
+ RRDR_TIME_GROUPING group_method)
318
+{
319
+ QUERY_TARGET *qt = r->internal.qt;
320
+
321
+ long rows = rrdr_rows(r);
322
+
323
+ char kq[2] = "", // key quote
324
+ sq[2] = ""; // string quote
325
+
326
+ if( options & RRDR_OPTION_GOOGLE_JSON ) {
327
+ kq[0] = '\0';
328
+ sq[0] = '\'';
329
+ }
330
+ else {
331
+ kq[0] = '"';
332
+ sq[0] = '"';
333
}
334
403
- buffer_sprintf(wb, "],\n"
404
- " %sdimensions%s: %ld,\n"
405
- " %spoints%s: %ld,\n"
406
- " %sformat%s: %s"
407
- , kq, kq, i
408
- , kq, kq, rows
409
- , kq, kq, sq
410
- );
335
+ buffer_json_initialize(wb, kq, sq, 0, true);
336
+
337
+ buffer_json_member_add_uint64(wb, "api", 1);
338
+ buffer_json_member_add_string(wb, "id", qt->id);
339
+ buffer_json_member_add_string(wb, "name", qt->id);
340
+ buffer_json_member_add_time_t(wb, "view_update_every", r->update_every);
341
+ buffer_json_member_add_time_t(wb, "update_every", qt->db.minimum_latest_update_every_s);
342
+ buffer_json_member_add_time_t(wb, "first_entry", qt->db.first_time_s);
343
+ buffer_json_member_add_time_t(wb, "last_entry", qt->db.last_time_s);
344
+ buffer_json_member_add_time_t(wb, "after", r->after);
345
+ buffer_json_member_add_time_t(wb, "before", r->before);
346
+ buffer_json_member_add_string(wb, "group", time_grouping_tostring(group_method));
347
+ web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", r->internal.query_options);
348
+
349
+ if(!jsonwrap_dimension_names(wb, "dimension_names", r, options))
350
+ rows = 0;
351
412
- rrdr_buffer_print_format(wb, format);
352
+ if(!jsonwrap_dimension_ids(wb, "dimension_ids", r, options))
353
+ rows = 0;
354
414
- buffer_sprintf(wb, "%s,\n"
415
- " %sdb_points_per_tier%s: [ "
416
- , sq
417
- , kq, kq
418
- );
355
+ if (r->internal.query_options & RRDR_OPTION_ALL_DIMENSIONS)
356
+ jsonwrap_full_dimension_list(wb, r);
357
420
- for(size_t tier = 0; tier < storage_tiers ; tier++)
421
- buffer_sprintf(wb, "%s%zu", tier>0?", ":"", r->internal.tier_points_read[tier]);
358
+ jsonwrap_functions(wb, "functions", r);
359
423
- buffer_strcat(wb, " ],");
360
+ if (!qt->request.st && !jsonwrap_chart_ids(wb, "chart_ids", r, options))
361
+ rows = 0;
362
425
- if(options & RRDR_OPTION_SHOW_PLAN)
426
- rrdr_show_plan(r, wb, kq, sq);
363
+ if (qt->instances.chart_label_key_pattern && !jsonwrap_chart_labels_filter(wb, "chart_labels", r, options))
364
+ rows = 0;
365
428
- buffer_sprintf(wb, "\n %sresult%s: ", kq, kq);
366
+ if(!jsonwrap_latest_values(wb, "latest_values", r, options))
367
+ rows = 0;
368
369
+ long dimensions = jsonwrap_view_latest_values(wb, "view_latest_values", r, options);
370
+ if(!dimensions)
371
+ rows = 0;
372
+
373
+ buffer_json_member_add_uint64(wb, "dimensions", dimensions);
374
+ buffer_json_member_add_uint64(wb, "points", rows);
375
+ buffer_json_member_add_string(wb, "format", rrdr_format_to_string(format));
376
+
377
+ buffer_json_member_add_array(wb, "db_points_per_tier");
378
+ for(size_t tier = 0; tier < storage_tiers ; tier++)
379
+ buffer_json_add_array_item_uint64(wb, r->internal.tier_points_read[tier]);
380
+ buffer_json_array_close(wb);
381
+
382
+ if(options & RRDR_OPTION_SHOW_PLAN)
383
+ jsonwrap_query_plan(r, wb);
384
+
385
+ buffer_sprintf(wb, ",\n %sresult%s:", kq, kq);
386
if(string_value) buffer_strcat(wb, sq);
431
- //info("JSONWRAPPER(): %s: END", r->st->id);
387
}
388
389
void rrdr_json_wrapper_anomaly_rates(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
410
void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
411
(void)format;
412
458
- char kq[2] = "", // key quote
459
- sq[2] = ""; // string quote
413
+ char sq[2] = ""; // string quote
414
415
if( options & RRDR_OPTION_GOOGLE_JSON ) {
462
- kq[0] = '\0';
416
sq[0] = '\'';
417
}
418
else {
466
- kq[0] = '"';
419
sq[0] = '"';
420
}
421
422
if(string_value) buffer_strcat(wb, sq);
423
472
- buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
473
- buffer_rrd_value(wb, r->min);
474
- buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
475
- buffer_rrd_value(wb, r->max);
476
- buffer_strcat(wb, "\n}\n");
424
+ buffer_json_member_add_double(wb, "min", r->min);
425
+ buffer_json_member_add_double(wb, "max", r->max);
426
+ buffer_json_finalize(wb);
427
}