analytics.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  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, aclk_use_new_cloud_arch;
  9. struct collector {
  10. char *plugin;
  11. 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. debug(D_ANALYTICS, "NETDATA_CONFIG_STREAM_ENABLED : [%s]", analytics_data.netdata_config_stream_enabled);
  23. debug(D_ANALYTICS, "NETDATA_CONFIG_MEMORY_MODE : [%s]", analytics_data.netdata_config_memory_mode);
  24. debug(D_ANALYTICS, "NETDATA_CONFIG_EXPORTING_ENABLED : [%s]", analytics_data.netdata_config_exporting_enabled);
  25. debug(D_ANALYTICS, "NETDATA_EXPORTING_CONNECTORS : [%s]", analytics_data.netdata_exporting_connectors);
  26. debug(D_ANALYTICS, "NETDATA_ALLMETRICS_PROMETHEUS_USED : [%s]", analytics_data.netdata_allmetrics_prometheus_used);
  27. debug(D_ANALYTICS, "NETDATA_ALLMETRICS_SHELL_USED : [%s]", analytics_data.netdata_allmetrics_shell_used);
  28. debug(D_ANALYTICS, "NETDATA_ALLMETRICS_JSON_USED : [%s]", analytics_data.netdata_allmetrics_json_used);
  29. debug(D_ANALYTICS, "NETDATA_DASHBOARD_USED : [%s]", analytics_data.netdata_dashboard_used);
  30. debug(D_ANALYTICS, "NETDATA_COLLECTORS : [%s]", analytics_data.netdata_collectors);
  31. debug(D_ANALYTICS, "NETDATA_COLLECTORS_COUNT : [%s]", analytics_data.netdata_collectors_count);
  32. debug(D_ANALYTICS, "NETDATA_BUILDINFO : [%s]", analytics_data.netdata_buildinfo);
  33. debug(D_ANALYTICS, "NETDATA_CONFIG_PAGE_CACHE_SIZE : [%s]", analytics_data.netdata_config_page_cache_size);
  34. debug(D_ANALYTICS, "NETDATA_CONFIG_MULTIDB_DISK_QUOTA : [%s]", analytics_data.netdata_config_multidb_disk_quota);
  35. debug(D_ANALYTICS, "NETDATA_CONFIG_HTTPS_ENABLED : [%s]", analytics_data.netdata_config_https_enabled);
  36. debug(D_ANALYTICS, "NETDATA_CONFIG_WEB_ENABLED : [%s]", analytics_data.netdata_config_web_enabled);
  37. debug(D_ANALYTICS, "NETDATA_CONFIG_RELEASE_CHANNEL : [%s]", analytics_data.netdata_config_release_channel);
  38. debug(D_ANALYTICS, "NETDATA_MIRRORED_HOST_COUNT : [%s]", analytics_data.netdata_mirrored_host_count);
  39. debug(D_ANALYTICS, "NETDATA_MIRRORED_HOSTS_REACHABLE : [%s]", analytics_data.netdata_mirrored_hosts_reachable);
  40. debug(D_ANALYTICS, "NETDATA_MIRRORED_HOSTS_UNREACHABLE : [%s]", analytics_data.netdata_mirrored_hosts_unreachable);
  41. debug(D_ANALYTICS, "NETDATA_NOTIFICATION_METHODS : [%s]", analytics_data.netdata_notification_methods);
  42. debug(D_ANALYTICS, "NETDATA_ALARMS_NORMAL : [%s]", analytics_data.netdata_alarms_normal);
  43. debug(D_ANALYTICS, "NETDATA_ALARMS_WARNING : [%s]", analytics_data.netdata_alarms_warning);
  44. debug(D_ANALYTICS, "NETDATA_ALARMS_CRITICAL : [%s]", analytics_data.netdata_alarms_critical);
  45. debug(D_ANALYTICS, "NETDATA_CHARTS_COUNT : [%s]", analytics_data.netdata_charts_count);
  46. debug(D_ANALYTICS, "NETDATA_METRICS_COUNT : [%s]", analytics_data.netdata_metrics_count);
  47. debug(D_ANALYTICS, "NETDATA_CONFIG_IS_PARENT : [%s]", analytics_data.netdata_config_is_parent);
  48. debug(D_ANALYTICS, "NETDATA_CONFIG_HOSTS_AVAILABLE : [%s]", analytics_data.netdata_config_hosts_available);
  49. debug(D_ANALYTICS, "NETDATA_HOST_CLOUD_AVAILABLE : [%s]", analytics_data.netdata_host_cloud_available);
  50. debug(D_ANALYTICS, "NETDATA_HOST_ACLK_AVAILABLE : [%s]", analytics_data.netdata_host_aclk_available);
  51. debug(D_ANALYTICS, "NETDATA_HOST_ACLK_PROTOCOL : [%s]", analytics_data.netdata_host_aclk_protocol);
  52. debug(D_ANALYTICS, "NETDATA_HOST_ACLK_IMPLEMENTATION : [%s]", analytics_data.netdata_host_aclk_implementation);
  53. debug(D_ANALYTICS, "NETDATA_HOST_AGENT_CLAIMED : [%s]", analytics_data.netdata_host_agent_claimed);
  54. debug(D_ANALYTICS, "NETDATA_HOST_CLOUD_ENABLED : [%s]", analytics_data.netdata_host_cloud_enabled);
  55. debug(D_ANALYTICS, "NETDATA_CONFIG_HTTPS_AVAILABLE : [%s]", analytics_data.netdata_config_https_available);
  56. debug(D_ANALYTICS, "NETDATA_INSTALL_TYPE : [%s]", analytics_data.netdata_install_type);
  57. debug(D_ANALYTICS, "NETDATA_PREBUILT_DISTRO : [%s]", analytics_data.netdata_prebuilt_distro);
  58. debug(D_ANALYTICS, "NETDATA_CONFIG_IS_PRIVATE_REGISTRY : [%s]", analytics_data.netdata_config_is_private_registry);
  59. debug(D_ANALYTICS, "NETDATA_CONFIG_USE_PRIVATE_REGISTRY: [%s]", analytics_data.netdata_config_use_private_registry);
  60. 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. }
  107. /*
  108. * Set a numeric/boolean data with a value
  109. */
  110. void analytics_set_data(char **name, char *value)
  111. {
  112. if (*name) {
  113. analytics_data.data_length -= strlen(*name);
  114. freez(*name);
  115. }
  116. *name = strdupz(value);
  117. analytics_data.data_length += strlen(*name);
  118. }
  119. /*
  120. * Set a string data with a value
  121. */
  122. void analytics_set_data_str(char **name, char *value)
  123. {
  124. size_t value_string_len;
  125. if (*name) {
  126. analytics_data.data_length -= strlen(*name);
  127. freez(*name);
  128. }
  129. value_string_len = strlen(value) + 4;
  130. *name = mallocz(sizeof(char) * value_string_len);
  131. snprintfz(*name, value_string_len - 1, "\"%s\"", value);
  132. analytics_data.data_length += strlen(*name);
  133. }
  134. /*
  135. * Get data, used by web api v1
  136. */
  137. void analytics_get_data(char *name, BUFFER *wb)
  138. {
  139. buffer_strcat(wb, name);
  140. }
  141. /*
  142. * Log hits on the allmetrics page, with prometheus parameter
  143. */
  144. void analytics_log_prometheus(void)
  145. {
  146. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.prometheus_hits < ANALYTICS_MAX_PROMETHEUS_HITS)) {
  147. analytics_data.prometheus_hits++;
  148. char b[7];
  149. snprintfz(b, 6, "%d", analytics_data.prometheus_hits);
  150. analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
  151. }
  152. }
  153. /*
  154. * Log hits on the allmetrics page, with shell parameter (or default)
  155. */
  156. void analytics_log_shell(void)
  157. {
  158. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.shell_hits < ANALYTICS_MAX_SHELL_HITS)) {
  159. analytics_data.shell_hits++;
  160. char b[7];
  161. snprintfz(b, 6, "%d", analytics_data.shell_hits);
  162. analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
  163. }
  164. }
  165. /*
  166. * Log hits on the allmetrics page, with json parameter
  167. */
  168. void analytics_log_json(void)
  169. {
  170. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.json_hits < ANALYTICS_MAX_JSON_HITS)) {
  171. analytics_data.json_hits++;
  172. char b[7];
  173. snprintfz(b, 6, "%d", analytics_data.json_hits);
  174. analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
  175. }
  176. }
  177. /*
  178. * Log hits on the dashboard, (when calling HELLO).
  179. */
  180. void analytics_log_dashboard(void)
  181. {
  182. if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.dashboard_hits < ANALYTICS_MAX_DASHBOARD_HITS)) {
  183. analytics_data.dashboard_hits++;
  184. char b[7];
  185. snprintfz(b, 6, "%d", analytics_data.dashboard_hits);
  186. analytics_set_data(&analytics_data.netdata_dashboard_used, b);
  187. }
  188. }
  189. /*
  190. * Called when setting the oom score
  191. */
  192. void analytics_report_oom_score(long long int score){
  193. char b[7];
  194. snprintfz(b, 6, "%d", (int)score);
  195. analytics_set_data(&analytics_data.netdata_config_oom_score, b);
  196. }
  197. void analytics_mirrored_hosts(void)
  198. {
  199. RRDHOST *host;
  200. int count = 0;
  201. int reachable = 0;
  202. int unreachable = 0;
  203. char b[11];
  204. rrd_rdlock();
  205. rrdhost_foreach_read(host)
  206. {
  207. if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))
  208. continue;
  209. netdata_mutex_lock(&host->receiver_lock);
  210. ((host->receiver || host == localhost) ? reachable++ : unreachable++);
  211. netdata_mutex_unlock(&host->receiver_lock);
  212. count++;
  213. }
  214. rrd_unlock();
  215. snprintfz(b, 10, "%d", count);
  216. analytics_set_data(&analytics_data.netdata_mirrored_host_count, b);
  217. snprintfz(b, 10, "%d", reachable);
  218. analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, b);
  219. snprintfz(b, 10, "%d", unreachable);
  220. analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, b);
  221. }
  222. void analytics_exporters(void)
  223. {
  224. //when no exporters are available, an empty string will be sent
  225. //decide if something else is more suitable (but probably not null)
  226. BUFFER *bi = buffer_create(1000);
  227. analytics_exporting_connectors(bi);
  228. analytics_set_data_str(&analytics_data.netdata_exporting_connectors, (char *)buffer_tostring(bi));
  229. buffer_free(bi);
  230. }
  231. int collector_counter_callb(const char *name, void *entry, void *data) {
  232. (void)name;
  233. struct array_printer *ap = (struct array_printer *)data;
  234. struct collector *col = (struct collector *)entry;
  235. BUFFER *bt = ap->both;
  236. if (likely(ap->c)) {
  237. buffer_strcat(bt, ",");
  238. }
  239. buffer_strcat(bt, "{");
  240. buffer_strcat(bt, " \"plugin\": \"");
  241. buffer_strcat(bt, col->plugin);
  242. buffer_strcat(bt, "\", \"module\":\"");
  243. buffer_strcat(bt, col->module);
  244. buffer_strcat(bt, "\" }");
  245. (ap->c)++;
  246. return 0;
  247. }
  248. /*
  249. * Create a JSON array of available collectors, same as in api/v1/info
  250. */
  251. void analytics_collectors(void)
  252. {
  253. RRDSET *st;
  254. DICTIONARY *dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
  255. char name[500];
  256. BUFFER *bt = buffer_create(1000);
  257. rrdset_foreach_read(st, localhost)
  258. {
  259. if (rrdset_is_available_for_viewers(st)) {
  260. struct collector col = { .plugin = st->plugin_name ? st->plugin_name : "",
  261. .module = st->module_name ? st->module_name : "" };
  262. snprintfz(name, 499, "%s:%s", col.plugin, col.module);
  263. dictionary_set(dict, name, &col, sizeof(struct collector));
  264. }
  265. }
  266. struct array_printer ap;
  267. ap.c = 0;
  268. ap.both = bt;
  269. dictionary_walkthrough_read(dict, collector_counter_callb, &ap);
  270. dictionary_destroy(dict);
  271. analytics_set_data(&analytics_data.netdata_collectors, (char *)buffer_tostring(ap.both));
  272. {
  273. char b[7];
  274. snprintfz(b, 6, "%d", ap.c);
  275. analytics_set_data(&analytics_data.netdata_collectors_count, b);
  276. }
  277. buffer_free(bt);
  278. }
  279. /*
  280. * Run alarm-notify.sh script using the dump_methods parameter
  281. * SEND_CUSTOM is always available
  282. */
  283. void analytics_alarms_notifications(void)
  284. {
  285. char *script;
  286. script = mallocz(
  287. sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("alarm-notify.sh dump_methods") + 2));
  288. sprintf(script, "%s/%s", netdata_configured_primary_plugins_dir, "alarm-notify.sh");
  289. if (unlikely(access(script, R_OK) != 0)) {
  290. info("Alarm notify script %s not found.", script);
  291. freez(script);
  292. return;
  293. }
  294. strcat(script, " dump_methods");
  295. pid_t command_pid;
  296. debug(D_ANALYTICS, "Executing %s", script);
  297. BUFFER *b = buffer_create(1000);
  298. int cnt = 0;
  299. FILE *fp = mypopen(script, &command_pid);
  300. if (fp) {
  301. char line[200 + 1];
  302. while (fgets(line, 200, fp) != NULL) {
  303. char *end = line;
  304. while (*end && *end != '\n')
  305. end++;
  306. *end = '\0';
  307. if (likely(cnt))
  308. buffer_strcat(b, "|");
  309. buffer_strcat(b, line);
  310. cnt++;
  311. }
  312. mypclose(fp, command_pid);
  313. }
  314. freez(script);
  315. analytics_set_data_str(&analytics_data.netdata_notification_methods, (char *)buffer_tostring(b));
  316. buffer_free(b);
  317. }
  318. void analytics_get_install_type(void)
  319. {
  320. if (localhost->system_info->install_type == NULL) {
  321. analytics_set_data_str(&analytics_data.netdata_install_type, "unknown");
  322. } else {
  323. analytics_set_data_str(&analytics_data.netdata_install_type, localhost->system_info->install_type);
  324. }
  325. if (localhost->system_info->prebuilt_dist != NULL) {
  326. analytics_set_data_str(&analytics_data.netdata_prebuilt_distro, localhost->system_info->prebuilt_dist);
  327. }
  328. }
  329. /*
  330. * Pick up if https is actually used
  331. */
  332. void analytics_https(void)
  333. {
  334. BUFFER *b = buffer_create(30);
  335. #ifdef ENABLE_HTTPS
  336. analytics_exporting_connectors_ssl(b);
  337. buffer_strcat(b, netdata_client_ctx && localhost->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE && localhost->rrdpush_sender_connected == 1 ? "streaming|" : "|");
  338. buffer_strcat(b, netdata_srv_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. int c = 0;
  349. rrdset_foreach_read(st, localhost)
  350. {
  351. if (rrdset_is_available_for_viewers(st)) {
  352. c++;
  353. }
  354. }
  355. {
  356. char b[7];
  357. snprintfz(b, 6, "%d", c);
  358. analytics_set_data(&analytics_data.netdata_charts_count, b);
  359. }
  360. }
  361. void analytics_metrics(void)
  362. {
  363. RRDSET *st;
  364. long int dimensions = 0;
  365. RRDDIM *rd;
  366. rrdset_foreach_read(st, localhost)
  367. {
  368. rrdset_rdlock(st);
  369. if (rrdset_is_available_for_viewers(st)) {
  370. rrddim_foreach_read(rd, st)
  371. {
  372. if (rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN) || rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE))
  373. continue;
  374. dimensions++;
  375. }
  376. }
  377. rrdset_unlock(st);
  378. }
  379. {
  380. char b[7];
  381. snprintfz(b, 6, "%ld", dimensions);
  382. analytics_set_data(&analytics_data.netdata_metrics_count, b);
  383. }
  384. }
  385. void analytics_alarms(void)
  386. {
  387. int alarm_warn = 0, alarm_crit = 0, alarm_normal = 0;
  388. char b[10];
  389. RRDCALC *rc;
  390. for (rc = localhost->alarms; rc; rc = rc->next) {
  391. if (unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
  392. continue;
  393. switch (rc->status) {
  394. case RRDCALC_STATUS_WARNING:
  395. alarm_warn++;
  396. break;
  397. case RRDCALC_STATUS_CRITICAL:
  398. alarm_crit++;
  399. break;
  400. default:
  401. alarm_normal++;
  402. }
  403. }
  404. snprintfz(b, 9, "%d", alarm_normal);
  405. analytics_set_data(&analytics_data.netdata_alarms_normal, b);
  406. snprintfz(b, 9, "%d", alarm_warn);
  407. analytics_set_data(&analytics_data.netdata_alarms_warning, b);
  408. snprintfz(b, 9, "%d", alarm_crit);
  409. analytics_set_data(&analytics_data.netdata_alarms_critical, b);
  410. }
  411. /*
  412. * Misc attributes to get (run from start)
  413. */
  414. void analytics_misc(void)
  415. {
  416. #ifdef ENABLE_ACLK
  417. analytics_set_data(&analytics_data.netdata_host_cloud_available, "true");
  418. analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "Next Generation");
  419. #else
  420. analytics_set_data(&analytics_data.netdata_host_cloud_available, "false");
  421. analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "");
  422. #endif
  423. analytics_set_data(&analytics_data.netdata_config_exporting_enabled, appconfig_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, "enabled", CONFIG_BOOLEAN_NO) ? "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. #ifdef ENABLE_NEW_CLOUD_PROTOCOL
  441. if (aclk_use_new_cloud_arch)
  442. analytics_set_data_str(&analytics_data.netdata_host_aclk_protocol, "New");
  443. else
  444. #endif
  445. analytics_set_data_str(&analytics_data.netdata_host_aclk_protocol, "Legacy");
  446. }
  447. else
  448. #endif
  449. analytics_set_data(&analytics_data.netdata_host_aclk_available, "false");
  450. }
  451. /*
  452. * Get the meta data, called from the thread once after the original delay
  453. * These are values that won't change during agent runtime, and therefore
  454. * don't try to read them on each META event send
  455. */
  456. void analytics_gather_immutable_meta_data(void)
  457. {
  458. analytics_misc();
  459. analytics_exporters();
  460. analytics_https();
  461. }
  462. /*
  463. * Get the meta data, called from the thread on every heartbeat, and right before the EXIT event
  464. * These are values that can change between agent restarts, and therefore
  465. * try to read them on each META event send
  466. */
  467. void analytics_gather_mutable_meta_data(void)
  468. {
  469. rrdhost_rdlock(localhost);
  470. analytics_collectors();
  471. analytics_alarms();
  472. analytics_charts();
  473. analytics_metrics();
  474. analytics_aclk();
  475. rrdhost_unlock(localhost);
  476. analytics_mirrored_hosts();
  477. analytics_alarms_notifications();
  478. analytics_set_data(
  479. &analytics_data.netdata_config_is_parent, (localhost->next || configured_as_parent()) ? "true" : "false");
  480. char *claim_id = is_agent_claimed();
  481. analytics_set_data(&analytics_data.netdata_host_agent_claimed, claim_id ? "true" : "false");
  482. freez(claim_id);
  483. {
  484. char b[7];
  485. snprintfz(b, 6, "%d", analytics_data.prometheus_hits);
  486. analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
  487. snprintfz(b, 6, "%d", analytics_data.shell_hits);
  488. analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
  489. snprintfz(b, 6, "%d", analytics_data.json_hits);
  490. analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
  491. snprintfz(b, 6, "%d", analytics_data.dashboard_hits);
  492. analytics_set_data(&analytics_data.netdata_dashboard_used, b);
  493. snprintfz(b, 6, "%zu", rrd_hosts_available);
  494. analytics_set_data(&analytics_data.netdata_config_hosts_available, b);
  495. }
  496. }
  497. void analytics_main_cleanup(void *ptr)
  498. {
  499. struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
  500. static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
  501. debug(D_ANALYTICS, "Cleaning up...");
  502. analytics_free_data();
  503. static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
  504. }
  505. /*
  506. * The analytics thread. Sleep for ANALYTICS_INIT_SLEEP_SEC,
  507. * gather the data, and then go to a loop where every ANALYTICS_HEARTBEAT
  508. * it will send a new META event after gathering data that could be changed
  509. * while the agent is running
  510. */
  511. void *analytics_main(void *ptr)
  512. {
  513. netdata_thread_cleanup_push(analytics_main_cleanup, ptr);
  514. unsigned int sec = 0;
  515. heartbeat_t hb;
  516. heartbeat_init(&hb);
  517. usec_t step_ut = USEC_PER_SEC;
  518. debug(D_ANALYTICS, "Analytics thread starts");
  519. //first delay after agent start
  520. while (!netdata_exit && likely(sec <= ANALYTICS_INIT_SLEEP_SEC)) {
  521. heartbeat_next(&hb, step_ut);
  522. sec++;
  523. }
  524. if (unlikely(netdata_exit))
  525. goto cleanup;
  526. analytics_gather_immutable_meta_data();
  527. analytics_gather_mutable_meta_data();
  528. send_statistics("META_START", "-", "-");
  529. analytics_log_data();
  530. sec = 0;
  531. while (1) {
  532. heartbeat_next(&hb, step_ut * 2);
  533. sec += 2;
  534. if (unlikely(netdata_exit))
  535. break;
  536. if (likely(sec < ANALYTICS_HEARTBEAT))
  537. continue;
  538. analytics_gather_mutable_meta_data();
  539. send_statistics("META", "-", "-");
  540. analytics_log_data();
  541. sec = 0;
  542. }
  543. cleanup:
  544. netdata_thread_cleanup_pop(1);
  545. return NULL;
  546. }
  547. static const char *verify_required_directory(const char *dir)
  548. {
  549. if (chdir(dir) == -1)
  550. fatal("Cannot change directory to '%s'", dir);
  551. DIR *d = opendir(dir);
  552. if (!d)
  553. fatal("Cannot examine the contents of directory '%s'", dir);
  554. closedir(d);
  555. return 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()
  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(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", CONFIG_BOOLEAN_YES) ? "true" : "false");
  571. #endif
  572. #ifdef ENABLE_DBENGINE
  573. {
  574. char b[16];
  575. snprintfz(b, 15, "%d", default_rrdeng_page_cache_mb);
  576. analytics_set_data(&analytics_data.netdata_config_page_cache_size, b);
  577. snprintfz(b, 15, "%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);
  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();
  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. 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. 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. 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. info("TIMEZONE: using strftime(): '%s'", timezone);
  647. }
  648. }
  649. }
  650. if (timezone && *timezone) {
  651. // make sure it does not have illegal characters
  652. // 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. 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. {
  710. char b[16];
  711. snprintfz(b, 15, "%d", default_rrd_update_every);
  712. setenv("NETDATA_UPDATE_EVERY", b, 1);
  713. }
  714. setenv("NETDATA_VERSION", program_version, 1);
  715. setenv("NETDATA_HOSTNAME", netdata_configured_hostname, 1);
  716. setenv("NETDATA_CONFIG_DIR", verify_required_directory(netdata_configured_user_config_dir), 1);
  717. setenv("NETDATA_USER_CONFIG_DIR", verify_required_directory(netdata_configured_user_config_dir), 1);
  718. setenv("NETDATA_STOCK_CONFIG_DIR", verify_required_directory(netdata_configured_stock_config_dir), 1);
  719. setenv("NETDATA_PLUGINS_DIR", verify_required_directory(netdata_configured_primary_plugins_dir), 1);
  720. setenv("NETDATA_WEB_DIR", verify_required_directory(netdata_configured_web_dir), 1);
  721. setenv("NETDATA_CACHE_DIR", verify_required_directory(netdata_configured_cache_dir), 1);
  722. setenv("NETDATA_LIB_DIR", verify_required_directory(netdata_configured_varlib_dir), 1);
  723. setenv("NETDATA_LOCK_DIR", netdata_configured_lock_dir, 1);
  724. setenv("NETDATA_LOG_DIR", verify_required_directory(netdata_configured_log_dir), 1);
  725. setenv("HOME", verify_required_directory(netdata_configured_home_dir), 1);
  726. setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
  727. analytics_data.data_length = 0;
  728. analytics_set_data(&analytics_data.netdata_config_stream_enabled, "null");
  729. analytics_set_data(&analytics_data.netdata_config_memory_mode, "null");
  730. analytics_set_data(&analytics_data.netdata_config_exporting_enabled, "null");
  731. analytics_set_data(&analytics_data.netdata_exporting_connectors, "null");
  732. analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, "null");
  733. analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, "null");
  734. analytics_set_data(&analytics_data.netdata_allmetrics_json_used, "null");
  735. analytics_set_data(&analytics_data.netdata_dashboard_used, "null");
  736. analytics_set_data(&analytics_data.netdata_collectors, "null");
  737. analytics_set_data(&analytics_data.netdata_collectors_count, "null");
  738. analytics_set_data(&analytics_data.netdata_buildinfo, "null");
  739. analytics_set_data(&analytics_data.netdata_config_page_cache_size, "null");
  740. analytics_set_data(&analytics_data.netdata_config_multidb_disk_quota, "null");
  741. analytics_set_data(&analytics_data.netdata_config_https_enabled, "null");
  742. analytics_set_data(&analytics_data.netdata_config_web_enabled, "null");
  743. analytics_set_data(&analytics_data.netdata_config_release_channel, "null");
  744. analytics_set_data(&analytics_data.netdata_mirrored_host_count, "null");
  745. analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, "null");
  746. analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, "null");
  747. analytics_set_data(&analytics_data.netdata_notification_methods, "null");
  748. analytics_set_data(&analytics_data.netdata_alarms_normal, "null");
  749. analytics_set_data(&analytics_data.netdata_alarms_warning, "null");
  750. analytics_set_data(&analytics_data.netdata_alarms_critical, "null");
  751. analytics_set_data(&analytics_data.netdata_charts_count, "null");
  752. analytics_set_data(&analytics_data.netdata_metrics_count, "null");
  753. analytics_set_data(&analytics_data.netdata_config_is_parent, "null");
  754. analytics_set_data(&analytics_data.netdata_config_hosts_available, "null");
  755. analytics_set_data(&analytics_data.netdata_host_cloud_available, "null");
  756. analytics_set_data(&analytics_data.netdata_host_aclk_implementation, "null");
  757. analytics_set_data(&analytics_data.netdata_host_aclk_available, "null");
  758. analytics_set_data(&analytics_data.netdata_host_aclk_protocol, "null");
  759. analytics_set_data(&analytics_data.netdata_host_agent_claimed, "null");
  760. analytics_set_data(&analytics_data.netdata_host_cloud_enabled, "null");
  761. analytics_set_data(&analytics_data.netdata_config_https_available, "null");
  762. analytics_set_data(&analytics_data.netdata_install_type, "null");
  763. analytics_set_data(&analytics_data.netdata_config_is_private_registry, "null");
  764. analytics_set_data(&analytics_data.netdata_config_use_private_registry, "null");
  765. analytics_set_data(&analytics_data.netdata_config_oom_score, "null");
  766. analytics_set_data(&analytics_data.netdata_prebuilt_distro, "null");
  767. analytics_data.prometheus_hits = 0;
  768. analytics_data.shell_hits = 0;
  769. analytics_data.json_hits = 0;
  770. analytics_data.dashboard_hits = 0;
  771. char *default_port = appconfig_get(&netdata_config, CONFIG_SECTION_WEB, "default port", NULL);
  772. int clean = 0;
  773. if (!default_port) {
  774. default_port = strdupz("19999");
  775. clean = 1;
  776. }
  777. setenv("NETDATA_LISTEN_PORT", default_port, 1);
  778. if (clean)
  779. freez(default_port);
  780. // set the path we need
  781. char path[1024 + 1], *p = getenv("PATH");
  782. if (!p)
  783. p = "/bin:/usr/bin";
  784. snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
  785. setenv("PATH", config_get(CONFIG_SECTION_ENV_VARS, "PATH", path), 1);
  786. // python options
  787. p = getenv("PYTHONPATH");
  788. if (!p)
  789. p = "";
  790. setenv("PYTHONPATH", config_get(CONFIG_SECTION_ENV_VARS, "PYTHONPATH", p), 1);
  791. // disable buffering for python plugins
  792. setenv("PYTHONUNBUFFERED", "1", 1);
  793. // switch to standard locale for plugins
  794. setenv("LC_ALL", "C", 1);
  795. }
  796. void send_statistics(const char *action, const char *action_result, const char *action_data)
  797. {
  798. static char *as_script;
  799. if (netdata_anonymous_statistics_enabled == -1) {
  800. char *optout_file = mallocz(
  801. sizeof(char) *
  802. (strlen(netdata_configured_user_config_dir) + strlen(".opt-out-from-anonymous-statistics") + 2));
  803. sprintf(optout_file, "%s/%s", netdata_configured_user_config_dir, ".opt-out-from-anonymous-statistics");
  804. if (likely(access(optout_file, R_OK) != 0)) {
  805. as_script = mallocz(
  806. sizeof(char) *
  807. (strlen(netdata_configured_primary_plugins_dir) + strlen("anonymous-statistics.sh") + 2));
  808. sprintf(as_script, "%s/%s", netdata_configured_primary_plugins_dir, "anonymous-statistics.sh");
  809. if (unlikely(access(as_script, R_OK) != 0)) {
  810. netdata_anonymous_statistics_enabled = 0;
  811. info("Anonymous statistics script %s not found.", as_script);
  812. freez(as_script);
  813. } else {
  814. netdata_anonymous_statistics_enabled = 1;
  815. }
  816. } else {
  817. netdata_anonymous_statistics_enabled = 0;
  818. as_script = NULL;
  819. }
  820. freez(optout_file);
  821. }
  822. if (!netdata_anonymous_statistics_enabled)
  823. return;
  824. if (!action)
  825. return;
  826. if (!action_result)
  827. action_result = "";
  828. if (!action_data)
  829. action_data = "";
  830. char *command_to_run = mallocz(
  831. sizeof(char) * (strlen(action) + strlen(action_result) + strlen(action_data) + strlen(as_script) +
  832. analytics_data.data_length + (ANALYTICS_NO_OF_ITEMS * 3) + 15));
  833. pid_t command_pid;
  834. sprintf(
  835. command_to_run,
  836. "%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' ",
  837. as_script,
  838. action,
  839. action_result,
  840. action_data,
  841. analytics_data.netdata_config_stream_enabled,
  842. analytics_data.netdata_config_memory_mode,
  843. analytics_data.netdata_config_exporting_enabled,
  844. analytics_data.netdata_exporting_connectors,
  845. analytics_data.netdata_allmetrics_prometheus_used,
  846. analytics_data.netdata_allmetrics_shell_used,
  847. analytics_data.netdata_allmetrics_json_used,
  848. analytics_data.netdata_dashboard_used,
  849. analytics_data.netdata_collectors,
  850. analytics_data.netdata_collectors_count,
  851. analytics_data.netdata_buildinfo,
  852. analytics_data.netdata_config_page_cache_size,
  853. analytics_data.netdata_config_multidb_disk_quota,
  854. analytics_data.netdata_config_https_enabled,
  855. analytics_data.netdata_config_web_enabled,
  856. analytics_data.netdata_config_release_channel,
  857. analytics_data.netdata_mirrored_host_count,
  858. analytics_data.netdata_mirrored_hosts_reachable,
  859. analytics_data.netdata_mirrored_hosts_unreachable,
  860. analytics_data.netdata_notification_methods,
  861. analytics_data.netdata_alarms_normal,
  862. analytics_data.netdata_alarms_warning,
  863. analytics_data.netdata_alarms_critical,
  864. analytics_data.netdata_charts_count,
  865. analytics_data.netdata_metrics_count,
  866. analytics_data.netdata_config_is_parent,
  867. analytics_data.netdata_config_hosts_available,
  868. analytics_data.netdata_host_cloud_available,
  869. analytics_data.netdata_host_aclk_available,
  870. analytics_data.netdata_host_aclk_protocol,
  871. analytics_data.netdata_host_aclk_implementation,
  872. analytics_data.netdata_host_agent_claimed,
  873. analytics_data.netdata_host_cloud_enabled,
  874. analytics_data.netdata_config_https_available,
  875. analytics_data.netdata_install_type,
  876. analytics_data.netdata_config_is_private_registry,
  877. analytics_data.netdata_config_use_private_registry,
  878. analytics_data.netdata_config_oom_score,
  879. analytics_data.netdata_prebuilt_distro);
  880. info("%s '%s' '%s' '%s'", as_script, action, action_result, action_data);
  881. FILE *fp = mypopen(command_to_run, &command_pid);
  882. if (fp) {
  883. char buffer[4 + 1];
  884. char *s = fgets(buffer, 4, fp);
  885. int exit_code = mypclose(fp, command_pid);
  886. if (exit_code)
  887. error("Execution of anonymous statistics script returned %d.", exit_code);
  888. if (s && strncmp(buffer, "200", 3))
  889. error("Execution of anonymous statistics script returned http code %s.", buffer);
  890. } else {
  891. error("Failed to run anonymous statistics script %s.", as_script);
  892. }
  893. freez(command_to_run);
  894. }