rrd2json.c 14 KB

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