rrdset2json.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "rrdset2json.h"
  3. void chart_labels2json(RRDSET *st, BUFFER *wb, size_t indentation)
  4. {
  5. char tabs[11];
  6. struct label_index *labels = &st->state->labels;
  7. if (indentation > 10)
  8. indentation = 10;
  9. tabs[0] = '\0';
  10. while (indentation) {
  11. strcat(tabs, "\t");
  12. indentation--;
  13. }
  14. int count = 0;
  15. netdata_rwlock_rdlock(&labels->labels_rwlock);
  16. for (struct label *label = labels->head; label; label = label->next) {
  17. if(count > 0) buffer_strcat(wb, ",\n");
  18. buffer_strcat(wb, tabs);
  19. char value[CONFIG_MAX_VALUE * 2 + 1];
  20. sanitize_json_string(value, label->value, CONFIG_MAX_VALUE * 2);
  21. buffer_sprintf(wb, "\"%s\": \"%s\"", label->key, value);
  22. count++;
  23. }
  24. buffer_strcat(wb, "\n");
  25. netdata_rwlock_unlock(&labels->labels_rwlock);
  26. }
  27. // generate JSON for the /api/v1/chart API call
  28. void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used, int skip_volatile) {
  29. rrdset_rdlock(st);
  30. time_t first_entry_t = rrdset_first_entry_t_nolock(st);
  31. time_t last_entry_t = rrdset_last_entry_t_nolock(st);
  32. buffer_sprintf(
  33. wb,
  34. "\t\t{\n"
  35. "\t\t\t\"id\": \"%s\",\n"
  36. "\t\t\t\"name\": \"%s\",\n"
  37. "\t\t\t\"type\": \"%s\",\n"
  38. "\t\t\t\"family\": \"%s\",\n"
  39. "\t\t\t\"context\": \"%s\",\n"
  40. "\t\t\t\"title\": \"%s (%s)\",\n"
  41. "\t\t\t\"priority\": %ld,\n"
  42. "\t\t\t\"plugin\": \"%s\",\n"
  43. "\t\t\t\"module\": \"%s\",\n"
  44. "\t\t\t\"enabled\": %s,\n"
  45. "\t\t\t\"units\": \"%s\",\n"
  46. "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
  47. "\t\t\t\"chart_type\": \"%s\",\n",
  48. st->id,
  49. st->name,
  50. st->type,
  51. st->family,
  52. st->context,
  53. st->title,
  54. st->name,
  55. st->priority,
  56. st->plugin_name ? st->plugin_name : "",
  57. st->module_name ? st->module_name : "",
  58. rrdset_flag_check(st, RRDSET_FLAG_ENABLED) ? "true" : "false",
  59. st->units,
  60. st->name,
  61. rrdset_type_name(st->chart_type));
  62. if (likely(!skip_volatile))
  63. buffer_sprintf(
  64. wb,
  65. "\t\t\t\"duration\": %"PRId64",\n",
  66. (int64_t)(last_entry_t - first_entry_t + st->update_every) //st->entries * st->update_every
  67. );
  68. buffer_sprintf(
  69. wb,
  70. "\t\t\t\"first_entry\": %"PRId64",\n",
  71. (int64_t)first_entry_t //rrdset_first_entry_t(st)
  72. );
  73. if (likely(!skip_volatile))
  74. buffer_sprintf(
  75. wb,
  76. "\t\t\t\"last_entry\": %"PRId64",\n",
  77. (int64_t)last_entry_t //rrdset_last_entry_t(st)
  78. );
  79. buffer_sprintf(
  80. wb,
  81. "\t\t\t\"update_every\": %d,\n"
  82. "\t\t\t\"dimensions\": {\n",
  83. st->update_every);
  84. unsigned long memory = st->memsize;
  85. size_t dimensions = 0;
  86. RRDDIM *rd;
  87. rrddim_foreach_read(rd, st) {
  88. if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN) || rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) continue;
  89. memory += rd->memsize;
  90. if (dimensions)
  91. buffer_strcat(wb, ",\n\t\t\t\t\"");
  92. else
  93. buffer_strcat(wb, "\t\t\t\t\"");
  94. buffer_strcat_jsonescape(wb, rd->id);
  95. buffer_strcat(wb, "\": { \"name\": \"");
  96. buffer_strcat_jsonescape(wb, rd->name);
  97. buffer_strcat(wb, "\" }");
  98. dimensions++;
  99. }
  100. if(dimensions_count) *dimensions_count += dimensions;
  101. if(memory_used) *memory_used += memory;
  102. buffer_sprintf(wb, "\n\t\t\t},\n\t\t\t\"chart_variables\": ");
  103. health_api_v1_chart_custom_variables2json(st, wb);
  104. buffer_strcat(wb, ",\n\t\t\t\"green\": ");
  105. buffer_rrd_value(wb, st->green);
  106. buffer_strcat(wb, ",\n\t\t\t\"red\": ");
  107. buffer_rrd_value(wb, st->red);
  108. if (likely(!skip_volatile)) {
  109. buffer_strcat(wb, ",\n\t\t\t\"alarms\": {\n");
  110. size_t alarms = 0;
  111. RRDCALC *rc;
  112. for (rc = st->alarms; rc; rc = rc->rrdset_next) {
  113. buffer_sprintf(
  114. wb,
  115. "%s"
  116. "\t\t\t\t\"%s\": {\n"
  117. "\t\t\t\t\t\"id\": %u,\n"
  118. "\t\t\t\t\t\"status\": \"%s\",\n"
  119. "\t\t\t\t\t\"units\": \"%s\",\n"
  120. "\t\t\t\t\t\"update_every\": %d\n"
  121. "\t\t\t\t}",
  122. (alarms) ? ",\n" : "", rc->name, rc->id, rrdcalc_status2string(rc->status), rc->units,
  123. rc->update_every);
  124. alarms++;
  125. }
  126. buffer_sprintf(wb,
  127. "\n\t\t\t}"
  128. );
  129. }
  130. buffer_strcat(wb, ",\n\t\t\t\"chart_labels\": {\n");
  131. chart_labels2json(st, wb, 2);
  132. buffer_strcat(wb, "\t\t\t}\n");
  133. buffer_sprintf(wb,
  134. "\n\t\t}"
  135. );
  136. rrdset_unlock(st);
  137. }