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/> <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/> <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: ' ',
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: ' ',
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) {