json_wrapper.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "json_wrapper.h"
  3. struct value_output {
  4. int c;
  5. BUFFER *wb;
  6. };
  7. static int value_list_output(const char *name, void *entry, void *data) {
  8. (void)name;
  9. struct value_output *ap = (struct value_output *)data;
  10. BUFFER *wb = ap->wb;
  11. char *output = (char *) entry;
  12. if(ap->c) buffer_strcat(wb, ",");
  13. buffer_strcat(wb, output);
  14. (ap->c)++;
  15. return 0;
  16. }
  17. static int fill_formatted_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
  18. (void)ls;
  19. DICTIONARY *dict = (DICTIONARY *)data;
  20. char n[RRD_ID_LENGTH_MAX * 2 + 2];
  21. char output[RRD_ID_LENGTH_MAX * 2 + 8];
  22. char v[RRD_ID_LENGTH_MAX * 2 + 1];
  23. sanitize_json_string(v, (char *)value, RRD_ID_LENGTH_MAX * 2);
  24. int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\", \"%s\"]", name, v);
  25. snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, v);
  26. dictionary_set(dict, n, output, len + 1);
  27. return 1;
  28. }
  29. void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
  30. RRDR_GROUPING group_method, QUERY_PARAMS *rrdset_query_data)
  31. {
  32. struct context_param *context_param_list = rrdset_query_data->context_param_list;
  33. char *chart_label_key = rrdset_query_data->chart_label_key;
  34. RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL;
  35. int should_lock = (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE));
  36. uint8_t context_mode = (!context_param_list || (context_param_list->flags & CONTEXT_FLAGS_CONTEXT));
  37. if (should_lock)
  38. rrdset_check_rdlock(r->st);
  39. long rows = rrdr_rows(r);
  40. long c, i;
  41. RRDDIM *rd;
  42. //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
  43. char kq[2] = "", // key quote
  44. sq[2] = ""; // string quote
  45. if( options & RRDR_OPTION_GOOGLE_JSON ) {
  46. kq[0] = '\0';
  47. sq[0] = '\'';
  48. }
  49. else {
  50. kq[0] = '"';
  51. sq[0] = '"';
  52. }
  53. if (should_lock)
  54. rrdset_rdlock(r->st);
  55. buffer_sprintf(wb, "{\n"
  56. " %sapi%s: 1,\n"
  57. " %sid%s: %s%s%s,\n"
  58. " %sname%s: %s%s%s,\n"
  59. " %sview_update_every%s: %d,\n"
  60. " %supdate_every%s: %d,\n"
  61. " %sfirst_entry%s: %u,\n"
  62. " %slast_entry%s: %u,\n"
  63. " %sbefore%s: %u,\n"
  64. " %safter%s: %u,\n"
  65. " %sgroup%s: %s%s%s,\n"
  66. " %soptions%s: %s"
  67. , kq, kq
  68. , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->id, sq
  69. , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->name, sq
  70. , kq, kq, r->update_every
  71. , kq, kq, r->st->update_every
  72. , kq, kq, (uint32_t) (context_param_list ? context_param_list->first_entry_t : rrdset_first_entry_t_nolock(r->st))
  73. , kq, kq, (uint32_t) (context_param_list ? context_param_list->last_entry_t : rrdset_last_entry_t_nolock(r->st))
  74. , kq, kq, (uint32_t)r->before
  75. , kq, kq, (uint32_t)r->after
  76. , kq, kq, sq, web_client_api_request_v1_data_group_to_string(group_method), sq
  77. , kq, kq, sq);
  78. web_client_api_request_v1_data_options_to_string(wb, r->internal.query_options);
  79. buffer_sprintf(wb, "%s,\n %sdimension_names%s: [", sq, kq, kq);
  80. if (should_lock)
  81. rrdset_unlock(r->st);
  82. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  83. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  84. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  85. if(i) buffer_strcat(wb, ", ");
  86. buffer_strcat(wb, sq);
  87. buffer_strcat(wb, rd->name);
  88. buffer_strcat(wb, sq);
  89. i++;
  90. }
  91. if(!i) {
  92. #ifdef NETDATA_INTERNAL_CHECKS
  93. error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
  94. #endif
  95. rows = 0;
  96. buffer_strcat(wb, sq);
  97. buffer_strcat(wb, "no data");
  98. buffer_strcat(wb, sq);
  99. }
  100. buffer_sprintf(wb, "],\n"
  101. " %sdimension_ids%s: ["
  102. , kq, kq);
  103. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  104. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  105. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  106. if(i) buffer_strcat(wb, ", ");
  107. buffer_strcat(wb, sq);
  108. buffer_strcat(wb, rd->id);
  109. buffer_strcat(wb, sq);
  110. i++;
  111. }
  112. if(!i) {
  113. rows = 0;
  114. buffer_strcat(wb, sq);
  115. buffer_strcat(wb, "no data");
  116. buffer_strcat(wb, sq);
  117. }
  118. buffer_strcat(wb, "],\n");
  119. if (rrdset_query_data->show_dimensions) {
  120. buffer_sprintf(wb, " %sfull_dimension_list%s: [", kq, kq);
  121. char name[RRD_ID_LENGTH_MAX * 2 + 2];
  122. char output[RRD_ID_LENGTH_MAX * 2 + 8];
  123. struct value_output co = {.c = 0, .wb = wb};
  124. DICTIONARY *dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
  125. for (i = 0, rd = temp_rd ? temp_rd : r->st->dimensions; rd; rd = rd->next) {
  126. snprintfz(name, RRD_ID_LENGTH_MAX * 2, "%s:%s", rd->id, rd->name);
  127. int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]", rd->id, rd->name);
  128. dictionary_set(dict, name, output, len+1);
  129. }
  130. dictionary_walkthrough_read(dict, value_list_output, &co);
  131. dictionary_destroy(dict);
  132. co.c = 0;
  133. buffer_sprintf(wb, "],\n %sfull_chart_list%s: [", kq, kq);
  134. dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
  135. for (i = 0, rd = temp_rd ? temp_rd : r->st->dimensions; rd; rd = rd->next) {
  136. int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]", rd->rrdset->id, rd->rrdset->name);
  137. snprintfz(name, RRD_ID_LENGTH_MAX * 2, "%s:%s", rd->rrdset->id, rd->rrdset->name);
  138. dictionary_set(dict, name, output, len + 1);
  139. }
  140. dictionary_walkthrough_read(dict, value_list_output, &co);
  141. dictionary_destroy(dict);
  142. RRDSET *st;
  143. co.c = 0;
  144. buffer_sprintf(wb, "],\n %sfull_chart_labels%s: [", kq, kq);
  145. dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
  146. for (i = 0, rd = temp_rd ? temp_rd : r->st->dimensions; rd; rd = rd->next) {
  147. st = rd->rrdset;
  148. if (st->state && st->state->chart_labels)
  149. rrdlabels_walkthrough_read(st->state->chart_labels, fill_formatted_callback, dict);
  150. }
  151. dictionary_walkthrough_read(dict, value_list_output, &co);
  152. dictionary_destroy(dict);
  153. buffer_strcat(wb, "],\n");
  154. }
  155. // Composite charts
  156. if (context_mode && temp_rd) {
  157. buffer_sprintf(
  158. wb,
  159. " %schart_ids%s: [",
  160. kq, kq);
  161. for (c = 0, i = 0, rd = temp_rd ; rd && c < r->d; c++, rd = rd->next) {
  162. if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
  163. continue;
  164. if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
  165. continue;
  166. if (i)
  167. buffer_strcat(wb, ", ");
  168. buffer_strcat(wb, sq);
  169. buffer_strcat(wb, rd->rrdset->id);
  170. buffer_strcat(wb, sq);
  171. i++;
  172. }
  173. if (!i) {
  174. rows = 0;
  175. buffer_strcat(wb, sq);
  176. buffer_strcat(wb, "no data");
  177. buffer_strcat(wb, sq);
  178. }
  179. buffer_strcat(wb, "],\n");
  180. if (chart_label_key) {
  181. buffer_sprintf(wb, " %schart_labels%s: { ", kq, kq);
  182. SIMPLE_PATTERN *pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
  183. SIMPLE_PATTERN *original_pattern = pattern;
  184. char *label_key = NULL;
  185. int keys = 0;
  186. while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
  187. if (keys)
  188. buffer_strcat(wb, ", ");
  189. buffer_sprintf(wb, "%s%s%s : [", kq, label_key, kq);
  190. keys++;
  191. for (c = 0, i = 0, rd = temp_rd; rd && c < r->d; c++, rd = rd->next) {
  192. if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
  193. continue;
  194. if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
  195. continue;
  196. if (i)
  197. buffer_strcat(wb, ", ");
  198. rrdlabels_get_value_to_buffer_or_null(rd->rrdset->state->chart_labels, wb, label_key, sq, "null");
  199. i++;
  200. }
  201. if (!i) {
  202. rows = 0;
  203. buffer_strcat(wb, sq);
  204. buffer_strcat(wb, "no data");
  205. buffer_strcat(wb, sq);
  206. }
  207. buffer_strcat(wb, "]");
  208. }
  209. buffer_strcat(wb, "},\n");
  210. simple_pattern_free(original_pattern);
  211. }
  212. }
  213. buffer_sprintf(wb, " %slatest_values%s: ["
  214. , kq, kq);
  215. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  216. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  217. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  218. if(i) buffer_strcat(wb, ", ");
  219. i++;
  220. NETDATA_DOUBLE value = rd->last_stored_value;
  221. if (NAN == value)
  222. buffer_strcat(wb, "null");
  223. else
  224. buffer_rrd_value(wb, value);
  225. /*
  226. storage_number n = rd->values[rrdset_last_slot(r->st)];
  227. if(!does_storage_number_exist(n))
  228. buffer_strcat(wb, "null");
  229. else
  230. buffer_rrd_value(wb, unpack_storage_number(n));
  231. */
  232. }
  233. if(!i) {
  234. rows = 0;
  235. buffer_strcat(wb, "null");
  236. }
  237. buffer_sprintf(wb, "],\n"
  238. " %sview_latest_values%s: ["
  239. , kq, kq);
  240. i = 0;
  241. if(rows) {
  242. NETDATA_DOUBLE total = 1;
  243. if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
  244. total = 0;
  245. for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  246. NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
  247. NETDATA_DOUBLE n = cn[c];
  248. if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
  249. n = -n;
  250. total += n;
  251. }
  252. // prevent a division by zero
  253. if(total == 0) total = 1;
  254. }
  255. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  256. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  257. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  258. if(i) buffer_strcat(wb, ", ");
  259. i++;
  260. NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
  261. RRDR_VALUE_FLAGS *co = &r->o[ (rrdr_rows(r) - 1) * r->d ];
  262. NETDATA_DOUBLE n = cn[c];
  263. if(co[c] & RRDR_VALUE_EMPTY) {
  264. if(options & RRDR_OPTION_NULL2ZERO)
  265. buffer_strcat(wb, "0");
  266. else
  267. buffer_strcat(wb, "null");
  268. }
  269. else {
  270. if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
  271. n = -n;
  272. if(unlikely(options & RRDR_OPTION_PERCENTAGE))
  273. n = n * 100 / total;
  274. buffer_rrd_value(wb, n);
  275. }
  276. }
  277. }
  278. if(!i) {
  279. rows = 0;
  280. buffer_strcat(wb, "null");
  281. }
  282. buffer_sprintf(wb, "],\n"
  283. " %sdimensions%s: %ld,\n"
  284. " %spoints%s: %ld,\n"
  285. " %sformat%s: %s"
  286. , kq, kq, i
  287. , kq, kq, rows
  288. , kq, kq, sq
  289. );
  290. rrdr_buffer_print_format(wb, format);
  291. buffer_sprintf(wb, "%s,\n"
  292. " %sdb_points_per_tier%s: [ "
  293. , sq
  294. , kq, kq
  295. );
  296. for(int tier = 0; tier < storage_tiers ; tier++)
  297. buffer_sprintf(wb, "%s%zu", tier>0?", ":"", r->internal.tier_points_read[tier]);
  298. buffer_strcat(wb, " ]");
  299. if((options & RRDR_OPTION_CUSTOM_VARS) && (options & RRDR_OPTION_JSON_WRAP)) {
  300. buffer_sprintf(wb, ",\n %schart_variables%s: ", kq, kq);
  301. health_api_v1_chart_custom_variables2json(r->st, wb);
  302. }
  303. buffer_sprintf(wb, ",\n %sresult%s: ", kq, kq);
  304. if(string_value) buffer_strcat(wb, sq);
  305. //info("JSONWRAPPER(): %s: END", r->st->id);
  306. }
  307. void rrdr_json_wrapper_anomaly_rates(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
  308. (void)r;
  309. (void)format;
  310. char kq[2] = "", // key quote
  311. sq[2] = ""; // string quote
  312. if( options & RRDR_OPTION_GOOGLE_JSON ) {
  313. kq[0] = '\0';
  314. sq[0] = '\'';
  315. }
  316. else {
  317. kq[0] = '"';
  318. sq[0] = '"';
  319. }
  320. if(string_value) buffer_strcat(wb, sq);
  321. buffer_sprintf(wb, ",\n %sanomaly_rates%s: ", kq, kq);
  322. }
  323. void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
  324. (void)format;
  325. char kq[2] = "", // key quote
  326. sq[2] = ""; // string quote
  327. if( options & RRDR_OPTION_GOOGLE_JSON ) {
  328. kq[0] = '\0';
  329. sq[0] = '\'';
  330. }
  331. else {
  332. kq[0] = '"';
  333. sq[0] = '"';
  334. }
  335. if(string_value) buffer_strcat(wb, sq);
  336. buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
  337. buffer_rrd_value(wb, r->min);
  338. buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
  339. buffer_rrd_value(wb, r->max);
  340. buffer_strcat(wb, "\n}\n");
  341. }