json_wrapper.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "json_wrapper.h"
  3. void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
  4. struct context_param *context_param_list, char *chart_label_key)
  5. {
  6. RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL;
  7. int should_lock = (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE));
  8. uint8_t context_mode = (!context_param_list || (context_param_list->flags & CONTEXT_FLAGS_CONTEXT));
  9. if (should_lock)
  10. rrdset_check_rdlock(r->st);
  11. long rows = rrdr_rows(r);
  12. long c, i;
  13. RRDDIM *rd;
  14. //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
  15. char kq[2] = "", // key quote
  16. sq[2] = ""; // string quote
  17. if( options & RRDR_OPTION_GOOGLE_JSON ) {
  18. kq[0] = '\0';
  19. sq[0] = '\'';
  20. }
  21. else {
  22. kq[0] = '"';
  23. sq[0] = '"';
  24. }
  25. if (should_lock)
  26. rrdset_rdlock(r->st);
  27. buffer_sprintf(wb, "{\n"
  28. " %sapi%s: 1,\n"
  29. " %sid%s: %s%s%s,\n"
  30. " %sname%s: %s%s%s,\n"
  31. " %sview_update_every%s: %d,\n"
  32. " %supdate_every%s: %d,\n"
  33. " %sfirst_entry%s: %u,\n"
  34. " %slast_entry%s: %u,\n"
  35. " %sbefore%s: %u,\n"
  36. " %safter%s: %u,\n"
  37. " %sdimension_names%s: ["
  38. , kq, kq
  39. , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->id, sq
  40. , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->name, sq
  41. , kq, kq, r->update_every
  42. , kq, kq, r->st->update_every
  43. , kq, kq, (uint32_t) (context_param_list ? context_param_list->first_entry_t : rrdset_first_entry_t_nolock(r->st))
  44. , kq, kq, (uint32_t) (context_param_list ? context_param_list->last_entry_t : rrdset_last_entry_t_nolock(r->st))
  45. , kq, kq, (uint32_t)r->before
  46. , kq, kq, (uint32_t)r->after
  47. , kq, kq);
  48. if (should_lock)
  49. rrdset_unlock(r->st);
  50. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  51. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  52. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  53. if(i) buffer_strcat(wb, ", ");
  54. buffer_strcat(wb, sq);
  55. buffer_strcat(wb, rd->name);
  56. buffer_strcat(wb, sq);
  57. i++;
  58. }
  59. if(!i) {
  60. #ifdef NETDATA_INTERNAL_CHECKS
  61. error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
  62. #endif
  63. rows = 0;
  64. buffer_strcat(wb, sq);
  65. buffer_strcat(wb, "no data");
  66. buffer_strcat(wb, sq);
  67. }
  68. buffer_sprintf(wb, "],\n"
  69. " %sdimension_ids%s: ["
  70. , kq, kq);
  71. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  72. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  73. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  74. if(i) buffer_strcat(wb, ", ");
  75. buffer_strcat(wb, sq);
  76. buffer_strcat(wb, rd->id);
  77. buffer_strcat(wb, sq);
  78. i++;
  79. }
  80. if(!i) {
  81. rows = 0;
  82. buffer_strcat(wb, sq);
  83. buffer_strcat(wb, "no data");
  84. buffer_strcat(wb, sq);
  85. }
  86. buffer_strcat(wb, "],\n");
  87. // Composite charts
  88. if (context_mode && temp_rd) {
  89. buffer_sprintf(
  90. wb,
  91. " %schart_ids%s: [",
  92. kq, kq);
  93. for (c = 0, i = 0, rd = temp_rd ; rd && c < r->d; c++, rd = rd->next) {
  94. if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
  95. continue;
  96. if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
  97. continue;
  98. if (i)
  99. buffer_strcat(wb, ", ");
  100. buffer_strcat(wb, sq);
  101. buffer_strcat(wb, rd->rrdset->id);
  102. buffer_strcat(wb, sq);
  103. i++;
  104. }
  105. if (!i) {
  106. rows = 0;
  107. buffer_strcat(wb, sq);
  108. buffer_strcat(wb, "no data");
  109. buffer_strcat(wb, sq);
  110. }
  111. buffer_strcat(wb, "],\n");
  112. if (chart_label_key) {
  113. buffer_sprintf(wb, " %schart_labels%s: { ", kq, kq);
  114. SIMPLE_PATTERN *pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
  115. SIMPLE_PATTERN *original_pattern = pattern;
  116. char *label_key = NULL;
  117. int keys = 0;
  118. while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
  119. uint32_t key_hash = simple_hash(label_key);
  120. struct label *current_label;
  121. if (keys)
  122. buffer_strcat(wb, ", ");
  123. buffer_sprintf(wb, "%s%s%s : [", kq, label_key, kq);
  124. keys++;
  125. for (c = 0, i = 0, rd = temp_rd; rd && c < r->d; c++, rd = rd->next) {
  126. if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN))
  127. continue;
  128. if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
  129. continue;
  130. if (i)
  131. buffer_strcat(wb, ", ");
  132. current_label = rrdset_lookup_label_key(rd->rrdset, label_key, key_hash);
  133. if (current_label) {
  134. buffer_strcat(wb, sq);
  135. buffer_strcat(wb, current_label->value);
  136. buffer_strcat(wb, sq);
  137. } else
  138. buffer_strcat(wb, "null");
  139. i++;
  140. }
  141. if (!i) {
  142. rows = 0;
  143. buffer_strcat(wb, sq);
  144. buffer_strcat(wb, "no data");
  145. buffer_strcat(wb, sq);
  146. }
  147. buffer_strcat(wb, "]");
  148. }
  149. buffer_strcat(wb, "},\n");
  150. simple_pattern_free(original_pattern);
  151. }
  152. }
  153. buffer_sprintf(wb, " %slatest_values%s: ["
  154. , kq, kq);
  155. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  156. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  157. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  158. if(i) buffer_strcat(wb, ", ");
  159. i++;
  160. calculated_number value = rd->last_stored_value;
  161. if (NAN == value)
  162. buffer_strcat(wb, "null");
  163. else
  164. buffer_rrd_value(wb, value);
  165. /*
  166. storage_number n = rd->values[rrdset_last_slot(r->st)];
  167. if(!does_storage_number_exist(n))
  168. buffer_strcat(wb, "null");
  169. else
  170. buffer_rrd_value(wb, unpack_storage_number(n));
  171. */
  172. }
  173. if(!i) {
  174. rows = 0;
  175. buffer_strcat(wb, "null");
  176. }
  177. buffer_sprintf(wb, "],\n"
  178. " %sview_latest_values%s: ["
  179. , kq, kq);
  180. i = 0;
  181. if(rows) {
  182. calculated_number total = 1;
  183. if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
  184. total = 0;
  185. for(c = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  186. calculated_number *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
  187. calculated_number n = cn[c];
  188. if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
  189. n = -n;
  190. total += n;
  191. }
  192. // prevent a division by zero
  193. if(total == 0) total = 1;
  194. }
  195. for(c = 0, i = 0, rd = temp_rd?temp_rd:r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
  196. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  197. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  198. if(i) buffer_strcat(wb, ", ");
  199. i++;
  200. calculated_number *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
  201. RRDR_VALUE_FLAGS *co = &r->o[ (rrdr_rows(r) - 1) * r->d ];
  202. calculated_number n = cn[c];
  203. if(co[c] & RRDR_VALUE_EMPTY) {
  204. if(options & RRDR_OPTION_NULL2ZERO)
  205. buffer_strcat(wb, "0");
  206. else
  207. buffer_strcat(wb, "null");
  208. }
  209. else {
  210. if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
  211. n = -n;
  212. if(unlikely(options & RRDR_OPTION_PERCENTAGE))
  213. n = n * 100 / total;
  214. buffer_rrd_value(wb, n);
  215. }
  216. }
  217. }
  218. if(!i) {
  219. rows = 0;
  220. buffer_strcat(wb, "null");
  221. }
  222. buffer_sprintf(wb, "],\n"
  223. " %sdimensions%s: %ld,\n"
  224. " %spoints%s: %ld,\n"
  225. " %sformat%s: %s"
  226. , kq, kq, i
  227. , kq, kq, rows
  228. , kq, kq, sq
  229. );
  230. rrdr_buffer_print_format(wb, format);
  231. if((options & RRDR_OPTION_CUSTOM_VARS) && (options & RRDR_OPTION_JSON_WRAP)) {
  232. buffer_sprintf(wb, "%s,\n %schart_variables%s: ", sq, kq, kq);
  233. health_api_v1_chart_custom_variables2json(r->st, wb);
  234. }
  235. else
  236. buffer_sprintf(wb, "%s", sq);
  237. buffer_sprintf(wb, ",\n %sresult%s: ", kq, kq);
  238. if(string_value) buffer_strcat(wb, sq);
  239. //info("JSONWRAPPER(): %s: END", r->st->id);
  240. }
  241. void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
  242. (void)format;
  243. char kq[2] = "", // key quote
  244. sq[2] = ""; // string quote
  245. if( options & RRDR_OPTION_GOOGLE_JSON ) {
  246. kq[0] = '\0';
  247. sq[0] = '\'';
  248. }
  249. else {
  250. kq[0] = '"';
  251. sq[0] = '"';
  252. }
  253. if(string_value) buffer_strcat(wb, sq);
  254. buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
  255. buffer_rrd_value(wb, r->min);
  256. buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
  257. buffer_rrd_value(wb, r->max);
  258. buffer_strcat(wb, "\n}\n");
  259. }