rrd2json.c 12 KB

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