@cryptotaxi247 / netdata-1 / commits / 3d571ebb4

Revert "Provide more agent analytics to posthog (#10887)" (#11011)

This reverts commit a1ce482f3e336dbabe1b12b92f6339af6a2bbbf8.

Emmanuel Vasilakis committed Apr 21, 2021 at 20:53 UTC 3d571ebb44f1348ba3ed8aab80da2efe9a46a168
13 files changed +197 -1206
CMakeLists.txt
-2
@@ -828,8 +828,6 @@ set(DAEMON_FILES
828 daemon/daemon.h
829 daemon/global_statistics.c
830 daemon/global_statistics.h
831 - daemon/analytics.c
832 - daemon/analytics.h
831 daemon/main.c
832 daemon/main.h
833 daemon/signals.c
Makefile.am
-2
@@ -668,8 +668,6 @@ DAEMON_FILES = \
668 daemon/daemon.h \
669 daemon/global_statistics.c \
670 daemon/global_statistics.h \
671 - daemon/analytics.c \
672 - daemon/analytics.h \
671 daemon/main.c \
672 daemon/main.h \
673 daemon/signals.c \
daemon/analytics.c deleted
-880
@@ -1,880 +0,0 @@
1 -// SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -#include "common.h"
4 -
5 -struct analytics_data analytics_data;
6 -extern void analytics_exporting_connectors (BUFFER *b);
7 -extern void analytics_build_info (BUFFER *b);
8 -extern int aclk_connected;
9 -
10 -struct collector {
11 - char *plugin;
12 - char *module;
13 -};
14 -
15 -struct array_printer {
16 - int c;
17 - BUFFER *both;
18 -};
19 -
20 -/*
21 - * Set the env variables
22 - */
23 -void analytics_setenv_data(void)
24 -{
25 - setenv("NETDATA_CONFIG_STREAM_ENABLED", analytics_data.netdata_config_stream_enabled, 1);
26 - setenv("NETDATA_CONFIG_MEMORY_MODE", analytics_data.netdata_config_memory_mode, 1);
27 - setenv("NETDATA_CONFIG_EXPORTING_ENABLED", analytics_data.netdata_config_exporting_enabled, 1);
28 - setenv("NETDATA_EXPORTING_CONNECTORS", analytics_data.netdata_exporting_connectors, 1);
29 - setenv("NETDATA_ALLMETRICS_PROMETHEUS_USED", analytics_data.netdata_allmetrics_prometheus_used, 1);
30 - setenv("NETDATA_ALLMETRICS_SHELL_USED", analytics_data.netdata_allmetrics_shell_used, 1);
31 - setenv("NETDATA_ALLMETRICS_JSON_USED", analytics_data.netdata_allmetrics_json_used, 1);
32 - setenv("NETDATA_DASHBOARD_USED", analytics_data.netdata_dashboard_used, 1);
33 - setenv("NETDATA_COLLECTORS", analytics_data.netdata_collectors, 1);
34 - setenv("NETDATA_COLLECTORS_COUNT", analytics_data.netdata_collectors_count, 1);
35 - setenv("NETDATA_BUILDINFO", analytics_data.netdata_buildinfo, 1);
36 - setenv("NETDATA_CONFIG_PAGE_CACHE_SIZE", analytics_data.netdata_config_page_cache_size, 1);
37 - setenv("NETDATA_CONFIG_MULTIDB_DISK_QUOTA", analytics_data.netdata_config_multidb_disk_quota, 1);
38 - setenv("NETDATA_CONFIG_HTTPS_ENABLED", analytics_data.netdata_config_https_enabled, 1);
39 - setenv("NETDATA_CONFIG_WEB_ENABLED", analytics_data.netdata_config_web_enabled, 1);
40 - setenv("NETDATA_CONFIG_RELEASE_CHANNEL", analytics_data.netdata_config_release_channel, 1);
41 - setenv("NETDATA_MIRRORED_HOST_COUNT", analytics_data.netdata_mirrored_host_count, 1);
42 - setenv("NETDATA_MIRRORED_HOSTS_REACHABLE", analytics_data.netdata_mirrored_hosts_reachable, 1);
43 - setenv("NETDATA_MIRRORED_HOSTS_UNREACHABLE", analytics_data.netdata_mirrored_hosts_unreachable, 1);
44 - setenv("NETDATA_NOTIFICATION_METHODS", analytics_data.netdata_notification_methods, 1);
45 - setenv("NETDATA_ALARMS_NORMAL", analytics_data.netdata_alarms_normal, 1);
46 - setenv("NETDATA_ALARMS_WARNING", analytics_data.netdata_alarms_warning, 1);
47 - setenv("NETDATA_ALARMS_CRITICAL", analytics_data.netdata_alarms_critical, 1);
48 - setenv("NETDATA_CHARTS_COUNT", analytics_data.netdata_charts_count, 1);
49 - setenv("NETDATA_METRICS_COUNT", analytics_data.netdata_metrics_count, 1);
50 - setenv("NETDATA_CONFIG_IS_PARENT", analytics_data.netdata_config_is_parent, 1);
51 - setenv("NETDATA_CONFIG_HOSTS_AVAILABLE", analytics_data.netdata_config_hosts_available, 1);
52 - setenv("NETDATA_HOST_CLOUD_AVAILABLE", analytics_data.netdata_host_cloud_available, 1);
53 - setenv("NETDATA_HOST_ACLK_AVAILABLE", analytics_data.netdata_host_aclk_available, 1);
54 - setenv("NETDATA_HOST_ACLK_IMPLEMENTATION", analytics_data.netdata_host_aclk_implementation, 1);
55 - setenv("NETDATA_HOST_AGENT_CLAIMED", analytics_data.netdata_host_agent_claimed, 1);
56 -}
57 -
58 -/*
59 - * Debug logging
60 - */
61 -void analytics_log_data(void)
62 -{
63 - debug(D_ANALYTICS, "NETDATA_CONFIG_STREAM_ENABLED : [%s]", analytics_data.netdata_config_stream_enabled);
64 - debug(D_ANALYTICS, "NETDATA_CONFIG_MEMORY_MODE : [%s]", analytics_data.netdata_config_memory_mode);
65 - debug(D_ANALYTICS, "NETDATA_CONFIG_EXPORTING_ENABLED : [%s]", analytics_data.netdata_config_exporting_enabled);
66 - debug(D_ANALYTICS, "NETDATA_EXPORTING_CONNECTORS : [%s]", analytics_data.netdata_exporting_connectors);
67 - debug(D_ANALYTICS, "NETDATA_ALLMETRICS_PROMETHEUS_USED : [%s]", analytics_data.netdata_allmetrics_prometheus_used);
68 - debug(D_ANALYTICS, "NETDATA_ALLMETRICS_SHELL_USED : [%s]", analytics_data.netdata_allmetrics_shell_used);
69 - debug(D_ANALYTICS, "NETDATA_ALLMETRICS_JSON_USED : [%s]", analytics_data.netdata_allmetrics_json_used);
70 - debug(D_ANALYTICS, "NETDATA_DASHBOARD_USED : [%s]", analytics_data.netdata_dashboard_used);
71 - debug(D_ANALYTICS, "NETDATA_COLLECTORS : [%s]", analytics_data.netdata_collectors);
72 - debug(D_ANALYTICS, "NETDATA_COLLECTORS_COUNT : [%s]", analytics_data.netdata_collectors_count);
73 - debug(D_ANALYTICS, "NETDATA_BUILDINFO : [%s]", analytics_data.netdata_buildinfo);
74 - debug(D_ANALYTICS, "NETDATA_CONFIG_PAGE_CACHE_SIZE : [%s]", analytics_data.netdata_config_page_cache_size);
75 - debug(D_ANALYTICS, "NETDATA_CONFIG_MULTIDB_DISK_QUOTA : [%s]", analytics_data.netdata_config_multidb_disk_quota);
76 - debug(D_ANALYTICS, "NETDATA_CONFIG_HTTPS_ENABLED : [%s]", analytics_data.netdata_config_https_enabled);
77 - debug(D_ANALYTICS, "NETDATA_CONFIG_WEB_ENABLED : [%s]", analytics_data.netdata_config_web_enabled);
78 - debug(D_ANALYTICS, "NETDATA_CONFIG_RELEASE_CHANNEL : [%s]", analytics_data.netdata_config_release_channel);
79 - debug(D_ANALYTICS, "NETDATA_MIRRORED_HOST_COUNT : [%s]", analytics_data.netdata_mirrored_host_count);
80 - debug(D_ANALYTICS, "NETDATA_MIRRORED_HOSTS_REACHABLE : [%s]", analytics_data.netdata_mirrored_hosts_reachable);
81 - debug(D_ANALYTICS, "NETDATA_MIRRORED_HOSTS_UNREACHABLE : [%s]", analytics_data.netdata_mirrored_hosts_unreachable);
82 - debug(D_ANALYTICS, "NETDATA_NOTIFICATION_METHODS : [%s]", analytics_data.netdata_notification_methods);
83 - debug(D_ANALYTICS, "NETDATA_ALARMS_NORMAL : [%s]", analytics_data.netdata_alarms_normal);
84 - debug(D_ANALYTICS, "NETDATA_ALARMS_WARNING : [%s]", analytics_data.netdata_alarms_warning);
85 - debug(D_ANALYTICS, "NETDATA_ALARMS_CRITICAL : [%s]", analytics_data.netdata_alarms_critical);
86 - debug(D_ANALYTICS, "NETDATA_CHARTS_COUNT : [%s]", analytics_data.netdata_charts_count);
87 - debug(D_ANALYTICS, "NETDATA_METRICS_COUNT : [%s]", analytics_data.netdata_metrics_count);
88 - debug(D_ANALYTICS, "NETDATA_CONFIG_IS_PARENT : [%s]", analytics_data.netdata_config_is_parent);
89 - debug(D_ANALYTICS, "NETDATA_CONFIG_HOSTS_AVAILABLE : [%s]", analytics_data.netdata_config_hosts_available);
90 - debug(D_ANALYTICS, "NETDATA_HOST_CLOUD_AVAILABLE : [%s]", analytics_data.netdata_host_cloud_available);
91 - debug(D_ANALYTICS, "NETDATA_HOST_ACLK_AVAILABLE : [%s]", analytics_data.netdata_host_aclk_available);
92 - debug(D_ANALYTICS, "NETDATA_HOST_ACLK_IMPLEMENTATION : [%s]", analytics_data.netdata_host_aclk_implementation);
93 - debug(D_ANALYTICS, "NETDATA_HOST_AGENT_CLAIMED : [%s]", analytics_data.netdata_host_agent_claimed);
94 -}
95 -
96 -/*
97 - * Free data
98 - */
99 -void analytics_free_data(void)
100 -{
101 - freez(analytics_data.netdata_config_stream_enabled);
102 - freez(analytics_data.netdata_config_memory_mode);
103 - freez(analytics_data.netdata_config_exporting_enabled);
104 - freez(analytics_data.netdata_exporting_connectors);
105 - freez(analytics_data.netdata_allmetrics_prometheus_used);
106 - freez(analytics_data.netdata_allmetrics_shell_used);
107 - freez(analytics_data.netdata_allmetrics_json_used);
108 - freez(analytics_data.netdata_dashboard_used);
109 - freez(analytics_data.netdata_collectors);
110 - freez(analytics_data.netdata_collectors_count);
111 - freez(analytics_data.netdata_buildinfo);
112 - freez(analytics_data.netdata_config_page_cache_size);
113 - freez(analytics_data.netdata_config_multidb_disk_quota);
114 - freez(analytics_data.netdata_config_https_enabled);
115 - freez(analytics_data.netdata_config_web_enabled);
116 - freez(analytics_data.netdata_config_release_channel);
117 - freez(analytics_data.netdata_mirrored_host_count);
118 - freez(analytics_data.netdata_mirrored_hosts_reachable);
119 - freez(analytics_data.netdata_mirrored_hosts_unreachable);
120 - freez(analytics_data.netdata_notification_methods);
121 - freez(analytics_data.netdata_alarms_normal);
122 - freez(analytics_data.netdata_alarms_warning);
123 - freez(analytics_data.netdata_alarms_critical);
124 - freez(analytics_data.netdata_charts_count);
125 - freez(analytics_data.netdata_metrics_count);
126 - freez(analytics_data.netdata_config_is_parent);
127 - freez(analytics_data.netdata_config_hosts_available);
128 - freez(analytics_data.netdata_host_cloud_available);
129 - freez(analytics_data.netdata_host_aclk_available);
130 - freez(analytics_data.netdata_host_aclk_implementation);
131 - freez(analytics_data.netdata_host_agent_claimed);
132 -}
133 -
134 -/*
135 - * Set a numeric/boolean data with a value
136 - */
137 -void analytics_set_data(char **name, char *value)
138 -{
139 - if (*name)
140 - freez(*name);
141 - *name = strdupz(value);
142 -}
143 -
144 -/*
145 - * Set a string data with a value
146 - */
147 -void analytics_set_data_str(char **name, char *value)
148 -{
149 - size_t value_string_len;
150 - if (*name)
151 - freez(*name);
152 - value_string_len = strlen(value) + 4;
153 - *name = mallocz(sizeof(char) * value_string_len);
154 - snprintfz(*name, value_string_len - 1, "\"%s\"", value);
155 -}
156 -
157 -/*
158 - * Get data, used by web api v1
159 - */
160 -void analytics_get_data(char *name, BUFFER *wb)
161 -{
162 - buffer_strcat(wb, name);
163 -}
164 -
165 -/*
166 - * Log hits on the allmetrics page, with prometheus parameter
167 - */
168 -void analytics_log_prometheus(void)
169 -{
170 - if (likely(analytics_data.prometheus_hits < ANALYTICS_MAX_PROMETHEUS_HITS)) {
171 - analytics_data.prometheus_hits++;
172 - char b[7];
173 - snprintfz(b, 6, "%d", analytics_data.prometheus_hits);
174 - analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
175 - }
176 -}
177 -
178 -/*
179 - * Log hits on the allmetrics page, with shell parameter (or default)
180 - */
181 -void analytics_log_shell(void)
182 -{
183 - if (likely(analytics_data.shell_hits < ANALYTICS_MAX_SHELL_HITS)) {
184 - analytics_data.shell_hits++;
185 - char b[7];
186 - snprintfz(b, 6, "%d", analytics_data.shell_hits);
187 - analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
188 - }
189 -}
190 -
191 -/*
192 - * Log hits on the allmetrics page, with json parameter
193 - */
194 -void analytics_log_json(void)
195 -{
196 - if (likely(analytics_data.json_hits < ANALYTICS_MAX_JSON_HITS)) {
197 - analytics_data.json_hits++;
198 - char b[7];
199 - snprintfz(b, 6, "%d", analytics_data.json_hits);
200 - analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
201 - }
202 -}
203 -
204 -/*
205 - * Log hits on the dashboard, (when calling HELLO).
206 - */
207 -void analytics_log_dashboard(void)
208 -{
209 - if (likely(analytics_data.dashboard_hits < ANALYTICS_MAX_DASHBOARD_HITS)) {
210 - analytics_data.dashboard_hits++;
211 - char b[7];
212 - snprintfz(b, 6, "%d", analytics_data.dashboard_hits);
213 - analytics_set_data(&analytics_data.netdata_dashboard_used, b);
214 - }
215 -}
216 -
217 -void analytics_mirrored_hosts(void)
218 -{
219 - RRDHOST *host;
220 - int count = 0;
221 - int reachable = 0;
222 - int unreachable = 0;
223 - char b[11];
224 -
225 - rrd_rdlock();
226 - rrdhost_foreach_read(host)
227 - {
228 - if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))
229 - continue;
230 -
231 - netdata_mutex_lock(&host->receiver_lock);
232 - ((host->receiver || host == localhost) ? reachable++ : unreachable++);
233 - netdata_mutex_unlock(&host->receiver_lock);
234 -
235 - count++;
236 - }
237 - rrd_unlock();
238 -
239 - snprintfz(b, 10, "%d", count);
240 - analytics_set_data(&analytics_data.netdata_mirrored_host_count, b);
241 - snprintfz(b, 10, "%d", reachable);
242 - analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, b);
243 - snprintfz(b, 10, "%d", unreachable);
244 - analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, b);
245 -}
246 -
247 -void analytics_exporters(void)
248 -{
249 - //when no exporters are available, an empty string will be sent
250 - //decide if something else is more suitable (but propably not null)
251 - BUFFER *bi = buffer_create(1000);
252 - analytics_exporting_connectors(bi);
253 - analytics_set_data_str(&analytics_data.netdata_exporting_connectors, (char *)buffer_tostring(bi));
254 - buffer_free(bi);
255 -}
256 -
257 -int collector_counter_callb(void *entry, void *data)
258 -{
259 - struct array_printer *ap = (struct array_printer *)data;
260 - struct collector *col = (struct collector *)entry;
261 -
262 - BUFFER *bt = ap->both;
263 -
264 - if (likely(ap->c)) {
265 - buffer_strcat(bt, ",");
266 - }
267 -
268 - buffer_strcat(bt, "{");
269 - buffer_strcat(bt, " \"plugin\": \"");
270 - buffer_strcat(bt, col->plugin);
271 - buffer_strcat(bt, "\", \"module\":\"");
272 - buffer_strcat(bt, col->module);
273 - buffer_strcat(bt, "\" }");
274 -
275 - (ap->c)++;
276 -
277 - return 0;
278 -}
279 -
280 -/*
281 - * Create a JSON array of available collectors, same as in api/v1/info
282 - */
283 -void analytics_collectors(void)
284 -{
285 - RRDSET *st;
286 - DICTIONARY *dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
287 - char name[500];
288 - BUFFER *bt = buffer_create(1000);
289 -
290 - rrdset_foreach_read(st, localhost)
291 - {
292 - if (rrdset_is_available_for_viewers(st)) {
293 - struct collector col = { .plugin = st->plugin_name ? st->plugin_name : "",
294 - .module = st->module_name ? st->module_name : "" };
295 - snprintfz(name, 499, "%s:%s", col.plugin, col.module);
296 - dictionary_set(dict, name, &col, sizeof(struct collector));
297 - }
298 - }
299 -
300 - struct array_printer ap;
301 - ap.c = 0;
302 - ap.both = bt;
303 -
304 - dictionary_get_all(dict, collector_counter_callb, &ap);
305 - dictionary_destroy(dict);
306 -
307 - analytics_set_data(&analytics_data.netdata_collectors, (char *)buffer_tostring(ap.both));
308 -
309 - {
310 - char b[7];
311 - snprintfz(b, 6, "%d", ap.c);
312 - analytics_set_data(&analytics_data.netdata_collectors_count, b);
313 - }
314 -
315 - buffer_free(bt);
316 -}
317 -
318 -/*
319 - * Run alarm-notify.sh script using the dump_methods parameter
320 - * SEND_CUSTOM is always available
321 - */
322 -void analytics_alarms_notifications(void)
323 -{
324 - char *script;
325 - script = mallocz(
326 - sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("alarm-notify.sh dump_methods") + 2));
327 - sprintf(script, "%s/%s", netdata_configured_primary_plugins_dir, "alarm-notify.sh");
328 - if (unlikely(access(script, R_OK) != 0)) {
329 - info("Alarm notify script %s not found.", script);
330 - freez(script);
331 - return;
332 - }
333 -
334 - strcat(script, " dump_methods");
335 -
336 - pid_t command_pid;
337 -
338 - info("Executing %s", script);
339 -
340 - BUFFER *b = buffer_create(1000);
341 - int cnt = 0;
342 - FILE *fp = mypopen(script, &command_pid);
343 - if (fp) {
344 - char line[200 + 1];
345 -
346 - while (fgets(line, 200, fp) != NULL) {
347 - char *end = line;
348 - while (*end && *end != '\n')
349 - end++;
350 - *end = '\0';
351 -
352 - if (likely(cnt))
353 - buffer_strcat(b, "|");
354 -
355 - buffer_strcat(b, line);
356 -
357 - cnt++;
358 - }
359 - mypclose(fp, command_pid);
360 - }
361 - freez(script);
362 -
363 - analytics_set_data_str(&analytics_data.netdata_notification_methods, (char *)buffer_tostring(b));
364 -
365 - buffer_free(b);
366 -}
367 -
368 -void analytics_charts(void)
369 -{
370 - RRDSET *st;
371 - int c = 0;
372 - rrdset_foreach_read(st, localhost)
373 - {
374 - if (rrdset_is_available_for_viewers(st)) {
375 - c++;
376 - }
377 - }
378 - {
379 - char b[7];
380 - snprintfz(b, 6, "%d", c);
381 - analytics_set_data(&analytics_data.netdata_charts_count, b);
382 - }
383 -}
384 -
385 -void analytics_metrics(void)
386 -{
387 - RRDSET *st;
388 - long int dimensions = 0;
389 - RRDDIM *rd;
390 - rrdset_foreach_read(st, localhost)
391 - {
392 - rrdset_rdlock(st);
393 - rrddim_foreach_read(rd, st)
394 - {
395 - if (rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN) || rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE))
396 - continue;
397 - dimensions++;
398 - }
399 - rrdset_unlock(st);
400 - }
401 - {
402 - char b[7];
403 - snprintfz(b, 6, "%ld", dimensions);
404 - analytics_set_data(&analytics_data.netdata_metrics_count, b);
405 - }
406 -}
407 -
408 -void analytics_alarms(void)
409 -{
410 - int alarm_warn = 0, alarm_crit = 0, alarm_normal = 0;
411 - char b[10];
412 - RRDCALC *rc;
413 - for (rc = localhost->alarms; rc; rc = rc->next) {
414 - if (unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
415 - continue;
416 -
417 - switch (rc->status) {
418 - case RRDCALC_STATUS_WARNING:
419 - alarm_warn++;
420 - break;
421 - case RRDCALC_STATUS_CRITICAL:
422 - alarm_crit++;
423 - break;
424 - default:
425 - alarm_normal++;
426 - }
427 - }
428 -
429 - snprintfz(b, 9, "%d", alarm_normal);
430 - analytics_set_data(&analytics_data.netdata_alarms_normal, b);
431 - snprintfz(b, 9, "%d", alarm_warn);
432 - analytics_set_data(&analytics_data.netdata_alarms_warning, b);
433 - snprintfz(b, 9, "%d", alarm_crit);
434 - analytics_set_data(&analytics_data.netdata_alarms_critical, b);
435 -}
436 -
437 -/*
438 - * Misc attributes to get (run from meta)
439 - */
440 -void analytics_misc(void)
441 -{
442 -#ifdef ENABLE_ACLK
443 - analytics_set_data(&analytics_data.netdata_host_cloud_available, "true");
444 -#ifdef ACLK_NG
445 - analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "Next Generation");
446 -#else
447 - analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "legacy");
448 -#endif
449 -#else
450 - analytics_set_data(&analytics_data.netdata_host_cloud_available, "false");
451 -#endif
452 -
453 -#ifdef ENABLE_ACLK
454 - if (aclk_connected)
455 - analytics_set_data(&analytics_data.netdata_host_aclk_available, "true");
456 - else
457 -#endif
458 - analytics_set_data(&analytics_data.netdata_host_aclk_available, "false");
459 -}
460 -
461 -/*
462 - * Get the meta data, called from the thread once after the original delay
463 - * These are values that won't change between agent restarts, and therefore
464 - * don't try to read them on each META event send
465 - */
466 -void analytics_gather_immutable_meta_data(void)
467 -{
468 - analytics_misc();
469 - analytics_exporters();
470 -
471 - analytics_setenv_data();
472 -}
473 -
474 -/*
475 - * Get the meta data, called from the thread on every heartbeat, and right before the EXIT event
476 - * These are values that can change between agent restarts, and therefore
477 - * try to read them on each META event send
478 - */
479 -void analytics_gather_mutable_meta_data(void)
480 -{
481 - rrdhost_rdlock(localhost);
482 -
483 - analytics_collectors();
484 - analytics_alarms();
485 - analytics_charts();
486 - analytics_metrics();
487 -
488 - rrdhost_unlock(localhost);
489 -
490 - analytics_mirrored_hosts();
491 - analytics_alarms_notifications();
492 -
493 - analytics_set_data(
494 - &analytics_data.netdata_config_is_parent, (localhost->next || configured_as_parent()) ? "true" : "false");
495 -
496 - if (is_agent_claimed())
497 - analytics_set_data(&analytics_data.netdata_host_agent_claimed, "true");
498 - else {
499 - analytics_set_data(&analytics_data.netdata_host_agent_claimed, "false");
500 - }
501 -
502 - {
503 - char b[7];
504 - snprintfz(b, 6, "%d", analytics_data.prometheus_hits);
505 - analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
506 -
507 - snprintfz(b, 6, "%d", analytics_data.shell_hits);
508 - analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
509 -
510 - snprintfz(b, 6, "%d", analytics_data.json_hits);
511 - analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
512 -
513 - snprintfz(b, 6, "%d", analytics_data.dashboard_hits);
514 - analytics_set_data(&analytics_data.netdata_dashboard_used, b);
515 -
516 - snprintfz(b, 6, "%zu", rrd_hosts_available);
517 - analytics_set_data(&analytics_data.netdata_config_hosts_available, b);
518 - }
519 -
520 - analytics_setenv_data();
521 -}
522 -
523 -void analytics_main_cleanup(void *ptr)
524 -{
525 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
526 - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
527 -
528 - debug(D_ANALYTICS, "Cleaning up...");
529 -
530 - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
531 -}
532 -
533 -/*
534 - * The analytics thread. Sleep for ANALYTICS_INIT_SLEEP_SEC,
535 - * gather the data, and then go to a loop where every ANALYTICS_HEARTBEAT
536 - * it will send a new META event after gathering data that could be changed
537 - * while the agent is running
538 - */
539 -void *analytics_main(void *ptr)
540 -{
541 - netdata_thread_cleanup_push(analytics_main_cleanup, ptr);
542 - unsigned int sec = 0;
543 - heartbeat_t hb;
544 - heartbeat_init(&hb);
545 - usec_t step_ut = USEC_PER_SEC;
546 -
547 - debug(D_ANALYTICS, "Analytics thread starts");
548 -
549 - //first delay after agent start
550 - while (!netdata_exit && likely(sec <= ANALYTICS_INIT_SLEEP_SEC)) {
551 - heartbeat_next(&hb, step_ut);
552 - sec++;
553 - }
554 -
555 - if (unlikely(netdata_exit))
556 - goto cleanup;
557 -
558 - analytics_gather_immutable_meta_data();
559 - analytics_gather_mutable_meta_data();
560 - send_statistics("META", "-", "-");
561 - analytics_log_data();
562 -
563 - sec = 0;
564 - while (1) {
565 - heartbeat_next(&hb, step_ut * 2);
566 - sec += 2;
567 -
568 - if (unlikely(netdata_exit))
569 - break;
570 -
571 - if (likely(sec < ANALYTICS_HEARTBEAT))
572 - continue;
573 -
574 - analytics_gather_mutable_meta_data();
575 - send_statistics("META", "-", "-");
576 - analytics_log_data();
577 - sec = 0;
578 - }
579 -
580 -cleanup:
581 - netdata_thread_cleanup_pop(1);
582 - return NULL;
583 -}
584 -
585 -static const char *verify_required_directory(const char *dir)
586 -{
587 - if (chdir(dir) == -1)
588 - fatal("Cannot change directory to '%s'", dir);
589 -
590 - DIR *d = opendir(dir);
591 - if (!d)
592 - fatal("Cannot examine the contents of directory '%s'", dir);
593 - closedir(d);
594 -
595 - return dir;
596 -}
597 -
598 -/*
599 - * This is called after the rrdinit
600 - * These values will be sent on the START event
601 - */
602 -void set_late_global_environment()
603 -{
604 - analytics_set_data(&analytics_data.netdata_config_stream_enabled, default_rrdpush_enabled ? "true" : "false");
605 - analytics_set_data_str(&analytics_data.netdata_config_memory_mode, (char *)rrd_memory_mode_name(default_rrd_memory_mode));
606 - analytics_set_data(&analytics_data.netdata_config_exporting_enabled, appconfig_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, "enabled", 1) ? "true" : "false");
607 -
608 -#ifdef ENABLE_DBENGINE
609 - {
610 - char b[16];
611 - snprintfz(b, 15, "%d", default_rrdeng_page_cache_mb);
612 - analytics_set_data(&analytics_data.netdata_config_page_cache_size, b);
613 -
614 - snprintfz(b, 15, "%d", default_multidb_disk_quota_mb);
615 - analytics_set_data(&analytics_data.netdata_config_multidb_disk_quota, b);
616 - }
617 -#endif
618 -
619 -#ifdef ENABLE_HTTPS
620 - analytics_set_data(&analytics_data.netdata_config_https_enabled, "true");
621 -#else
622 - analytics_set_data(&analytics_data.netdata_config_https_enabled, "false");
623 -#endif
624 -
625 - if (web_server_mode == WEB_SERVER_MODE_NONE)
626 - analytics_set_data(&analytics_data.netdata_config_web_enabled, "false");
627 - else
628 - analytics_set_data(&analytics_data.netdata_config_web_enabled, "true");
629 -
630 - analytics_set_data_str(&analytics_data.netdata_config_release_channel, (char *)get_release_channel());
631 -
632 - {
633 - BUFFER *bi = buffer_create(1000);
634 - analytics_build_info(bi);
635 - analytics_set_data_str(&analytics_data.netdata_buildinfo, (char *)buffer_tostring(bi));
636 - buffer_free(bi);
637 - }
638 -
639 - /* set what we have, to send the START event */
640 - analytics_setenv_data();
641 -}
642 -
643 -static void get_system_timezone(void)
644 -{
645 - // avoid flood calls to stat(/etc/localtime)
646 - // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
647 - const char *tz = getenv("TZ");
648 - if (!tz || !*tz)
649 - setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0);
650 -
651 - char buffer[FILENAME_MAX + 1] = "";
652 - const char *timezone = NULL;
653 - ssize_t ret;
654 -
655 - // use the TZ variable
656 - if (tz && *tz && *tz != ':') {
657 - timezone = tz;
658 - info("TIMEZONE: using TZ variable '%s'", timezone);
659 - }
660 -
661 - // use the contents of /etc/timezone
662 - if (!timezone && !read_file("/etc/timezone", buffer, FILENAME_MAX)) {
663 - char *c = buffer;
664 - while (*c) {
665 - if (unlikely(*c == '\n'))
666 - *c = '\0';
667 - c++;
668 - }
669 - timezone = buffer;
670 - info("TIMEZONE: using the contents of /etc/timezone: '%s'", timezone);
671 - }
672 -
673 - // read the link /etc/localtime
674 - if (!timezone) {
675 - ret = readlink("/etc/localtime", buffer, FILENAME_MAX);
676 -
677 - if (ret > 0) {
678 - buffer[ret] = '\0';
679 -
680 - char *cmp = "/usr/share/zoneinfo/";
681 - size_t cmp_len = strlen(cmp);
682 -
683 - char *s = strstr(buffer, cmp);
684 - if (s && s[cmp_len]) {
685 - timezone = &s[cmp_len];
686 - info("TIMEZONE: using the link of /etc/localtime: '%s'", timezone);
687 - }
688 - } else
689 - buffer[0] = '\0';
690 - }
691 -
692 - // find the timezone from strftime()
693 - if (!timezone) {
694 - time_t t;
695 - struct tm *tmp, tmbuf;
696 -
697 - t = now_realtime_sec();
698 - tmp = localtime_r(&t, &tmbuf);
699 -
700 - if (tmp != NULL) {
701 - if (strftime(buffer, FILENAME_MAX, "%Z", tmp) == 0)
702 - buffer[0] = '\0';
703 - else {
704 - buffer[FILENAME_MAX] = '\0';
705 - timezone = buffer;
706 - info("TIMEZONE: using strftime(): '%s'", timezone);
707 - }
708 - }
709 - }
710 -
711 - if (timezone && *timezone) {
712 - // make sure it does not have illegal characters
713 - // info("TIMEZONE: fixing '%s'", timezone);
714 -
715 - size_t len = strlen(timezone);
716 - char tmp[len + 1];
717 - char *d = tmp;
718 - *d = '\0';
719 -
720 - while (*timezone) {
721 - if (isalnum(*timezone) || *timezone == '_' || *timezone == '/')
722 - *d++ = *timezone++;
723 - else
724 - timezone++;
725 - }
726 - *d = '\0';
727 - strncpyz(buffer, tmp, len);
728 - timezone = buffer;
729 - // info("TIMEZONE: fixed as '%s'", timezone);
730 - }
731 -
732 - if (!timezone || !*timezone)
733 - timezone = "unknown";
734 -
735 - netdata_configured_timezone = config_get(CONFIG_SECTION_GLOBAL, "timezone", timezone);
736 -}
737 -
738 -void set_global_environment()
739 -{
740 - {
741 - char b[16];
742 - snprintfz(b, 15, "%d", default_rrd_update_every);
743 - setenv("NETDATA_UPDATE_EVERY", b, 1);
744 - }
745 -
746 - setenv("NETDATA_VERSION", program_version, 1);
747 - setenv("NETDATA_HOSTNAME", netdata_configured_hostname, 1);
748 - setenv("NETDATA_CONFIG_DIR", verify_required_directory(netdata_configured_user_config_dir), 1);
749 - setenv("NETDATA_USER_CONFIG_DIR", verify_required_directory(netdata_configured_user_config_dir), 1);
750 - setenv("NETDATA_STOCK_CONFIG_DIR", verify_required_directory(netdata_configured_stock_config_dir), 1);
751 - setenv("NETDATA_PLUGINS_DIR", verify_required_directory(netdata_configured_primary_plugins_dir), 1);
752 - setenv("NETDATA_WEB_DIR", verify_required_directory(netdata_configured_web_dir), 1);
753 - setenv("NETDATA_CACHE_DIR", verify_required_directory(netdata_configured_cache_dir), 1);
754 - setenv("NETDATA_LIB_DIR", verify_required_directory(netdata_configured_varlib_dir), 1);
755 - setenv("NETDATA_LOCK_DIR", netdata_configured_lock_dir, 1);
756 - setenv("NETDATA_LOG_DIR", verify_required_directory(netdata_configured_log_dir), 1);
757 - setenv("HOME", verify_required_directory(netdata_configured_home_dir), 1);
758 - setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
759 -
760 - analytics_set_data(&analytics_data.netdata_config_stream_enabled, "null");
761 - analytics_set_data(&analytics_data.netdata_config_memory_mode, "null");
762 - analytics_set_data(&analytics_data.netdata_config_exporting_enabled, "null");
763 - analytics_set_data(&analytics_data.netdata_exporting_connectors, "null");
764 - analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, "null");
765 - analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, "null");
766 - analytics_set_data(&analytics_data.netdata_allmetrics_json_used, "null");
767 - analytics_set_data(&analytics_data.netdata_dashboard_used, "null");
768 - analytics_set_data(&analytics_data.netdata_collectors, "null");
769 - analytics_set_data(&analytics_data.netdata_collectors_count, "null");
770 - analytics_set_data(&analytics_data.netdata_buildinfo, "null");
771 - analytics_set_data(&analytics_data.netdata_config_page_cache_size, "null");
772 - analytics_set_data(&analytics_data.netdata_config_multidb_disk_quota, "null");
773 - analytics_set_data(&analytics_data.netdata_config_https_enabled, "null");
774 - analytics_set_data(&analytics_data.netdata_config_web_enabled, "null");
775 - analytics_set_data(&analytics_data.netdata_config_release_channel, "null");
776 - analytics_set_data(&analytics_data.netdata_mirrored_host_count, "null");
777 - analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, "null");
778 - analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, "null");
779 - analytics_set_data(&analytics_data.netdata_notification_methods, "null");
780 - analytics_set_data(&analytics_data.netdata_alarms_normal, "null");
781 - analytics_set_data(&analytics_data.netdata_alarms_warning, "null");
782 - analytics_set_data(&analytics_data.netdata_alarms_critical, "null");
783 - analytics_set_data(&analytics_data.netdata_charts_count, "null");
784 - analytics_set_data(&analytics_data.netdata_metrics_count, "null");
785 - analytics_set_data(&analytics_data.netdata_config_is_parent, "null");
786 - analytics_set_data(&analytics_data.netdata_config_hosts_available, "null");
787 - analytics_set_data(&analytics_data.netdata_host_cloud_available, "null");
788 - analytics_set_data(&analytics_data.netdata_host_aclk_implementation, "null");
789 - analytics_set_data(&analytics_data.netdata_host_aclk_available, "null");
790 - analytics_set_data(&analytics_data.netdata_host_agent_claimed, "null");
791 -
792 - analytics_data.prometheus_hits = 0;
793 - analytics_data.shell_hits = 0;
794 - analytics_data.json_hits = 0;
795 - analytics_data.dashboard_hits = 0;
796 -
797 - char *default_port = appconfig_get(&netdata_config, CONFIG_SECTION_WEB, "default port", NULL);
798 - int clean = 0;
799 - if (!default_port) {
800 - default_port = strdupz("19999");
801 - clean = 1;
802 - }
803 -
804 - setenv("NETDATA_LISTEN_PORT", default_port, 1);
805 - if (clean)
806 - freez(default_port);
807 -
808 - get_system_timezone();
809 -
810 - // set the path we need
811 - char path[1024 + 1], *p = getenv("PATH");
812 - if (!p)
813 - p = "/bin:/usr/bin";
814 - snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
815 - setenv("PATH", config_get(CONFIG_SECTION_PLUGINS, "PATH environment variable", path), 1);
816 -
817 - // python options
818 - p = getenv("PYTHONPATH");
819 - if (!p)
820 - p = "";
821 - setenv("PYTHONPATH", config_get(CONFIG_SECTION_PLUGINS, "PYTHONPATH environment variable", p), 1);
822 -
823 - // disable buffering for python plugins
824 - setenv("PYTHONUNBUFFERED", "1", 1);
825 -
826 - // switch to standard locale for plugins
827 - setenv("LC_ALL", "C", 1);
828 -}
829 -
830 -void send_statistics(const char *action, const char *action_result, const char *action_data)
831 -{
832 - static char *as_script;
833 -
834 - if (netdata_anonymous_statistics_enabled == -1) {
835 - char *optout_file = mallocz(
836 - sizeof(char) *
837 - (strlen(netdata_configured_user_config_dir) + strlen(".opt-out-from-anonymous-statistics") + 2));
838 - sprintf(optout_file, "%s/%s", netdata_configured_user_config_dir, ".opt-out-from-anonymous-statistics");
839 - if (likely(access(optout_file, R_OK) != 0)) {
840 - as_script = mallocz(
841 - sizeof(char) *
842 - (strlen(netdata_configured_primary_plugins_dir) + strlen("anonymous-statistics.sh") + 2));
843 - sprintf(as_script, "%s/%s", netdata_configured_primary_plugins_dir, "anonymous-statistics.sh");
844 - if (unlikely(access(as_script, R_OK) != 0)) {
845 - netdata_anonymous_statistics_enabled = 0;
846 - info("Anonymous statistics script %s not found.", as_script);
847 - freez(as_script);
848 - } else {
849 - netdata_anonymous_statistics_enabled = 1;
850 - }
851 - } else {
852 - netdata_anonymous_statistics_enabled = 0;
853 - as_script = NULL;
854 - }
855 - freez(optout_file);
856 - }
857 - if (!netdata_anonymous_statistics_enabled)
858 - return;
859 - if (!action)
860 - return;
861 - if (!action_result)
862 - action_result = "";
863 - if (!action_data)
864 - action_data = "";
865 - char *command_to_run =
866 - mallocz(sizeof(char) * (strlen(action) + strlen(action_result) + strlen(action_data) + strlen(as_script) + 10));
867 - pid_t command_pid;
868 -
869 - sprintf(command_to_run, "%s '%s' '%s' '%s'", as_script, action, action_result, action_data);
870 - info("%s", command_to_run);
871 -
872 - FILE *fp = mypopen(command_to_run, &command_pid);
873 - if (fp) {
874 - char buffer[100 + 1];
875 - while (fgets(buffer, 100, fp) != NULL)
876 - ;
877 - mypclose(fp, command_pid);
878 - }
879 - freez(command_to_run);
880 -}
daemon/analytics.h deleted
-84
@@ -1,84 +0,0 @@
1 -// SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -#ifndef NETDATA_ANALYTICS_H
4 -#define NETDATA_ANALYTICS_H 1
5 -
6 -#include "../daemon/common.h"
7 -
8 -/* Max number of seconds before the first META analytics is sent */
9 -#define ANALYTICS_INIT_SLEEP_SEC 120
10 -
11 -/* Send a META event every X seconds */
12 -#define ANALYTICS_HEARTBEAT 7200
13 -
14 -/* Maximum number of hits to log */
15 -#define ANALYTICS_MAX_PROMETHEUS_HITS 255
16 -#define ANALYTICS_MAX_SHELL_HITS 255
17 -#define ANALYTICS_MAX_JSON_HITS 255
18 -#define ANALYTICS_MAX_DASHBOARD_HITS 255
19 -
20 -#define NETDATA_PLUGIN_HOOK_ANALYTICS \
21 - { \
22 - .name = "ANALYTICS", \
23 - .config_section = NULL, \
24 - .config_name = NULL, \
25 - .enabled = 0, \
26 - .thread = NULL, \
27 - .init_routine = NULL, \
28 - .start_routine = analytics_main \
29 - },
30 -
31 -struct analytics_data {
32 - char *netdata_config_stream_enabled;
33 - char *netdata_config_memory_mode;
34 - char *netdata_exporting_connectors;
35 - char *netdata_config_exporting_enabled;
36 - char *netdata_allmetrics_prometheus_used;
37 - char *netdata_allmetrics_shell_used;
38 - char *netdata_allmetrics_json_used;
39 - char *netdata_dashboard_used;
40 - char *netdata_collectors;
41 - char *netdata_collectors_count;
42 - char *netdata_buildinfo;
43 - char *netdata_config_page_cache_size;
44 - char *netdata_config_multidb_disk_quota;
45 - char *netdata_config_https_enabled;
46 - char *netdata_config_web_enabled;
47 - char *netdata_config_release_channel;
48 - char *netdata_mirrored_host_count;
49 - char *netdata_mirrored_hosts_reachable;
50 - char *netdata_mirrored_hosts_unreachable;
51 - char *netdata_notification_methods;
52 - char *netdata_alarms_normal;
53 - char *netdata_alarms_warning;
54 - char *netdata_alarms_critical;
55 - char *netdata_charts_count;
56 - char *netdata_metrics_count;
57 - char *netdata_config_is_parent;
58 - char *netdata_config_hosts_available;
59 - char *netdata_host_cloud_available;
60 - char *netdata_host_aclk_available;
61 - char *netdata_host_aclk_implementation;
62 - char *netdata_host_agent_claimed;
63 -
64 - uint8_t prometheus_hits;
65 - uint8_t shell_hits;
66 - uint8_t json_hits;
67 - uint8_t dashboard_hits;
68 -};
69 -
70 -extern void *analytics_main(void *ptr);
71 -extern void analytics_get_data(char *name, BUFFER *wb);
72 -extern void set_late_global_environment(void);
73 -extern void analytics_free_data(void);
74 -extern void set_global_environment(void);
75 -extern void send_statistics(const char *action, const char *action_result, const char *action_data);
76 -extern void analytics_log_shell(void);
77 -extern void analytics_log_json(void);
78 -extern void analytics_log_prometheus(void);
79 -extern void analytics_log_dashboard(void);
80 -extern void analytics_gather_mutable_meta_data(void);
81 -
82 -extern struct analytics_data analytics_data;
83 -
84 -#endif //NETDATA_ANALYTICS_H
daemon/anonymous-statistics.sh.in
+1 -34
@@ -44,8 +44,6 @@ REQ_BODY="$(cat << EOF
44 "action_data": "${ACTION_DATA}",
45 "netdata_machine_guid": "${NETDATA_REGISTRY_UNIQUE_ID}",
46 "netdata_version": "${NETDATA_VERSION}",
47 - "netdata_buildinfo": ${NETDATA_BUILDINFO},
48 - "netdata_release_channel": ${NETDATA_CONFIG_RELEASE_CHANNEL},
47 "host_os_name": "${NETDATA_HOST_OS_NAME}",
48 "host_os_id": "${NETDATA_HOST_OS_ID}",
49 "host_os_id_like": "${NETDATA_HOST_OS_ID_LIKE}",
@@ -74,38 +72,7 @@ REQ_BODY="$(cat << EOF
72 "system_disk_detection": "${NETDATA_SYSTEM_DISK_DETECTION}",
73 "system_ram_detection": "${NETDATA_SYSTEM_RAM_DETECTION}",
74 "system_total_disk_size": "${NETDATA_SYSTEM_TOTAL_DISK_SIZE}",
77 - "system_total_ram": "${NETDATA_SYSTEM_TOTAL_RAM}",
78 - "config_stream_enabled": ${NETDATA_CONFIG_STREAM_ENABLED},
79 - "config_memory_mode": ${NETDATA_CONFIG_MEMORY_MODE},
80 - "config_page_cache_size": ${NETDATA_CONFIG_PAGE_CACHE_SIZE},
81 - "config_multidb_disk_quota": ${NETDATA_CONFIG_MULTIDB_DISK_QUOTA},
82 - "config_https_enabled": ${NETDATA_CONFIG_HTTPS_ENABLED},
83 - "config_web_enabled": ${NETDATA_CONFIG_WEB_ENABLED},
84 - "config_exporting_enabled": ${NETDATA_CONFIG_EXPORTING_ENABLED},
85 - "config_is_parent": ${NETDATA_CONFIG_IS_PARENT},
86 - "config_hosts_available": ${NETDATA_CONFIG_HOSTS_AVAILABLE},
87 - "alarms_normal": ${NETDATA_ALARMS_NORMAL},
88 - "alarms_warning": ${NETDATA_ALARMS_WARNING},
89 - "alarms_critical": ${NETDATA_ALARMS_CRITICAL},
90 - "host_charts_count": ${NETDATA_CHARTS_COUNT},
91 - "host_metrics_count": ${NETDATA_METRICS_COUNT},
92 - "host_collectors":[
93 - ${NETDATA_COLLECTORS}
94 - ],
95 - "host_collectors_count": ${NETDATA_COLLECTORS_COUNT},
96 - "host_notification_methods": ${NETDATA_NOTIFICATION_METHODS},
97 - "host_allmetrics_prometheus_used": ${NETDATA_ALLMETRICS_PROMETHEUS_USED},
98 - "host_allmetrics_shell_used": ${NETDATA_ALLMETRICS_SHELL_USED},
99 - "host_allmetrics_json_used": ${NETDATA_ALLMETRICS_JSON_USED},
100 - "host_dashboard_used": ${NETDATA_DASHBOARD_USED},
101 - "host_cloud_available": ${NETDATA_HOST_CLOUD_AVAILABLE},
102 - "host_agent_claimed": ${NETDATA_HOST_AGENT_CLAIMED},
103 - "host_aclk_available": ${NETDATA_HOST_ACLK_AVAILABLE},
104 - "host_aclk_implementation": ${NETDATA_HOST_ACLK_IMPLEMENTATION},
105 - "mirrored_host_count": ${NETDATA_MIRRORED_HOST_COUNT},
106 - "mirrored_hosts_reachable": ${NETDATA_MIRRORED_HOSTS_REACHABLE},
107 - "mirrored_hosts_unreachable": ${NETDATA_MIRRORED_HOSTS_UNREACHABLE},
108 - "exporting_connectors": ${NETDATA_EXPORTING_CONNECTORS}
75 + "system_total_ram": "${NETDATA_SYSTEM_TOTAL_RAM}"
76 }
77 }
78 EOF
daemon/buildinfo.c
-47
@@ -2,7 +2,6 @@
2
3 #include <stdio.h>
4 #include "./config.h"
5 -#include "common.h"
5
6 // Optional features
7
@@ -313,49 +312,3 @@ void print_build_info_json(void) {
312 printf(" }\n");
313 printf("}\n");
314 };
316 -
317 -//return a list of enabled features for use in analytics
318 -//find a way to have proper |
319 -void analytics_build_info(BUFFER *b) {
320 - if(FEAT_DBENGINE) buffer_strcat (b, "dbengine");
321 - if(FEAT_NATIVE_HTTPS) buffer_strcat (b, "|Native HTTPS");
322 - if(FEAT_CLOUD) buffer_strcat (b, "|Netdata Cloud");
323 - if(FEAT_TLS_HOST_VERIFY) buffer_strcat (b, "|TLS Host Verification");
324 -
325 - if(FEAT_JEMALLOC) buffer_strcat (b, "|jemalloc");
326 - if(FEAT_JSONC) buffer_strcat (b, "|JSON-C");
327 - if(FEAT_LIBCAP) buffer_strcat (b, "|libcap");
328 - if(FEAT_CRYPTO) buffer_strcat (b, "|libcrypto");
329 - if(FEAT_LIBM) buffer_strcat (b, "|libm");
330 -
331 -#ifndef ACLK_NG
332 -#if defined(ENABLE_ACLK)
333 - {
334 - char buf[20];
335 - snprintfz(buf, 19, "|LWS v%d.%d.%d", LWS_LIBRARY_VERSION_MAJOR, LWS_LIBRARY_VERSION_MINOR, LWS_LIBRARY_VERSION_PATCH);
336 - if(FEAT_LWS) buffer_strcat(b, buf);
337 - }
338 -#else
339 - if(FEAT_LWS) buffer_strcat(b, "|LWS");
340 -#endif
341 - if(FEAT_MOSQUITTO) buffer_strcat(b, "|mosquitto");
342 -#endif
343 - if(FEAT_TCMALLOC) buffer_strcat(b, "|tcalloc");
344 - if(FEAT_ZLIB) buffer_strcat(b, "|zlib");
345 -
346 - if(FEAT_APPS_PLUGIN) buffer_strcat(b, "|apps");
347 - if(FEAT_CGROUP_NET) buffer_strcat(b, "|cgroup Network Tracking");
348 - if(FEAT_CUPS) buffer_strcat(b, "|CUPS");
349 - if(FEAT_EBPF) buffer_strcat(b, "|EBPF");
350 - if(FEAT_IPMI) buffer_strcat(b, "|IPMI");
351 - if(FEAT_NFACCT) buffer_strcat(b, "|NFACCT");
352 - if(FEAT_PERF) buffer_strcat(b, "|perf");
353 - if(FEAT_SLABINFO) buffer_strcat(b, "|slabinfo");
354 - if(FEAT_XEN) buffer_strcat(b, "|Xen");
355 - if(FEAT_XEN_VBD_ERROR) buffer_strcat(b, "|Xen VBD Error Tracking");
356 -
357 - if(FEAT_KINESIS) buffer_strcat(b, "|AWS Kinesis");
358 - if(FEAT_PUBSUB) buffer_strcat(b, "|GCP PubSub");
359 - if(FEAT_MONGO) buffer_strcat(b, "|MongoDB");
360 - if(FEAT_REMOTE_WRITE) buffer_strcat(b, "|Prometheus Remote Write");
361 -}
daemon/common.h
-1
@@ -82,7 +82,6 @@
82 #include "main.h"
83 #include "signals.h"
84 #include "commands.h"
85 -#include "analytics.h"
85
86 // global netdata daemon variables
87 extern char *netdata_configured_hostname;
daemon/main.c
+194 -17
@@ -28,7 +28,6 @@ void netdata_cleanup_and_exit(int ret) {
28 info("EXIT: netdata prepares to exit with code %d...", ret);
29
30 send_statistics("EXIT", ret?"ERROR":"OK","-");
31 - analytics_free_data();
31
32 char agent_crash_file[FILENAME_MAX + 1];
33 snprintfz(agent_crash_file, FILENAME_MAX, "%s/.agent_crash", netdata_configured_varlib_dir);
@@ -100,7 +99,6 @@ struct netdata_static_thread static_threads[] = {
99
100 NETDATA_PLUGIN_HOOK_PLUGINSD
101 NETDATA_PLUGIN_HOOK_HEALTH
103 - NETDATA_PLUGIN_HOOK_ANALYTICS
102
103 {NULL, NULL, NULL, 0, NULL, NULL, NULL}
104 };
@@ -399,6 +397,18 @@ void remove_option(int opt_index, int *argc, char **argv) {
397 } while(argv[i][0] != '-' && opt_index >= *argc);
398 }
399
400 +static const char *verify_required_directory(const char *dir) {
401 + if(chdir(dir) == -1)
402 + fatal("Cannot cd to directory '%s'", dir);
403 +
404 + DIR *d = opendir(dir);
405 + if(!d)
406 + fatal("Cannot examine the contents of directory '%s'", dir);
407 + closedir(d);
408 +
409 + return dir;
410 +}
411 +
412 #ifdef ENABLE_HTTPS
413 static void security_init(){
414 char filename[FILENAME_MAX + 1];
@@ -602,6 +612,147 @@ static void get_netdata_configured_variables() {
612
613 }
614
615 +static void get_system_timezone(void) {
616 + // avoid flood calls to stat(/etc/localtime)
617 + // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
618 + const char *tz = getenv("TZ");
619 + if(!tz || !*tz)
620 + setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0);
621 +
622 + char buffer[FILENAME_MAX + 1] = "";
623 + const char *timezone = NULL;
624 + ssize_t ret;
625 +
626 + // use the TZ variable
627 + if(tz && *tz && *tz != ':') {
628 + timezone = tz;
629 + // info("TIMEZONE: using TZ variable '%s'", timezone);
630 + }
631 +
632 + // use the contents of /etc/timezone
633 + if(!timezone && !read_file("/etc/timezone", buffer, FILENAME_MAX)) {
634 + timezone = buffer;
635 + // info("TIMEZONE: using the contents of /etc/timezone: '%s'", timezone);
636 + }
637 +
638 + // read the link /etc/localtime
639 + if(!timezone) {
640 + ret = readlink("/etc/localtime", buffer, FILENAME_MAX);
641 +
642 + if(ret > 0) {
643 + buffer[ret] = '\0';
644 +
645 + char *cmp = "/usr/share/zoneinfo/";
646 + size_t cmp_len = strlen(cmp);
647 +
648 + char *s = strstr(buffer, cmp);
649 + if (s && s[cmp_len]) {
650 + timezone = &s[cmp_len];
651 + // info("TIMEZONE: using the link of /etc/localtime: '%s'", timezone);
652 + }
653 + }
654 + else
655 + buffer[0] = '\0';
656 + }
657 +
658 + // find the timezone from strftime()
659 + if(!timezone) {
660 + time_t t;
661 + struct tm *tmp, tmbuf;
662 +
663 + t = now_realtime_sec();
664 + tmp = localtime_r(&t, &tmbuf);
665 +
666 + if (tmp != NULL) {
667 + if(strftime(buffer, FILENAME_MAX, "%Z", tmp) == 0)
668 + buffer[0] = '\0';
669 + else {
670 + buffer[FILENAME_MAX] = '\0';
671 + timezone = buffer;
672 + // info("TIMEZONE: using strftime(): '%s'", timezone);
673 + }
674 + }
675 + }
676 +
677 + if(timezone && *timezone) {
678 + // make sure it does not have illegal characters
679 + // info("TIMEZONE: fixing '%s'", timezone);
680 +
681 + size_t len = strlen(timezone);
682 + char tmp[len + 1];
683 + char *d = tmp;
684 + *d = '\0';
685 +
686 + while(*timezone) {
687 + if(isalnum(*timezone) || *timezone == '_' || *timezone == '/')
688 + *d++ = *timezone++;
689 + else
690 + timezone++;
691 + }
692 + *d = '\0';
693 + strncpyz(buffer, tmp, len);
694 + timezone = buffer;
695 + // info("TIMEZONE: fixed as '%s'", timezone);
696 + }
697 +
698 + if(!timezone || !*timezone)
699 + timezone = "unknown";
700 +
701 + netdata_configured_timezone = config_get(CONFIG_SECTION_GLOBAL, "timezone", timezone);
702 +}
703 +
704 +void set_global_environment() {
705 + {
706 + char b[16];
707 + snprintfz(b, 15, "%d", default_rrd_update_every);
708 + setenv("NETDATA_UPDATE_EVERY", b, 1);
709 + }
710 +
711 + setenv("NETDATA_VERSION" , program_version, 1);
712 + setenv("NETDATA_HOSTNAME" , netdata_configured_hostname, 1);
713 + setenv("NETDATA_CONFIG_DIR" , verify_required_directory(netdata_configured_user_config_dir), 1);
714 + setenv("NETDATA_USER_CONFIG_DIR" , verify_required_directory(netdata_configured_user_config_dir), 1);
715 + setenv("NETDATA_STOCK_CONFIG_DIR" , verify_required_directory(netdata_configured_stock_config_dir), 1);
716 + setenv("NETDATA_PLUGINS_DIR" , verify_required_directory(netdata_configured_primary_plugins_dir), 1);
717 + setenv("NETDATA_WEB_DIR" , verify_required_directory(netdata_configured_web_dir), 1);
718 + setenv("NETDATA_CACHE_DIR" , verify_required_directory(netdata_configured_cache_dir), 1);
719 + setenv("NETDATA_LIB_DIR" , verify_required_directory(netdata_configured_varlib_dir), 1);
720 + setenv("NETDATA_LOCK_DIR" , netdata_configured_lock_dir, 1);
721 + setenv("NETDATA_LOG_DIR" , verify_required_directory(netdata_configured_log_dir), 1);
722 + setenv("HOME" , verify_required_directory(netdata_configured_home_dir), 1);
723 + setenv("NETDATA_HOST_PREFIX" , netdata_configured_host_prefix, 1);
724 +
725 + char *default_port = appconfig_get(&netdata_config, CONFIG_SECTION_WEB, "default port", NULL);
726 + int clean = 0;
727 + if (!default_port) {
728 + default_port = strdupz("19999");
729 + clean = 1;
730 + }
731 +
732 + setenv("NETDATA_LISTEN_PORT" , default_port, 1);
733 + if(clean)
734 + freez(default_port);
735 +
736 + get_system_timezone();
737 +
738 + // set the path we need
739 + char path[1024 + 1], *p = getenv("PATH");
740 + if(!p) p = "/bin:/usr/bin";
741 + snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
742 + setenv("PATH", config_get(CONFIG_SECTION_PLUGINS, "PATH environment variable", path), 1);
743 +
744 + // python options
745 + p = getenv("PYTHONPATH");
746 + if(!p) p = "";
747 + setenv("PYTHONPATH", config_get(CONFIG_SECTION_PLUGINS, "PYTHONPATH environment variable", p), 1);
748 +
749 + // disable buffering for python plugins
750 + setenv("PYTHONUNBUFFERED", "1", 1);
751 +
752 + // switch to standard locale for plugins
753 + setenv("LC_ALL", "C", 1);
754 +}
755 +
756 static int load_netdata_conf(char *filename, char overwrite_used) {
757 errno = 0;
758
@@ -684,6 +835,47 @@ int get_system_info(struct rrdhost_system_info *system_info) {
835 return 0;
836 }
837
838 +void send_statistics( const char *action, const char *action_result, const char *action_data) {
839 + static char *as_script;
840 +
841 + if (netdata_anonymous_statistics_enabled == -1) {
842 + char *optout_file = mallocz(sizeof(char) * (strlen(netdata_configured_user_config_dir) +strlen(".opt-out-from-anonymous-statistics") + 2));
843 + sprintf(optout_file, "%s/%s", netdata_configured_user_config_dir, ".opt-out-from-anonymous-statistics");
844 + if (likely(access(optout_file, R_OK) != 0)) {
845 + as_script = mallocz(sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("anonymous-statistics.sh") + 2));
846 + sprintf(as_script, "%s/%s", netdata_configured_primary_plugins_dir, "anonymous-statistics.sh");
847 + if (unlikely(access(as_script, R_OK) != 0)) {
848 + netdata_anonymous_statistics_enabled=0;
849 + info("Anonymous statistics script %s not found.",as_script);
850 + freez(as_script);
851 + } else {
852 + netdata_anonymous_statistics_enabled=1;
853 + }
854 + } else {
855 + netdata_anonymous_statistics_enabled = 0;
856 + as_script = NULL;
857 + }
858 + freez(optout_file);
859 + }
860 + if(!netdata_anonymous_statistics_enabled) return;
861 + if (!action) return;
862 + if (!action_result) action_result="";
863 + if (!action_data) action_data="";
864 + char *command_to_run=mallocz(sizeof(char) * (strlen(action) + strlen(action_result) + strlen(action_data) + strlen(as_script) + 10));
865 + pid_t command_pid;
866 +
867 + sprintf(command_to_run,"%s '%s' '%s' '%s'", as_script, action, action_result, action_data);
868 + info("%s", command_to_run);
869 +
870 + FILE *fp = mypopen(command_to_run, &command_pid);
871 + if(fp) {
872 + char buffer[100 + 1];
873 + while (fgets(buffer, 100, fp) != NULL);
874 + mypclose(fp, command_pid);
875 + }
876 + freez(command_to_run);
877 +}
878 +
879 void set_silencers_filename() {
880 char filename[FILENAME_MAX + 1];
881 snprintfz(filename, FILENAME_MAX, "%s/health.silencers.json", netdata_configured_varlib_dir);
@@ -1319,25 +1511,10 @@ int main(int argc, char **argv) {
1511 info("netdata initialization completed. Enjoy real-time performance monitoring!");
1512 netdata_ready = 1;
1513
1322 - set_late_global_environment();
1323 -
1514 send_statistics("START", "-", "-");
1515 if (crash_detected)
1516 send_statistics("CRASH", "-", "-");
1517
1328 - //check if ANALYTICS needs to start
1329 - if (netdata_anonymous_statistics_enabled == 1) {
1330 - for (i = 0; static_threads[i].name != NULL; i++) {
1331 - if (!strncmp(static_threads[i].name, "ANALYTICS", 9)) {
1332 - struct netdata_static_thread *st = &static_threads[i];
1333 - st->thread = mallocz(sizeof(netdata_thread_t));
1334 - st->enabled = 1;
1335 - debug(D_SYSTEM, "Starting thread %s.", st->name);
1336 - netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st);
1337 - }
1338 - }
1339 - }
1340 -
1518 // ------------------------------------------------------------------------
1519 // Report ACLK build failure
1520 #ifndef ENABLE_ACLK
exporting/exporting_engine.c
-58
@@ -4,64 +4,6 @@
4
5 static struct engine *engine = NULL;
6
7 -void analytics_exporting_connectors(BUFFER *b)
8 -{
9 - if (!engine)
10 - return;
11 -
12 - uint8_t count = 0;
13 -
14 - for (struct instance *instance = engine->instance_root; instance; instance = instance->next) {
15 - if (count)
16 - buffer_strcat(b, "|");
17 -
18 - switch (instance->config.type) {
19 - case EXPORTING_CONNECTOR_TYPE_GRAPHITE:
20 - buffer_strcat(b, "Graphite");
21 - break;
22 - case EXPORTING_CONNECTOR_TYPE_GRAPHITE_HTTP:
23 - buffer_strcat(b, "GraphiteHTTP");
24 - break;
25 - case EXPORTING_CONNECTOR_TYPE_JSON:
26 - buffer_strcat(b, "JSON");
27 - break;
28 - case EXPORTING_CONNECTOR_TYPE_JSON_HTTP:
29 - buffer_strcat(b, "JSONHTTP");
30 - break;
31 - case EXPORTING_CONNECTOR_TYPE_OPENTSDB:
32 - buffer_strcat(b, "OpenTSDB");
33 - break;
34 - case EXPORTING_CONNECTOR_TYPE_OPENTSDB_HTTP:
35 - buffer_strcat(b, "OpenTSDBHTTP");
36 - break;
37 - case EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE:
38 -#if ENABLE_PROMETHEUS_REMOTE_WRITE
39 - buffer_strcat(b, "PrometheusRemoteWrite");
40 -#endif
41 - break;
42 - case EXPORTING_CONNECTOR_TYPE_KINESIS:
43 -#if HAVE_KINESIS
44 - buffer_strcat(b, "Kinesis");
45 -#endif
46 - break;
47 - case EXPORTING_CONNECTOR_TYPE_PUBSUB:
48 -#if ENABLE_EXPORTING_PUBSUB
49 - buffer_strcat(b, "Pubsub");
50 -#endif
51 - break;
52 - case EXPORTING_CONNECTOR_TYPE_MONGODB:
53 -#if HAVE_MONGOC
54 - buffer_strcat(b, "MongoDB");
55 -#endif
56 - break;
57 - default:
58 - buffer_strcat(b, "Unknown");
59 - }
60 -
61 - count++;
62 - }
63 -}
64 -
7 /**
8 * Exporting Clean Engine
9 *
exporting/prometheus/prometheus.c
-3
@@ -794,9 +794,6 @@ static inline time_t prometheus_preparation(
794 time_t now,
795 PROMETHEUS_OUTPUT_OPTIONS output_options)
796 {
797 -#ifndef UNIT_TESTING
798 - analytics_log_prometheus();
799 -#endif
797 if (!server || !*server)
798 server = "default";
799
libnetdata/log/log.h
-1
@@ -40,7 +40,6 @@ extern "C" {
40 #define D_STATSD 0x0000000010000000
41 #define D_POLLFD 0x0000000020000000
42 #define D_STREAM 0x0000000040000000
43 -#define D_ANALYTICS 0x0000000080000000
43 #define D_RRDENGINE 0x0000000100000000
44 #define D_ACLK 0x0000000200000000
45 #define D_METADATALOG 0x0000000400000000
web/api/exporters/shell/allmetrics_shell.c
-2
@@ -23,7 +23,6 @@ static inline size_t shell_name_copy(char *d, const char *s, size_t usable) {
23 #define SHELL_ELEMENT_MAX 100
24
25 void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
26 - analytics_log_shell();
26 rrdhost_rdlock(host);
27
28 // for each chart
@@ -93,7 +92,6 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
92 // ----------------------------------------------------------------------------
93
94 void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) {
96 - analytics_log_json();
95 rrdhost_rdlock(host);
96
97 buffer_strcat(wb, "{");
web/api/web_api_v1.c
+2 -75
@@ -750,7 +750,6 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
750
751 if(unlikely(action == 'H')) {
752 // HELLO request, dashboard ACL
753 - analytics_log_dashboard();
753 if(unlikely(!web_client_can_access_dashboard(w)))
754 return web_client_permission_denied(w);
755 }
@@ -996,82 +995,10 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
995 }
996 #ifdef ENABLE_ACLK
997 if (aclk_connected)
999 - buffer_strcat(wb, "\t\"aclk-available\": true,\n");
998 + buffer_strcat(wb, "\t\"aclk-available\": true\n");
999 else
1000 #endif
1002 - buffer_strcat(wb, "\t\"aclk-available\": false,\n"); // Intentionally valid with/without #ifdef above
1003 -
1004 - buffer_strcat(wb, "\t\"memory-mode\": ");
1005 - analytics_get_data(analytics_data.netdata_config_memory_mode, wb);
1006 - buffer_strcat(wb, ",\n");
1007 -
1008 - buffer_strcat(wb, "\t\"multidb-disk-quota\": ");
1009 - analytics_get_data(analytics_data.netdata_config_multidb_disk_quota, wb);
1010 - buffer_strcat(wb, ",\n");
1011 -
1012 - buffer_strcat(wb, "\t\"page-cache-size\": ");
1013 - analytics_get_data(analytics_data.netdata_config_page_cache_size, wb);
1014 - buffer_strcat(wb, ",\n");
1015 -
1016 - buffer_strcat(wb, "\t\"stream-enabled\": ");
1017 - analytics_get_data(analytics_data.netdata_config_stream_enabled, wb);
1018 - buffer_strcat(wb, ",\n");
1019 -
1020 - buffer_strcat(wb, "\t\"hosts-available\": ");
1021 - analytics_get_data(analytics_data.netdata_config_hosts_available, wb);
1022 - buffer_strcat(wb, ",\n");
1023 -
1024 - buffer_strcat(wb, "\t\"https-enabled\": ");
1025 - analytics_get_data(analytics_data.netdata_config_https_enabled, wb);
1026 - buffer_strcat(wb, ",\n");
1027 -
1028 - buffer_strcat(wb, "\t\"buildinfo\": ");
1029 - analytics_get_data(analytics_data.netdata_buildinfo, wb);
1030 - buffer_strcat(wb, ",\n");
1031 -
1032 - buffer_strcat(wb, "\t\"release-channel\": ");
1033 - analytics_get_data(analytics_data.netdata_config_release_channel, wb);
1034 - buffer_strcat(wb, ",\n");
1035 -
1036 - buffer_strcat(wb, "\t\"web-enabled\": ");
1037 - analytics_get_data(analytics_data.netdata_config_web_enabled, wb);
1038 - buffer_strcat(wb, ",\n");
1039 -
1040 - buffer_strcat(wb, "\t\"notification-methods\": ");
1041 - analytics_get_data(analytics_data.netdata_notification_methods, wb);
1042 - buffer_strcat(wb, ",\n");
1043 -
1044 - buffer_strcat(wb, "\t\"exporting-enabled\": ");
1045 - analytics_get_data(analytics_data.netdata_config_exporting_enabled, wb);
1046 - buffer_strcat(wb, ",\n");
1047 -
1048 - buffer_strcat(wb, "\t\"exporting-connectors\": ");
1049 - analytics_get_data(analytics_data.netdata_exporting_connectors, wb);
1050 - buffer_strcat(wb, ",\n");
1051 -
1052 - buffer_strcat(wb, "\t\"allmetrics-prometheus-used\": ");
1053 - analytics_get_data(analytics_data.netdata_allmetrics_prometheus_used, wb);
1054 - buffer_strcat(wb, ",\n");
1055 -
1056 - buffer_strcat(wb, "\t\"allmetrics-shell-used\": ");
1057 - analytics_get_data(analytics_data.netdata_allmetrics_shell_used, wb);
1058 - buffer_strcat(wb, ",\n");
1059 -
1060 - buffer_strcat(wb, "\t\"allmetrics-json-used\": ");
1061 - analytics_get_data(analytics_data.netdata_allmetrics_json_used, wb);
1062 - buffer_strcat(wb, ",\n");
1063 -
1064 - buffer_strcat(wb, "\t\"dashboard-used\": ");
1065 - analytics_get_data(analytics_data.netdata_dashboard_used, wb);
1066 - buffer_strcat(wb, ",\n");
1067 -
1068 - buffer_strcat(wb, "\t\"charts-count\": ");
1069 - analytics_get_data(analytics_data.netdata_charts_count, wb);
1070 - buffer_strcat(wb, ",\n");
1071 -
1072 - buffer_strcat(wb, "\t\"metrics-count\": ");
1073 - analytics_get_data(analytics_data.netdata_metrics_count, wb);
1074 - buffer_strcat(wb, "\n");
1001 + buffer_strcat(wb, "\t\"aclk-available\": false\n"); // Intentionally valid with/without #ifdef above
1002
1003 buffer_strcat(wb, "}");
1004 return 0;