analytics.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "common.h"
  3. #include "buildinfo.h"
  4. struct analytics_data analytics_data;
  5. extern void analytics_exporting_connectors (BUFFER *b);
  6. extern void analytics_exporting_connectors_ssl (BUFFER *b);
  7. extern void analytics_build_info (BUFFER *b);
  8. extern int aclk_connected;
  9. struct collector {
  10. const char *plugin;
  11. const char *module;
  12. };
  13. struct array_printer {
  14. int c;
  15. BUFFER *both;
  16. };
  17. /*
  18. * Debug logging
  19. */
  20. void analytics_log_data(void)
  21. {
  22. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_STREAM_ENABLED : [%s]", analytics_data.netdata_config_stream_enabled);
  23. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_MEMORY_MODE : [%s]", analytics_data.netdata_config_memory_mode);
  24. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_EXPORTING_ENABLED : [%s]", analytics_data.netdata_config_exporting_enabled);
  25. netdata_log_debug(D_ANALYTICS, "NETDATA_EXPORTING_CONNECTORS : [%s]", analytics_data.netdata_exporting_connectors);
  26. netdata_log_debug(D_ANALYTICS, "NETDATA_ALLMETRICS_PROMETHEUS_USED : [%s]", analytics_data.netdata_allmetrics_prometheus_used);
  27. netdata_log_debug(D_ANALYTICS, "NETDATA_ALLMETRICS_SHELL_USED : [%s]", analytics_data.netdata_allmetrics_shell_used);
  28. netdata_log_debug(D_ANALYTICS, "NETDATA_ALLMETRICS_JSON_USED : [%s]", analytics_data.netdata_allmetrics_json_used);
  29. netdata_log_debug(D_ANALYTICS, "NETDATA_DASHBOARD_USED : [%s]", analytics_data.netdata_dashboard_used);
  30. netdata_log_debug(D_ANALYTICS, "NETDATA_COLLECTORS : [%s]", analytics_data.netdata_collectors);
  31. netdata_log_debug(D_ANALYTICS, "NETDATA_COLLECTORS_COUNT : [%s]", analytics_data.netdata_collectors_count);
  32. netdata_log_debug(D_ANALYTICS, "NETDATA_BUILDINFO : [%s]", analytics_data.netdata_buildinfo);
  33. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_PAGE_CACHE_SIZE : [%s]", analytics_data.netdata_config_page_cache_size);
  34. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_MULTIDB_DISK_QUOTA : [%s]", analytics_data.netdata_config_multidb_disk_quota);
  35. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_HTTPS_ENABLED : [%s]", analytics_data.netdata_config_https_enabled);
  36. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_WEB_ENABLED : [%s]", analytics_data.netdata_config_web_enabled);
  37. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_RELEASE_CHANNEL : [%s]", analytics_data.netdata_config_release_channel);
  38. netdata_log_debug(D_ANALYTICS, "NETDATA_MIRRORED_HOST_COUNT : [%s]", analytics_data.netdata_mirrored_host_count);
  39. netdata_log_debug(D_ANALYTICS, "NETDATA_MIRRORED_HOSTS_REACHABLE : [%s]", analytics_data.netdata_mirrored_hosts_reachable);
  40. netdata_log_debug(D_ANALYTICS, "NETDATA_MIRRORED_HOSTS_UNREACHABLE : [%s]", analytics_data.netdata_mirrored_hosts_unreachable);
  41. netdata_log_debug(D_ANALYTICS, "NETDATA_NOTIFICATION_METHODS : [%s]", analytics_data.netdata_notification_methods);
  42. netdata_log_debug(D_ANALYTICS, "NETDATA_ALARMS_NORMAL : [%s]", analytics_data.netdata_alarms_normal);
  43. netdata_log_debug(D_ANALYTICS, "NETDATA_ALARMS_WARNING : [%s]", analytics_data.netdata_alarms_warning);
  44. netdata_log_debug(D_ANALYTICS, "NETDATA_ALARMS_CRITICAL : [%s]", analytics_data.netdata_alarms_critical);
  45. netdata_log_debug(D_ANALYTICS, "NETDATA_CHARTS_COUNT : [%s]", analytics_data.netdata_charts_count);
  46. netdata_log_debug(D_ANALYTICS, "NETDATA_METRICS_COUNT : [%s]", analytics_data.netdata_metrics_count);
  47. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_IS_PARENT : [%s]", analytics_data.netdata_config_is_parent);
  48. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_HOSTS_AVAILABLE : [%s]", analytics_data.netdata_config_hosts_available);
  49. netdata_log_debug(D_ANALYTICS, "NETDATA_HOST_CLOUD_AVAILABLE : [%s]", analytics_data.netdata_host_cloud_available);
  50. netdata_log_debug(D_ANALYTICS, "NETDATA_HOST_ACLK_AVAILABLE : [%s]", analytics_data.netdata_host_aclk_available);
  51. netdata_log_debug(D_ANALYTICS, "NETDATA_HOST_ACLK_PROTOCOL : [%s]", analytics_data.netdata_host_aclk_protocol);
  52. netdata_log_debug(D_ANALYTICS, "NETDATA_HOST_ACLK_IMPLEMENTATION : [%s]", analytics_data.netdata_host_aclk_implementation);
  53. netdata_log_debug(D_ANALYTICS, "NETDATA_HOST_AGENT_CLAIMED : [%s]", analytics_data.netdata_host_agent_claimed);
  54. netdata_log_debug(D_ANALYTICS, "NETDATA_HOST_CLOUD_ENABLED : [%s]", analytics_data.netdata_host_cloud_enabled);
  55. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_HTTPS_AVAILABLE : [%s]", analytics_data.netdata_config_https_available);
  56. netdata_log_debug(D_ANALYTICS, "NETDATA_INSTALL_TYPE : [%s]", analytics_data.netdata_install_type);
  57. netdata_log_debug(D_ANALYTICS, "NETDATA_PREBUILT_DISTRO : [%s]", analytics_data.netdata_prebuilt_distro);
  58. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_IS_PRIVATE_REGISTRY : [%s]", analytics_data.netdata_config_is_private_registry);
  59. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_USE_PRIVATE_REGISTRY: [%s]", analytics_data.netdata_config_use_private_registry);
  60. netdata_log_debug(D_ANALYTICS, "NETDATA_CONFIG_OOM_SCORE : [%s]", analytics_data.netdata_config_oom_score);
  61. }
  62. /*
  63. * Free data
  64. */
  65. void analytics_free_data(void)
  66. {
  67. freez(analytics_data.netdata_config_stream_enabled);
  68. freez(analytics_data.netdata_config_memory_mode);
  69. freez(analytics_data.netdata_config_exporting_enabled);
  70. freez(analytics_data.netdata_exporting_connectors);
  71. freez(analytics_data.netdata_allmetrics_prometheus_used);
  72. freez(analytics_data.netdata_allmetrics_shell_used);
  73. freez(analytics_data.netdata_allmetrics_json_used);
  74. freez(analytics_data.netdata_dashboard_used);
  75. freez(analytics_data.netdata_collectors);
  76. freez(analytics_data.netdata_collectors_count);
  77. freez(analytics_data.netdata_buildinfo);
  78. freez(analytics_data.netdata_config_page_cache_size);
  79. freez(analytics_data.netdata_config_multidb_disk_quota);
  80. freez(analytics_data.netdata_config_https_enabled);
  81. freez(analytics_data.netdata_config_web_enabled);
  82. freez(analytics_data.netdata_config_release_channel);
  83. freez(analytics_data.netdata_mirrored_host_count);
  84. freez(analytics_data.netdata_mirrored_hosts_reachable);
  85. freez(analytics_data.netdata_mirrored_hosts_unreachable);
  86. freez(analytics_data.netdata_notification_methods);
  87. freez(analytics_data.netdata_alarms_normal);
  88. freez(analytics_data.netdata_alarms_warning);
  89. freez(analytics_data.netdata_alarms_critical);
  90. freez(analytics_data.netdata_charts_count);
  91. freez(analytics_data.netdata_metrics_count);
  92. freez(analytics_data.netdata_config_is_parent);
  93. freez(analytics_data.netdata_config_hosts_available);
  94. freez(analytics_data.netdata_host_cloud_available);
  95. freez(analytics_data.netdata_host_aclk_available);
  96. freez(analytics_data.netdata_host_aclk_protocol);
  97. freez(analytics_data.netdata_host_aclk_implementation);
  98. freez(analytics_data.netdata_host_agent_claimed);
  99. freez(analytics_data.netdata_host_cloud_enabled);
  100. freez(analytics_data.netdata_config_https_available);
  101. freez(analytics_data.netdata_install_type);
  102. freez(analytics_data.netdata_config_is_private_registry);
  103. freez(analytics_data.netdata_config_use_private_registry);
  104. freez(analytics_data.netdata_config_oom_score);
  105. freez(analytics_data.netdata_prebuilt_distro);
  106. freez(analytics_data.netdata_fail_reason);
  107. }
  108. /*
  109. * Set a numeric/boolean data with a value
  110. */
  111. void analytics_set_data(char **name, char *value)
  112. {
  113. spinlock_lock(&analytics_data.spinlock);
  114. if (*name) {
  115. analytics_data.data_length -= strlen(*name);
  116. freez(*name);
  117. }
  118. *name = strdupz(value);
  119. analytics_data.data_length += strlen(*name);
  120. spinlock_unlock(&analytics_data.spinlock);
  121. }
  122. /*
  123. * Set a string data with a value
  124. */
  125. void analytics_set_data_str(char **name, const char *value)
  126. {
  127. size_t value_string_len;
  128. spinlock_lock(&analytics_data.spinlock);
  129. if (*name) {
  130. analytics_data.data_length -= strlen(*name);
  131. freez(*name);
  132. }
  133. value_string_len = strlen(value) + 4;
  134. *name = mallocz(sizeof(char) * value_string_len);
  135. snprintfz(*name, value_string_len - 1, "\"%s\"", value);
  136. analytics_data.data_length += strlen(*name);
  137. spinlock_unlock(&analytics_data.spinlock);
  138. }
  139. /*
  140. * Log hits on the allmetrics page, with prometheus parameter
  141. */
  142. void analytics_log_prometheus(void)
  143. {
  144. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.prometheus_hits < ANALYTICS_MAX_PROMETHEUS_HITS)) {
  145. analytics_data.prometheus_hits++;
  146. char b[21];
  147. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.prometheus_hits);
  148. analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
  149. }
  150. }
  151. /*
  152. * Log hits on the allmetrics page, with shell parameter (or default)
  153. */
  154. void analytics_log_shell(void)
  155. {
  156. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.shell_hits < ANALYTICS_MAX_SHELL_HITS)) {
  157. analytics_data.shell_hits++;
  158. char b[21];
  159. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.shell_hits);
  160. analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
  161. }
  162. }
  163. /*
  164. * Log hits on the allmetrics page, with json parameter
  165. */
  166. void analytics_log_json(void)
  167. {
  168. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.json_hits < ANALYTICS_MAX_JSON_HITS)) {
  169. analytics_data.json_hits++;
  170. char b[21];
  171. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.json_hits);
  172. analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
  173. }
  174. }
  175. /*
  176. * Log hits on the dashboard, (when calling HELLO).
  177. */
  178. void analytics_log_dashboard(void)
  179. {
  180. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.dashboard_hits < ANALYTICS_MAX_DASHBOARD_HITS)) {
  181. analytics_data.dashboard_hits++;
  182. char b[21];
  183. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.dashboard_hits);
  184. analytics_set_data(&analytics_data.netdata_dashboard_used, b);
  185. }
  186. }
  187. /*
  188. * Called when setting the oom score
  189. */
  190. void analytics_report_oom_score(long long int score){
  191. char b[21];
  192. snprintfz(b, sizeof(b) - 1, "%lld", score);
  193. analytics_set_data(&analytics_data.netdata_config_oom_score, b);
  194. }
  195. void analytics_mirrored_hosts(void)
  196. {
  197. RRDHOST *host;
  198. size_t count = 0;
  199. size_t reachable = 0;
  200. size_t unreachable = 0;
  201. char b[21];
  202. rrd_rdlock();
  203. rrdhost_foreach_read(host)
  204. {
  205. if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))
  206. continue;
  207. ((host == localhost || !rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)) ? reachable++ : unreachable++);
  208. count++;
  209. }
  210. rrd_unlock();
  211. snprintfz(b, sizeof(b) - 1, "%zu", count);
  212. analytics_set_data(&analytics_data.netdata_mirrored_host_count, b);
  213. snprintfz(b, sizeof(b) - 1, "%zu", reachable);
  214. analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, b);
  215. snprintfz(b, sizeof(b) - 1, "%zu", unreachable);
  216. analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, b);
  217. }
  218. void analytics_exporters(void)
  219. {
  220. //when no exporters are available, an empty string will be sent
  221. //decide if something else is more suitable (but probably not null)
  222. BUFFER *bi = buffer_create(1000, NULL);
  223. analytics_exporting_connectors(bi);
  224. analytics_set_data_str(&analytics_data.netdata_exporting_connectors, (char *)buffer_tostring(bi));
  225. buffer_free(bi);
  226. }
  227. int collector_counter_callb(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) {
  228. struct array_printer *ap = (struct array_printer *)data;
  229. struct collector *col = (struct collector *)entry;
  230. BUFFER *bt = ap->both;
  231. if (likely(ap->c)) {
  232. buffer_strcat(bt, ",");
  233. }
  234. buffer_strcat(bt, "{");
  235. buffer_strcat(bt, " \"plugin\": \"");
  236. buffer_strcat(bt, col->plugin);
  237. buffer_strcat(bt, "\", \"module\":\"");
  238. buffer_strcat(bt, col->module);
  239. buffer_strcat(bt, "\" }");
  240. (ap->c)++;
  241. return 0;
  242. }
  243. /*
  244. * Create a JSON array of available collectors, same as in api/v1/info
  245. */
  246. void analytics_collectors(void)
  247. {
  248. RRDSET *st;
  249. DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED);
  250. char name[500];
  251. BUFFER *bt = buffer_create(1000, NULL);
  252. rrdset_foreach_read(st, localhost) {
  253. if(!rrdset_is_available_for_viewers(st))
  254. continue;
  255. struct collector col = {
  256. .plugin = rrdset_plugin_name(st),
  257. .module = rrdset_module_name(st)
  258. };
  259. snprintfz(name, sizeof(name) - 1, "%s:%s", col.plugin, col.module);
  260. dictionary_set(dict, name, &col, sizeof(struct collector));
  261. }
  262. rrdset_foreach_done(st);
  263. struct array_printer ap;
  264. ap.c = 0;
  265. ap.both = bt;
  266. dictionary_walkthrough_read(dict, collector_counter_callb, &ap);
  267. dictionary_destroy(dict);
  268. analytics_set_data(&analytics_data.netdata_collectors, (char *)buffer_tostring(ap.both));
  269. {
  270. char b[21];
  271. snprintfz(b, sizeof(b) - 1, "%d", ap.c);
  272. analytics_set_data(&analytics_data.netdata_collectors_count, b);
  273. }
  274. buffer_free(bt);
  275. }
  276. /*
  277. * Run alarm-notify.sh script using the dump_methods parameter
  278. * SEND_CUSTOM is always available
  279. */
  280. void analytics_alarms_notifications(void)
  281. {
  282. char *script;
  283. script = mallocz(
  284. sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("alarm-notify.sh dump_methods") + 2));
  285. sprintf(script, "%s/%s", netdata_configured_primary_plugins_dir, "alarm-notify.sh");
  286. if (unlikely(access(script, R_OK) != 0)) {
  287. netdata_log_info("Alarm notify script %s not found.", script);
  288. freez(script);
  289. return;
  290. }
  291. strcat(script, " dump_methods");
  292. pid_t command_pid;
  293. netdata_log_debug(D_ANALYTICS, "Executing %s", script);
  294. BUFFER *b = buffer_create(1000, NULL);
  295. int cnt = 0;
  296. FILE *fp_child_input;
  297. FILE *fp_child_output = netdata_popen(script, &command_pid, &fp_child_input);
  298. if (fp_child_output) {
  299. char line[200 + 1];
  300. while (fgets(line, 200, fp_child_output) != NULL) {
  301. char *end = line;
  302. while (*end && *end != '\n')
  303. end++;
  304. *end = '\0';
  305. if (likely(cnt))
  306. buffer_strcat(b, "|");
  307. buffer_strcat(b, line);
  308. cnt++;
  309. }
  310. netdata_pclose(fp_child_input, fp_child_output, command_pid);
  311. }
  312. freez(script);
  313. analytics_set_data_str(&analytics_data.netdata_notification_methods, (char *)buffer_tostring(b));
  314. buffer_free(b);
  315. }
  316. static void analytics_get_install_type(struct rrdhost_system_info *system_info)
  317. {
  318. if (system_info->install_type == NULL) {
  319. analytics_set_data_str(&analytics_data.netdata_install_type, "unknown");
  320. } else {
  321. analytics_set_data_str(&analytics_data.netdata_install_type, system_info->install_type);
  322. }
  323. if (system_info->prebuilt_dist != NULL) {
  324. analytics_set_data_str(&analytics_data.netdata_prebuilt_distro, system_info->prebuilt_dist);
  325. }
  326. }
  327. /*
  328. * Pick up if https is actually used
  329. */
  330. void analytics_https(void)
  331. {
  332. BUFFER *b = buffer_create(30, NULL);
  333. #ifdef ENABLE_HTTPS
  334. analytics_exporting_connectors_ssl(b);
  335. buffer_strcat(b, netdata_ssl_streaming_sender_ctx &&
  336. rrdhost_flag_check(localhost, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED) &&
  337. SSL_connection(&localhost->sender->ssl) ? "streaming|" : "|");
  338. buffer_strcat(b, netdata_ssl_web_server_ctx ? "web" : "");
  339. #else
  340. buffer_strcat(b, "||");
  341. #endif
  342. analytics_set_data_str(&analytics_data.netdata_config_https_available, (char *)buffer_tostring(b));
  343. buffer_free(b);
  344. }
  345. void analytics_charts(void)
  346. {
  347. RRDSET *st;
  348. size_t c = 0;
  349. rrdset_foreach_read(st, localhost)
  350. if(rrdset_is_available_for_viewers(st)) c++;
  351. rrdset_foreach_done(st);
  352. analytics_data.charts_count = c;
  353. {
  354. char b[21];
  355. snprintfz(b, sizeof(b) - 1, "%zu", c);
  356. analytics_set_data(&analytics_data.netdata_charts_count, b);
  357. }
  358. }
  359. void analytics_metrics(void)
  360. {
  361. RRDSET *st;
  362. size_t dimensions = 0;
  363. rrdset_foreach_read(st, localhost) {
  364. if (rrdset_is_available_for_viewers(st)) {
  365. RRDDIM *rd;
  366. rrddim_foreach_read(rd, st) {
  367. if (rrddim_option_check(rd, RRDDIM_OPTION_HIDDEN) || rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE))
  368. continue;
  369. dimensions++;
  370. }
  371. rrddim_foreach_done(rd);
  372. }
  373. }
  374. rrdset_foreach_done(st);
  375. analytics_data.metrics_count = dimensions;
  376. {
  377. char b[21];
  378. snprintfz(b, sizeof(b) - 1, "%zu", dimensions);
  379. analytics_set_data(&analytics_data.netdata_metrics_count, b);
  380. }
  381. }
  382. void analytics_alarms(void)
  383. {
  384. size_t alarm_warn = 0, alarm_crit = 0, alarm_normal = 0;
  385. char b[21];
  386. RRDCALC *rc;
  387. foreach_rrdcalc_in_rrdhost_read(localhost, rc) {
  388. if (unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
  389. continue;
  390. switch (rc->status) {
  391. case RRDCALC_STATUS_WARNING:
  392. alarm_warn++;
  393. break;
  394. case RRDCALC_STATUS_CRITICAL:
  395. alarm_crit++;
  396. break;
  397. default:
  398. alarm_normal++;
  399. }
  400. }
  401. foreach_rrdcalc_in_rrdhost_done(rc);
  402. snprintfz(b, sizeof(b) - 1, "%zu", alarm_normal);
  403. analytics_set_data(&analytics_data.netdata_alarms_normal, b);
  404. snprintfz(b, sizeof(b) - 1, "%zu", alarm_warn);
  405. analytics_set_data(&analytics_data.netdata_alarms_warning, b);
  406. snprintfz(b, sizeof(b) - 1, "%zu", alarm_crit);
  407. analytics_set_data(&analytics_data.netdata_alarms_critical, b);
  408. }
  409. /*
  410. * Misc attributes to get (run from start)
  411. */
  412. void analytics_misc(void)
  413. {
  414. analytics_data.spinlock.locked = false;
  415. #ifdef ENABLE_ACLK
  416. analytics_set_data(&analytics_data.netdata_host_cloud_available, "true");
  417. analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "Next Generation");
  418. #else
  419. analytics_set_data(&analytics_data.netdata_host_cloud_available, "false");
  420. analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "");
  421. #endif
  422. analytics_data.exporting_enabled = appconfig_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, "enabled", CONFIG_BOOLEAN_NO);
  423. analytics_set_data(&analytics_data.netdata_config_exporting_enabled, analytics_data.exporting_enabled ? "true" : "false");
  424. analytics_set_data(&analytics_data.netdata_config_is_private_registry, "false");
  425. analytics_set_data(&analytics_data.netdata_config_use_private_registry, "false");
  426. if (strcmp(
  427. config_get(CONFIG_SECTION_REGISTRY, "registry to announce", "https://registry.my-netdata.io"),
  428. "https://registry.my-netdata.io"))
  429. analytics_set_data(&analytics_data.netdata_config_use_private_registry, "true");
  430. //do we need both registry to announce and enabled to indicate that this is a private registry ?
  431. if (config_get_boolean(CONFIG_SECTION_REGISTRY, "enabled", CONFIG_BOOLEAN_NO) &&
  432. web_server_mode != WEB_SERVER_MODE_NONE)
  433. analytics_set_data(&analytics_data.netdata_config_is_private_registry, "true");
  434. }
  435. void analytics_aclk(void)
  436. {
  437. #ifdef ENABLE_ACLK
  438. if (aclk_connected) {
  439. analytics_set_data(&analytics_data.netdata_host_aclk_available, "true");
  440. analytics_set_data_str(&analytics_data.netdata_host_aclk_protocol, "New");
  441. }
  442. else
  443. #endif
  444. analytics_set_data(&analytics_data.netdata_host_aclk_available, "false");
  445. }
  446. /*
  447. * Get the meta data, called from the thread once after the original delay
  448. * These are values that won't change during agent runtime, and therefore
  449. * don't try to read them on each META event send
  450. */
  451. void analytics_gather_immutable_meta_data(void)
  452. {
  453. analytics_misc();
  454. analytics_exporters();
  455. analytics_https();
  456. }
  457. /*
  458. * Get the meta data, called from the thread on every heartbeat, and right before the EXIT event
  459. * These are values that can change between agent restarts, and therefore
  460. * try to read them on each META event send
  461. */
  462. void analytics_gather_mutable_meta_data(void)
  463. {
  464. analytics_collectors();
  465. analytics_alarms();
  466. analytics_charts();
  467. analytics_metrics();
  468. analytics_aclk();
  469. analytics_mirrored_hosts();
  470. analytics_alarms_notifications();
  471. analytics_set_data(
  472. &analytics_data.netdata_config_is_parent, (rrdhost_hosts_available() > 1 || configured_as_parent()) ? "true" : "false");
  473. char *claim_id = get_agent_claimid();
  474. analytics_set_data(&analytics_data.netdata_host_agent_claimed, claim_id ? "true" : "false");
  475. freez(claim_id);
  476. {
  477. char b[21];
  478. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.prometheus_hits);
  479. analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
  480. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.shell_hits);
  481. analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
  482. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.json_hits);
  483. analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
  484. snprintfz(b, sizeof(b) - 1, "%zu", analytics_data.dashboard_hits);
  485. analytics_set_data(&analytics_data.netdata_dashboard_used, b);
  486. snprintfz(b, sizeof(b) - 1, "%zu", rrdhost_hosts_available());
  487. analytics_set_data(&analytics_data.netdata_config_hosts_available, b);
  488. }
  489. }
  490. void analytics_main_cleanup(void *ptr)
  491. {
  492. struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
  493. static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
  494. netdata_log_debug(D_ANALYTICS, "Cleaning up...");
  495. analytics_free_data();
  496. static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
  497. }
  498. /*
  499. * The analytics thread. Sleep for ANALYTICS_INIT_SLEEP_SEC,
  500. * gather the data, and then go to a loop where every ANALYTICS_HEARTBEAT
  501. * it will send a new META event after gathering data that could be changed
  502. * while the agent is running
  503. */
  504. void *analytics_main(void *ptr)
  505. {
  506. netdata_thread_cleanup_push(analytics_main_cleanup, ptr);
  507. unsigned int sec = 0;
  508. heartbeat_t hb;
  509. heartbeat_init(&hb);
  510. usec_t step_ut = USEC_PER_SEC;
  511. netdata_log_debug(D_ANALYTICS, "Analytics thread starts");
  512. //first delay after agent start
  513. while (service_running(SERVICE_ANALYTICS) && likely(sec <= ANALYTICS_INIT_SLEEP_SEC)) {
  514. heartbeat_next(&hb, step_ut);
  515. sec++;
  516. }
  517. if (unlikely(!service_running(SERVICE_ANALYTICS)))
  518. goto cleanup;
  519. analytics_gather_immutable_meta_data();
  520. analytics_gather_mutable_meta_data();
  521. send_statistics("META_START", "-", "-");
  522. analytics_log_data();
  523. sec = 0;
  524. while (1) {
  525. heartbeat_next(&hb, step_ut * 2);
  526. sec += 2;
  527. if (unlikely(!service_running(SERVICE_ANALYTICS)))
  528. break;
  529. if (likely(sec < ANALYTICS_HEARTBEAT))
  530. continue;
  531. analytics_gather_mutable_meta_data();
  532. send_statistics("META", "-", "-");
  533. analytics_log_data();
  534. sec = 0;
  535. }
  536. cleanup:
  537. netdata_thread_cleanup_pop(1);
  538. return NULL;
  539. }
  540. static const char *verify_required_directory(const char *dir)
  541. {
  542. if (chdir(dir) == -1)
  543. fatal("Cannot change directory to '%s'", dir);
  544. DIR *d = opendir(dir);
  545. if (!d)
  546. fatal("Cannot examine the contents of directory '%s'", dir);
  547. closedir(d);
  548. return dir;
  549. }
  550. static const char *verify_or_create_required_directory(const char *dir) {
  551. int result;
  552. result = mkdir(dir, 0755);
  553. if (result != 0 && errno != EEXIST)
  554. fatal("Cannot create required directory '%s'", dir);
  555. return verify_required_directory(dir);
  556. }
  557. /*
  558. * This is called after the rrdinit
  559. * These values will be sent on the START event
  560. */
  561. void set_late_global_environment(struct rrdhost_system_info *system_info)
  562. {
  563. analytics_set_data(&analytics_data.netdata_config_stream_enabled, default_rrdpush_enabled ? "true" : "false");
  564. analytics_set_data_str(&analytics_data.netdata_config_memory_mode, (char *)rrd_memory_mode_name(default_rrd_memory_mode));
  565. #ifdef DISABLE_CLOUD
  566. analytics_set_data(&analytics_data.netdata_host_cloud_enabled, "false");
  567. #else
  568. analytics_set_data(
  569. &analytics_data.netdata_host_cloud_enabled,
  570. appconfig_get_boolean_ondemand(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", netdata_cloud_enabled) ? "true" : "false");
  571. #endif
  572. #ifdef ENABLE_DBENGINE
  573. {
  574. char b[16];
  575. snprintfz(b, sizeof(b) - 1, "%d", default_rrdeng_page_cache_mb);
  576. analytics_set_data(&analytics_data.netdata_config_page_cache_size, b);
  577. snprintfz(b, sizeof(b) - 1, "%d", default_multidb_disk_quota_mb);
  578. analytics_set_data(&analytics_data.netdata_config_multidb_disk_quota, b);
  579. }
  580. #endif
  581. #ifdef ENABLE_HTTPS
  582. analytics_set_data(&analytics_data.netdata_config_https_enabled, "true");
  583. #else
  584. analytics_set_data(&analytics_data.netdata_config_https_enabled, "false");
  585. #endif
  586. if (web_server_mode == WEB_SERVER_MODE_NONE)
  587. analytics_set_data(&analytics_data.netdata_config_web_enabled, "false");
  588. else
  589. analytics_set_data(&analytics_data.netdata_config_web_enabled, "true");
  590. analytics_set_data_str(&analytics_data.netdata_config_release_channel, (char *)get_release_channel());
  591. {
  592. BUFFER *bi = buffer_create(1000, NULL);
  593. analytics_build_info(bi);
  594. analytics_set_data_str(&analytics_data.netdata_buildinfo, (char *)buffer_tostring(bi));
  595. buffer_free(bi);
  596. }
  597. analytics_get_install_type(system_info);
  598. }
  599. void get_system_timezone(void)
  600. {
  601. // avoid flood calls to stat(/etc/localtime)
  602. // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
  603. const char *tz = getenv("TZ");
  604. if (!tz || !*tz)
  605. setenv("TZ", config_get(CONFIG_SECTION_ENV_VARS, "TZ", ":/etc/localtime"), 0);
  606. char buffer[FILENAME_MAX + 1] = "";
  607. const char *timezone = NULL;
  608. ssize_t ret;
  609. // use the TZ variable
  610. if (tz && *tz && *tz != ':') {
  611. timezone = tz;
  612. netdata_log_info("TIMEZONE: using TZ variable '%s'", timezone);
  613. }
  614. // use the contents of /etc/timezone
  615. if (!timezone && !read_file("/etc/timezone", buffer, FILENAME_MAX)) {
  616. timezone = buffer;
  617. netdata_log_info("TIMEZONE: using the contents of /etc/timezone");
  618. }
  619. // read the link /etc/localtime
  620. if (!timezone) {
  621. ret = readlink("/etc/localtime", buffer, FILENAME_MAX);
  622. if (ret > 0) {
  623. buffer[ret] = '\0';
  624. char *cmp = "/usr/share/zoneinfo/";
  625. size_t cmp_len = strlen(cmp);
  626. char *s = strstr(buffer, cmp);
  627. if (s && s[cmp_len]) {
  628. timezone = &s[cmp_len];
  629. netdata_log_info("TIMEZONE: using the link of /etc/localtime: '%s'", timezone);
  630. }
  631. } else
  632. buffer[0] = '\0';
  633. }
  634. // find the timezone from strftime()
  635. if (!timezone) {
  636. time_t t;
  637. struct tm *tmp, tmbuf;
  638. t = now_realtime_sec();
  639. tmp = localtime_r(&t, &tmbuf);
  640. if (tmp != NULL) {
  641. if (strftime(buffer, FILENAME_MAX, "%Z", tmp) == 0)
  642. buffer[0] = '\0';
  643. else {
  644. buffer[FILENAME_MAX] = '\0';
  645. timezone = buffer;
  646. netdata_log_info("TIMEZONE: using strftime(): '%s'", timezone);
  647. }
  648. }
  649. }
  650. if (timezone && *timezone) {
  651. // make sure it does not have illegal characters
  652. // netdata_log_info("TIMEZONE: fixing '%s'", timezone);
  653. size_t len = strlen(timezone);
  654. char tmp[len + 1];
  655. char *d = tmp;
  656. *d = '\0';
  657. while (*timezone) {
  658. if (isalnum(*timezone) || *timezone == '_' || *timezone == '/')
  659. *d++ = *timezone++;
  660. else
  661. timezone++;
  662. }
  663. *d = '\0';
  664. strncpyz(buffer, tmp, len);
  665. timezone = buffer;
  666. netdata_log_info("TIMEZONE: fixed as '%s'", timezone);
  667. }
  668. if (!timezone || !*timezone)
  669. timezone = "unknown";
  670. netdata_configured_timezone = config_get(CONFIG_SECTION_GLOBAL, "timezone", timezone);
  671. //get the utc offset, and the timezone as returned by strftime
  672. //will be sent to the cloud
  673. //Note: This will need an agent restart to get new offset on time change (dst, etc).
  674. {
  675. time_t t;
  676. struct tm *tmp, tmbuf;
  677. char zone[FILENAME_MAX + 1];
  678. char sign[2], hh[3], mm[3];
  679. t = now_realtime_sec();
  680. tmp = localtime_r(&t, &tmbuf);
  681. if (tmp != NULL) {
  682. if (strftime(zone, FILENAME_MAX, "%Z", tmp) == 0) {
  683. netdata_configured_abbrev_timezone = strdupz("UTC");
  684. } else
  685. netdata_configured_abbrev_timezone = strdupz(zone);
  686. if (strftime(zone, FILENAME_MAX, "%z", tmp) == 0) {
  687. netdata_configured_utc_offset = 0;
  688. } else {
  689. sign[0] = zone[0] == '-' || zone[0] == '+' ? zone[0] : '0';
  690. sign[1] = '\0';
  691. hh[0] = isdigit(zone[1]) ? zone[1] : '0';
  692. hh[1] = isdigit(zone[2]) ? zone[2] : '0';
  693. hh[2] = '\0';
  694. mm[0] = isdigit(zone[3]) ? zone[3] : '0';
  695. mm[1] = isdigit(zone[4]) ? zone[4] : '0';
  696. mm[2] = '\0';
  697. netdata_configured_utc_offset = (str2i(hh) * 3600) + (str2i(mm) * 60);
  698. netdata_configured_utc_offset =
  699. sign[0] == '-' ? -netdata_configured_utc_offset : netdata_configured_utc_offset;
  700. }
  701. } else {
  702. netdata_configured_abbrev_timezone = strdupz("UTC");
  703. netdata_configured_utc_offset = 0;
  704. }
  705. }
  706. }
  707. void set_global_environment() {
  708. {
  709. char b[16];
  710. snprintfz(b, sizeof(b) - 1, "%d", default_rrd_update_every);
  711. setenv("NETDATA_UPDATE_EVERY", b, 1);
  712. }
  713. setenv("NETDATA_VERSION", program_version, 1);
  714. setenv("NETDATA_HOSTNAME", netdata_configured_hostname, 1);
  715. setenv("NETDATA_CONFIG_DIR", verify_required_directory(netdata_configured_user_config_dir), 1);
  716. setenv("NETDATA_USER_CONFIG_DIR", verify_required_directory(netdata_configured_user_config_dir), 1);
  717. setenv("NETDATA_STOCK_CONFIG_DIR", verify_required_directory(netdata_configured_stock_config_dir), 1);
  718. setenv("NETDATA_PLUGINS_DIR", verify_required_directory(netdata_configured_primary_plugins_dir), 1);
  719. setenv("NETDATA_WEB_DIR", verify_required_directory(netdata_configured_web_dir), 1);
  720. setenv("NETDATA_CACHE_DIR", verify_or_create_required_directory(netdata_configured_cache_dir), 1);
  721. setenv("NETDATA_LIB_DIR", verify_or_create_required_directory(netdata_configured_varlib_dir), 1);
  722. setenv("NETDATA_LOCK_DIR", verify_or_create_required_directory(netdata_configured_lock_dir), 1);
  723. setenv("NETDATA_LOG_DIR", verify_or_create_required_directory(netdata_configured_log_dir), 1);
  724. setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
  725. {
  726. BUFFER *user_plugins_dirs = buffer_create(FILENAME_MAX, NULL);
  727. for (size_t i = 1; i < PLUGINSD_MAX_DIRECTORIES && plugin_directories[i]; i++) {
  728. if (i > 1)
  729. buffer_strcat(user_plugins_dirs, " ");
  730. buffer_strcat(user_plugins_dirs, plugin_directories[i]);
  731. }
  732. setenv("NETDATA_USER_PLUGINS_DIRS", buffer_tostring(user_plugins_dirs), 1);
  733. buffer_free(user_plugins_dirs);
  734. }
  735. analytics_data.data_length = 0;
  736. analytics_set_data(&analytics_data.netdata_config_stream_enabled, "null");
  737. analytics_set_data(&analytics_data.netdata_config_memory_mode, "null");
  738. analytics_set_data(&analytics_data.netdata_config_exporting_enabled, "null");
  739. analytics_set_data(&analytics_data.netdata_exporting_connectors, "null");
  740. analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, "null");
  741. analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, "null");
  742. analytics_set_data(&analytics_data.netdata_allmetrics_json_used, "null");
  743. analytics_set_data(&analytics_data.netdata_dashboard_used, "null");
  744. analytics_set_data(&analytics_data.netdata_collectors, "null");
  745. analytics_set_data(&analytics_data.netdata_collectors_count, "null");
  746. analytics_set_data(&analytics_data.netdata_buildinfo, "null");
  747. analytics_set_data(&analytics_data.netdata_config_page_cache_size, "null");
  748. analytics_set_data(&analytics_data.netdata_config_multidb_disk_quota, "null");
  749. analytics_set_data(&analytics_data.netdata_config_https_enabled, "null");
  750. analytics_set_data(&analytics_data.netdata_config_web_enabled, "null");
  751. analytics_set_data(&analytics_data.netdata_config_release_channel, "null");
  752. analytics_set_data(&analytics_data.netdata_mirrored_host_count, "null");
  753. analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, "null");
  754. analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, "null");
  755. analytics_set_data(&analytics_data.netdata_notification_methods, "null");
  756. analytics_set_data(&analytics_data.netdata_alarms_normal, "null");
  757. analytics_set_data(&analytics_data.netdata_alarms_warning, "null");
  758. analytics_set_data(&analytics_data.netdata_alarms_critical, "null");
  759. analytics_set_data(&analytics_data.netdata_charts_count, "null");
  760. analytics_set_data(&analytics_data.netdata_metrics_count, "null");
  761. analytics_set_data(&analytics_data.netdata_config_is_parent, "null");
  762. analytics_set_data(&analytics_data.netdata_config_hosts_available, "null");
  763. analytics_set_data(&analytics_data.netdata_host_cloud_available, "null");
  764. analytics_set_data(&analytics_data.netdata_host_aclk_implementation, "null");
  765. analytics_set_data(&analytics_data.netdata_host_aclk_available, "null");
  766. analytics_set_data(&analytics_data.netdata_host_aclk_protocol, "null");
  767. analytics_set_data(&analytics_data.netdata_host_agent_claimed, "null");
  768. analytics_set_data(&analytics_data.netdata_host_cloud_enabled, "null");
  769. analytics_set_data(&analytics_data.netdata_config_https_available, "null");
  770. analytics_set_data(&analytics_data.netdata_install_type, "null");
  771. analytics_set_data(&analytics_data.netdata_config_is_private_registry, "null");
  772. analytics_set_data(&analytics_data.netdata_config_use_private_registry, "null");
  773. analytics_set_data(&analytics_data.netdata_config_oom_score, "null");
  774. analytics_set_data(&analytics_data.netdata_prebuilt_distro, "null");
  775. analytics_set_data(&analytics_data.netdata_fail_reason, "null");
  776. analytics_data.prometheus_hits = 0;
  777. analytics_data.shell_hits = 0;
  778. analytics_data.json_hits = 0;
  779. analytics_data.dashboard_hits = 0;
  780. analytics_data.charts_count = 0;
  781. analytics_data.metrics_count = 0;
  782. analytics_data.exporting_enabled = false;
  783. char *default_port = appconfig_get(&netdata_config, CONFIG_SECTION_WEB, "default port", NULL);
  784. int clean = 0;
  785. if (!default_port) {
  786. default_port = strdupz("19999");
  787. clean = 1;
  788. }
  789. setenv("NETDATA_LISTEN_PORT", default_port, 1);
  790. if (clean)
  791. freez(default_port);
  792. // set the path we need
  793. char path[4096], *p = getenv("PATH");
  794. if (!p) p = "/bin:/usr/bin";
  795. snprintfz(path, sizeof(path), "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
  796. setenv("PATH", config_get(CONFIG_SECTION_ENV_VARS, "PATH", path), 1);
  797. // python options
  798. p = getenv("PYTHONPATH");
  799. if (!p) p = "";
  800. setenv("PYTHONPATH", config_get(CONFIG_SECTION_ENV_VARS, "PYTHONPATH", p), 1);
  801. // disable buffering for python plugins
  802. setenv("PYTHONUNBUFFERED", "1", 1);
  803. // switch to standard locale for plugins
  804. setenv("LC_ALL", "C", 1);
  805. }
  806. void send_statistics(const char *action, const char *action_result, const char *action_data) {
  807. static char *as_script;
  808. if (netdata_anonymous_statistics_enabled == -1) {
  809. char *optout_file = mallocz(
  810. sizeof(char) *
  811. (strlen(netdata_configured_user_config_dir) + strlen(".opt-out-from-anonymous-statistics") + 2));
  812. sprintf(optout_file, "%s/%s", netdata_configured_user_config_dir, ".opt-out-from-anonymous-statistics");
  813. if (likely(access(optout_file, R_OK) != 0)) {
  814. as_script = mallocz(
  815. sizeof(char) *
  816. (strlen(netdata_configured_primary_plugins_dir) + strlen("anonymous-statistics.sh") + 2));
  817. sprintf(as_script, "%s/%s", netdata_configured_primary_plugins_dir, "anonymous-statistics.sh");
  818. if (unlikely(access(as_script, R_OK) != 0)) {
  819. netdata_anonymous_statistics_enabled = 0;
  820. nd_log(NDLS_DAEMON, NDLP_DEBUG,
  821. "Statistics script '%s' not found.",
  822. as_script);
  823. freez(as_script);
  824. }
  825. else
  826. netdata_anonymous_statistics_enabled = 1;
  827. }
  828. else {
  829. netdata_anonymous_statistics_enabled = 0;
  830. as_script = NULL;
  831. }
  832. freez(optout_file);
  833. }
  834. if (!netdata_anonymous_statistics_enabled || !action)
  835. return;
  836. if (!action_result)
  837. action_result = "";
  838. if (!action_data)
  839. action_data = "";
  840. char *command_to_run = mallocz(
  841. sizeof(char) * (strlen(action) + strlen(action_result) + strlen(action_data) + strlen(as_script) +
  842. analytics_data.data_length + (ANALYTICS_NO_OF_ITEMS * 3) + 15));
  843. pid_t command_pid;
  844. sprintf(
  845. command_to_run,
  846. "%s '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' ",
  847. as_script,
  848. action,
  849. action_result,
  850. action_data,
  851. analytics_data.netdata_config_stream_enabled,
  852. analytics_data.netdata_config_memory_mode,
  853. analytics_data.netdata_config_exporting_enabled,
  854. analytics_data.netdata_exporting_connectors,
  855. analytics_data.netdata_allmetrics_prometheus_used,
  856. analytics_data.netdata_allmetrics_shell_used,
  857. analytics_data.netdata_allmetrics_json_used,
  858. analytics_data.netdata_dashboard_used,
  859. analytics_data.netdata_collectors,
  860. analytics_data.netdata_collectors_count,
  861. analytics_data.netdata_buildinfo,
  862. analytics_data.netdata_config_page_cache_size,
  863. analytics_data.netdata_config_multidb_disk_quota,
  864. analytics_data.netdata_config_https_enabled,
  865. analytics_data.netdata_config_web_enabled,
  866. analytics_data.netdata_config_release_channel,
  867. analytics_data.netdata_mirrored_host_count,
  868. analytics_data.netdata_mirrored_hosts_reachable,
  869. analytics_data.netdata_mirrored_hosts_unreachable,
  870. analytics_data.netdata_notification_methods,
  871. analytics_data.netdata_alarms_normal,
  872. analytics_data.netdata_alarms_warning,
  873. analytics_data.netdata_alarms_critical,
  874. analytics_data.netdata_charts_count,
  875. analytics_data.netdata_metrics_count,
  876. analytics_data.netdata_config_is_parent,
  877. analytics_data.netdata_config_hosts_available,
  878. analytics_data.netdata_host_cloud_available,
  879. analytics_data.netdata_host_aclk_available,
  880. analytics_data.netdata_host_aclk_protocol,
  881. analytics_data.netdata_host_aclk_implementation,
  882. analytics_data.netdata_host_agent_claimed,
  883. analytics_data.netdata_host_cloud_enabled,
  884. analytics_data.netdata_config_https_available,
  885. analytics_data.netdata_install_type,
  886. analytics_data.netdata_config_is_private_registry,
  887. analytics_data.netdata_config_use_private_registry,
  888. analytics_data.netdata_config_oom_score,
  889. analytics_data.netdata_prebuilt_distro,
  890. analytics_data.netdata_fail_reason);
  891. nd_log(NDLS_DAEMON, NDLP_DEBUG,
  892. "%s '%s' '%s' '%s'",
  893. as_script, action, action_result, action_data);
  894. FILE *fp_child_input;
  895. FILE *fp_child_output = netdata_popen(command_to_run, &command_pid, &fp_child_input);
  896. if (fp_child_output) {
  897. char buffer[4 + 1];
  898. char *s = fgets(buffer, 4, fp_child_output);
  899. int exit_code = netdata_pclose(fp_child_input, fp_child_output, command_pid);
  900. if (exit_code)
  901. nd_log(NDLS_DAEMON, NDLP_NOTICE,
  902. "Statistics script returned error: %d",
  903. exit_code);
  904. if (s && strncmp(buffer, "200", 3) != 0)
  905. nd_log(NDLS_DAEMON, NDLP_NOTICE,
  906. "Statistics script returned http code: %s",
  907. buffer);
  908. }
  909. else
  910. nd_log(NDLS_DAEMON, NDLP_NOTICE,
  911. "Failed to run statistics script: %s.",
  912. as_script);
  913. freez(command_to_run);
  914. }