rrd2json.c 12 KB

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