2
3
#include "json_wrapper.h"
4
5
+static void jsonwrap_query_metric_plan(BUFFER *wb, QUERY_METRIC *qm) {
6
+ buffer_json_member_add_array(wb, "plans");
7
+ for (size_t p = 0; p < qm->plan.used; p++) {
8
+ QUERY_PLAN_ENTRY *qp = &qm->plan.array[p];
9
+
10
+ buffer_json_add_array_item_object(wb);
11
+ buffer_json_member_add_uint64(wb, "tr", qp->tier);
12
+ buffer_json_member_add_time_t(wb, "af", qp->after);
13
+ buffer_json_member_add_time_t(wb, "bf", qp->before);
14
+ buffer_json_object_close(wb);
15
+ }
16
+ buffer_json_array_close(wb);
17
+
18
+ buffer_json_member_add_array(wb, "tiers");
19
+ for (size_t tier = 0; tier < storage_tiers; tier++) {
20
+ buffer_json_add_array_item_object(wb);
21
+ buffer_json_member_add_uint64(wb, "tr", tier);
22
+ buffer_json_member_add_time_t(wb, "fe", qm->tiers[tier].db_first_time_s);
23
+ buffer_json_member_add_time_t(wb, "le", qm->tiers[tier].db_last_time_s);
24
+ buffer_json_member_add_int64(wb, "wg", qm->tiers[tier].weight);
25
+ buffer_json_object_close(wb);
26
+ }
27
+ buffer_json_array_close(wb);
28
+}
29
+
30
void jsonwrap_query_plan(RRDR *r, BUFFER *wb) {
31
QUERY_TARGET *qt = r->internal.qt;
32
33
buffer_json_member_add_object(wb, "query_plan");
34
for(size_t m = 0; m < qt->query.used; m++) {
10
- QUERY_METRIC *qm = &qt->query.array[m];
11
-
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
- }
35
+ QUERY_METRIC *qm = query_metric(qt, m);
36
+ buffer_json_member_add_object(wb, query_metric_id(qt, qm));
37
+ jsonwrap_query_metric_plan(wb, qm);
38
buffer_json_object_close(wb);
39
}
40
buffer_json_object_close(wb);
41
}
42
42
-static inline long jsonwrap_dimension_names(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
43
- QUERY_TARGET *qt = r->internal.qt;
44
- const long query_used = qt->query.used;
45
- long c, i;
43
+static inline size_t rrdr_dimension_names(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
44
+ const size_t dimensions = r->d;
45
+ size_t c, i;
46
47
buffer_json_member_add_array(wb, key);
48
- for(c = 0, i = 0; c < query_used ; c++) {
48
+ for(c = 0, i = 0; c < dimensions ; c++) {
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));
52
+ buffer_json_add_array_item_string(wb, string2str(r->dn[c]));
53
i++;
54
}
55
buffer_json_array_close(wb);
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;
60
+static inline size_t rrdr_dimension_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
61
+ const size_t dimensions = r->d;
62
+ size_t c, i;
63
64
buffer_json_member_add_array(wb, key);
66
- for(c = 0, i = 0; c < query_used ; c++) {
65
+ for(c = 0, i = 0; c < dimensions ; c++) {
66
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
67
continue;
68
70
- buffer_json_add_array_item_string(wb, string2str(qt->query.array[c].dimension.id));
69
+ buffer_json_add_array_item_string(wb, string2str(r->di[c]));
70
i++;
71
}
72
buffer_json_array_close(wb);
74
return i;
75
}
76
78
-static inline long jsonwrap_chart_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
77
+static inline long jsonwrap_v1_chart_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
78
QUERY_TARGET *qt = r->internal.qt;
79
const long query_used = qt->query.used;
80
long c, i;
84
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
85
continue;
86
88
- QUERY_METRIC *qm = &qt->query.array[c];
89
- buffer_json_add_array_item_string(wb, string2str(qm->chart.id));
87
+ QUERY_METRIC *qm = query_metric(qt, c);
88
+ QUERY_INSTANCE *qi = query_instance(qt, qm->link.query_instance_id);
89
+ buffer_json_add_array_item_string(wb, string2str(qi->id_fqdn));
90
i++;
91
}
92
buffer_json_array_close(wb);
94
return i;
95
}
96
97
-struct rrdlabels_formatting_v2 {
98
- BUFFER *wb;
99
- DICTIONARY *dict;
100
-};
97
+static inline void query_target_metric_counts(BUFFER *wb, struct query_metrics_counts *metrics) {
98
+ buffer_json_member_add_object(wb, "ds");
99
+ buffer_json_member_add_uint64(wb, "sl", metrics->selected);
100
+ buffer_json_member_add_uint64(wb, "ex", metrics->excluded);
101
+ buffer_json_member_add_uint64(wb, "qr", metrics->queried);
102
+ buffer_json_member_add_uint64(wb, "fl", metrics->failed);
103
+ buffer_json_object_close(wb);
104
+}
105
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
+static inline void query_target_instance_counts(BUFFER *wb, struct query_instances_counts *instances) {
107
+ buffer_json_member_add_object(wb, "is");
108
+ buffer_json_member_add_uint64(wb, "sl", instances->selected);
109
+ buffer_json_member_add_uint64(wb, "ex", instances->excluded);
110
+ buffer_json_object_close(wb);
111
+}
112
107
- char n[RRD_ID_LENGTH_MAX * 2 + 2];
108
- snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, value);
113
+static inline void query_target_alerts_counts(BUFFER *wb, struct query_alerts_counts *alerts, const char *name, bool array) {
114
+ if(array)
115
+ buffer_json_add_array_item_object(wb);
116
+ else
117
+ buffer_json_member_add_object(wb, "al");
118
+
119
+ if(name)
120
+ buffer_json_member_add_string(wb, "nm", name);
121
+ buffer_json_member_add_uint64(wb, "cl", alerts->clear);
122
+ buffer_json_member_add_uint64(wb, "wr", alerts->warning);
123
+ buffer_json_member_add_uint64(wb, "cr", alerts->critical);
124
+ buffer_json_member_add_uint64(wb, "ot", alerts->other);
125
+ buffer_json_object_close(wb);
126
+}
127
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
- }
128
+static inline void query_target_data_statistics(BUFFER *wb, QUERY_TARGET *qt, struct query_data_statistics *d) {
129
+ buffer_json_member_add_object(wb, "sts");
130
+// buffer_json_member_add_double(wb, "min", d->min);
131
+// buffer_json_member_add_double(wb, "max", d->max);
132
+// buffer_json_member_add_double(wb, "sum", d->sum);
133
+ buffer_json_member_add_double(wb, "avg", (d->count) ? d->sum / (NETDATA_DOUBLE)d->count : 0.0);
134
+// buffer_json_member_add_double(wb, "vol", d->volume);
135
+ buffer_json_member_add_double(wb, "con", (qt->query_stats.volume > 0) ? d->volume * 100.0 / qt->query_stats.volume : 0.0);
136
+ buffer_json_object_close(wb);
137
+}
138
120
- return 1;
139
+static void query_target_summary_hosts_v2(BUFFER *wb, QUERY_TARGET *qt, const char *key) {
140
+ buffer_json_member_add_array(wb, key);
141
+ for (long c = 0; c < (long) qt->hosts.used; c++) {
142
+ QUERY_HOST *qh = query_host(qt, c);
143
+ RRDHOST *host = qh->host;
144
+ buffer_json_add_array_item_object(wb);
145
+ buffer_json_member_add_string(wb, "mg", host->machine_guid);
146
+ if(qh->node_id[0])
147
+ buffer_json_member_add_string(wb, "nd", qh->node_id);
148
+ buffer_json_member_add_string(wb, "nm", rrdhost_hostname(host));
149
+ query_target_instance_counts(wb, &qh->instances);
150
+ query_target_metric_counts(wb, &qh->metrics);
151
+ query_target_alerts_counts(wb, &qh->alerts, NULL, false);
152
+ query_target_data_statistics(wb, qt, &qh->query_stats);
153
+ buffer_json_object_close(wb);
154
+ }
155
+ buffer_json_array_close(wb);
156
}
157
123
-static inline void jsonwrap_full_dimension_list(BUFFER *wb, RRDR *r) {
124
- QUERY_TARGET *qt = r->internal.qt;
158
+static size_t query_target_summary_contexts_v2(BUFFER *wb, QUERY_TARGET *qt, const char *key) {
159
+ buffer_json_member_add_array(wb, key);
160
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
161
+
162
+ struct {
163
+ struct query_data_statistics query_stats;
164
+ struct query_instances_counts instances;
165
+ struct query_metrics_counts metrics;
166
+ struct query_alerts_counts alerts;
167
+ } x = {
168
+ .instances = (struct query_instances_counts){ 0 },
169
+ .metrics = (struct query_metrics_counts){ 0 },
170
+ .alerts = (struct query_alerts_counts){ 0 },
171
+ }, *z;
172
+
173
+ for (long c = 0; c < (long) qt->contexts.used; c++) {
174
+ QUERY_CONTEXT *qc = query_context(qt, c);
175
+
176
+ z = dictionary_set(dict, rrdcontext_acquired_id(qc->rca), &x, sizeof(x));
177
+
178
+ z->instances.selected += qc->instances.selected;
179
+ z->instances.excluded += qc->instances.selected;
180
181
+ z->metrics.selected += qc->metrics.selected;
182
+ z->metrics.excluded += qc->metrics.excluded;
183
+ z->metrics.queried += qc->metrics.queried;
184
+ z->metrics.failed += qc->metrics.failed;
185
+
186
+ z->alerts.clear += qc->alerts.clear;
187
+ z->alerts.warning += qc->alerts.warning;
188
+ z->alerts.critical += qc->alerts.critical;
189
+
190
+ query_target_merge_data_statistics(&z->query_stats, &qc->query_stats);
191
+ }
192
+
193
+ size_t unique_contexts = dictionary_entries(dict);
194
+ dfe_start_read(dict, z) {
195
+ buffer_json_add_array_item_object(wb);
196
+ buffer_json_member_add_string(wb, "id", z_dfe.name);
197
+ query_target_instance_counts(wb, &z->instances);
198
+ query_target_metric_counts(wb, &z->metrics);
199
+ query_target_alerts_counts(wb, &z->alerts, NULL, false);
200
+ query_target_data_statistics(wb, qt, &z->query_stats);
201
+ buffer_json_object_close(wb);
202
+ }
203
+ dfe_done(z);
204
+ buffer_json_array_close(wb);
205
+ dictionary_destroy(dict);
206
+
207
+ return unique_contexts;
208
+}
209
+
210
+static void query_target_summary_instances_v1(BUFFER *wb, QUERY_TARGET *qt, const char *key) {
211
char name[RRD_ID_LENGTH_MAX * 2 + 2];
212
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];
213
+ buffer_json_member_add_array(wb, key);
214
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
215
+ for (long c = 0; c < (long) qt->instances.used; c++) {
216
+ QUERY_INSTANCE *qi = query_instance(qt, c);
217
218
snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
134
- rrdmetric_acquired_id(rma),
135
- rrdmetric_acquired_name(rma));
219
+ rrdinstance_acquired_id(qi->ria),
220
+ rrdinstance_acquired_name(qi->ria));
221
222
bool existing = 0;
223
bool *set = dictionary_set(dict, name, &existing, sizeof(bool));
139
- if(!*set) {
224
+ if (!*set) {
225
*set = true;
226
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));
227
+ buffer_json_add_array_item_string(wb, rrdinstance_acquired_id(qi->ria));
228
+ buffer_json_add_array_item_string(wb, rrdinstance_acquired_name(qi->ria));
229
buffer_json_array_close(wb);
230
}
231
}
232
dictionary_destroy(dict);
233
buffer_json_array_close(wb);
234
+}
235
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];
236
+static void query_target_summary_instances_v2(BUFFER *wb, QUERY_TARGET *qt, const char *key) {
237
+ buffer_json_member_add_array(wb, key);
238
+ for (long c = 0; c < (long) qt->instances.used; c++) {
239
+ QUERY_INSTANCE *qi = query_instance(qt, c);
240
+ QUERY_HOST *qh = query_host(qt, qi->query_host_id);
241
+
242
+ buffer_json_add_array_item_object(wb);
243
+ buffer_json_member_add_string(wb, "id", string2str(qi->id_fqdn));
244
+ buffer_json_member_add_string(wb, "nm", string2str(qi->name_fqdn));
245
+ buffer_json_member_add_string(wb, "lc", rrdinstance_acquired_name(qi->ria));
246
+ buffer_json_member_add_string(wb, "mg", qh->host->machine_guid);
247
+ if(qh->node_id[0])
248
+ buffer_json_member_add_string(wb, "nd", qh->node_id);
249
+ query_target_metric_counts(wb, &qi->metrics);
250
+ query_target_alerts_counts(wb, &qi->alerts, NULL, false);
251
+ query_target_data_statistics(wb, qt, &qi->query_stats);
252
+ buffer_json_object_close(wb);
253
+ }
254
+ buffer_json_array_close(wb);
255
+}
256
+
257
+static void query_target_summary_dimensions_v12(BUFFER *wb, QUERY_TARGET *qt, const char *key, bool v2) {
258
+ char name[RRD_ID_LENGTH_MAX * 2 + 2];
259
+
260
+ buffer_json_member_add_array(wb, key);
261
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
262
+ struct {
263
+ const char *id;
264
+ const char *name;
265
+ struct query_data_statistics query_stats;
266
+ struct query_metrics_counts metrics;
267
+ } x, *z;
268
+ size_t q = 0;
269
+ for (long c = 0; c < (long) qt->dimensions.used; c++) {
270
+ QUERY_DIMENSION * qd = query_dimension(qt, c);
271
+ RRDMETRIC_ACQUIRED *rma = qd->rma;
272
+
273
+ QUERY_METRIC *qm = NULL;
274
+ for( ; q < qt->query.used ;q++) {
275
+ QUERY_METRIC *tqm = query_metric(qt, q);
276
+ QUERY_DIMENSION *tqd = query_dimension(qt, tqm->link.query_dimension_id);
277
+ if(tqd->rma != rma) break;
278
+ qm = tqm;
279
+ }
280
281
snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
156
- rrdinstance_acquired_id(ria),
157
- rrdinstance_acquired_name(ria));
282
+ rrdmetric_acquired_id(rma),
283
+ rrdmetric_acquired_name(rma));
284
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);
285
+ x.id = rrdmetric_acquired_id(rma);
286
+ x.name = rrdmetric_acquired_name(rma);
287
+ x.metrics = (struct query_metrics_counts){ 0 };
288
+
289
+ z = dictionary_set(dict, name, &x, sizeof(x));
290
+
291
+ if(qm) {
292
+ z->metrics.selected += (qm->status & RRDR_DIMENSION_SELECTED) ? 1 : 0;
293
+ z->metrics.failed += (qm->status & RRDR_DIMENSION_FAILED) ? 1 : 0;
294
+
295
+ if(qm->status & RRDR_DIMENSION_QUERIED) {
296
+ z->metrics.queried++;
297
+ query_target_merge_data_statistics(&z->query_stats, &qm->query_stats);
298
+ }
299
}
300
+ else
301
+ z->metrics.excluded++;
302
}
303
+ dfe_start_read(dict, z) {
304
+ if(v2) {
305
+ buffer_json_add_array_item_object(wb);
306
+ buffer_json_member_add_string(wb, "id", z->id);
307
+ buffer_json_member_add_string(wb, "nm", z->name);
308
+ query_target_metric_counts(wb, &z->metrics);
309
+ query_target_data_statistics(wb, qt, &z->query_stats);
310
+ buffer_json_object_close(wb);
311
+ }
312
+ else {
313
+ buffer_json_add_array_item_array(wb);
314
+ buffer_json_add_array_item_string(wb, z->id);
315
+ buffer_json_add_array_item_string(wb, z->name);
316
+ buffer_json_array_close(wb);
317
+ }
318
+ }
319
+ dfe_done(z);
320
dictionary_destroy(dict);
321
buffer_json_array_close(wb);
322
+}
323
+
324
+struct rrdlabels_formatting_v2 {
325
+ DICTIONARY *keys;
326
+ QUERY_INSTANCE *qi;
327
+ bool v2;
328
+};
329
+
330
+struct rrdlabels_keys_dict_entry {
331
+ const char *name;
332
+ DICTIONARY *values;
333
+ struct query_data_statistics query_stats;
334
+ struct query_metrics_counts metrics;
335
+};
336
172
- buffer_json_member_add_array(wb, "full_chart_labels");
337
+struct rrdlabels_key_value_dict_entry {
338
+ const char *key;
339
+ const char *value;
340
+ struct query_data_statistics query_stats;
341
+ struct query_metrics_counts metrics;
342
+};
343
+
344
+static int rrdlabels_formatting_v2(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
345
+ struct rrdlabels_formatting_v2 *t = data;
346
+
347
+ struct rrdlabels_keys_dict_entry k = {
348
+ .name = name,
349
+ .values = NULL,
350
+ .metrics = (struct query_metrics_counts){ 0 },
351
+ }, *d = dictionary_set(t->keys, name, &k, sizeof(k));
352
+
353
+ if(!d->values)
354
+ d->values = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
355
+
356
+ char n[RRD_ID_LENGTH_MAX * 2 + 2];
357
+ snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, value);
358
+
359
+ struct rrdlabels_key_value_dict_entry x = {
360
+ .key = name,
361
+ .value = value,
362
+ .metrics = (struct query_metrics_counts){ 0 },
363
+ }, *z = dictionary_set(d->values, n, &x, sizeof(x));
364
+
365
+ if(t->v2) {
366
+ QUERY_INSTANCE *qi = t->qi;
367
+
368
+ z->metrics.selected += qi->metrics.selected;
369
+ z->metrics.excluded += qi->metrics.excluded;
370
+ z->metrics.queried += qi->metrics.queried;
371
+ z->metrics.failed += qi->metrics.failed;
372
+
373
+ d->metrics.selected += qi->metrics.selected;
374
+ d->metrics.excluded += qi->metrics.excluded;
375
+ d->metrics.queried += qi->metrics.queried;
376
+ d->metrics.failed += qi->metrics.failed;
377
+
378
+ query_target_merge_data_statistics(&z->query_stats, &qi->query_stats);
379
+ query_target_merge_data_statistics(&d->query_stats, &qi->query_stats);
380
+ }
381
+
382
+ return 1;
383
+}
384
+
385
+static void query_target_summary_labels_v12(BUFFER *wb, QUERY_TARGET *qt, const char *key, bool v2) {
386
+ buffer_json_member_add_array(wb, key);
387
struct rrdlabels_formatting_v2 t = {
174
- .wb = wb,
175
- .dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE),
388
+ .keys = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE),
389
+ .v2 = v2,
390
};
177
- for (long c = 0; c < (long)qt->instances.used ; c++) {
178
- RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
391
+ for (long c = 0; c < (long) qt->instances.used; c++) {
392
+ QUERY_INSTANCE *qi = query_instance(qt, c);
393
+ RRDINSTANCE_ACQUIRED *ria = qi->ria;
394
+ t.qi = qi;
395
rrdlabels_walkthrough_read(rrdinstance_acquired_labels(ria), rrdlabels_formatting_v2, &t);
396
}
181
- dictionary_destroy(t.dict);
397
+ struct rrdlabels_keys_dict_entry *d;
398
+ dfe_start_read(t.keys, d) {
399
+ if(v2) {
400
+ buffer_json_add_array_item_object(wb);
401
+ buffer_json_member_add_string(wb, "id", d_dfe.name);
402
+ query_target_metric_counts(wb, &d->metrics);
403
+ query_target_data_statistics(wb, qt, &d->query_stats);
404
+ buffer_json_member_add_array(wb, "vl");
405
+ }
406
+ struct rrdlabels_key_value_dict_entry *z;
407
+ dfe_start_read(d->values, z){
408
+ if (v2) {
409
+ buffer_json_add_array_item_object(wb);
410
+ buffer_json_member_add_string(wb, "id", z->value);
411
+ query_target_metric_counts(wb, &z->metrics);
412
+ query_target_data_statistics(wb, qt, &z->query_stats);
413
+ buffer_json_object_close(wb);
414
+ } else {
415
+ buffer_json_add_array_item_array(wb);
416
+ buffer_json_add_array_item_string(wb, z->key);
417
+ buffer_json_add_array_item_string(wb, z->value);
418
+ buffer_json_array_close(wb);
419
+ }
420
+ }
421
+ dfe_done(z);
422
+ dictionary_destroy(d->values);
423
+ if(v2) {
424
+ buffer_json_array_close(wb);
425
+ buffer_json_object_close(wb);
426
+ }
427
+ }
428
+ dfe_done(d);
429
+ dictionary_destroy(t.keys);
430
buffer_json_array_close(wb);
431
}
432
185
-static inline void jsonwrap_functions(BUFFER *wb, const char *key, RRDR *r) {
433
+static void query_target_summary_alerts_v2(BUFFER *wb, QUERY_TARGET *qt, const char *key) {
434
+ buffer_json_member_add_array(wb, key);
435
+ struct query_alerts_counts x = { 0 }, *z;
436
+
437
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
438
+ for (long c = 0; c < (long) qt->instances.used; c++) {
439
+ QUERY_INSTANCE *qi = query_instance(qt, c);
440
+ RRDSET *st = rrdinstance_acquired_rrdset(qi->ria);
441
+ if (st) {
442
+ netdata_rwlock_rdlock(&st->alerts.rwlock);
443
+ if (st->alerts.base) {
444
+ for (RRDCALC *rc = st->alerts.base; rc; rc = rc->next) {
445
+ z = dictionary_set(dict, string2str(rc->name), &x, sizeof(x));
446
+
447
+ switch(rc->status) {
448
+ case RRDCALC_STATUS_CLEAR:
449
+ z->clear++;
450
+ break;
451
+
452
+ case RRDCALC_STATUS_WARNING:
453
+ z->warning++;
454
+ break;
455
+
456
+ case RRDCALC_STATUS_CRITICAL:
457
+ z->critical++;
458
+ break;
459
+
460
+ default:
461
+ case RRDCALC_STATUS_UNINITIALIZED:
462
+ case RRDCALC_STATUS_UNDEFINED:
463
+ case RRDCALC_STATUS_REMOVED:
464
+ z->other++;
465
+ break;
466
+ }
467
+ }
468
+ }
469
+ netdata_rwlock_unlock(&st->alerts.rwlock);
470
+ }
471
+ }
472
+ dfe_start_read(dict, z)
473
+ query_target_alerts_counts(wb, z, z_dfe.name, true);
474
+ dfe_done(z);
475
+ dictionary_destroy(dict);
476
+ buffer_json_array_close(wb); // alerts
477
+}
478
+
479
+static inline void query_target_functions(BUFFER *wb, const char *key, RRDR *r) {
480
QUERY_TARGET *qt = r->internal.qt;
481
const long query_used = qt->query.used;
482
483
DICTIONARY *funcs = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
484
RRDINSTANCE_ACQUIRED *ria = NULL;
485
for (long c = 0; c < query_used ; c++) {
192
- QUERY_METRIC *qm = &qt->query.array[c];
193
- if(qm->link.ria == ria)
486
+ QUERY_METRIC *qm = query_metric(qt, c);
487
+ QUERY_INSTANCE *qi = query_instance(qt, qm->link.query_instance_id);
488
+ if(qi->ria == ria)
489
continue;
490
196
- ria = qm->link.ria;
491
+ ria = qi->ria;
492
chart_functions_to_dict(rrdinstance_acquired_functions(ria), funcs);
493
}
494
501
buffer_json_array_close(wb);
502
}
503
209
-static inline long jsonwrap_chart_labels_filter(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
504
+static inline long query_target_chart_labels_filter(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
505
QUERY_TARGET *qt = r->internal.qt;
506
const long query_used = qt->query.used;
507
long c, i = 0;
517
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
518
continue;
519
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);
520
+ QUERY_METRIC *qm = query_metric(qt, c);
521
+ QUERY_INSTANCE *qi = query_instance(qt, qm->link.query_instance_id);
522
+ rrdlabels_value_to_buffer_array_item_or_null(rrdinstance_acquired_labels(qi->ria), wb, label_key);
523
i++;
524
}
525
buffer_json_array_close(wb);
530
return i;
531
}
532
237
-static inline long jsonwrap_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
533
+static inline long query_target_metrics_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
534
QUERY_TARGET *qt = r->internal.qt;
535
const long query_used = qt->query.used;
536
long c, i;
541
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
542
continue;
543
248
- QUERY_METRIC *qm = &qt->query.array[c];
249
- buffer_json_add_array_item_double(wb, rrdmetric_acquired_last_stored_value(qm->link.rma));
544
+ QUERY_METRIC *qm = query_metric(qt, c);
545
+ QUERY_DIMENSION *qd = query_dimension(qt, qm->link.query_dimension_id);
546
+ buffer_json_add_array_item_double(wb, rrdmetric_acquired_last_stored_value(qd->rma));
547
i++;
548
}
549
552
return i;
553
}
554
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;
555
+static inline size_t rrdr_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
556
+ size_t c, i;
557
558
buffer_json_member_add_array(wb, key);
559
561
562
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
563
total = 0;
269
- for(c = 0; c < query_used ;c++) {
564
+ for(c = 0; c < r->d ; c++) {
565
if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
566
567
NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
576
if(total == 0) total = 1;
577
}
578
284
- for(c = 0, i = 0; c < query_used ;c++) {
579
+ for(c = 0, i = 0; c < r->d ; c++) {
580
if(!rrdr_dimension_should_be_exposed(r->od[c], options))
581
continue;
582
608
return i;
609
}
610
316
-void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
611
+void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, DATASOURCE_FORMAT format, RRDR_OPTIONS options, bool string_value,
612
RRDR_TIME_GROUPING group_method)
613
{
614
QUERY_TARGET *qt = r->internal.qt;
632
buffer_json_member_add_uint64(wb, "api", 1);
633
buffer_json_member_add_string(wb, "id", qt->id);
634
buffer_json_member_add_string(wb, "name", qt->id);
340
- buffer_json_member_add_time_t(wb, "view_update_every", r->update_every);
635
+ buffer_json_member_add_time_t(wb, "view_update_every", r->view.update_every);
636
buffer_json_member_add_time_t(wb, "update_every", qt->db.minimum_latest_update_every_s);
637
buffer_json_member_add_time_t(wb, "first_entry", qt->db.first_time_s);
638
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);
639
+ buffer_json_member_add_time_t(wb, "after", r->view.after);
640
+ buffer_json_member_add_time_t(wb, "before", r->view.before);
641
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);
642
+ web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", r->view.options);
643
349
- if(!jsonwrap_dimension_names(wb, "dimension_names", r, options))
644
+ if(!rrdr_dimension_names(wb, "dimension_names", r, options))
645
rows = 0;
646
352
- if(!jsonwrap_dimension_ids(wb, "dimension_ids", r, options))
647
+ if(!rrdr_dimension_ids(wb, "dimension_ids", r, options))
648
rows = 0;
649
355
- if (r->internal.query_options & RRDR_OPTION_ALL_DIMENSIONS)
356
- jsonwrap_full_dimension_list(wb, r);
650
+ if (r->view.options & RRDR_OPTION_ALL_DIMENSIONS) {
651
+ query_target_summary_instances_v1(wb, qt, "full_chart_list");
652
+ query_target_summary_dimensions_v12(wb, qt, "full_dimension_list", false);
653
+ query_target_summary_labels_v12(wb, qt, "full_chart_labels", false);
654
+ }
655
358
- jsonwrap_functions(wb, "functions", r);
656
+ query_target_functions(wb, "functions", r);
657
360
- if (!qt->request.st && !jsonwrap_chart_ids(wb, "chart_ids", r, options))
658
+ if (!qt->request.st && !jsonwrap_v1_chart_ids(wb, "chart_ids", r, options))
659
rows = 0;
660
363
- if (qt->instances.chart_label_key_pattern && !jsonwrap_chart_labels_filter(wb, "chart_labels", r, options))
661
+ if (qt->instances.chart_label_key_pattern && !query_target_chart_labels_filter(wb, "chart_labels", r, options))
662
rows = 0;
663
366
- if(!jsonwrap_latest_values(wb, "latest_values", r, options))
664
+ if(!query_target_metrics_latest_values(wb, "latest_values", r, options))
665
rows = 0;
666
369
- long dimensions = jsonwrap_view_latest_values(wb, "view_latest_values", r, options);
667
+ size_t dimensions = rrdr_latest_values(wb, "view_latest_values", r, options);
668
if(!dimensions)
669
rows = 0;
670
674
675
buffer_json_member_add_array(wb, "db_points_per_tier");
676
for(size_t tier = 0; tier < storage_tiers ; tier++)
379
- buffer_json_add_array_item_uint64(wb, r->internal.tier_points_read[tier]);
677
+ buffer_json_add_array_item_uint64(wb, r->stats.tier_points_read[tier]);
678
buffer_json_array_close(wb);
679
680
if(options & RRDR_OPTION_SHOW_PLAN)
681
jsonwrap_query_plan(r, wb);
682
385
- buffer_sprintf(wb, ",\n %sresult%s:", kq, kq);
683
+ buffer_sprintf(wb, ",\n %sresult%s:", kq, kq);
684
if(string_value) buffer_strcat(wb, sq);
685
}
686
389
-void rrdr_json_wrapper_anomaly_rates(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
390
- (void)r;
391
- (void)format;
687
+static void rrdset_rrdcalc_entries(BUFFER *wb, RRDINSTANCE_ACQUIRED *ria) {
688
+ RRDSET *st = rrdinstance_acquired_rrdset(ria);
689
+ if(st) {
690
+ netdata_rwlock_rdlock(&st->alerts.rwlock);
691
+ if(st->alerts.base) {
692
+ buffer_json_member_add_object(wb, "alerts");
693
+ for(RRDCALC *rc = st->alerts.base; rc ;rc = rc->next) {
694
+ if(rc->status < RRDCALC_STATUS_CLEAR)
695
+ continue;
696
+
697
+ buffer_json_member_add_object(wb, string2str(rc->name));
698
+ buffer_json_member_add_string(wb, "st", rrdcalc_status2string(rc->status));
699
+ buffer_json_member_add_double(wb, "vl", rc->value);
700
+ buffer_json_member_add_string(wb, "un", string2str(rc->units));
701
+ buffer_json_object_close(wb);
702
+ }
703
+ buffer_json_object_close(wb);
704
+ }
705
+ netdata_rwlock_unlock(&st->alerts.rwlock);
706
+ }
707
+}
708
+
709
+static void query_target_combined_units(BUFFER *wb, QUERY_TARGET *qt, size_t contexts) {
710
+ if(contexts == 1) {
711
+ buffer_json_member_add_string(wb, "units", rrdcontext_acquired_units(qt->contexts.array[0].rca));
712
+ }
713
+ else if(contexts > 1) {
714
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
715
+ for(size_t c = 0; c < qt->contexts.used ;c++)
716
+ dictionary_set(dict, rrdcontext_acquired_units(qt->contexts.array[c].rca), NULL, 0);
717
+
718
+ if(dictionary_entries(dict) == 1)
719
+ buffer_json_member_add_string(wb, "units", rrdcontext_acquired_units(qt->contexts.array[0].rca));
720
+ else {
721
+ buffer_json_member_add_array(wb, "units");
722
+ const char *s;
723
+ dfe_start_read(dict, s)
724
+ buffer_json_add_array_item_string(wb, s_dfe.name);
725
+ dfe_done(s);
726
+ buffer_json_array_close(wb);
727
+ }
728
+ dictionary_destroy(dict);
729
+ }
730
+}
731
+
732
+static void query_target_combined_chart_type(BUFFER *wb, QUERY_TARGET *qt, size_t contexts) {
733
+ if(contexts >= 1)
734
+ buffer_json_member_add_string(wb, "chart_type", rrdset_type_name(rrdcontext_acquired_chart_type(qt->contexts.array[0].rca)));
735
+}
736
+
737
+static void rrdr_dimension_units_array(BUFFER *wb, RRDR *r) {
738
+ if(!r->du)
739
+ return;
740
+
741
+ buffer_json_member_add_array(wb, "units");
742
+ for(size_t c = 0; c < r->d ; c++)
743
+ buffer_json_add_array_item_string(wb, string2str(r->du[c]));
744
+ buffer_json_array_close(wb);
745
+}
746
+
747
+static void rrdr_dimension_priority_array(BUFFER *wb, RRDR *r) {
748
+ if(!r->dp)
749
+ return;
750
+
751
+ buffer_json_member_add_array(wb, "priorities");
752
+ for(size_t c = 0; c < r->d ; c++)
753
+ buffer_json_add_array_item_uint64(wb, r->dp[c]);
754
+ buffer_json_array_close(wb);
755
+}
756
+
757
+static void rrdr_dimension_grouped_array(BUFFER *wb, RRDR *r) {
758
+ if(!r->dgbc)
759
+ return;
760
+
761
+ buffer_json_member_add_array(wb, "grouped");
762
+ for(size_t c = 0; c < r->d ;c++)
763
+ buffer_json_add_array_item_uint64(wb, r->dgbc[c]);
764
+ buffer_json_array_close(wb);
765
+}
766
+
767
+static void query_target_title(BUFFER *wb, QUERY_TARGET *qt, size_t contexts) {
768
+ if(contexts == 1) {
769
+ buffer_json_member_add_string(wb, "title", rrdcontext_acquired_title(qt->contexts.array[0].rca));
770
+ }
771
+ else if(contexts > 1) {
772
+ BUFFER *t = buffer_create(0, NULL);
773
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
774
+
775
+ buffer_strcat(t, "Chart for contexts: ");
776
+
777
+ size_t added = 0;
778
+ for(size_t c = 0; c < qt->contexts.used ;c++) {
779
+ bool old = false;
780
+ bool *set = dictionary_set(dict, rrdcontext_acquired_id(qt->contexts.array[c].rca), &old, sizeof(old));
781
+ if(!*set) {
782
+ *set = true;
783
+ if(added)
784
+ buffer_fast_strcat(t, ", ", 2);
785
+
786
+ buffer_strcat(t, rrdcontext_acquired_id(qt->contexts.array[c].rca));
787
+ added++;
788
+ }
789
+ }
790
+ buffer_json_member_add_string(wb, "title", buffer_tostring(t));
791
+ dictionary_destroy(dict);
792
+ buffer_free(t);
793
+ }
794
+}
795
+
796
+static void query_target_detailed_objects_tree(BUFFER *wb, RRDR *r, RRDR_OPTIONS options) {
797
+ QUERY_TARGET *qt = r->internal.qt;
798
+ buffer_json_member_add_object(wb, "hosts");
799
+
800
+ time_t now_s = now_realtime_sec();
801
+ RRDHOST *last_host = NULL;
802
+ RRDCONTEXT_ACQUIRED *last_rca = NULL;
803
+ RRDINSTANCE_ACQUIRED *last_ria = NULL;
804
+
805
+ size_t h = 0, c = 0, i = 0, m = 0, q = 0;
806
+ for(; h < qt->hosts.used ; h++) {
807
+ QUERY_HOST *qh = query_host(qt, h);
808
+ RRDHOST *host = qh->host;
809
+
810
+ for( ;c < qt->contexts.used ;c++) {
811
+ QUERY_CONTEXT *qc = query_context(qt, c);
812
+ RRDCONTEXT_ACQUIRED *rca = qc->rca;
813
+ if(!rrdcontext_acquired_belongs_to_host(rca, host)) break;
814
+
815
+ for( ;i < qt->instances.used ;i++) {
816
+ QUERY_INSTANCE *qi = query_instance(qt, i);
817
+ RRDINSTANCE_ACQUIRED *ria = qi->ria;
818
+ if(!rrdinstance_acquired_belongs_to_context(ria, rca)) break;
819
+
820
+ for( ; m < qt->dimensions.used ; m++) {
821
+ QUERY_DIMENSION *qd = query_dimension(qt, m);
822
+ RRDMETRIC_ACQUIRED *rma = qd->rma;
823
+ if(!rrdmetric_acquired_belongs_to_instance(rma, ria)) break;
824
+
825
+ QUERY_METRIC *qm = NULL;
826
+ bool queried = false;
827
+ for( ; q < qt->query.used ;q++) {
828
+ QUERY_METRIC *tqm = query_metric(qt, q);
829
+ QUERY_DIMENSION *tqd = query_dimension(qt, tqm->link.query_dimension_id);
830
+ if(tqd->rma != rma) break;
831
+
832
+ queried = tqm->status & RRDR_DIMENSION_QUERIED;
833
+ qm = tqm;
834
+ }
835
+
836
+ if(!queried & !(options & RRDR_OPTION_ALL_DIMENSIONS))
837
+ continue;
838
+
839
+ if(host != last_host) {
840
+ if(last_host) {
841
+ if(last_rca) {
842
+ if(last_ria) {
843
+ buffer_json_object_close(wb); // dimensions
844
+ buffer_json_object_close(wb); // instance
845
+ last_ria = NULL;
846
+ }
847
+ buffer_json_object_close(wb); // instances
848
+ buffer_json_object_close(wb); // context
849
+ last_rca = NULL;
850
+ }
851
+ buffer_json_object_close(wb); // contexts
852
+ buffer_json_object_close(wb); // host
853
+ last_host = NULL;
854
+ }
855
+
856
+ buffer_json_member_add_object(wb, host->machine_guid);
857
+ if(qh->node_id[0])
858
+ buffer_json_member_add_string(wb, "nd", qh->node_id);
859
+ buffer_json_member_add_uint64(wb, "idx", qh->slot);
860
+ buffer_json_member_add_string(wb, "nm", rrdhost_hostname(host));
861
+ buffer_json_member_add_object(wb, "contexts");
862
+
863
+ last_host = host;
864
+ }
865
+
866
+ if(rca != last_rca) {
867
+ if(last_rca) {
868
+ if(last_ria) {
869
+ buffer_json_object_close(wb); // dimensions
870
+ buffer_json_object_close(wb); // instance
871
+ last_ria = NULL;
872
+ }
873
+ buffer_json_object_close(wb); // instances
874
+ buffer_json_object_close(wb); // context
875
+ last_rca = NULL;
876
+ }
877
+
878
+ buffer_json_member_add_object(wb, rrdcontext_acquired_id(rca));
879
+ buffer_json_member_add_object(wb, "instances");
880
+
881
+ last_rca = rca;
882
+ }
883
+
884
+ if(ria != last_ria) {
885
+ if(last_ria) {
886
+ buffer_json_object_close(wb); // dimensions
887
+ buffer_json_object_close(wb); // instance
888
+ last_ria = NULL;
889
+ }
890
+
891
+ buffer_json_member_add_object(wb, rrdinstance_acquired_id(ria));
892
+ buffer_json_member_add_uint64(wb, "idx", qi->slot);
893
+ buffer_json_member_add_string(wb, "nm", rrdinstance_acquired_name(ria));
894
+ buffer_json_member_add_time_t(wb, "ue", rrdinstance_acquired_update_every(ria));
895
+ DICTIONARY *labels = rrdinstance_acquired_labels(ria);
896
+ if(labels) {
897
+ buffer_json_member_add_object(wb, "labels");
898
+ rrdlabels_to_buffer_json_members(labels, wb);
899
+ buffer_json_object_close(wb);
900
+ }
901
+ rrdset_rrdcalc_entries(wb, ria);
902
+ buffer_json_member_add_object(wb, "dimensions");
903
+
904
+ last_ria = ria;
905
+ }
906
+
907
+ buffer_json_member_add_object(wb, rrdmetric_acquired_id(rma));
908
+ {
909
+ buffer_json_member_add_string(wb, "nm", rrdmetric_acquired_name(rma));
910
+ buffer_json_member_add_uint64(wb, "qr", queried ? 1 : 0);
911
+ time_t first_entry_s = rrdmetric_acquired_first_entry(rma);
912
+ time_t last_entry_s = rrdmetric_acquired_last_entry(rma);
913
+ buffer_json_member_add_time_t(wb, "fe", first_entry_s);
914
+ buffer_json_member_add_time_t(wb, "le", last_entry_s ? last_entry_s : now_s);
915
+
916
+ if(qm) {
917
+ if(qm->status & RRDR_DIMENSION_GROUPED) {
918
+ // buffer_json_member_add_string(wb, "grouped_as_id", string2str(qm->grouped_as.id));
919
+ buffer_json_member_add_string(wb, "as", string2str(qm->grouped_as.name));
920
+ }
921
+
922
+ query_target_data_statistics(wb, qt, &qm->query_stats);
923
+
924
+ if(options & RRDR_OPTION_SHOW_PLAN)
925
+ jsonwrap_query_metric_plan(wb, qm);
926
+ }
927
+ }
928
+ buffer_json_object_close(wb); // metric
929
+ }
930
+ }
931
+ }
932
+ }
933
+
934
+ if(last_host) {
935
+ if(last_rca) {
936
+ if(last_ria) {
937
+ buffer_json_object_close(wb); // dimensions
938
+ buffer_json_object_close(wb); // instance
939
+ last_ria = NULL;
940
+ }
941
+ buffer_json_object_close(wb); // instances
942
+ buffer_json_object_close(wb); // context
943
+ last_rca = NULL;
944
+ }
945
+ buffer_json_object_close(wb); // contexts
946
+ buffer_json_object_close(wb); // host
947
+ last_host = NULL;
948
+ }
949
+ buffer_json_object_close(wb); // hosts
950
+}
951
+
952
+void rrdr_json_wrapper_begin2(RRDR *r, BUFFER *wb, DATASOURCE_FORMAT format, RRDR_OPTIONS options, bool string_value,
953
+ RRDR_TIME_GROUPING group_method)
954
+{
955
+ QUERY_TARGET *qt = r->internal.qt;
956
+
957
+ long rows = rrdr_rows(r);
958
+
959
+ char kq[2] = "\"", // key quote
960
+ sq[2] = "\""; // string quote
961
+
962
+ if(unlikely(options & RRDR_OPTION_GOOGLE_JSON)) {
963
+ kq[0] = '\0';
964
+ sq[0] = '\'';
965
+ }
966
+
967
+ buffer_json_initialize(wb, kq, sq, 0, true);
968
+
969
+ buffer_json_member_add_uint64(wb, "api", 2);
970
+
971
+ if(options & RRDR_OPTION_DEBUG) {
972
+ buffer_json_member_add_string(wb, "id", qt->id);
973
+ buffer_json_member_add_object(wb, "request");
974
+ {
975
+ buffer_json_member_add_string(wb, "format", rrdr_format_to_string(qt->request.format));
976
+ web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", qt->request.options);
977
+
978
+ buffer_json_member_add_object(wb, "scope");
979
+ buffer_json_member_add_string(wb, "scope_hosts", qt->request.scope_hosts);
980
+ buffer_json_member_add_string(wb, "scope_contexts", qt->request.scope_contexts);
981
+ buffer_json_object_close(wb); // scope
982
+
983
+ buffer_json_member_add_object(wb, "selectors");
984
+ if (qt->request.host)
985
+ buffer_json_member_add_string(wb, "host", rrdhost_hostname(qt->request.host));
986
+ else
987
+ buffer_json_member_add_string(wb, "hosts", qt->request.hosts);
988
+ buffer_json_member_add_string(wb, "contexts", qt->request.contexts);
989
+ buffer_json_member_add_string(wb, "instances", qt->request.charts);
990
+ buffer_json_member_add_string(wb, "dimensions", qt->request.dimensions);
991
+ buffer_json_member_add_string(wb, "labels", qt->request.labels);
992
+ buffer_json_member_add_string(wb, "alerts", qt->request.alerts);
993
+ buffer_json_object_close(wb); // selectors
994
+
995
+ buffer_json_member_add_object(wb, "window");
996
+ buffer_json_member_add_time_t(wb, "after", qt->request.after);
997
+ buffer_json_member_add_time_t(wb, "before", qt->request.before);
998
+ buffer_json_member_add_uint64(wb, "points", qt->request.points);
999
+ if (qt->request.options & RRDR_OPTION_SELECTED_TIER)
1000
+ buffer_json_member_add_uint64(wb, "tier", qt->request.tier);
1001
+ else
1002
+ buffer_json_member_add_string(wb, "tier", NULL);
1003
+ buffer_json_object_close(wb); // window
1004
+
1005
+ buffer_json_member_add_object(wb, "aggregations");
1006
+ {
1007
+ buffer_json_member_add_object(wb, "time");
1008
+ buffer_json_member_add_string(wb, "time_group", time_grouping_tostring(qt->request.time_group_method));
1009
+ buffer_json_member_add_string(wb, "time_group_options", qt->request.time_group_options);
1010
+ if (qt->request.resampling_time > 0)
1011
+ buffer_json_member_add_time_t(wb, "time_resampling", qt->request.resampling_time);
1012
+ else
1013
+ buffer_json_member_add_string(wb, "time_resampling", NULL);
1014
+ buffer_json_object_close(wb); // time
1015
+
1016
+ buffer_json_member_add_object(wb, "metrics");
1017
+
1018
+ buffer_json_member_add_array(wb, "group_by");
1019
+ buffer_json_group_by_to_array(wb, qt->request.group_by);
1020
+ buffer_json_array_close(wb);
1021
+
1022
+ buffer_json_member_add_array(wb, "group_by_label");
1023
+ for(size_t l = 0; l < qt->group_by.used ;l++)
1024
+ buffer_json_add_array_item_string(wb, qt->group_by.label_keys[l]);
1025
+ buffer_json_array_close(wb);
1026
+
1027
+ buffer_json_member_add_string(wb, "group_by_aggregate",
1028
+ group_by_aggregate_function_to_string(
1029
+ qt->request.group_by_aggregate_function));
1030
+ buffer_json_object_close(wb); // dimensions
1031
+ }
1032
+ buffer_json_object_close(wb); // aggregations
1033
+
1034
+ buffer_json_member_add_uint64(wb, "timeout", qt->request.timeout);
1035
+ }
1036
+ buffer_json_object_close(wb); // request
1037
+ }
1038
+
1039
+ size_t contexts;
1040
+ buffer_json_member_add_object(wb, "summary");
1041
+ {
1042
+ query_target_summary_hosts_v2(wb, qt, "hosts");
1043
+ contexts = query_target_summary_contexts_v2(wb, qt, "contexts");
1044
+ query_target_summary_instances_v2(wb, qt, "instances");
1045
+ query_target_summary_dimensions_v12(wb, qt, "dimensions", true);
1046
+ query_target_summary_labels_v12(wb, qt, "labels", true);
1047
+ query_target_summary_alerts_v2(wb, qt, "alerts");
1048
+ }
1049
+ buffer_json_object_close(wb); // summary
1050
+
1051
+ if(options & RRDR_OPTION_SHOW_DETAILS) {
1052
+ buffer_json_member_add_object(wb, "detailed");
1053
+ query_target_detailed_objects_tree(wb, r, options);
1054
+ buffer_json_object_close(wb); // detailed
1055
+ }
1056
+
1057
+ query_target_functions(wb, "functions", r);
1058
+
1059
+ buffer_json_member_add_object(wb, "db");
1060
+ {
1061
+ buffer_json_member_add_time_t(wb, "update_every", qt->db.minimum_latest_update_every_s);
1062
+ buffer_json_member_add_time_t(wb, "first_entry", qt->db.first_time_s);
1063
+ buffer_json_member_add_time_t(wb, "last_entry", qt->db.last_time_s);
1064
+ buffer_json_member_add_array(wb, "points_per_tier");
1065
+ for(size_t tier = 0; tier < storage_tiers ; tier++)
1066
+ buffer_json_add_array_item_uint64(wb, r->stats.tier_points_read[tier]);
1067
+ buffer_json_array_close(wb);
1068
+ }
1069
+ buffer_json_object_close(wb);
1070
+
1071
+ buffer_json_member_add_object(wb, "view");
1072
+ {
1073
+ query_target_title(wb, qt, contexts);
1074
+ buffer_json_member_add_string(wb, "format", rrdr_format_to_string(format));
1075
+ web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", r->view.options);
1076
+ buffer_json_member_add_string(wb, "time_group", time_grouping_tostring(group_method));
1077
+ buffer_json_member_add_time_t(wb, "update_every", r->view.update_every);
1078
+ buffer_json_member_add_time_t(wb, "after", r->view.after);
1079
+ buffer_json_member_add_time_t(wb, "before", r->view.before);
1080
+ buffer_json_member_add_uint64(wb, "points", rows);
1081
+ query_target_combined_units(wb, qt, contexts);
1082
+ query_target_combined_chart_type(wb, qt, contexts);
1083
+ buffer_json_member_add_object(wb, "dimensions");
1084
+ {
1085
+ rrdr_dimension_ids(wb, "ids", r, options);
1086
+ rrdr_dimension_names(wb, "names", r, options);
1087
+ rrdr_dimension_units_array(wb, r);
1088
+ rrdr_dimension_priority_array(wb, r);
1089
+ rrdr_dimension_grouped_array(wb, r);
1090
+ size_t dims = rrdr_latest_values(wb, "view_latest_values", r, options);
1091
+ buffer_json_member_add_uint64(wb, "count", dims);
1092
+ }
1093
+ buffer_json_object_close(wb);
1094
+ }
1095
+ buffer_json_object_close(wb);
1096
+
1097
+ buffer_sprintf(wb, ",\n %sresult%s:", kq, kq);
1098
+ if(string_value) buffer_strcat(wb, sq);
1099
+}
1100
+
1101
+void rrdr_json_wrapper_anomaly_rates(RRDR *r __maybe_unused, BUFFER *wb, DATASOURCE_FORMAT format __maybe_unused, RRDR_OPTIONS options, bool string_value) {
1102
1103
char kq[2] = "", // key quote
1104
sq[2] = ""; // string quote
1114
1115
if(string_value) buffer_strcat(wb, sq);
1116
407
- buffer_sprintf(wb, ",\n %sanomaly_rates%s: ", kq, kq);
1117
+ buffer_sprintf(wb, ",\n %sanomaly_rates%s: ", kq, kq);
1118
}
1119
410
-void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
411
- (void)format;
1120
+void rrdr_json_wrapper_group_by_count(RRDR *r __maybe_unused, BUFFER *wb, DATASOURCE_FORMAT format __maybe_unused, RRDR_OPTIONS options, bool string_value) {
1121
+
1122
+ char kq[2] = "", // key quote
1123
+ sq[2] = ""; // string quote
1124
+
1125
+ if( options & RRDR_OPTION_GOOGLE_JSON ) {
1126
+ kq[0] = '\0';
1127
+ sq[0] = '\'';
1128
+ }
1129
+ else {
1130
+ kq[0] = '"';
1131
+ sq[0] = '"';
1132
+ }
1133
+
1134
+ if(string_value) buffer_strcat(wb, sq);
1135
+
1136
+ buffer_sprintf(wb, ",\n %sgroup_by_count%s: ", kq, kq);
1137
+}
1138
+
1139
+void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, DATASOURCE_FORMAT format __maybe_unused, RRDR_OPTIONS options, bool string_value) {
1140
+ QUERY_TARGET *qt = r->internal.qt;
1141
1142
char sq[2] = ""; // string quote
1143
1150
1151
if(string_value) buffer_strcat(wb, sq);
1152
424
- buffer_json_member_add_double(wb, "min", r->min);
425
- buffer_json_member_add_double(wb, "max", r->max);
1153
+ buffer_json_member_add_double(wb, "min", r->view.min);
1154
+ buffer_json_member_add_double(wb, "max", r->view.max);
1155
+
1156
+ qt->timings.finished_ut = now_monotonic_usec();
1157
+ buffer_json_member_add_object(wb, "timings");
1158
+ buffer_json_member_add_double(wb, "prep_ms", (NETDATA_DOUBLE)(qt->timings.preprocessed_ut - qt->timings.received_ut) / USEC_PER_MS);
1159
+ buffer_json_member_add_double(wb, "query_ms", (NETDATA_DOUBLE)(qt->timings.executed_ut - qt->timings.preprocessed_ut) / USEC_PER_MS);
1160
+ buffer_json_member_add_double(wb, "group_by_ms", (NETDATA_DOUBLE)(qt->timings.group_by_ut - qt->timings.executed_ut) / USEC_PER_MS);
1161
+ buffer_json_member_add_double(wb, "output_ms", (NETDATA_DOUBLE)(qt->timings.finished_ut - qt->timings.group_by_ut) / USEC_PER_MS);
1162
+ buffer_json_member_add_double(wb, "total_ms", (NETDATA_DOUBLE)(qt->timings.finished_ut - qt->timings.received_ut) / USEC_PER_MS);
1163
+ buffer_json_object_close(wb);
1164
+
1165
buffer_json_finalize(wb);
1166
}