master
c 391 lines 12.1 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "web/api/web_api_v1.h"
4 #include "database/storage-engine.h"
5
6 void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb)
7 {
8 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
9 rrdset2json(st, wb, NULL, NULL);
10 buffer_json_finalize(wb);
11 }
12
13 int rrdset2value_api_v1_with_owa(
14 ONEWAYALLOC *owa
15 , RRDSET *st
16 , BUFFER *wb
17 , NETDATA_DOUBLE *n
18 , const char *dimensions
19 , size_t points
20 , time_t after
21 , time_t before
22 , RRDR_TIME_GROUPING group_method
23 , const char *group_options
24 , time_t resampling_time
25 , uint32_t options
26 , time_t *db_after
27 , time_t *db_before
28 , size_t *db_points_read
29 , size_t *db_points_per_tier
30 , size_t *result_points_generated
31 , int *value_is_null
32 , NETDATA_DOUBLE *anomaly_rate
33 , time_t timeout
34 , size_t tier
35 , QUERY_SOURCE query_source
36 , STORAGE_PRIORITY priority
37 ) {
38 internal_fatal(!owa, "rrdset2value_api_v1_with_owa(): owa must be non-NULL");
39
40 int ret = HTTP_RESP_INTERNAL_SERVER_ERROR;
41
42 RRDR *r = rrd2rrdr_legacy(
43 owa,
44 st,
45 points,
46 after,
47 before,
48 group_method,
49 resampling_time,
50 options,
51 dimensions,
52 group_options,
53 timeout,
54 tier,
55 query_source,
56 priority);
57
58 if(!r) {
59 if(value_is_null) *value_is_null = 1;
60 ret = HTTP_RESP_INTERNAL_SERVER_ERROR;
61 goto cleanup;
62 }
63
64 if(db_points_read)
65 *db_points_read += r->stats.db_points_read;
66
67 if(db_points_per_tier) {
68 for(size_t t = 0; t < nd_profile.storage_tiers;t++)
69 db_points_per_tier[t] += r->internal.qt->db.tiers[t].points;
70 }
71
72 if(result_points_generated)
73 *result_points_generated += r->stats.result_points_generated;
74
75 if(rrdr_rows(r) == 0) {
76 if(db_after) *db_after = 0;
77 if(db_before) *db_before = 0;
78 if(value_is_null) *value_is_null = 1;
79
80 ret = HTTP_RESP_BAD_REQUEST;
81 goto cleanup;
82 }
83
84 if(wb) {
85 if (r->view.flags & RRDR_RESULT_FLAG_RELATIVE)
86 buffer_no_cacheable(wb);
87 else if (r->view.flags & RRDR_RESULT_FLAG_ABSOLUTE)
88 buffer_cacheable(wb);
89 }
90
91 if(db_after) *db_after = r->view.after;
92 if(db_before) *db_before = r->view.before;
93
94 long i = (!(options & RRDR_OPTION_REVERSED))?(long)rrdr_rows(r) - 1:0;
95 *n = rrdr2value(r, i, options, value_is_null, anomaly_rate);
96 ret = HTTP_RESP_OK;
97
98 cleanup:
99 rrdr_free(owa, r);
100 return ret;
101 }
102
103 int rrdset2value_api_v1(
104 RRDSET *st
105 , BUFFER *wb
106 , NETDATA_DOUBLE *n
107 , const char *dimensions
108 , size_t points
109 , time_t after
110 , time_t before
111 , RRDR_TIME_GROUPING group_method
112 , const char *group_options
113 , time_t resampling_time
114 , uint32_t options
115 , time_t *db_after
116 , time_t *db_before
117 , size_t *db_points_read
118 , size_t *db_points_per_tier
119 , size_t *result_points_generated
120 , int *value_is_null
121 , NETDATA_DOUBLE *anomaly_rate
122 , time_t timeout
123 , size_t tier
124 , QUERY_SOURCE query_source
125 , STORAGE_PRIORITY priority
126 ) {
127 // Back-compat wrapper for callers that don't need to reuse the arena
128 // across calls (e.g. the badge code path). Creates a throwaway owa.
129 ONEWAYALLOC *owa = onewayalloc_create(0);
130 int ret = rrdset2value_api_v1_with_owa(
131 owa, st, wb, n, dimensions, points, after, before,
132 group_method, group_options, resampling_time, options,
133 db_after, db_before, db_points_read, db_points_per_tier,
134 result_points_generated, value_is_null, anomaly_rate,
135 timeout, tier, query_source, priority);
136 onewayalloc_destroy(owa);
137 return ret;
138 }
139
140 static inline void buffer_json_member_add_key_only(BUFFER *wb, const char *key) {
141 buffer_print_json_comma_newline_spacing(wb);
142 buffer_print_json_key(wb, key);
143 buffer_fast_strcat(wb, ":", 1);
144 wb->json.stack[wb->json.depth].count++;
145 }
146
147 static inline void buffer_json_member_add_string_open(BUFFER *wb, const char *key) {
148 buffer_json_member_add_key_only(wb, key);
149 buffer_strcat(wb, wb->json.value_quote);
150 }
151
152 static inline void buffer_json_member_add_string_close(BUFFER *wb) {
153 buffer_strcat(wb, wb->json.value_quote);
154 }
155
156 int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *latest_timestamp) {
157 wrapper_begin_t wrapper_begin = rrdr_json_wrapper_begin;
158 wrapper_end_t wrapper_end = rrdr_json_wrapper_end;
159
160 if(qt->request.version >= 2) {
161 wrapper_begin = rrdr_json_wrapper_begin2;
162 wrapper_end = rrdr_json_wrapper_end2;
163 }
164
165 stream_control_user_data_query_started();
166 RRDR *r = rrd2rrdr(owa, qt);
167 stream_control_user_data_query_finished();
168
169 if(!r) {
170 buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
171 return HTTP_RESP_INTERNAL_SERVER_ERROR;
172 }
173
174 if (r->view.flags & RRDR_RESULT_FLAG_CANCEL) {
175 rrdr_free(owa, r);
176 return HTTP_RESP_CLIENT_CLOSED_REQUEST;
177 }
178
179 if(r->view.flags & RRDR_RESULT_FLAG_RELATIVE)
180 buffer_no_cacheable(wb);
181 else if(r->view.flags & RRDR_RESULT_FLAG_ABSOLUTE)
182 buffer_cacheable(wb);
183
184 if(latest_timestamp && rrdr_rows(r) > 0)
185 *latest_timestamp = r->view.before;
186
187 DATASOURCE_FORMAT format = qt->request.format;
188 RRDR_OPTIONS options = qt->window.options;
189
190 switch(format) {
191 case DATASOURCE_SSV:
192 if(options & RRDR_OPTION_JSON_WRAP) {
193 wb->content_type = CT_APPLICATION_JSON;
194 wrapper_begin(r, wb);
195 buffer_json_member_add_string_open(wb, "result");
196 rrdr2ssv(r, wb, options, "", " ", "");
197 buffer_json_member_add_string_close(wb);
198 wrapper_end(r, wb);
199 }
200 else {
201 wb->content_type = CT_TEXT_PLAIN;
202 rrdr2ssv(r, wb, options, "", " ", "");
203 }
204 break;
205
206 case DATASOURCE_SSV_COMMA:
207 if(options & RRDR_OPTION_JSON_WRAP) {
208 wb->content_type = CT_APPLICATION_JSON;
209 wrapper_begin(r, wb);
210 buffer_json_member_add_string_open(wb, "result");
211 rrdr2ssv(r, wb, options, "", ",", "");
212 buffer_json_member_add_string_close(wb);
213 wrapper_end(r, wb);
214 }
215 else {
216 wb->content_type = CT_TEXT_PLAIN;
217 rrdr2ssv(r, wb, options, "", ",", "");
218 }
219 break;
220
221 case DATASOURCE_JS_ARRAY:
222 if(options & RRDR_OPTION_JSON_WRAP) {
223 wb->content_type = CT_APPLICATION_JSON;
224 wrapper_begin(r, wb);
225 buffer_json_member_add_array(wb, "result");
226 rrdr2ssv(r, wb, options, "", ",", "");
227 buffer_json_array_close(wb);
228 wrapper_end(r, wb);
229 }
230 else {
231 wb->content_type = CT_APPLICATION_JSON;
232 rrdr2ssv(r, wb, options, "[", ",", "]");
233 }
234 break;
235
236 case DATASOURCE_CSV:
237 if(options & RRDR_OPTION_JSON_WRAP) {
238 wb->content_type = CT_APPLICATION_JSON;
239 wrapper_begin(r, wb);
240 buffer_json_member_add_string_open(wb, "result");
241 rrdr2csv(r, wb, format, options, "", ",", "\\n", "");
242 buffer_json_member_add_string_close(wb);
243 wrapper_end(r, wb);
244 }
245 else {
246 wb->content_type = CT_TEXT_PLAIN;
247 rrdr2csv(r, wb, format, options, "", ",", "\r\n", "");
248 }
249 break;
250
251 case DATASOURCE_CSV_MARKDOWN:
252 if(options & RRDR_OPTION_JSON_WRAP) {
253 wb->content_type = CT_APPLICATION_JSON;
254 wrapper_begin(r, wb);
255 buffer_json_member_add_string_open(wb, "result");
256 rrdr2csv(r, wb, format, options, "", "|", "\\n", "");
257 buffer_json_member_add_string_close(wb);
258 wrapper_end(r, wb);
259 }
260 else {
261 wb->content_type = CT_TEXT_PLAIN;
262 rrdr2csv(r, wb, format, options, "", "|", "\r\n", "");
263 }
264 break;
265
266 case DATASOURCE_CSV_JSON_ARRAY:
267 wb->content_type = CT_APPLICATION_JSON;
268 if(options & RRDR_OPTION_JSON_WRAP) {
269 wrapper_begin(r, wb);
270 buffer_json_member_add_array(wb, "result");
271 rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
272 buffer_json_array_close(wb);
273 wrapper_end(r, wb);
274 }
275 else {
276 wb->content_type = CT_APPLICATION_JSON;
277 buffer_strcat(wb, "[\n");
278 rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
279 buffer_strcat(wb, "\n]");
280 }
281 break;
282
283 case DATASOURCE_TSV:
284 if(options & RRDR_OPTION_JSON_WRAP) {
285 wb->content_type = CT_APPLICATION_JSON;
286 wrapper_begin(r, wb);
287 buffer_json_member_add_string_open(wb, "result");
288 rrdr2csv(r, wb, format, options, "", "\t", "\\n", "");
289 buffer_json_member_add_string_close(wb);
290 wrapper_end(r, wb);
291 }
292 else {
293 wb->content_type = CT_TEXT_PLAIN;
294 rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "");
295 }
296 break;
297
298 case DATASOURCE_HTML:
299 if(options & RRDR_OPTION_JSON_WRAP) {
300 wb->content_type = CT_APPLICATION_JSON;
301 wrapper_begin(r, wb);
302 buffer_json_member_add_string_open(wb, "result");
303 buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
304 rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
305 buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
306 buffer_json_member_add_string_close(wb);
307 wrapper_end(r, wb);
308 }
309 else {
310 wb->content_type = CT_TEXT_HTML;
311 buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
312 rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
313 buffer_strcat(wb, "</table>\n</center>\n</html>\n");
314 }
315 break;
316
317 case DATASOURCE_DATATABLE_JSONP:
318 wb->content_type = CT_APPLICATION_X_JAVASCRIPT;
319
320 if(options & RRDR_OPTION_JSON_WRAP) {
321 wrapper_begin(r, wb);
322 buffer_json_member_add_key_only(wb, "result");
323 }
324
325 rrdr2json(r, wb, options, 1);
326
327 if(options & RRDR_OPTION_JSON_WRAP)
328 wrapper_end(r, wb);
329
330 break;
331
332 case DATASOURCE_DATATABLE_JSON:
333 wb->content_type = CT_APPLICATION_JSON;
334
335 if(options & RRDR_OPTION_JSON_WRAP) {
336 wrapper_begin(r, wb);
337 buffer_json_member_add_key_only(wb, "result");
338 }
339
340 rrdr2json(r, wb, options, 1);
341
342 if(options & RRDR_OPTION_JSON_WRAP)
343 wrapper_end(r, wb);
344
345 break;
346
347 case DATASOURCE_JSONP:
348 wb->content_type = CT_APPLICATION_X_JAVASCRIPT;
349 if(options & RRDR_OPTION_JSON_WRAP) {
350 wrapper_begin(r, wb);
351 buffer_json_member_add_key_only(wb, "result");
352 }
353
354 rrdr2json(r, wb, options, 0);
355
356 if(options & RRDR_OPTION_JSON_WRAP)
357 wrapper_end(r, wb);
358
359 break;
360
361 case DATASOURCE_JSON:
362 default:
363 wb->content_type = CT_APPLICATION_JSON;
364
365 if(options & RRDR_OPTION_JSON_WRAP) {
366 wrapper_begin(r, wb);
367 buffer_json_member_add_key_only(wb, "result");
368 }
369
370 rrdr2json(r, wb, options, 0);
371
372 if(options & RRDR_OPTION_JSON_WRAP) {
373 if (options & RRDR_OPTION_RETURN_JWAR) {
374 buffer_json_member_add_key_only(wb, "anomaly_rates");
375 rrdr2json(r, wb, options | RRDR_OPTION_INTERNAL_AR, false);
376 }
377 wrapper_end(r, wb);
378 }
379 break;
380
381 case DATASOURCE_JSON2:
382 wb->content_type = CT_APPLICATION_JSON;
383 wrapper_begin(r, wb);
384 rrdr2json_v2(r, wb);
385 wrapper_end(r, wb);
386 break;
387 }
388
389 rrdr_free(owa, r);
390 return HTTP_RESP_OK;
391 }