charts2json.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "charts2json.h"
  3. // generate JSON for the /api/v1/charts API call
  4. const char* get_release_channel() {
  5. static int use_stable = -1;
  6. if (use_stable == -1) {
  7. char filename[FILENAME_MAX + 1];
  8. snprintfz(filename, FILENAME_MAX, "%s/.environment", netdata_configured_user_config_dir);
  9. procfile *ff = procfile_open(filename, "=", PROCFILE_FLAG_DEFAULT);
  10. if(!ff) {
  11. use_stable=1;
  12. } else {
  13. procfile_set_quotes(ff, "'\"");
  14. ff = procfile_readall(ff);
  15. if(!ff) {
  16. use_stable=1;
  17. } else {
  18. unsigned int i;
  19. for(i = 0; i < procfile_lines(ff); i++) {
  20. if (!procfile_linewords(ff, i)) continue;
  21. if (!strcmp(procfile_lineword(ff, i, 0), "RELEASE_CHANNEL") && !strcmp(procfile_lineword(ff, i, 1), "stable")) {
  22. use_stable = 1;
  23. break;
  24. }
  25. }
  26. procfile_close(ff);
  27. if (use_stable == -1) use_stable = 0;
  28. }
  29. }
  30. }
  31. return (use_stable)?"stable":"nightly";
  32. }
  33. void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived) {
  34. static char *custom_dashboard_info_js_filename = NULL;
  35. size_t c, dimensions = 0, memory = 0, alarms = 0;
  36. RRDSET *st;
  37. time_t now = now_realtime_sec();
  38. if(unlikely(!custom_dashboard_info_js_filename))
  39. custom_dashboard_info_js_filename = config_get(CONFIG_SECTION_WEB, "custom dashboard_info.js", "");
  40. buffer_sprintf(wb, "{\n"
  41. "\t\"hostname\": \"%s\""
  42. ",\n\t\"version\": \"%s\""
  43. ",\n\t\"release_channel\": \"%s\""
  44. ",\n\t\"os\": \"%s\""
  45. ",\n\t\"timezone\": \"%s\""
  46. ",\n\t\"update_every\": %d"
  47. ",\n\t\"history\": %ld"
  48. ",\n\t\"memory_mode\": \"%s\""
  49. ",\n\t\"custom_info\": \"%s\""
  50. ",\n\t\"charts\": {"
  51. , host->hostname
  52. , host->program_version
  53. , get_release_channel()
  54. , host->os
  55. , host->timezone
  56. , host->rrd_update_every
  57. , host->rrd_history_entries
  58. , rrd_memory_mode_name(host->rrd_memory_mode)
  59. , custom_dashboard_info_js_filename
  60. );
  61. c = 0;
  62. rrdhost_rdlock(host);
  63. rrdset_foreach_read(st, host) {
  64. if ((!show_archived && rrdset_is_available_for_viewers(st)) || (show_archived && rrdset_is_archived(st))) {
  65. if(c) buffer_strcat(wb, ",");
  66. buffer_strcat(wb, "\n\t\t\"");
  67. buffer_strcat(wb, st->id);
  68. buffer_strcat(wb, "\": ");
  69. rrdset2json(st, wb, &dimensions, &memory, skip_volatile);
  70. c++;
  71. st->last_accessed_time = now;
  72. }
  73. }
  74. RRDCALC *rc;
  75. for(rc = host->alarms; rc ; rc = rc->next) {
  76. if(rc->rrdset)
  77. alarms++;
  78. }
  79. rrdhost_unlock(host);
  80. buffer_sprintf(wb
  81. , "\n\t}"
  82. ",\n\t\"charts_count\": %zu"
  83. ",\n\t\"dimensions_count\": %zu"
  84. ",\n\t\"alarms_count\": %zu"
  85. ",\n\t\"rrd_memory_bytes\": %zu"
  86. ",\n\t\"hosts_count\": %zu"
  87. ",\n\t\"hosts\": ["
  88. , c
  89. , dimensions
  90. , alarms
  91. , memory
  92. , rrd_hosts_available
  93. );
  94. if(unlikely(rrd_hosts_available > 1)) {
  95. rrd_rdlock();
  96. size_t found = 0;
  97. RRDHOST *h;
  98. rrdhost_foreach_read(h) {
  99. if(!rrdhost_should_be_removed(h, host, now) && !rrdhost_flag_check(h, RRDHOST_FLAG_ARCHIVED)) {
  100. buffer_sprintf(wb
  101. , "%s\n\t\t{"
  102. "\n\t\t\t\"hostname\": \"%s\""
  103. "\n\t\t}"
  104. , (found > 0) ? "," : ""
  105. , h->hostname
  106. );
  107. found++;
  108. }
  109. }
  110. rrd_unlock();
  111. }
  112. else {
  113. buffer_sprintf(wb
  114. , "\n\t\t{"
  115. "\n\t\t\t\"hostname\": \"%s\""
  116. "\n\t\t}"
  117. , host->hostname
  118. );
  119. }
  120. buffer_sprintf(wb, "\n\t]\n}\n");
  121. }
  122. // generate collectors list for the api/v1/info call
  123. struct collector {
  124. char *plugin;
  125. char *module;
  126. };
  127. struct array_printer {
  128. int c;
  129. BUFFER *wb;
  130. };
  131. int print_collector(void *entry, void *data) {
  132. struct array_printer *ap = (struct array_printer *)data;
  133. BUFFER *wb = ap->wb;
  134. struct collector *col=(struct collector *) entry;
  135. if(ap->c) buffer_strcat(wb, ",");
  136. buffer_strcat(wb, "\n\t\t{\n\t\t\t\"plugin\": \"");
  137. buffer_strcat(wb, col->plugin);
  138. buffer_strcat(wb, "\",\n\t\t\t\"module\": \"");
  139. buffer_strcat(wb, col->module);
  140. buffer_strcat(wb, "\"\n\t\t}");
  141. (ap->c)++;
  142. return 0;
  143. }
  144. void chartcollectors2json(RRDHOST *host, BUFFER *wb) {
  145. DICTIONARY *dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
  146. RRDSET *st;
  147. char name[500];
  148. time_t now = now_realtime_sec();
  149. rrdhost_rdlock(host);
  150. rrdset_foreach_read(st, host) {
  151. if (rrdset_is_available_for_viewers(st)) {
  152. struct collector col = {
  153. .plugin = st->plugin_name ? st->plugin_name : "",
  154. .module = st->module_name ? st->module_name : ""
  155. };
  156. sprintf(name, "%s:%s", col.plugin, col.module);
  157. dictionary_set(dict, name, &col, sizeof(struct collector));
  158. st->last_accessed_time = now;
  159. }
  160. }
  161. rrdhost_unlock(host);
  162. struct array_printer ap = {
  163. .c = 0,
  164. .wb = wb
  165. };
  166. dictionary_get_all(dict, print_collector, &ap);
  167. dictionary_destroy(dict);
  168. }