@cryptotaxi247 / netdata-1 / commits / 489f4dfcc

draft implementation of netdata central push server - untested

Costa Tsaousis (ktsaou) committed Feb 20, 2017 at 00:58 UTC 489f4dfccb2259103175c01c4b51d76946248629
23 files changed +523 -184
CMakeLists.txt
+1 -1
@@ -124,7 +124,7 @@ set(NETDATA_SOURCE_FILES
124 src/web_client.h
125 src/web_server.c
126 src/web_server.h
127 - src/rrdhost.c src/rrdfamily.c src/rrdset.c src/rrddim.c src/health_log.c src/health_config.c src/health_json.c src/rrdcalc.c src/rrdcalctemplate.c src/rrdvar.c src/rrddimvar.c src/rrdsetvar.c)
127 + src/rrdhost.c src/rrdfamily.c src/rrdset.c src/rrddim.c src/health_log.c src/health_config.c src/health_json.c src/rrdcalc.c src/rrdcalctemplate.c src/rrdvar.c src/rrddimvar.c src/rrdsetvar.c src/rrdpush.c src/rrdpush.h)
128
129 set(APPS_PLUGIN_SOURCE_FILES
130 src/appconfig.c
src/Makefile.am
+1
@@ -75,6 +75,7 @@ netdata_SOURCES = \
75 rrddimvar.c \
76 rrdsetvar.c \
77 rrd2json.c rrd2json.h \
78 + rrdpush.c rrdpush.h \
79 storage_number.c storage_number.h \
80 unit_test.c unit_test.h \
81 url.c url.h \
src/backends.c
+12 -22
@@ -128,11 +128,13 @@ static inline int process_opentsdb_response(BUFFER *b) {
128 }
129
130 void *backends_main(void *ptr) {
131 + int default_port = 0;
132 + int sock = -1;
133 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
134
135 BUFFER *b = buffer_create(1), *response = buffer_create(1);
134 - int (*backend_request_formatter)(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) = NULL;
135 - int (*backend_response_checker)(BUFFER *b) = NULL;
136 + int (*backend_request_formatter)(BUFFER *, const char *, RRDHOST *, const char *, RRDSET *, RRDDIM *, time_t, time_t, uint32_t) = NULL;
137 + int (*backend_response_checker)(BUFFER *) = NULL;
138
139 info("BACKEND thread created with task id %d", gettid());
140
@@ -145,12 +147,15 @@ void *backends_main(void *ptr) {
147 // ------------------------------------------------------------------------
148 // collect configuration options
149
150 + if(central_netdata_to_push_data) {
151 + info("Backend is disabled - use the central netdata");
152 + goto cleanup;
153 + }
154 +
155 struct timeval timeout = {
156 .tv_sec = 0,
157 .tv_usec = 0
158 };
152 - int default_port = 0;
153 - int sock = -1;
159 uint32_t options;
160 int enabled = config_get_boolean("backend", "enabled", 0);
161 const char *source = config_get("backend", "data source", "average");
@@ -398,26 +403,11 @@ void *backends_main(void *ptr) {
403
404 if(unlikely(sock == -1)) {
405 usec_t start_ut = now_monotonic_usec();
401 - const char *s = destination;
402 - while(*s) {
403 - const char *e = s;
404 -
405 - // skip separators, moving both s(tart) and e(nd)
406 - while(isspace(*e) || *e == ',') s = ++e;
406 + size_t reconnects = 0;
407
408 - // move e(nd) to the first separator
409 - while(*e && !isspace(*e) && *e != ',') e++;
408 + sock = connect_to_one_of(destination, default_port, &timeout, &reconnects);
409
411 - // is there anything?
412 - if(!*s || s == e) break;
413 -
414 - char buf[e - s + 1];
415 - strncpyz(buf, s, e - s);
416 - chart_backend_reconnects++;
417 - sock = connect_to(buf, default_port, &timeout);
418 - if(sock != -1) break;
419 - s = e;
420 - }
410 + chart_backend_reconnects += reconnects;
411 chart_backend_latency += now_monotonic_usec() - start_ut;
412 }
413
src/common.h
+4 -2
@@ -199,12 +199,12 @@
199 #define NETDATA_OS_TYPE "linux"
200 #endif /* __FreeBSD__, __APPLE__*/
201
202 -#include "plugin_tc.h"
203 -#include "plugins_d.h"
202 #include "socket.h"
203 #include "eval.h"
204 #include "health.h"
205 #include "rrd.h"
206 +#include "plugin_tc.h"
207 +#include "plugins_d.h"
208 #include "rrd2json.h"
209 #include "web_client.h"
210 #include "web_server.h"
@@ -216,6 +216,7 @@
216 #include "backends.h"
217 #include "inlined.h"
218 #include "adaptive_resortable_list.h"
219 +#include "rrdpush.h"
220
221 extern char *netdata_configured_config_dir;
222 extern char *netdata_configured_log_dir;
@@ -225,6 +226,7 @@ extern char *netdata_configured_cache_dir;
226 extern char *netdata_configured_varlib_dir;
227 extern char *netdata_configured_home_dir;
228 extern char *netdata_configured_host_prefix;
229 +extern char *central_netdata_to_push_data;
230
231 extern void netdata_fix_chart_id(char *s);
232 extern void netdata_fix_chart_name(char *s);
src/health.c
+11 -4
@@ -1,7 +1,7 @@
1 #define NETDATA_HEALTH_INTERNALS
2 #include "common.h"
3
4 -int default_localhost_health_enabled = 1;
4 +int default_health_enabled = 1;
5
6 // ----------------------------------------------------------------------------
7 // health initialization
@@ -15,9 +15,16 @@ inline char *health_config_dir(void) {
15 void health_init(void) {
16 debug(D_HEALTH, "Health configuration initializing");
17
18 - if(!(default_localhost_health_enabled = config_get_boolean("health", "enabled", 1))) {
19 - debug(D_HEALTH, "Health is disabled.");
20 - return;
18 + if(!central_netdata_to_push_data) {
19 + if(!(default_health_enabled = config_get_boolean("health", "enabled", 1))) {
20 + debug(D_HEALTH, "Health is disabled.");
21 + return;
22 + }
23 + }
24 + else {
25 + info("Health is disabled - setup alarms at the central netdata.");
26 + config_set_boolean("health", "enabled", 0);
27 + default_health_enabled = 0;
28 }
29
30 char pathname[FILENAME_MAX + 1];
src/health.h
+1 -1
@@ -1,7 +1,7 @@
1 #ifndef NETDATA_HEALTH_H
2 #define NETDATA_HEALTH_H
3
4 -extern int default_localhost_health_enabled;
4 +extern int default_health_enabled;
5
6 extern int rrdvar_compare(void *a, void *b);
7
src/main.c
+124 -39
@@ -2,6 +2,8 @@
2
3 extern void *cgroups_main(void *ptr);
4
5 +char *central_netdata_to_push_data = NULL;
6 +
7 void netdata_cleanup_and_exit(int ret) {
8 netdata_exit = 1;
9
@@ -55,21 +57,39 @@ struct netdata_static_thread static_threads[] = {
57 {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main},
58 {"web", NULL, NULL, 1, NULL, NULL, socket_listen_main_multi_threaded},
59 {"web-single-threaded", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded},
60 + {"central-netdata-push",NULL, NULL, 0, NULL, NULL, central_netdata_push_thread},
61 {NULL, NULL, NULL, 0, NULL, NULL, NULL}
62 };
63
64 void web_server_threading_selection(void) {
62 - int threaded = config_get_boolean("global", "multi threaded web server", 1);
65 + int multi_threaded = 0;
66 + int single_threaded = 0;
67 + int central_thread = 0;
68 +
69 + if(!central_netdata_to_push_data) {
70 + multi_threaded = config_get_boolean("global", "multi threaded web server", 1);
71 + single_threaded = !multi_threaded;
72 + }
73 + else {
74 + central_thread = 1;
75 + info("Web servers are disabled - use the central netdata.");
76 + }
77
78 int i;
79 for(i = 0; static_threads[i].name ; i++) {
80 if(static_threads[i].start_routine == socket_listen_main_multi_threaded)
67 - static_threads[i].enabled = threaded?1:0;
81 + static_threads[i].enabled = multi_threaded;
82
83 if(static_threads[i].start_routine == socket_listen_main_single_threaded)
70 - static_threads[i].enabled = threaded?0:1;
84 + static_threads[i].enabled = single_threaded;
85 +
86 + if(static_threads[i].start_routine == central_netdata_push_thread)
87 + static_threads[i].enabled = central_thread;
88 }
89
90 + if(central_netdata_to_push_data)
91 + return;
92 +
93 web_client_timeout = (int) config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
94
95 respect_web_browser_do_not_track_policy = config_get_boolean("global", "respect web browser do not track policy", respect_web_browser_do_not_track_policy);
@@ -443,7 +463,7 @@ int main(int argc, char **argv) {
463 char* stacksize_string = "stacksize=";
464 char* debug_flags_string = "debug_flags=";
465 if(strcmp(optarg, "unittest") == 0) {
446 - default_localhost_rrd_update_every = 1;
466 + default_rrd_update_every = 1;
467 if(run_all_mockup_tests()) exit(1);
468 if(unit_test_storage()) exit(1);
469 fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
@@ -528,7 +548,7 @@ int main(int argc, char **argv) {
548 setenv("MALLOC_ARENA_MAX", pmax, 1);
549
550 #if defined(HAVE_C_MALLOPT)
531 - int i = config_get_number("global", "glibc malloc arena max for netdata", 1);
551 + i = (int)config_get_number("global", "glibc malloc arena max for netdata", 1);
552 if(i > 0)
553 mallopt(M_ARENA_MAX, 1);
554 #endif
@@ -578,7 +598,11 @@ int main(int argc, char **argv) {
598 }
599
600 char *user = NULL;
601 +
602 {
603 + // --------------------------------------------------------------------
604 + // get the debugging flags from the configuration file
605 +
606 char *flags = config_get("global", "debug flags", "0x0000000000000000");
607 setenv("NETDATA_DEBUG_FLAGS", flags, 1);
608
@@ -595,21 +619,9 @@ int main(int argc, char **argv) {
619 #endif
620 }
621
598 - // --------------------------------------------------------------------
599 -
600 -#ifdef MADV_MERGEABLE
601 - enable_ksm = config_get_boolean("global", "memory deduplication (ksm)", enable_ksm);
602 -#else
603 -#warning "Kernel memory deduplication (KSM) is not available"
604 -#endif
605 -
606 - // --------------------------------------------------------------------
622
608 - get_system_HZ();
609 - get_system_cpus();
610 - get_system_pid_max();
611 -
623 // --------------------------------------------------------------------
624 + // get log filenames and settings
625
626 {
627 char filename[FILENAME_MAX + 1];
@@ -624,11 +636,12 @@ int main(int argc, char **argv) {
636 }
637
638 error_log_throttle_period_backup =
627 - error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
639 + error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
640 +
641 setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period" , ""), 1);
642
630 - error_log_errors_per_period = (unsigned long)config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
631 - setenv("NETDATA_ERRORS_PER_PERIOD" , config_get("global", "errors to trigger flood protection", ""), 1);
643 + error_log_errors_per_period = (unsigned long)config_get_number("global", "errors to trigger flood protection", (long long int)error_log_errors_per_period);
644 + setenv("NETDATA_ERRORS_PER_PERIOD", config_get("global", "errors to trigger flood protection", ""), 1);
645
646 if(check_config) {
647 stdout_filename = stderr_filename = stdaccess_filename = "system";
@@ -637,49 +650,102 @@ int main(int argc, char **argv) {
650 }
651 error_log_limit_unlimited();
652
653 +
654 + // --------------------------------------------------------------------
655 + // get KSM settings
656 +
657 +#ifdef MADV_MERGEABLE
658 + enable_ksm = config_get_boolean("global", "memory deduplication (ksm)", enable_ksm);
659 +#else
660 +#warning "Kernel memory deduplication (KSM) is not available"
661 +#endif
662 +
663 // --------------------------------------------------------------------
664 + // get various system parameters
665 +
666 + get_system_HZ();
667 + get_system_cpus();
668 + get_system_pid_max();
669
642 - default_localhost_rrd_memory_mode = rrd_memory_mode_id(config_get("global", "memory mode", rrd_memory_mode_name(default_localhost_rrd_memory_mode)));
670
671 // --------------------------------------------------------------------
672 + // find the system hostname
673
674 {
675 char hostnamebuf[HOSTNAME_MAX + 1];
676 if(gethostname(hostnamebuf, HOSTNAME_MAX) == -1)
677 error("WARNING: Cannot get machine hostname.");
678 +
679 hostname = config_get("global", "hostname", hostnamebuf);
680 debug(D_OPTIONS, "hostname set to '%s'", hostname);
681 +
682 setenv("NETDATA_HOSTNAME", hostname, 1);
683 }
684
685 +
686 + // --------------------------------------------------------------------
687 + // find we need to send data to a central netdata
688 +
689 + central_netdata_to_push_data = config_get("global", "central netdata to send all data", "");
690 + if(central_netdata_to_push_data && !*central_netdata_to_push_data)
691 + central_netdata_to_push_data = NULL;
692 +
693 +
694 + // --------------------------------------------------------------------
695 + // get default memory mode for the database
696 +
697 + if(central_netdata_to_push_data) {
698 + default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
699 + config_set("global", "memory mode", rrd_memory_mode_name(default_rrd_memory_mode));
700 + }
701 + else
702 + default_rrd_memory_mode = rrd_memory_mode_id(config_get("global", "memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));
703 +
704 +
705 // --------------------------------------------------------------------
706 + // get default database size
707
657 - default_localhost_rrd_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
658 - if(default_localhost_rrd_history_entries < 5 || default_localhost_rrd_history_entries > RRD_HISTORY_ENTRIES_MAX) {
659 - error("Invalid history entries %d given. Defaulting to %d.", default_localhost_rrd_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
660 - default_localhost_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
708 + if(central_netdata_to_push_data) {
709 + default_rrd_history_entries = 10;
710 + config_set_number("global", "history", default_rrd_history_entries);
711 }
662 - else {
663 - debug(D_OPTIONS, "save lines set to %d.", default_localhost_rrd_history_entries);
712 + else
713 + default_rrd_history_entries = (int) config_get_number("global", "history", align_entries_to_pagesize(RRD_DEFAULT_HISTORY_ENTRIES));
714 +
715 + long h = align_entries_to_pagesize(default_rrd_history_entries);
716 + if(h != default_rrd_history_entries) {
717 + config_set_number("global", "history", h);
718 + default_rrd_history_entries = (int)h;
719 + }
720 +
721 + if(default_rrd_history_entries < 5 || default_rrd_history_entries > RRD_HISTORY_ENTRIES_MAX) {
722 + error("Invalid history entries %d given. Defaulting to %d.", default_rrd_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
723 + default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
724 }
725 + else
726 + debug(D_OPTIONS, "save lines set to %d.", default_rrd_history_entries);
727 +
728
729 // --------------------------------------------------------------------
730 + // get default database update frequency
731
668 - default_localhost_rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
669 - if(default_localhost_rrd_update_every < 1 || default_localhost_rrd_update_every > 600) {
670 - error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", default_localhost_rrd_update_every, UPDATE_EVERY_MAX);
671 - default_localhost_rrd_update_every = UPDATE_EVERY;
732 + default_rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
733 + if(default_rrd_update_every < 1 || default_rrd_update_every > 600) {
734 + error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", default_rrd_update_every, UPDATE_EVERY_MAX);
735 + default_rrd_update_every = UPDATE_EVERY;
736 }
673 - else debug(D_OPTIONS, "update timer set to %d.", default_localhost_rrd_update_every);
737 + else debug(D_OPTIONS, "update timer set to %d.", default_rrd_update_every);
738
739 // let the plugins know the min update_every
740 {
741 char buf[16];
678 - snprintfz(buf, 15, "%d", default_localhost_rrd_update_every);
742 + snprintfz(buf, 15, "%d", default_rrd_update_every);
743 setenv("NETDATA_UPDATE_EVERY", buf, 1);
744 }
745
746 +
747 // --------------------------------------------------------------------
748 + // setup process signals
749
750 // block signals while initializing threads.
751 // this causes the threads to block signals.
@@ -725,7 +791,9 @@ int main(int argc, char **argv) {
791 if(sigaction(SIGUSR2, &sa, NULL) == -1)
792 error("Failed to change signal handler for SIGUSR2");
793
794 +
795 // --------------------------------------------------------------------
796 + // get the required stack size of the threads of netdata
797
798 i = pthread_attr_init(&attr);
799 if(i != 0)
@@ -739,18 +807,24 @@ int main(int argc, char **argv) {
807
808 wanted_stacksize = (size_t)config_get_number("global", "pthread stack size", (long)stacksize);
809
810 +
811 // --------------------------------------------------------------------
812 + // check which threads are enabled and initialize them
813
814 for (i = 0; static_threads[i].name != NULL ; i++) {
815 struct netdata_static_thread *st = &static_threads[i];
816
747 - if(st->config_name) st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
748 - if(st->enabled && st->init_routine) st->init_routine();
817 + if(st->config_name)
818 + st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
819 +
820 + if(st->enabled && st->init_routine)
821 + st->init_routine();
822 }
823
751 - // --------------------------------------------------------------------
824
825 + // --------------------------------------------------------------------
826 // get the user we should run
827 +
828 // IMPORTANT: this is required before web_files_uid()
829 user = config_get("global", "run as user" , (getuid() == 0)?NETDATA_USER:"");
830
@@ -758,9 +832,11 @@ int main(int argc, char **argv) {
832 web_files_uid(); // IMPORTANT: web_files_uid() before web_files_gid()
833 web_files_gid();
834
835 +
836 // --------------------------------------------------------------------
837 + // create the listening sockets
838
763 - if(!check_config)
839 + if(!check_config && !central_netdata_to_push_data)
840 create_listen_sockets();
841 }
842
@@ -778,14 +854,16 @@ int main(int argc, char **argv) {
854 }
855 #endif /* NETDATA_INTERNAL_CHECKS */
856
857 +
858 // fork, switch user, create pid file, set process priority
859 if(become_daemon(dont_fork, user) == -1)
860 fatal("Cannot daemonize myself.");
861
862 info("netdata started on pid %d.", getpid());
863
864 +
865 // ------------------------------------------------------------------------
788 - // get default pthread stack size
866 + // set default pthread stack size - after we have forked
867
868 if(stacksize < wanted_stacksize) {
869 i = pthread_attr_setstacksize(&attr, wanted_stacksize);
@@ -795,29 +873,35 @@ int main(int argc, char **argv) {
873 debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
874 }
875
876 +
877 // ------------------------------------------------------------------------
878 // initialize health monitoring
879
880 health_init();
881
882 +
883 // ------------------------------------------------------------------------
884 // initialize the registry
885
886 registry_init();
887
888 +
889 // ------------------------------------------------------------------------
890 // initialize rrd host
891
892 rrd_init(hostname);
893
894 +
895 if(check_config)
896 exit(1);
897
898 +
899 // ------------------------------------------------------------------------
900 // enable log flood protection
901
902 error_log_limit_reset();
903
904 +
905 // ------------------------------------------------------------------------
906 // spawn the threads
907
@@ -842,6 +926,7 @@ int main(int argc, char **argv) {
926
927 info("netdata initialization completed. Enjoy real-time performance monitoring!");
928
929 +
930 // ------------------------------------------------------------------------
931 // block signals while initializing threads.
932 sigset_t sigset;
src/plugin_nfacct.c
+8 -8
@@ -128,8 +128,8 @@ void *nfacct_main(void *ptr) {
128 usec = dt_usec(&now, &last) - susec;
129 debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
130
131 - if(usec < (default_localhost_rrd_update_every * 1000000ULL / 2ULL)) susec = (default_localhost_rrd_update_every * 1000000ULL) - usec;
132 - else susec = default_localhost_rrd_update_every * 1000000ULL / 2ULL;
131 + if(usec < (default_rrd_update_every * 1000000ULL / 2ULL)) susec = (default_rrd_update_every * 1000000ULL) - usec;
132 + else susec = default_rrd_update_every * 1000000ULL / 2ULL;
133
134
135 // --------------------------------------------------------------------
@@ -139,17 +139,17 @@ void *nfacct_main(void *ptr) {
139
140 st = rrdset_find_bytype("netfilter", "nfacct_packets");
141 if(!st) {
142 - st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 3206, default_localhost_rrd_update_every, RRDSET_TYPE_STACKED);
142 + st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 3206, default_rrd_update_every, RRDSET_TYPE_STACKED);
143
144 for(i = 0; i < nfacct_list->len ; i++)
145 - rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_localhost_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
145 + rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
146 }
147 else rrdset_next(st);
148
149 for(i = 0; i < nfacct_list->len ; i++) {
150 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
151
152 - if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_localhost_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
152 + if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
153 if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
154 }
155
@@ -159,17 +159,17 @@ void *nfacct_main(void *ptr) {
159
160 st = rrdset_find_bytype("netfilter", "nfacct_bytes");
161 if(!st) {
162 - st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 3207, default_localhost_rrd_update_every, RRDSET_TYPE_STACKED);
162 + st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 3207, default_rrd_update_every, RRDSET_TYPE_STACKED);
163
164 for(i = 0; i < nfacct_list->len ; i++)
165 - rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_localhost_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
165 + rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
166 }
167 else rrdset_next(st);
168
169 for(i = 0; i < nfacct_list->len ; i++) {
170 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
171
172 - if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_localhost_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
172 + if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
173 if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
174 }
175
src/plugins_d.c
+2 -3
@@ -83,7 +83,7 @@ static int pluginsd_split_words(char *str, char **words, int max_words) {
83 return i;
84 }
85
86 -inline size_t pluginsd_process(struct plugind *cd, FILE *fp, int trust_durations) {
86 +inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
87 int enabled = cd->enabled;
88
89 if(!fp || !enabled) {
@@ -92,7 +92,6 @@ inline size_t pluginsd_process(struct plugind *cd, FILE *fp, int trust_durations
92 }
93
94 size_t count = 0;
95 - RRDHOST *host = localhost;
95
96 char line[PLUGINSD_LINE_MAX + 1];
97
@@ -365,7 +364,7 @@ void *pluginsd_worker_thread(void *arg) {
364
365 info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
366
368 - count = pluginsd_process(cd, fp, 0);
367 + count = pluginsd_process(localhost, cd, fp, 0);
368 error("PLUGINSD: plugin '%s' disconnected.", cd->fullfilename);
369
370 killpid(cd->pid, SIGTERM);
src/plugins_d.h
+1 -1
@@ -34,6 +34,6 @@ struct plugind {
34 extern struct plugind *pluginsd_root;
35
36 extern void *pluginsd_main(void *ptr);
37 -extern size_t pluginsd_process(struct plugind *cd, FILE *fp, int trust_durations);
37 +extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations);
38
39 #endif /* NETDATA_PLUGINS_D_H */
src/registry_init.c
+8 -1
@@ -4,7 +4,14 @@ int registry_init(void) {
4 char filename[FILENAME_MAX + 1];
5
6 // registry enabled?
7 - registry.enabled = config_get_boolean("registry", "enabled", 0);
7 + if(!central_netdata_to_push_data) {
8 + registry.enabled = config_get_boolean("registry", "enabled", 0);
9 + }
10 + else {
11 + info("Registry is disabled - use the central netdata");
12 + config_set_boolean("registry", "enabled", 0);
13 + registry.enabled = 0;
14 + }
15
16 // pathnames
17 snprintfz(filename, FILENAME_MAX, "%s/registry", netdata_configured_varlib_dir);
src/rrd.c
+3 -3
@@ -11,9 +11,9 @@
11 int rrd_delete_unupdated_dimensions = 0;
12 */
13
14 -int default_localhost_rrd_update_every = UPDATE_EVERY;
15 -int default_localhost_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
16 -RRD_MEMORY_MODE default_localhost_rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
14 +int default_rrd_update_every = UPDATE_EVERY;
15 +int default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
16 +RRD_MEMORY_MODE default_rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
17
18
19 // ----------------------------------------------------------------------------
src/rrd.h
+8 -5
@@ -7,8 +7,8 @@
7 #define RRD_DEFAULT_HISTORY_ENTRIES 3600
8 #define RRD_HISTORY_ENTRIES_MAX (86400*10)
9
10 -extern int default_localhost_rrd_update_every;
11 -extern int default_localhost_rrd_history_entries;
10 +extern int default_rrd_update_every;
11 +extern int default_rrd_history_entries;
12
13 #define RRD_ID_LENGTH_MAX 200
14
@@ -48,7 +48,7 @@ typedef enum rrd_memory_mode {
48 #define RRD_MEMORY_MODE_MAP_NAME "map"
49 #define RRD_MEMORY_MODE_SAVE_NAME "save"
50
51 -extern RRD_MEMORY_MODE default_localhost_rrd_memory_mode;
51 +extern RRD_MEMORY_MODE default_rrd_memory_mode;
52
53 extern const char *rrd_memory_mode_name(RRD_MEMORY_MODE id);
54 extern RRD_MEMORY_MODE rrd_memory_mode_id(const char *name);
@@ -78,7 +78,8 @@ extern const char *rrd_algorithm_name(RRD_ALGORITHM algorithm);
78 typedef enum rrddim_flags {
79 RRDDIM_FLAG_HIDDEN = 1 << 0, // this dimension will not be offered to callers
80 RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS = 1 << 1, // do not offer RESET or OVERFLOW info to callers
81 - RRDDIM_FLAG_UPDATED = 1 << 31 // the dimension has been updated since the last processing
81 + RRDDIM_FLAG_UPDATED = 1 << 2, // the dimension has been updated since the last processing
82 + RRDDIM_FLAG_EXPOSED = 1 << 3 // when set what have sent this dimension to the central netdata
83 } RRDDIM_FLAGS;
84
85 #define rrddim_flag_check(rd, flag) ((rd)->flags & flag)
@@ -430,7 +431,7 @@ extern void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds);
431 extern void rrdset_next_usec(RRDSET *st, usec_t microseconds);
432 #define rrdset_next(st) rrdset_next_usec(st, 0ULL)
433
433 -extern usec_t rrdset_done(RRDSET *st);
434 +extern void rrdset_done(RRDSET *st);
435
436 // get the total duration in seconds of the round robin database
437 #define rrdset_duration(st) ((time_t)( (((st)->counter >= ((unsigned long)(st)->entries))?(unsigned long)(st)->entries:(st)->counter) * (st)->update_every ))
@@ -479,6 +480,8 @@ extern int rrddim_unhide(RRDSET *st, const char *id);
480 extern collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
481 extern collected_number rrddim_set(RRDSET *st, const char *id, collected_number value);
482
483 +extern long align_entries_to_pagesize(long entries);
484 +
485
486 // ----------------------------------------------------------------------------
487 // RRD internal functions
src/rrddim.c
+3
@@ -164,7 +164,10 @@ RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, collected_numbe
164
165 // prevent incremental calculation spikes
166 rd->counter = 0;
167 +
168 rrddim_flag_clear(rd, RRDDIM_FLAG_UPDATED);
169 + rrddim_flag_clear(rd, RRDDIM_FLAG_EXPOSED);
170 +
171 rd->calculated_value = 0;
172 rd->last_calculated_value = 0;
173 rd->collected_value = 0;
src/rrdhost.c
+8 -8
@@ -178,10 +178,10 @@ RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid) {
178 if(!host)
179 host = rrdhost_create(hostname,
180 guid,
181 - default_localhost_rrd_update_every,
182 - default_localhost_rrd_history_entries,
183 - default_localhost_rrd_memory_mode,
184 - default_localhost_health_enabled
181 + default_rrd_update_every,
182 + default_rrd_history_entries,
183 + default_rrd_memory_mode,
184 + default_health_enabled
185 );
186
187 return host;
@@ -195,10 +195,10 @@ void rrd_init(char *hostname) {
195
196 localhost = rrdhost_create(hostname,
197 registry_get_this_machine_guid(),
198 - default_localhost_rrd_update_every,
199 - default_localhost_rrd_history_entries,
200 - default_localhost_rrd_memory_mode,
201 - default_localhost_health_enabled
198 + default_rrd_update_every,
199 + default_rrd_history_entries,
200 + default_rrd_memory_mode,
201 + default_health_enabled
202 );
203 }
204
src/rrdpush.c new
+207
@@ -0,0 +1,207 @@
1 +#include "common.h"
2 +
3 +#define PIPE_READ 0
4 +#define PIPE_WRITE 1
5 +
6 +int rrdpush_pipe[2];
7 +
8 +static BUFFER *rrdpush_buffer = NULL;
9 +static pthread_mutex_t rrdpush_mutex = PTHREAD_MUTEX_INITIALIZER;
10 +static RRDHOST *last_host = NULL;
11 +
12 +static inline void rrdpush_lock() {
13 + pthread_mutex_lock(&rrdpush_mutex);
14 +}
15 +
16 +static inline void rrdpush_unlock() {
17 + pthread_mutex_unlock(&rrdpush_mutex);
18 +}
19 +
20 +static inline int need_to_send_chart_definitions(RRDSET *st) {
21 + RRDDIM *rd;
22 + for(rd = st->dimensions; rd ;rd = rd->next)
23 + if(rrddim_flag_check(rd, RRDDIM_FLAG_UPDATED) && !rrddim_flag_check(rd, RRDDIM_FLAG_EXPOSED))
24 + return 1;
25 +
26 + return 0;
27 +}
28 +
29 +static inline void send_chart_definitions(RRDSET *st) {
30 + buffer_sprintf(rrdpush_buffer, "CHART '%s' '%s' '%s' '%s' '%s' '%s' '%s' %ld %d\n"
31 + , st->id
32 + , st->name
33 + , st->title
34 + , st->units
35 + , st->family
36 + , st->context
37 + , rrdset_type_name(st->chart_type)
38 + , st->priority
39 + , st->update_every
40 + );
41 +
42 + RRDDIM *rd;
43 + for(rd = st->dimensions; rd ;rd = rd->next) {
44 + buffer_sprintf(rrdpush_buffer, "DIMENSION '%s' '%s' '%s' " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " '%s %s'\n"
45 + , rd->id
46 + , rd->name
47 + , rrd_algorithm_name(rd->algorithm)
48 + , rd->multiplier
49 + , rd->divisor
50 + , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?"hidden":""
51 + , rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)?"noreset":""
52 + );
53 + }
54 +}
55 +
56 +static inline void send_chart_metrics(RRDSET *st) {
57 + buffer_sprintf(rrdpush_buffer, "BEGIN %s %llu\n", st->id, st->usec_since_last_update);
58 +
59 + RRDDIM *rd;
60 + for(rd = st->dimensions; rd ;rd = rd->next) {
61 + if(rrddim_flag_check(rd, RRDDIM_FLAG_UPDATED))
62 + buffer_sprintf(rrdpush_buffer, "SET %s = " COLLECTED_NUMBER_FORMAT "\n"
63 + , rd->id
64 + , rd->collected_value
65 + );
66 + }
67 +
68 + buffer_strcat(rrdpush_buffer, "END\n");
69 +}
70 +
71 +static void reset_all_charts(void) {
72 + rrd_rdlock();
73 +
74 + RRDHOST *h;
75 + for(h = localhost; h ;h = h->next) {
76 + RRDSET *st;
77 + for(st = h->rrdset_root ; st ; st = st->next) {
78 + rrdset_rdlock(st);
79 +
80 + RRDDIM *rd;
81 + for(rd = st->dimensions; rd ;rd = rd->next)
82 + rrddim_flag_clear(rd, RRDDIM_FLAG_EXPOSED);
83 +
84 + rrdset_unlock(st);
85 + }
86 + }
87 +
88 + last_host = NULL;
89 +
90 + rrd_unlock();
91 +}
92 +
93 +void rrdset_done_push(RRDSET *st) {
94 +
95 + if(!rrdset_flag_check(st, RRDSET_FLAG_ENABLED))
96 + return;
97 +
98 + rrdpush_lock();
99 + rrdset_rdlock(st);
100 +
101 + if(st->rrdhost != last_host)
102 + buffer_sprintf(rrdpush_buffer, "HOST '%s' '%s'\n", st->rrdhost->hostname, st->rrdhost->machine_guid);
103 +
104 + if(need_to_send_chart_definitions(st))
105 + send_chart_definitions(st);
106 +
107 + send_chart_metrics(st);
108 +
109 + // signal the sender there are more data
110 + if(write(rrdpush_pipe[PIPE_WRITE], " ", 1) == -1)
111 + error("Cannot write to internal pipe");
112 +
113 + rrdset_unlock(st);
114 + rrdpush_unlock();
115 +}
116 +
117 +void *central_netdata_push_thread(void *ptr) {
118 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
119 +
120 + info("Central netdata push thread created with task id %d", gettid());
121 +
122 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
123 + error("Cannot set pthread cancel type to DEFERRED.");
124 +
125 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
126 + error("Cannot set pthread cancel state to ENABLE.");
127 +
128 +
129 + rrdpush_buffer = buffer_create(1);
130 +
131 + if(pipe(rrdpush_pipe) == -1)
132 + fatal("Cannot create required pipe.");
133 +
134 + struct timeval tv = {
135 + .tv_sec = 60,
136 + .tv_usec = 0
137 + };
138 +
139 + size_t begin = 0;
140 + size_t max_size = 1024 * 1024;
141 + size_t reconnects_counter = 0;
142 + int sock = -1;
143 + char buffer[1];
144 +
145 + for(;;) {
146 + if(unlikely(sock == -1)) {
147 + sock = connect_to_one_of(central_netdata_to_push_data, 19999, &tv, &reconnects_counter);
148 +
149 + if(unlikely(sock != -1)) {
150 + if(fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
151 + error("Cannot set non-blocking mode for socket.");
152 +
153 + buffer_sprintf(rrdpush_buffer, "GET /stream?key=%s\r\n\r\n", config_get("global", "central netdata api key", ""));
154 + reset_all_charts();
155 + }
156 + }
157 +
158 + if(read(rrdpush_pipe[PIPE_READ], buffer, 1) == -1) {
159 + error("Cannot read from internal pipe.");
160 + sleep(1);
161 + }
162 +
163 + if(likely(sock != -1)) {
164 + rrdpush_lock();
165 + ssize_t ret = send(sock, &rrdpush_buffer->buffer[begin], rrdpush_buffer->len, MSG_DONTWAIT);
166 + if(ret == -1) {
167 + error("Failed to send metrics to central netdata at %s", central_netdata_to_push_data);
168 + close(sock);
169 + sock = -1;
170 + }
171 + else {
172 + begin += ret;
173 + if(begin == rrdpush_buffer->len) {
174 + buffer_flush(rrdpush_buffer);
175 + begin = 0;
176 + }
177 + }
178 + rrdpush_unlock();
179 + }
180 +
181 + // protection from overflow
182 + if(rrdpush_buffer->len > max_size) {
183 + rrdpush_lock();
184 +
185 + error("Discarding %zu bytes of metrics data, because we cannot connect to central netdata at %s"
186 + , buffer_strlen(rrdpush_buffer), central_netdata_to_push_data);
187 +
188 + buffer_flush(rrdpush_buffer);
189 +
190 + if(sock != -1) {
191 + close(sock);
192 + sock = -1;
193 + }
194 +
195 + rrdpush_unlock();
196 + }
197 + }
198 +
199 +cleanup:
200 + debug(D_WEB_CLIENT, "Central netdata push thread exits.");
201 + if(sock != -1)
202 + close(sock);
203 +
204 + static_thread->enabled = 0;
205 + pthread_exit(NULL);
206 + return NULL;
207 +}
src/rrdpush.h new
+7
@@ -0,0 +1,7 @@
1 +#ifndef NETDATA_RRDPUSH_H
2 +#define NETDATA_RRDPUSH_H
3 +
4 +extern void rrdset_done_push(RRDSET *st);
5 +extern void *central_netdata_push_thread(void *ptr);
6 +
7 +#endif //NETDATA_RRDPUSH_H
src/rrdset.c
+10 -10
@@ -178,13 +178,14 @@ void rrdset_reset(RRDSET *st) {
178 // ----------------------------------------------------------------------------
179 // RRDSET - helpers for rrdset_create()
180
181 -static inline long align_entries_to_pagesize(long entries) {
181 +inline long align_entries_to_pagesize(long entries) {
182 + if(central_netdata_to_push_data)
183 + return entries;
184 +
185 if(entries < 5) entries = 5;
186 if(entries > RRD_HISTORY_ENTRIES_MAX) entries = RRD_HISTORY_ENTRIES_MAX;
187
185 -#ifdef NETDATA_LOG_ALLOCATIONS
188 long page = (size_t)sysconf(_SC_PAGESIZE);
187 -
189 long size = sizeof(RRDDIM) + entries * sizeof(storage_number);
190 if(size % page) {
191 size -= (size % page);
@@ -195,9 +196,6 @@ static inline long align_entries_to_pagesize(long entries) {
196 }
197
198 return entries;
198 -#else
199 - return entries;
200 -#endif
199 }
200
201 static inline void timeval_align(struct timeval *tv, int update_every) {
@@ -541,8 +539,12 @@ void rrdset_next_usec(RRDSET *st, usec_t microseconds)
539 // ----------------------------------------------------------------------------
540 // RRDSET - process the collected values for all dimensions of a chart
541
544 -usec_t rrdset_done(RRDSET *st) {
545 - if(unlikely(netdata_exit)) return 0;
542 +void rrdset_done(RRDSET *st) {
543 + if(unlikely(netdata_exit)) return;
544 + if(unlikely(central_netdata_to_push_data)) {
545 + rrdset_done_push(st);
546 + return;
547 + }
548
549 debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
550
@@ -1138,7 +1140,5 @@ usec_t rrdset_done(RRDSET *st) {
1140
1141 if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
1142 error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
1141 -
1142 - return(st->usec_since_last_update);
1143 }
1144
src/socket.c
+31 -2
@@ -160,8 +160,10 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
160
161 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
162 if(fd != -1) {
163 - if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)timeout, sizeof(struct timeval)) < 0)
164 - error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
163 + if(timeout) {
164 + if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0)
165 + error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
166 + }
167
168 if(connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
169 error("Failed to connect to '%s', port '%s'", hostBfr, servBfr);
@@ -177,3 +179,30 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
179
180 return fd;
181 }
182 +
183 +int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter) {
184 + int sock = -1;
185 +
186 + const char *s = destination;
187 + while(*s) {
188 + const char *e = s;
189 +
190 + // skip separators, moving both s(tart) and e(nd)
191 + while(isspace(*e) || *e == ',') s = ++e;
192 +
193 + // move e(nd) to the first separator
194 + while(*e && !isspace(*e) && *e != ',') e++;
195 +
196 + // is there anything?
197 + if(!*s || s == e) break;
198 +
199 + char buf[e - s + 1];
200 + strncpyz(buf, s, e - s);
201 + if(reconnects_counter) *reconnects_counter += 1;
202 + sock = connect_to(buf, default_port, timeout);
203 + if(sock != -1) break;
204 + s = e;
205 + }
206 +
207 + return sock;
208 +}
src/socket.h
+1
@@ -6,5 +6,6 @@
6 #define NETDATA_SOCKET_H
7
8 extern int connect_to(const char *definition, int default_port, struct timeval *timeout);
9 +extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter);
10
11 #endif //NETDATA_SOCKET_H
src/unit_test.c
+4 -4
@@ -884,8 +884,8 @@ int run_test(struct test *test)
884 {
885 fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
886
887 - default_localhost_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
888 - default_localhost_rrd_update_every = test->update_every;
887 + default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
888 + default_rrd_update_every = test->update_every;
889
890 char name[101];
891 snprintfz(name, 100, "unittest-%s", test->name);
@@ -1091,8 +1091,8 @@ int unit_test(long delay, long shift)
1091 snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
1092
1093 //debug_flags = 0xffffffff;
1094 - default_localhost_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
1095 - default_localhost_rrd_update_every = 1;
1094 + default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
1095 + default_rrd_update_every = 1;
1096
1097 int do_abs = 1;
1098 int do_inc = 1;
src/web_client.c
+3 -5
@@ -1672,9 +1672,7 @@ int validate_stream_api_key(const char *key) {
1672 }
1673
1674 int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1675 - (void)host;
1676 -
1677 - info("STREAM request from client '%s:%s'", w->client_ip, w->client_port);
1675 + info("STREAM request from client '%s:%s' for host '%s'", w->client_ip, w->client_port, host->hostname);
1676
1677 char *key = NULL;
1678
@@ -1706,7 +1704,7 @@ int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1704
1705 struct plugind cd = {
1706 .enabled = 1,
1709 - .update_every = default_localhost_rrd_update_every,
1707 + .update_every = default_rrd_update_every,
1708 .pid = 0,
1709 .serial_failures = 0,
1710 .successful_collections = 0,
@@ -1735,7 +1733,7 @@ int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1733 }
1734
1735 // call the plugins.d processor to receive the metrics
1738 - size_t count = pluginsd_process(&cd, fp, 1);
1736 + size_t count = pluginsd_process(host, &cd, fp, 1);
1737 error("STREAM from '%s:%s': client disconnected.", w->client_ip, w->client_port);
1738
1739 // close all sockets, to let the socket worker we are done
web/index.html
+65 -65
@@ -1422,7 +1422,7 @@
1422
1423 sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/firehol/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more charts</a></li>';
1424 sidebar += '<li class=""><a href="https://github.com/firehol/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more alarms</a></li>';
1425 - sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every == 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + Math.round(data.history / (3600/data.update_every)).toLocaleString() + ' ' + ((data.history == (3600/data.update_every))?'hour':'hours').toString() + ' of real-time history.<br/>&nbsp;<br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>';
1425 + sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every == 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + seconds4human(data.update_every * data.history) + ' of real-time history.<br/>&nbsp;<br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>';
1426 sidebar += '</ul>';
1427 div.innerHTML = html;
1428 document.getElementById('sidebar').innerHTML = sidebar;
@@ -1576,70 +1576,6 @@
1576 return t.toLocaleDateString() + space + t.toLocaleTimeString();
1577 }
1578
1579 - function seconds4human(seconds, options) {
1580 - var default_options = {
1581 - now: 'now',
1582 - space: '&nbsp;',
1583 - negative_suffix: 'ago',
1584 - hour: 'hour',
1585 - hours: 'hours',
1586 - minute: 'minute',
1587 - minutes: 'minutes',
1588 - second: 'second',
1589 - seconds: 'seconds',
1590 - and: 'and'
1591 - };
1592 -
1593 - if(typeof options !== 'object')
1594 - options = default_options;
1595 - else {
1596 - var x;
1597 - for(x in default_options) {
1598 - if(typeof options[x] !== 'string')
1599 - options[x] = default_options[x];
1600 - }
1601 - }
1602 -
1603 - if(typeof seconds === 'string')
1604 - seconds = parseInt(seconds);
1605 -
1606 - if(seconds === 0)
1607 - return options.now;
1608 -
1609 - var suffix = '';
1610 - if(seconds < 0) {
1611 - seconds = -seconds;
1612 - if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
1613 - }
1614 -
1615 - var hours = Math.floor(seconds / 3600);
1616 - seconds -= (hours * 3600);
1617 -
1618 - var minutes = Math.floor(seconds / 60);
1619 - seconds -= (minutes * 60);
1620 -
1621 - var txt = '';
1622 -
1623 - if(hours > 1) txt += hours.toString() + options.space + options.hours;
1624 - else if(hours === 1) txt += hours.toString() + options.space + options.hour;
1625 -
1626 - if(hours > 0 && minutes > 0 && seconds == 0)
1627 - txt += options.space + options.and + options.space;
1628 - else if(hours > 0 && minutes > 0 && seconds > 0)
1629 - txt += ',' + options.space;
1630 -
1631 - if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
1632 - else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
1633 -
1634 - if((minutes > 0 || minutes > 0) && seconds > 0)
1635 - txt += options.space + options.and + options.space;
1636 -
1637 - if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
1638 - else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
1639 -
1640 - return txt + suffix;
1641 - }
1642 -
1579 function alarm_lookup_explain(alarm, chart) {
1580 var dimensions = ' of all values ';
1581
@@ -2221,6 +2157,70 @@
2157 });
2158 }
2159
2160 + function seconds4human(seconds, options) {
2161 + var default_options = {
2162 + now: 'now',
2163 + space: '&nbsp;',
2164 + negative_suffix: 'ago',
2165 + hour: 'hour',
2166 + hours: 'hours',
2167 + minute: 'minute',
2168 + minutes: 'minutes',
2169 + second: 'second',
2170 + seconds: 'seconds',
2171 + and: 'and'
2172 + };
2173 +
2174 + if(typeof options !== 'object')
2175 + options = default_options;
2176 + else {
2177 + var x;
2178 + for(x in default_options) {
2179 + if(typeof options[x] !== 'string')
2180 + options[x] = default_options[x];
2181 + }
2182 + }
2183 +
2184 + if(typeof seconds === 'string')
2185 + seconds = parseInt(seconds);
2186 +
2187 + if(seconds === 0)
2188 + return options.now;
2189 +
2190 + var suffix = '';
2191 + if(seconds < 0) {
2192 + seconds = -seconds;
2193 + if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
2194 + }
2195 +
2196 + var hours = Math.floor(seconds / 3600);
2197 + seconds -= (hours * 3600);
2198 +
2199 + var minutes = Math.floor(seconds / 60);
2200 + seconds -= (minutes * 60);
2201 +
2202 + var txt = '';
2203 +
2204 + if(hours > 1) txt += hours.toString() + options.space + options.hours;
2205 + else if(hours === 1) txt += hours.toString() + options.space + options.hour;
2206 +
2207 + if(hours > 0 && minutes > 0 && seconds == 0)
2208 + txt += options.space + options.and + options.space;
2209 + else if(hours > 0 && minutes > 0 && seconds > 0)
2210 + txt += ',' + options.space;
2211 +
2212 + if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
2213 + else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
2214 +
2215 + if((minutes > 0 || minutes > 0) && seconds > 0)
2216 + txt += options.space + options.and + options.space;
2217 +
2218 + if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
2219 + else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
2220 +
2221 + return txt + suffix;
2222 + }
2223 +
2224 function alarmsCallback(data) {
2225 var count = 0;
2226 for(x in data.alarms) {