rrd2json.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "web/api/web_api_v1.h"
  3. static inline void free_single_rrdrim(ONEWAYALLOC *owa, RRDDIM *temp_rd, int archive_mode)
  4. {
  5. if (unlikely(!temp_rd))
  6. return;
  7. onewayalloc_freez(owa, (char *)temp_rd->id);
  8. if (unlikely(archive_mode)) {
  9. temp_rd->rrdset->counter--;
  10. if (!temp_rd->rrdset->counter) {
  11. onewayalloc_freez(owa, (char *)temp_rd->rrdset->name);
  12. onewayalloc_freez(owa, temp_rd->rrdset->context);
  13. onewayalloc_freez(owa, temp_rd->rrdset);
  14. }
  15. }
  16. onewayalloc_freez(owa, temp_rd->state);
  17. onewayalloc_freez(owa, temp_rd);
  18. }
  19. static inline void free_rrddim_list(ONEWAYALLOC *owa, RRDDIM *temp_rd, int archive_mode)
  20. {
  21. if (unlikely(!temp_rd))
  22. return;
  23. RRDDIM *t;
  24. while (temp_rd) {
  25. t = temp_rd->next;
  26. free_single_rrdrim(owa, temp_rd, archive_mode);
  27. temp_rd = t;
  28. }
  29. }
  30. void free_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list)
  31. {
  32. if (unlikely(!param_list || !*param_list))
  33. return;
  34. free_rrddim_list(owa, ((*param_list)->rd), (*param_list)->flags & CONTEXT_FLAGS_ARCHIVE);
  35. onewayalloc_freez(owa, (*param_list));
  36. *param_list = NULL;
  37. }
  38. void rebuild_context_param_list(ONEWAYALLOC *owa, struct context_param *context_param_list, time_t after_requested)
  39. {
  40. RRDDIM *temp_rd = context_param_list->rd;
  41. RRDDIM *new_rd_list = NULL, *t;
  42. int is_archived = (context_param_list->flags & CONTEXT_FLAGS_ARCHIVE);
  43. while (temp_rd) {
  44. t = temp_rd->next;
  45. RRDSET *st = temp_rd->rrdset;
  46. time_t last_entry_t = is_archived ? st->last_entry_t : rrdset_last_entry_t(st);
  47. if (last_entry_t >= after_requested) {
  48. temp_rd->next = new_rd_list;
  49. new_rd_list = temp_rd;
  50. } else
  51. free_single_rrdrim(owa, temp_rd, is_archived);
  52. temp_rd = t;
  53. }
  54. context_param_list->rd = new_rd_list;
  55. };
  56. void build_context_param_list(ONEWAYALLOC *owa, struct context_param **param_list, RRDSET *st)
  57. {
  58. if (unlikely(!param_list || !st))
  59. return;
  60. if (unlikely(!(*param_list))) {
  61. *param_list = onewayalloc_mallocz(owa, sizeof(struct context_param));
  62. (*param_list)->first_entry_t = LONG_MAX;
  63. (*param_list)->last_entry_t = 0;
  64. (*param_list)->flags = CONTEXT_FLAGS_CONTEXT;
  65. (*param_list)->rd = NULL;
  66. }
  67. RRDDIM *rd1;
  68. st->last_accessed_time = now_realtime_sec();
  69. rrdset_rdlock(st);
  70. (*param_list)->first_entry_t = MIN((*param_list)->first_entry_t, rrdset_first_entry_t_nolock(st));
  71. (*param_list)->last_entry_t = MAX((*param_list)->last_entry_t, rrdset_last_entry_t_nolock(st));
  72. rrddim_foreach_read(rd1, st) {
  73. RRDDIM *rd = onewayalloc_memdupz(owa, rd1, rd1->memsize);
  74. rd->id = onewayalloc_strdupz(owa, rd1->id);
  75. rd->name = onewayalloc_strdupz(owa, rd1->name);
  76. rd->state = onewayalloc_memdupz(owa, rd1->state, sizeof(*rd->state));
  77. rd->next = (*param_list)->rd;
  78. (*param_list)->rd = rd;
  79. }
  80. rrdset_unlock(st);
  81. }
  82. void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
  83. rrdset2json(st, wb, NULL, NULL, 0);
  84. }
  85. void rrdr_buffer_print_format(BUFFER *wb, uint32_t format) {
  86. switch(format) {
  87. case DATASOURCE_JSON:
  88. buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
  89. break;
  90. case DATASOURCE_DATATABLE_JSON:
  91. buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
  92. break;
  93. case DATASOURCE_DATATABLE_JSONP:
  94. buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
  95. break;
  96. case DATASOURCE_JSONP:
  97. buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
  98. break;
  99. case DATASOURCE_SSV:
  100. buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
  101. break;
  102. case DATASOURCE_CSV:
  103. buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
  104. break;
  105. case DATASOURCE_TSV:
  106. buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
  107. break;
  108. case DATASOURCE_HTML:
  109. buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
  110. break;
  111. case DATASOURCE_JS_ARRAY:
  112. buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
  113. break;
  114. case DATASOURCE_SSV_COMMA:
  115. buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
  116. break;
  117. default:
  118. buffer_strcat(wb, "unknown");
  119. break;
  120. }
  121. }
  122. int rrdset2value_api_v1(
  123. RRDSET *st
  124. , BUFFER *wb
  125. , calculated_number *n
  126. , const char *dimensions
  127. , long points
  128. , long long after
  129. , long long before
  130. , int group_method
  131. , long group_time
  132. , uint32_t options
  133. , time_t *db_after
  134. , time_t *db_before
  135. , int *value_is_null
  136. , int timeout
  137. ) {
  138. int ret = HTTP_RESP_INTERNAL_SERVER_ERROR;
  139. ONEWAYALLOC *owa = onewayalloc_create(0);
  140. RRDR *r = rrd2rrdr(owa, st, points, after, before, group_method, group_time, options, dimensions, NULL, timeout);
  141. if(!r) {
  142. if(value_is_null) *value_is_null = 1;
  143. ret = HTTP_RESP_INTERNAL_SERVER_ERROR;
  144. goto cleanup;
  145. }
  146. if(rrdr_rows(r) == 0) {
  147. rrdr_free(owa, r);
  148. if(db_after) *db_after = 0;
  149. if(db_before) *db_before = 0;
  150. if(value_is_null) *value_is_null = 1;
  151. ret = HTTP_RESP_BAD_REQUEST;
  152. goto cleanup;
  153. }
  154. if(wb) {
  155. if (r->result_options & RRDR_RESULT_OPTION_RELATIVE)
  156. buffer_no_cacheable(wb);
  157. else if (r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
  158. buffer_cacheable(wb);
  159. }
  160. if(db_after) *db_after = r->after;
  161. if(db_before) *db_before = r->before;
  162. long i = (!(options & RRDR_OPTION_REVERSED))?rrdr_rows(r) - 1:0;
  163. *n = rrdr2value(r, i, options, value_is_null, NULL);
  164. ret = HTTP_RESP_OK;
  165. cleanup:
  166. if(r) rrdr_free(owa, r);
  167. onewayalloc_destroy(owa);
  168. return ret;
  169. }
  170. int rrdset2anything_api_v1(
  171. ONEWAYALLOC *owa
  172. , RRDSET *st
  173. , QUERY_PARAMS *query_params
  174. , BUFFER *dimensions
  175. , uint32_t format
  176. , long points
  177. , long long after
  178. , long long before
  179. , int group_method
  180. , long group_time
  181. , uint32_t options
  182. , time_t *latest_timestamp
  183. )
  184. {
  185. BUFFER *wb = query_params->wb;
  186. if (query_params->context_param_list && !(query_params->context_param_list->flags & CONTEXT_FLAGS_ARCHIVE))
  187. st->last_accessed_time = now_realtime_sec();
  188. RRDR *r = rrd2rrdr(
  189. owa,
  190. st,
  191. points,
  192. after,
  193. before,
  194. group_method,
  195. group_time,
  196. options,
  197. dimensions ? buffer_tostring(dimensions) : NULL,
  198. query_params->context_param_list,
  199. query_params->timeout);
  200. if(!r) {
  201. buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
  202. return HTTP_RESP_INTERNAL_SERVER_ERROR;
  203. }
  204. if (r->result_options & RRDR_RESULT_OPTION_CANCEL) {
  205. rrdr_free(owa, r);
  206. return HTTP_RESP_BACKEND_FETCH_FAILED;
  207. }
  208. if (st && st->state && st->state->is_ar_chart)
  209. ml_process_rrdr(r, query_params->max_anomaly_rates);
  210. RRDDIM *temp_rd = query_params->context_param_list ? query_params->context_param_list->rd : NULL;
  211. if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
  212. buffer_no_cacheable(wb);
  213. else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
  214. buffer_cacheable(wb);
  215. if(latest_timestamp && rrdr_rows(r) > 0)
  216. *latest_timestamp = r->before;
  217. switch(format) {
  218. case DATASOURCE_SSV:
  219. if(options & RRDR_OPTION_JSON_WRAP) {
  220. wb->contenttype = CT_APPLICATION_JSON;
  221. rrdr_json_wrapper_begin(r, wb, format, options, 1, query_params);
  222. rrdr2ssv(r, wb, options, "", " ", "", temp_rd);
  223. rrdr_json_wrapper_end(r, wb, format, options, 1);
  224. }
  225. else {
  226. wb->contenttype = CT_TEXT_PLAIN;
  227. rrdr2ssv(r, wb, options, "", " ", "", temp_rd);
  228. }
  229. break;
  230. case DATASOURCE_SSV_COMMA:
  231. if(options & RRDR_OPTION_JSON_WRAP) {
  232. wb->contenttype = CT_APPLICATION_JSON;
  233. rrdr_json_wrapper_begin(r, wb, format, options, 1, query_params);
  234. rrdr2ssv(r, wb, options, "", ",", "", temp_rd);
  235. rrdr_json_wrapper_end(r, wb, format, options, 1);
  236. }
  237. else {
  238. wb->contenttype = CT_TEXT_PLAIN;
  239. rrdr2ssv(r, wb, options, "", ",", "", temp_rd);
  240. }
  241. break;
  242. case DATASOURCE_JS_ARRAY:
  243. if(options & RRDR_OPTION_JSON_WRAP) {
  244. wb->contenttype = CT_APPLICATION_JSON;
  245. rrdr_json_wrapper_begin(r, wb, format, options, 0, query_params);
  246. rrdr2ssv(r, wb, options, "[", ",", "]", temp_rd);
  247. rrdr_json_wrapper_end(r, wb, format, options, 0);
  248. }
  249. else {
  250. wb->contenttype = CT_APPLICATION_JSON;
  251. rrdr2ssv(r, wb, options, "[", ",", "]", temp_rd);
  252. }
  253. break;
  254. case DATASOURCE_CSV:
  255. if(options & RRDR_OPTION_JSON_WRAP) {
  256. wb->contenttype = CT_APPLICATION_JSON;
  257. rrdr_json_wrapper_begin(r, wb, format, options, 1, query_params);
  258. rrdr2csv(r, wb, format, options, "", ",", "\\n", "", temp_rd);
  259. rrdr_json_wrapper_end(r, wb, format, options, 1);
  260. }
  261. else {
  262. wb->contenttype = CT_TEXT_PLAIN;
  263. rrdr2csv(r, wb, format, options, "", ",", "\r\n", "", temp_rd);
  264. }
  265. break;
  266. case DATASOURCE_CSV_MARKDOWN:
  267. if(options & RRDR_OPTION_JSON_WRAP) {
  268. wb->contenttype = CT_APPLICATION_JSON;
  269. rrdr_json_wrapper_begin(r, wb, format, options, 1, query_params);
  270. rrdr2csv(r, wb, format, options, "", "|", "\\n", "", temp_rd);
  271. rrdr_json_wrapper_end(r, wb, format, options, 1);
  272. }
  273. else {
  274. wb->contenttype = CT_TEXT_PLAIN;
  275. rrdr2csv(r, wb, format, options, "", "|", "\r\n", "", temp_rd);
  276. }
  277. break;
  278. case DATASOURCE_CSV_JSON_ARRAY:
  279. wb->contenttype = CT_APPLICATION_JSON;
  280. if(options & RRDR_OPTION_JSON_WRAP) {
  281. rrdr_json_wrapper_begin(r, wb, format, options, 0, query_params);
  282. buffer_strcat(wb, "[\n");
  283. rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd);
  284. buffer_strcat(wb, "\n]");
  285. rrdr_json_wrapper_end(r, wb, format, options, 0);
  286. }
  287. else {
  288. wb->contenttype = CT_APPLICATION_JSON;
  289. buffer_strcat(wb, "[\n");
  290. rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n", temp_rd);
  291. buffer_strcat(wb, "\n]");
  292. }
  293. break;
  294. case DATASOURCE_TSV:
  295. if(options & RRDR_OPTION_JSON_WRAP) {
  296. wb->contenttype = CT_APPLICATION_JSON;
  297. rrdr_json_wrapper_begin(r, wb, format, options, 1, query_params);
  298. rrdr2csv(r, wb, format, options, "", "\t", "\\n", "", temp_rd);
  299. rrdr_json_wrapper_end(r, wb, format, options, 1);
  300. }
  301. else {
  302. wb->contenttype = CT_TEXT_PLAIN;
  303. rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "", temp_rd);
  304. }
  305. break;
  306. case DATASOURCE_HTML:
  307. if(options & RRDR_OPTION_JSON_WRAP) {
  308. wb->contenttype = CT_APPLICATION_JSON;
  309. rrdr_json_wrapper_begin(r, wb, format, options, 1, query_params);
  310. buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
  311. rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "", temp_rd);
  312. buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
  313. rrdr_json_wrapper_end(r, wb, format, options, 1);
  314. }
  315. else {
  316. wb->contenttype = CT_TEXT_HTML;
  317. buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
  318. rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\n", "", temp_rd);
  319. buffer_strcat(wb, "</table>\n</center>\n</html>\n");
  320. }
  321. break;
  322. case DATASOURCE_DATATABLE_JSONP:
  323. wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
  324. if(options & RRDR_OPTION_JSON_WRAP)
  325. rrdr_json_wrapper_begin(r, wb, format, options, 0, query_params);
  326. rrdr2json(r, wb, options, 1, query_params->context_param_list);
  327. if(options & RRDR_OPTION_JSON_WRAP)
  328. rrdr_json_wrapper_end(r, wb, format, options, 0);
  329. break;
  330. case DATASOURCE_DATATABLE_JSON:
  331. wb->contenttype = CT_APPLICATION_JSON;
  332. if(options & RRDR_OPTION_JSON_WRAP)
  333. rrdr_json_wrapper_begin(r, wb, format, options, 0, query_params);
  334. rrdr2json(r, wb, options, 1, query_params->context_param_list);
  335. if(options & RRDR_OPTION_JSON_WRAP)
  336. rrdr_json_wrapper_end(r, wb, format, options, 0);
  337. break;
  338. case DATASOURCE_JSONP:
  339. wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
  340. if(options & RRDR_OPTION_JSON_WRAP)
  341. rrdr_json_wrapper_begin(r, wb, format, options, 0, query_params);
  342. rrdr2json(r, wb, options, 0, query_params->context_param_list);
  343. if(options & RRDR_OPTION_JSON_WRAP)
  344. rrdr_json_wrapper_end(r, wb, format, options, 0);
  345. break;
  346. case DATASOURCE_JSON:
  347. default:
  348. wb->contenttype = CT_APPLICATION_JSON;
  349. if(options & RRDR_OPTION_JSON_WRAP)
  350. rrdr_json_wrapper_begin(r, wb, format, options, 0, query_params);
  351. rrdr2json(r, wb, options, 0, query_params->context_param_list);
  352. if(options & RRDR_OPTION_JSON_WRAP)
  353. rrdr_json_wrapper_end(r, wb, format, options, 0);
  354. break;
  355. }
  356. rrdr_free(owa, r);
  357. return HTTP_RESP_OK;
  358. }