summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am22
-rw-r--r--src/Makefile.in106
-rw-r--r--src/appconfig.c2
-rw-r--r--src/apps_plugin.c2
-rw-r--r--src/cgroup-network.c340
-rw-r--r--src/common.c15
-rw-r--r--src/common.h4
-rw-r--r--src/daemon.c101
-rw-r--r--src/daemon.h5
-rw-r--r--src/freebsd_getifaddrs.c36
-rw-r--r--src/freebsd_sysctl.c72
-rw-r--r--src/freeipmi_plugin.c2
-rw-r--r--src/global_statistics.c4
-rw-r--r--src/health.c53
-rw-r--r--src/health_config.c60
-rw-r--r--src/health_log.c22
-rw-r--r--src/inlined.h38
-rw-r--r--src/macos_fw.c4
-rw-r--r--src/macos_sysctl.c6
-rw-r--r--src/main.c77
-rw-r--r--src/plugin_freebsd.c1
-rw-r--r--src/plugin_freebsd.h1
-rw-r--r--src/plugin_proc.h4
-rw-r--r--src/plugin_proc_diskspace.c8
-rw-r--r--src/plugin_tc.c2
-rw-r--r--src/plugins_d.c58
-rw-r--r--src/popen.c34
-rw-r--r--src/proc_diskstats.c7
-rw-r--r--src/proc_interrupts.c92
-rw-r--r--src/proc_loadavg.c62
-rw-r--r--src/proc_meminfo.c288
-rw-r--r--src/proc_net_dev.c426
-rw-r--r--src/proc_net_ip_vs_stats.c4
-rw-r--r--src/proc_net_netstat.c509
-rw-r--r--src/proc_net_snmp.c2
-rw-r--r--src/proc_net_snmp6.c12
-rw-r--r--src/proc_softirqs.c107
-rw-r--r--src/proc_stat.c573
-rw-r--r--src/proc_sys_kernel_random_entropy_avail.c23
-rw-r--r--src/proc_uptime.c29
-rw-r--r--src/proc_vmstat.c131
-rw-r--r--src/rrd.h3
-rw-r--r--src/rrd2json.c10
-rw-r--r--src/rrddim.c4
-rw-r--r--src/rrdpush.c160
-rw-r--r--src/rrdset.c5
-rw-r--r--src/signals.c168
-rw-r--r--src/signals.h10
-rw-r--r--src/socket.c151
-rw-r--r--src/socket.h5
-rw-r--r--src/statsd.c49
-rw-r--r--src/storage_number.c76
-rw-r--r--src/storage_number.h16
-rw-r--r--src/sys_devices_system_edac_mc.c61
-rw-r--r--src/sys_fs_cgroup.c136
-rw-r--r--src/sys_kernel_mm_ksm.c173
-rw-r--r--src/unit_test.c60
-rw-r--r--src/unit_test.h1
-rw-r--r--src/web_api_v1.c10
-rw-r--r--src/web_buffer.c43
-rw-r--r--src/web_buffer.h1
-rw-r--r--src/web_buffer_svg.c11
-rw-r--r--src/web_client.c103
-rw-r--r--src/web_client.h77
-rw-r--r--src/web_server.c28
65 files changed, 3480 insertions, 1225 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 601d3204..feddc326 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,6 +37,10 @@ if ENABLE_PLUGIN_FREEIPMI
plugins_PROGRAMS += freeipmi.plugin
endif
+if ENABLE_PLUGIN_CGROUP_NETWORK
+plugins_PROGRAMS += cgroup-network
+endif
+
netdata_SOURCES = \
adaptive_resortable_list.c \
adaptive_resortable_list.h \
@@ -117,6 +121,8 @@ netdata_SOURCES = \
rrdset.c \
rrdsetvar.c \
rrdvar.c \
+ signals.c \
+ signals.h \
simple_pattern.c \
simple_pattern.h \
socket.c \
@@ -129,7 +135,6 @@ netdata_SOURCES = \
storage_number.h \
sys_devices_system_edac_mc.c \
sys_devices_system_node.c \
- sys_fs_cgroup.c \
unit_test.c \
unit_test.h \
url.c url.h \
@@ -199,6 +204,7 @@ netdata_SOURCES += \
proc_vmstat.c \
proc_uptime.c \
sys_kernel_mm_ksm.c \
+ sys_fs_cgroup.c \
$(NULL)
endif
endif
@@ -244,3 +250,17 @@ freeipmi_plugin_SOURCES = \
freeipmi_plugin_LDADD = \
$(OPTIONAL_IPMIMONITORING_LIBS) \
$(NULL)
+
+cgroup_network_SOURCES = \
+ cgroup-network.c \
+ clocks.c clocks.h \
+ common.c common.h \
+ inlined.h \
+ log.c log.h \
+ procfile.c procfile.h \
+ $(NULL)
+
+cgroup_network_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_LIBCAP_LIBS) \
+ $(NULL)
diff --git a/src/Makefile.in b/src/Makefile.in
index 3ce869b0..bc73c712 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -80,10 +80,11 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = netdata$(EXEEXT)
-plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
+plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
@ENABLE_PLUGIN_APPS_TRUE@am__append_1 = apps.plugin
@ENABLE_PLUGIN_FREEIPMI_TRUE@am__append_2 = freeipmi.plugin
-@FREEBSD_TRUE@am__append_3 = \
+@ENABLE_PLUGIN_CGROUP_NETWORK_TRUE@am__append_3 = cgroup-network
+@FREEBSD_TRUE@am__append_4 = \
@FREEBSD_TRUE@ plugin_freebsd.c \
@FREEBSD_TRUE@ plugin_freebsd.h \
@FREEBSD_TRUE@ freebsd_sysctl.c \
@@ -96,7 +97,7 @@ plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
@FREEBSD_TRUE@ freebsd_ipfw.c \
@FREEBSD_TRUE@ $(NULL)
-@FREEBSD_FALSE@@MACOS_TRUE@am__append_4 = \
+@FREEBSD_FALSE@@MACOS_TRUE@am__append_5 = \
@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.c \
@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.h \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_sysctl.c \
@@ -104,7 +105,7 @@ plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
@FREEBSD_FALSE@@MACOS_TRUE@ macos_fw.c \
@FREEBSD_FALSE@@MACOS_TRUE@ $(NULL)
-@FREEBSD_FALSE@@MACOS_FALSE@am__append_5 = \
+@FREEBSD_FALSE@@MACOS_FALSE@am__append_6 = \
@FREEBSD_FALSE@@MACOS_FALSE@ ipc.c ipc.h \
@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.c \
@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.h \
@@ -133,9 +134,10 @@ plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
@FREEBSD_FALSE@@MACOS_FALSE@ proc_vmstat.c \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_uptime.c \
@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.c \
+@FREEBSD_FALSE@@MACOS_FALSE@ sys_fs_cgroup.c \
@FREEBSD_FALSE@@MACOS_FALSE@ $(NULL)
-@FREEBSD_TRUE@am__append_6 = \
+@FREEBSD_TRUE@am__append_7 = \
@FREEBSD_TRUE@ plugin_freebsd.h \
@FREEBSD_TRUE@ $(NULL)
@@ -160,6 +162,8 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
@ENABLE_PLUGIN_APPS_TRUE@am__EXEEXT_1 = apps.plugin$(EXEEXT)
@ENABLE_PLUGIN_FREEIPMI_TRUE@am__EXEEXT_2 = freeipmi.plugin$(EXEEXT)
+@ENABLE_PLUGIN_CGROUP_NETWORK_TRUE@am__EXEEXT_3 = \
+@ENABLE_PLUGIN_CGROUP_NETWORK_TRUE@ cgroup-network$(EXEEXT)
am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" \
"$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)" \
"$(DESTDIR)$(registrydir)" "$(DESTDIR)$(varlibdir)"
@@ -174,6 +178,11 @@ am_apps_plugin_OBJECTS = apps_plugin.$(OBJEXT) avl.$(OBJEXT) \
apps_plugin_OBJECTS = $(am_apps_plugin_OBJECTS)
am__DEPENDENCIES_1 =
apps_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_cgroup_network_OBJECTS = cgroup-network.$(OBJEXT) clocks.$(OBJEXT) \
+ common.$(OBJEXT) log.$(OBJEXT) procfile.$(OBJEXT)
+cgroup_network_OBJECTS = $(am_cgroup_network_OBJECTS)
+cgroup_network_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
am_freeipmi_plugin_OBJECTS = freeipmi_plugin.$(OBJEXT) \
clocks.$(OBJEXT) common.$(OBJEXT) log.$(OBJEXT) \
procfile.$(OBJEXT)
@@ -197,20 +206,19 @@ am__netdata_SOURCES_DIST = adaptive_resortable_list.c \
registry_url.c registry_url.h rrd.c rrd.h rrd2json.c \
rrd2json.h rrd2json_api_old.c rrd2json_api_old.h rrdcalc.c \
rrdcalctemplate.c rrddim.c rrddimvar.c rrdfamily.c rrdhost.c \
- rrdpush.c rrdpush.h rrdset.c rrdsetvar.c rrdvar.c \
- simple_pattern.c simple_pattern.h socket.c socket.h \
+ rrdpush.c rrdpush.h rrdset.c rrdsetvar.c rrdvar.c signals.c \
+ signals.h simple_pattern.c simple_pattern.h socket.c socket.h \
statistical.c statistical.h statsd.c statsd.h storage_number.c \
storage_number.h sys_devices_system_edac_mc.c \
- sys_devices_system_node.c sys_fs_cgroup.c unit_test.c \
- unit_test.h url.c url.h web_api_old.c web_api_old.h \
- web_api_v1.c web_api_v1.h web_buffer.c web_buffer.h \
- web_buffer_svg.c web_buffer_svg.h web_client.c web_client.h \
- web_server.c web_server.h plugin_freebsd.c plugin_freebsd.h \
- freebsd_sysctl.c freebsd_getmntinfo.c freebsd_getifaddrs.c \
- freebsd_devstat.c zfs_common.c zfs_common.h \
- freebsd_kstat_zfs.c freebsd_ipfw.c plugin_macos.c \
- plugin_macos.h macos_sysctl.c macos_mach_smi.c macos_fw.c \
- ipc.c ipc.h plugin_proc.c plugin_proc.h \
+ sys_devices_system_node.c unit_test.c unit_test.h url.c url.h \
+ web_api_old.c web_api_old.h web_api_v1.c web_api_v1.h \
+ web_buffer.c web_buffer.h web_buffer_svg.c web_buffer_svg.h \
+ web_client.c web_client.h web_server.c web_server.h \
+ plugin_freebsd.c plugin_freebsd.h freebsd_sysctl.c \
+ freebsd_getmntinfo.c freebsd_getifaddrs.c freebsd_devstat.c \
+ zfs_common.c zfs_common.h freebsd_kstat_zfs.c freebsd_ipfw.c \
+ plugin_macos.c plugin_macos.h macos_sysctl.c macos_mach_smi.c \
+ macos_fw.c ipc.c ipc.h plugin_proc.c plugin_proc.h \
plugin_proc_diskspace.c plugin_proc_diskspace.h \
proc_diskstats.c proc_interrupts.c proc_softirqs.c \
proc_loadavg.c proc_meminfo.c proc_net_dev.c \
@@ -219,7 +227,7 @@ am__netdata_SOURCES_DIST = adaptive_resortable_list.c \
proc_net_softnet_stat.c proc_net_stat_conntrack.c \
proc_net_stat_synproxy.c proc_spl_kstat_zfs.c proc_stat.c \
proc_sys_kernel_random_entropy_avail.c proc_vmstat.c \
- proc_uptime.c sys_kernel_mm_ksm.c
+ proc_uptime.c sys_kernel_mm_ksm.c sys_fs_cgroup.c
@FREEBSD_TRUE@am__objects_2 = plugin_freebsd.$(OBJEXT) \
@FREEBSD_TRUE@ freebsd_sysctl.$(OBJEXT) \
@FREEBSD_TRUE@ freebsd_getmntinfo.$(OBJEXT) \
@@ -255,7 +263,8 @@ am__netdata_SOURCES_DIST = adaptive_resortable_list.c \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_sys_kernel_random_entropy_avail.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_vmstat.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_uptime.$(OBJEXT) \
-@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.$(OBJEXT)
+@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.$(OBJEXT) \
+@FREEBSD_FALSE@@MACOS_FALSE@ sys_fs_cgroup.$(OBJEXT)
am_netdata_OBJECTS = adaptive_resortable_list.$(OBJEXT) \
appconfig.$(OBJEXT) avl.$(OBJEXT) backend_prometheus.$(OBJEXT) \
backends.$(OBJEXT) clocks.$(OBJEXT) common.$(OBJEXT) \
@@ -275,15 +284,14 @@ am_netdata_OBJECTS = adaptive_resortable_list.$(OBJEXT) \
rrdcalc.$(OBJEXT) rrdcalctemplate.$(OBJEXT) rrddim.$(OBJEXT) \
rrddimvar.$(OBJEXT) rrdfamily.$(OBJEXT) rrdhost.$(OBJEXT) \
rrdpush.$(OBJEXT) rrdset.$(OBJEXT) rrdsetvar.$(OBJEXT) \
- rrdvar.$(OBJEXT) simple_pattern.$(OBJEXT) socket.$(OBJEXT) \
- statistical.$(OBJEXT) statsd.$(OBJEXT) \
+ rrdvar.$(OBJEXT) signals.$(OBJEXT) simple_pattern.$(OBJEXT) \
+ socket.$(OBJEXT) statistical.$(OBJEXT) statsd.$(OBJEXT) \
storage_number.$(OBJEXT) sys_devices_system_edac_mc.$(OBJEXT) \
- sys_devices_system_node.$(OBJEXT) sys_fs_cgroup.$(OBJEXT) \
- unit_test.$(OBJEXT) url.$(OBJEXT) web_api_old.$(OBJEXT) \
- web_api_v1.$(OBJEXT) web_buffer.$(OBJEXT) \
- web_buffer_svg.$(OBJEXT) web_client.$(OBJEXT) \
- web_server.$(OBJEXT) $(am__objects_2) $(am__objects_3) \
- $(am__objects_4)
+ sys_devices_system_node.$(OBJEXT) unit_test.$(OBJEXT) \
+ url.$(OBJEXT) web_api_old.$(OBJEXT) web_api_v1.$(OBJEXT) \
+ web_buffer.$(OBJEXT) web_buffer_svg.$(OBJEXT) \
+ web_client.$(OBJEXT) web_server.$(OBJEXT) $(am__objects_2) \
+ $(am__objects_3) $(am__objects_4)
netdata_OBJECTS = $(am_netdata_OBJECTS)
netdata_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -315,10 +323,11 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
-SOURCES = $(apps_plugin_SOURCES) $(freeipmi_plugin_SOURCES) \
- $(netdata_SOURCES)
+SOURCES = $(apps_plugin_SOURCES) $(cgroup_network_SOURCES) \
+ $(freeipmi_plugin_SOURCES) $(netdata_SOURCES)
DIST_SOURCES = $(am__apps_plugin_SOURCES_DIST) \
- $(freeipmi_plugin_SOURCES) $(am__netdata_SOURCES_DIST)
+ $(cgroup_network_SOURCES) $(freeipmi_plugin_SOURCES) \
+ $(am__netdata_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -563,16 +572,15 @@ netdata_SOURCES = adaptive_resortable_list.c \
registry_url.c registry_url.h rrd.c rrd.h rrd2json.c \
rrd2json.h rrd2json_api_old.c rrd2json_api_old.h rrdcalc.c \
rrdcalctemplate.c rrddim.c rrddimvar.c rrdfamily.c rrdhost.c \
- rrdpush.c rrdpush.h rrdset.c rrdsetvar.c rrdvar.c \
- simple_pattern.c simple_pattern.h socket.c socket.h \
+ rrdpush.c rrdpush.h rrdset.c rrdsetvar.c rrdvar.c signals.c \
+ signals.h simple_pattern.c simple_pattern.h socket.c socket.h \
statistical.c statistical.h statsd.c statsd.h storage_number.c \
storage_number.h sys_devices_system_edac_mc.c \
- sys_devices_system_node.c sys_fs_cgroup.c unit_test.c \
- unit_test.h url.c url.h web_api_old.c web_api_old.h \
- web_api_v1.c web_api_v1.h web_buffer.c web_buffer.h \
- web_buffer_svg.c web_buffer_svg.h web_client.c web_client.h \
- web_server.c web_server.h $(NULL) $(am__append_3) \
- $(am__append_4) $(am__append_5)
+ sys_devices_system_node.c unit_test.c unit_test.h url.c url.h \
+ web_api_old.c web_api_old.h web_api_v1.c web_api_v1.h \
+ web_buffer.c web_buffer.h web_buffer_svg.c web_buffer_svg.h \
+ web_client.c web_client.h web_server.c web_server.h $(NULL) \
+ $(am__append_4) $(am__append_5) $(am__append_6)
netdata_LDADD = \
$(OPTIONAL_MATH_LIBS) \
$(OPTIONAL_NFACCT_LIBS) \
@@ -582,7 +590,7 @@ netdata_LDADD = \
apps_plugin_SOURCES = apps_plugin.c avl.c avl.h clocks.c clocks.h \
common.c common.h inlined.h log.c log.h procfile.c procfile.h \
- web_buffer.c web_buffer.h $(NULL) $(am__append_6)
+ web_buffer.c web_buffer.h $(NULL) $(am__append_7)
apps_plugin_LDADD = \
$(OPTIONAL_MATH_LIBS) \
$(OPTIONAL_LIBCAP_LIBS) \
@@ -601,6 +609,20 @@ freeipmi_plugin_LDADD = \
$(OPTIONAL_IPMIMONITORING_LIBS) \
$(NULL)
+cgroup_network_SOURCES = \
+ cgroup-network.c \
+ clocks.c clocks.h \
+ common.c common.h \
+ inlined.h \
+ log.c log.h \
+ procfile.c procfile.h \
+ $(NULL)
+
+cgroup_network_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_LIBCAP_LIBS) \
+ $(NULL)
+
all: all-am
.SUFFIXES:
@@ -724,6 +746,10 @@ apps.plugin$(EXEEXT): $(apps_plugin_OBJECTS) $(apps_plugin_DEPENDENCIES) $(EXTRA
@rm -f apps.plugin$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(apps_plugin_OBJECTS) $(apps_plugin_LDADD) $(LIBS)
+cgroup-network$(EXEEXT): $(cgroup_network_OBJECTS) $(cgroup_network_DEPENDENCIES) $(EXTRA_cgroup_network_DEPENDENCIES)
+ @rm -f cgroup-network$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(cgroup_network_OBJECTS) $(cgroup_network_LDADD) $(LIBS)
+
freeipmi.plugin$(EXEEXT): $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_DEPENDENCIES) $(EXTRA_freeipmi_plugin_DEPENDENCIES)
@rm -f freeipmi.plugin$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_LDADD) $(LIBS)
@@ -744,6 +770,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_prometheus.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backends.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgroup-network.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clocks.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
@@ -820,6 +847,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdset.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdsetvar.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdvar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_pattern.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statistical.Po@am__quote@
diff --git a/src/appconfig.c b/src/appconfig.c
index 91c4c5c5..2c7721b8 100644
--- a/src/appconfig.c
+++ b/src/appconfig.c
@@ -317,7 +317,7 @@ int appconfig_get_boolean(struct config *root, const char *section, const char *
s = appconfig_get(root, section, name, s);
if(!s) return value;
- if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
+ if(!strcasecmp(s, "yes") || !strcasecmp(s, "true") || !strcasecmp(s, "on") || !strcasecmp(s, "auto") || !strcasecmp(s, "on demand")) return 1;
return 0;
}
diff --git a/src/apps_plugin.c b/src/apps_plugin.c
index ecb6aaea..c0eb5c08 100644
--- a/src/apps_plugin.c
+++ b/src/apps_plugin.c
@@ -3197,7 +3197,7 @@ static void parse_args(int argc, char **argv)
}
}
- if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
+ if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
printf("apps.plugin %s\n", VERSION);
exit(0);
}
diff --git a/src/cgroup-network.c b/src/cgroup-network.c
new file mode 100644
index 00000000..8894d60e
--- /dev/null
+++ b/src/cgroup-network.c
@@ -0,0 +1,340 @@
+#include "common.h"
+
+#ifdef HAVE_SETNS
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* See feature_test_macros(7) */
+#endif
+#include <sched.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// callback required by fatal()
+
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+struct iface {
+ const char *device;
+ uint32_t hash;
+
+ unsigned int ifindex;
+ unsigned int iflink;
+
+ struct iface *next;
+};
+
+unsigned int read_iface_iflink(const char *prefix, const char *iface) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix?prefix:"", iface);
+
+ unsigned long long iflink = 0;
+ int ret = read_single_number_file(filename, &iflink);
+ if(ret) error("Cannot read '%s'.", filename);
+
+ return (unsigned int)iflink;
+}
+
+unsigned int read_iface_ifindex(const char *prefix, const char *iface) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix?prefix:"", iface);
+
+ unsigned long long ifindex = 0;
+ int ret = read_single_number_file(filename, &ifindex);
+ if(ret) error("Cannot read '%s'.", filename);
+
+ return (unsigned int)ifindex;
+}
+
+struct iface *read_proc_net_dev(const char *prefix) {
+ procfile *ff = NULL;
+ char filename[FILENAME_MAX + 1];
+
+ snprintfz(filename, FILENAME_MAX, "%s%s", prefix?prefix:"", "/proc/net/dev");
+ ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT);
+ if(unlikely(!ff)) {
+ error("Cannot open file '%s'", filename);
+ return NULL;
+ }
+
+ ff = procfile_readall(ff);
+ if(unlikely(!ff)) {
+ error("Cannot read file '%s'", filename);
+ return NULL;
+ }
+
+ size_t lines = procfile_lines(ff), l;
+ struct iface *root = NULL;
+ for(l = 2; l < lines ;l++) {
+ if (unlikely(procfile_linewords(ff, l) < 1)) continue;
+
+ struct iface *t = callocz(1, sizeof(struct iface));
+ t->device = strdupz(procfile_lineword(ff, l, 0));
+ t->hash = simple_hash(t->device);
+ t->ifindex = read_iface_ifindex(prefix, t->device);
+ t->iflink = read_iface_iflink(prefix, t->device);
+ t->next = root;
+ root = t;
+ }
+
+ procfile_close(ff);
+
+ return root;
+}
+
+int iface_is_eligible(struct iface *iface) {
+ if(iface->iflink != iface->ifindex)
+ return 1;
+
+ return 0;
+}
+
+int eligible_ifaces(struct iface *root) {
+ int eligible = 0;
+
+ struct iface *t;
+ for(t = root; t ; t = t->next)
+ if(iface_is_eligible(t))
+ eligible++;
+
+ return eligible;
+}
+
+static void continue_as_child(void) {
+ pid_t child = fork();
+ int status;
+ pid_t ret;
+
+ if (child < 0)
+ error("fork() failed");
+
+ /* Only the child returns */
+ if (child == 0)
+ return;
+
+ for (;;) {
+ ret = waitpid(child, &status, WUNTRACED);
+ if ((ret == child) && (WIFSTOPPED(status))) {
+ /* The child suspended so suspend us as well */
+ kill(getpid(), SIGSTOP);
+ kill(child, SIGCONT);
+ } else {
+ break;
+ }
+ }
+
+ /* Return the child's exit code if possible */
+ if (WIFEXITED(status)) {
+ exit(WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ kill(getpid(), WTERMSIG(status));
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+int proc_pid_fd(const char *prefix, const char *ns, pid_t pid) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix?prefix:"", (int)pid, ns);
+ int fd = open(filename, O_RDONLY);
+
+ if(fd == -1)
+ error("Cannot open file '%s'", filename);
+
+ return fd;
+}
+
+static struct ns {
+ int nstype;
+ int fd;
+ int status;
+ const char *name;
+ const char *path;
+} all_ns[] = {
+ // { .nstype = CLONE_NEWUSER, .fd = -1, .status = -1, .name = "user", .path = "ns/user" },
+ // { .nstype = CLONE_NEWCGROUP, .fd = -1, .status = -1, .name = "cgroup", .path = "ns/cgroup" },
+ // { .nstype = CLONE_NEWIPC, .fd = -1, .status = -1, .name = "ipc", .path = "ns/ipc" },
+ // { .nstype = CLONE_NEWUTS, .fd = -1, .status = -1, .name = "uts", .path = "ns/uts" },
+ { .nstype = CLONE_NEWNET, .fd = -1, .status = -1, .name = "network", .path = "ns/net" },
+ { .nstype = CLONE_NEWPID, .fd = -1, .status = -1, .name = "pid", .path = "ns/pid" },
+ { .nstype = CLONE_NEWNS, .fd = -1, .status = -1, .name = "mount", .path = "ns/mnt" },
+
+ // terminator
+ { .nstype = 0, .fd = -1, .status = -1, .name = NULL, .path = NULL }
+};
+
+int switch_namespace(const char *prefix, pid_t pid) {
+#ifdef HAVE_SETNS
+
+ int i;
+ for(i = 0; all_ns[i].name ; i++)
+ all_ns[i].fd = proc_pid_fd(prefix, all_ns[i].path, pid);
+
+ int root_fd = proc_pid_fd(prefix, "root", pid);
+ int cwd_fd = proc_pid_fd(prefix, "cwd", pid);
+
+ setgroups(0, NULL);
+
+ // 2 passes - found it at nsenter source code
+ // this is related CLONE_NEWUSER functionality
+
+ // FIXME: this code cannot switch user namespace
+ // Fortunately, we don't need it.
+
+ int pass, errors = 0;
+ for(pass = 0; pass < 2 ;pass++) {
+ for(i = 0; all_ns[i].name ; i++) {
+ if (all_ns[i].fd != -1 && all_ns[i].status == -1) {
+ if(setns(all_ns[i].fd, all_ns[i].nstype) == -1) {
+ if(pass == 1) {
+ all_ns[i].status = 0;
+ error("Cannot switch to %s namespace of pid %d", all_ns[i].name, (int) pid);
+ errors++;
+ }
+ }
+ else
+ all_ns[i].status = 1;
+ }
+ }
+ }
+
+ setgroups(0, NULL);
+
+ if(root_fd != -1) {
+ if(fchdir(root_fd) < 0)
+ error("Cannot fchdir() to pid %d root directory", (int)pid);
+
+ if(chroot(".") < 0)
+ error("Cannot chroot() to pid %d root directory", (int)pid);
+
+ close(root_fd);
+ }
+
+ if(cwd_fd != -1) {
+ if(fchdir(cwd_fd) < 0)
+ error("Cannot fchdir() to pid %d current working directory", (int)pid);
+
+ close(cwd_fd);
+ }
+
+ int do_fork = 0;
+ for(i = 0; all_ns[i].name ; i++)
+ if(all_ns[i].fd != -1) {
+
+ // CLONE_NEWPID requires a fork() to become effective
+ if(all_ns[i].nstype == CLONE_NEWPID && all_ns[i].status)
+ do_fork = 1;
+
+ close(all_ns[i].fd);
+ }
+
+ if(do_fork)
+ continue_as_child();
+
+ return 0;
+
+#else
+
+ errno = ENOSYS;
+ error("setns() is missing on this system.");
+ return 1;
+
+#endif
+}
+
+pid_t read_pid_from_cgroup(const char *path) {
+ char buffer[FILENAME_MAX + 1];
+
+ snprintfz(buffer, FILENAME_MAX, "%s/cgroup.procs", path);
+ FILE *fp = fopen(buffer, "r");
+ if(!fp) {
+ error("Cannot read file '%s'.", buffer);
+ snprintfz(buffer, FILENAME_MAX, "%s/tasks", path);
+ fp = fopen(buffer, "r");
+ }
+
+ if(!fp) {
+ error("Cannot read file '%s'.", buffer);
+ return 0;
+ }
+
+ pid_t pid = 0;
+ char *s;
+ while((s = fgets(buffer, FILENAME_MAX, fp))) {
+ pid = atoi(s);
+ if(pid > 0) break;
+ }
+
+ fclose(fp);
+ return pid;
+}
+
+void usage(void) {
+ fprintf(stderr, "%s [ -p PID | --pid PID | --cgroup /path/to/cgroup ]\n", program_name);
+ exit(1);
+}
+
+int main(int argc, char **argv) {
+ pid_t pid = 0;
+
+ program_name = argv[0];
+ program_version = VERSION;
+ error_log_syslog = 0;
+
+ if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) {
+ fprintf(stderr, "cgroup-network %s\n", VERSION);
+ exit(0);
+ }
+
+ if(argc != 3)
+ usage();
+
+ if(!strcmp(argv[1], "-p") || !strcmp(argv[1], "--pid")) {
+ pid = atoi(argv[2]);
+ }
+ else if(!strcmp(argv[1], "--cgroup")) {
+ pid = read_pid_from_cgroup(argv[2]);
+ }
+ else
+ usage();
+
+ if(pid <= 0)
+ fatal("Invalid pid %d", (int)pid);
+
+ struct iface *host, *cgroup, *h, *c;
+ const char *prefix = getenv("NETDATA_HOST_PREFIX");
+
+ host = read_proc_net_dev(prefix);
+ if(!host)
+ fatal("cannot read host interface list.");
+
+ if(!eligible_ifaces(host))
+ fatal("there are no double-linked host interfaces available.");
+
+ if(switch_namespace(prefix, pid))
+ fatal("cannot switch to the namespace of pid %u", (unsigned int)pid);
+
+ cgroup = read_proc_net_dev(NULL);
+ if(!cgroup)
+ fatal("cannot read cgroup interface list.");
+
+ if(!eligible_ifaces(cgroup))
+ fatal("there are not double-linked cgroup interfaces available.");
+
+ int found = 0;
+ for(h = host; h ; h = h->next) {
+ if(iface_is_eligible(h)) {
+ for (c = cgroup; c; c = c->next) {
+ if(iface_is_eligible(c) && h->ifindex == c->iflink && h->iflink == c->ifindex) {
+ printf("%s %s\n", h->device, c->device);
+ found++;
+ }
+ }
+ }
+ }
+
+ if(!found)
+ return 1;
+
+ return 0;
+}
diff --git a/src/common.c b/src/common.c
index aa75c198..5a953672 100644
--- a/src/common.c
+++ b/src/common.c
@@ -227,9 +227,18 @@ void json_escape_string(char *dst, const char *src, size_t size) {
}
void json_fix_string(char *s) {
- for( ; *s ;s++) {
- if(unlikely(*s == '\\')) *s = '/';
- else if(unlikely(*s == '"')) *s = '\'';
+ unsigned char c;
+ while((c = (unsigned char)*s)) {
+ if(unlikely(c == '\\'))
+ *s++ = '/';
+ else if(unlikely(c == '"'))
+ *s++ = '\'';
+ else if(unlikely(isspace(c) || iscntrl(c)))
+ *s++ = ' ';
+ else if(unlikely(!isprint(c) || c > 127))
+ *s++ = '_';
+ else
+ s++;
}
}
diff --git a/src/common.h b/src/common.h
index efeebf16..51d2bba5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -80,6 +80,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#include <uuid/uuid.h>
@@ -215,6 +216,7 @@
#include "web_client.h"
#include "web_server.h"
#include "registry.h"
+#include "signals.h"
#include "daemon.h"
#include "main.h"
#include "unit_test.h"
@@ -309,4 +311,6 @@ extern const char *program_version;
#endif
#endif
+#define BITS_IN_A_KILOBIT 1000
+
#endif /* NETDATA_COMMON_H */
diff --git a/src/daemon.c b/src/daemon.c
index bc02446e..5c5333a3 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -3,45 +3,6 @@
char pidfile[FILENAME_MAX + 1] = "";
-void sig_handler_exit(int signo)
-{
- if(signo) {
- error_log_limit_unlimited();
- error("Received signal %d. Exiting...", signo);
- netdata_exit = 1;
- }
-}
-
-void sig_handler_logrotate(int signo)
-{
- if(signo) {
- error_log_limit_unlimited();
- info("Received signal %d to re-open the log files", signo);
- reopen_all_log_files();
- error_log_limit_reset();
- }
-}
-
-void sig_handler_save(int signo)
-{
- if(signo) {
- error_log_limit_unlimited();
- info("Received signal %d to save the database...", signo);
- rrdhost_save_all();
- error_log_limit_reset();
- }
-}
-
-void sig_handler_reload_health(int signo)
-{
- if(signo) {
- error_log_limit_unlimited();
- info("Received signal %d to reload health configuration...", signo);
- health_reload();
- error_log_limit_reset();
- }
-}
-
static void chown_open_file(int fd, uid_t uid, gid_t gid) {
if(fd == -1) return;
@@ -167,34 +128,70 @@ int become_user(const char *username, int pid_fd) {
#endif
static void oom_score_adj(void) {
- char buf[10 + 1];
- snprintfz(buf, 10, "%d", OOM_SCORE_ADJ_MAX);
+ char buf[30 + 1];
+ long long int old_score, wanted_score = OOM_SCORE_ADJ_MAX, final_score = 0;
+
+ // read the existing score
+ if(read_single_signed_number_file("/proc/self/oom_score_adj", &old_score)) {
+ error("Out-Of-Memory (OOM) score setting is not supported on this system.");
+ return;
+ }
+
+ if(old_score != 0)
+ wanted_score = old_score;
// check the environment
char *s = getenv("OOMScoreAdjust");
- if(!s || !*s) s = buf;
+ if(!s || !*s) {
+ snprintfz(buf, 30, "%d", (int)wanted_score);
+ s = buf;
+ }
// check netdata.conf configuration
s = config_get(CONFIG_SECTION_GLOBAL, "OOM score", s);
- if(!s || !*s) s = buf;
+ if(s && *s && (isdigit(*s) || *s == '-' || *s == '+'))
+ wanted_score = atoll(s);
+ else {
+ info("Out-Of-Memory (OOM) score not changed due to non-numeric setting: '%s' (running with %d)", s, (int)old_score);
+ return;
+ }
- if(!isdigit(*s) && *s != '-' && *s != '+') {
- info("Out-Of-Memory score not changed due to setting: '%s'", s);
+ if(wanted_score < OOM_SCORE_ADJ_MIN) {
+ error("Wanted Out-Of-Memory (OOM) score %d is too small. Using %d", (int)wanted_score, (int)OOM_SCORE_ADJ_MIN);
+ wanted_score = OOM_SCORE_ADJ_MIN;
+ }
+
+ if(wanted_score > OOM_SCORE_ADJ_MAX) {
+ error("Wanted Out-Of-Memory (OOM) score %d is too big. Using %d", (int)wanted_score, (int)OOM_SCORE_ADJ_MAX);
+ wanted_score = OOM_SCORE_ADJ_MAX;
+ }
+
+ if(old_score == wanted_score) {
+ info("Out-Of-Memory (OOM) score is already set to the wanted value %d", (int)old_score);
return;
}
- int done = 0;
+ int written = 0;
int fd = open("/proc/self/oom_score_adj", O_WRONLY);
if(fd != -1) {
- ssize_t len = strlen(s);
- if(len > 0 && write(fd, buf, (size_t)len) == len) done = 1;
+ snprintfz(buf, 30, "%d", (int)wanted_score);
+ ssize_t len = strlen(buf);
+ if(len > 0 && write(fd, buf, (size_t)len) == len) written = 1;
close(fd);
- }
- if(!done)
- error("Cannot adjust my Out-Of-Memory score to '%s'.", s);
+ if(written) {
+ if(read_single_signed_number_file("/proc/self/oom_score_adj", &final_score))
+ error("Adjusted my Out-Of-Memory (OOM) score to %d, but cannot verify it.", (int)wanted_score);
+ else if(final_score == wanted_score)
+ info("Adjusted my Out-Of-Memory (OOM) score from %d to %d.", (int)old_score, (int)final_score);
+ else
+ error("Adjusted my Out-Of-Memory (OOM) score from %d to %d, but it has been set to %d.", (int)old_score, (int)wanted_score, (int)final_score);
+ }
+ else
+ error("Failed to adjust my Out-Of-Memory (OOM) score to %d. Running with %d. (systemd systems may change it via netdata.service)", (int)wanted_score, (int)old_score);
+ }
else
- info("Adjusted my Out-Of-Memory score to '%s'.", s);
+ error("Failed to adjust my Out-Of-Memory (OOM) score. Cannot open /proc/self/oom_score_adj for writing.");
}
static void process_nice_level(void) {
diff --git a/src/daemon.h b/src/daemon.h
index b193602d..150d74e3 100644
--- a/src/daemon.h
+++ b/src/daemon.h
@@ -1,11 +1,6 @@
#ifndef NETDATA_DAEMON_H
#define NETDATA_DAEMON_H 1
-extern void sig_handler_exit(int signo);
-extern void sig_handler_save(int signo);
-extern void sig_handler_logrotate(int signo);
-extern void sig_handler_reload_health(int signo);
-
extern int become_user(const char *username, int pid_fd);
extern int become_daemon(int dont_fork, const char *user);
diff --git a/src/freebsd_getifaddrs.c b/src/freebsd_getifaddrs.c
index 7355fac9..1a4448bd 100644
--- a/src/freebsd_getifaddrs.c
+++ b/src/freebsd_getifaddrs.c
@@ -2,7 +2,7 @@
#include <ifaddrs.h>
-struct network_interface {
+struct cgroup_network_interface {
char *name;
uint32_t hash;
size_t len;
@@ -41,14 +41,14 @@ struct network_interface {
RRDSET *st_events;
RRDDIM *rd_events_coll;
- struct network_interface *next;
+ struct cgroup_network_interface *next;
};
-static struct network_interface *network_interfaces_root = NULL, *network_interfaces_last_used = NULL;
+static struct cgroup_network_interface *network_interfaces_root = NULL, *network_interfaces_last_used = NULL;
static size_t network_interfaces_added = 0, network_interfaces_found = 0;
-static void network_interface_free(struct network_interface *ifm) {
+static void network_interface_free(struct cgroup_network_interface *ifm) {
if (likely(ifm->st_bandwidth))
rrdset_is_obsolete(ifm->st_bandwidth);
if (likely(ifm->st_packets))
@@ -68,7 +68,7 @@ static void network_interface_free(struct network_interface *ifm) {
static void network_interfaces_cleanup() {
if (likely(network_interfaces_found == network_interfaces_added)) return;
- struct network_interface *ifm = network_interfaces_root, *last = NULL;
+ struct cgroup_network_interface *ifm = network_interfaces_root, *last = NULL;
while(ifm) {
if (unlikely(!ifm->updated)) {
// info("Removing network interface '%s', linked after '%s'", ifm->name, last?last->name:"ROOT");
@@ -76,7 +76,7 @@ static void network_interfaces_cleanup() {
if (network_interfaces_last_used == ifm)
network_interfaces_last_used = last;
- struct network_interface *t = ifm;
+ struct cgroup_network_interface *t = ifm;
if (ifm == network_interfaces_root || !last)
network_interfaces_root = ifm = ifm->next;
@@ -95,8 +95,8 @@ static void network_interfaces_cleanup() {
}
}
-static struct network_interface *get_network_interface(const char *name) {
- struct network_interface *ifm;
+static struct cgroup_network_interface *get_network_interface(const char *name) {
+ struct cgroup_network_interface *ifm;
uint32_t hash = simple_hash(name);
@@ -117,7 +117,7 @@ static struct network_interface *get_network_interface(const char *name) {
}
// create a new one
- ifm = callocz(1, sizeof(struct network_interface));
+ ifm = callocz(1, sizeof(struct cgroup_network_interface));
ifm->name = strdupz(name);
ifm->hash = simple_hash(ifm->name);
ifm->len = strlen(ifm->name);
@@ -125,7 +125,7 @@ static struct network_interface *get_network_interface(const char *name) {
// link it to the end
if (network_interfaces_root) {
- struct network_interface *e;
+ struct cgroup_network_interface *e;
for(e = network_interfaces_root; e->next ; e = e->next) ;
e->next = ifm;
}
@@ -233,8 +233,8 @@ int do_getifaddrs(int update_every, usec_t dt) {
RRDSET_TYPE_AREA
);
- rd_in = rrddim_add(st, "InOctets", "received", 8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st, "OutOctets", "sent", -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -270,8 +270,8 @@ int do_getifaddrs(int update_every, usec_t dt) {
RRDSET_TYPE_AREA
);
- rd_in = rrddim_add(st, "received", NULL, 8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
- rd_out = rrddim_add(st, "sent", NULL, -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -288,7 +288,7 @@ int do_getifaddrs(int update_every, usec_t dt) {
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
- struct network_interface *ifm = get_network_interface(ifa->ifa_name);
+ struct cgroup_network_interface *ifm = get_network_interface(ifa->ifa_name);
ifm->updated = 1;
network_interfaces_found++;
@@ -338,10 +338,8 @@ int do_getifaddrs(int update_every, usec_t dt) {
RRDSET_TYPE_AREA
);
- ifm->rd_bandwidth_in = rrddim_add(ifm->st_bandwidth, "received", NULL, 8, KILO_FACTOR,
- RRD_ALGORITHM_INCREMENTAL);
- ifm->rd_bandwidth_out = rrddim_add(ifm->st_bandwidth, "sent", NULL, -8, KILO_FACTOR,
- RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_bandwidth_in = rrddim_add(ifm->st_bandwidth, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_bandwidth_out = rrddim_add(ifm->st_bandwidth, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(ifm->st_bandwidth);
diff --git a/src/freebsd_sysctl.c b/src/freebsd_sysctl.c
index d2f0eaa8..a87b872d 100644
--- a/src/freebsd_sysctl.c
+++ b/src/freebsd_sysctl.c
@@ -373,6 +373,76 @@ int do_kern_cp_times(int update_every, usec_t dt) {
}
// --------------------------------------------------------------------------------------------------------------------
+// dev.cpu.temperature
+
+int do_dev_cpu_temperature(int update_every, usec_t dt) {
+ (void)dt;
+
+ int i;
+ static int *mib = NULL;
+ static int *pcpu_temperature = NULL;
+ static int old_number_of_cpus = 0;
+ char char_mib[MAX_INT_DIGITS + 21];
+ char char_rd[MAX_INT_DIGITS + 9];
+
+ if (unlikely(number_of_cpus != old_number_of_cpus)) {
+ pcpu_temperature = reallocz(pcpu_temperature, sizeof(int) * number_of_cpus);
+ mib = reallocz(mib, sizeof(int) * number_of_cpus * 4);
+ if (unlikely(number_of_cpus > old_number_of_cpus))
+ memset(&mib[old_number_of_cpus * 4], 0, sizeof(RRDDIM) * (number_of_cpus - old_number_of_cpus));
+ }
+ for (i = 0; i < number_of_cpus; i++) {
+ if (unlikely(!(mib[i * 4])))
+ sprintf(char_mib, "dev.cpu.%d.temperature", i);
+ if (unlikely(getsysctl_simple(char_mib, &mib[i * 4], 4, &pcpu_temperature[i], sizeof(int)))) {
+ error("DISABLED: cpu.temperature chart");
+ error("DISABLED: dev.cpu.temperature module");
+ return 1;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ static RRDSET *st;
+ static RRDDIM **rd_pcpu_temperature;
+
+ if (unlikely(number_of_cpus != old_number_of_cpus)) {
+ rd_pcpu_temperature = reallocz(rd_pcpu_temperature, sizeof(RRDDIM) * number_of_cpus);
+ if (unlikely(number_of_cpus > old_number_of_cpus))
+ memset(&rd_pcpu_temperature[old_number_of_cpus], 0, sizeof(RRDDIM) * (number_of_cpus - old_number_of_cpus));
+ }
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("cpu",
+ "temperature",
+ NULL,
+ "temperature",
+ "cpu.temperatute",
+ "Core temperature",
+ "degree",
+ 1050,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+ } else rrdset_next(st);
+
+ for (i = 0; i < number_of_cpus; i++) {
+ if (unlikely(!rd_pcpu_temperature[i])) {
+ sprintf(char_rd, "cpu%d.temp", i);
+ rd_pcpu_temperature[i] = rrddim_add(st, char_rd, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(st, rd_pcpu_temperature[i], (collected_number) ((double)pcpu_temperature[i] / 10 - 273.15));
+ }
+
+ rrdset_done(st);
+
+ old_number_of_cpus = number_of_cpus;
+
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
// hw.intrcnt
int do_hw_intcnt(int update_every, usec_t dt) {
@@ -1985,7 +2055,7 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) {
static RRDDIM *rd_in_reps = NULL, *rd_out_reps = NULL, *rd_in = NULL, *rd_out = NULL;
if (unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
+ st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messages",
"packets/s", 2604, update_every, RRDSET_TYPE_LINE);
rd_in_reps = rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
diff --git a/src/freeipmi_plugin.c b/src/freeipmi_plugin.c
index 146268a5..42a1ac01 100644
--- a/src/freeipmi_plugin.c
+++ b/src/freeipmi_plugin.c
@@ -1433,7 +1433,7 @@ int main (int argc, char **argv) {
continue;
}
}
- else if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
+ else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
printf("freeipmi.plugin %s\n", VERSION);
exit(0);
}
diff --git a/src/global_statistics.c b/src/global_statistics.c
index 8575061a..88688908 100644
--- a/src/global_statistics.c
+++ b/src/global_statistics.c
@@ -199,8 +199,8 @@ void global_statistics_charts(void) {
stbytes = rrdset_create_localhost("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic"
, "kilobits/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(stbytes, "in", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(stbytes, "out", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stbytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stbytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stbytes);
rrddim_set(stbytes, "in", (collected_number) gs.bytes_received);
diff --git a/src/health.c b/src/health.c
index cc470f81..136a1ecd 100644
--- a/src/health.c
+++ b/src/health.c
@@ -204,14 +204,13 @@ static inline void health_process_notifications(RRDHOST *host, ALARM_ENTRY *ae)
}
static inline void health_alarm_log_process(RRDHOST *host) {
- static uint32_t stop_at_id = 0;
uint32_t first_waiting = (host->health_log.alarms)?host->health_log.alarms->unique_id:0;
time_t now = now_realtime_sec();
netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *ae;
- for(ae = host->health_log.alarms; ae && ae->unique_id >= stop_at_id ; ae = ae->next) {
+ for(ae = host->health_log.alarms; ae && ae->unique_id >= host->health_last_processed_id ; ae = ae->next) {
if(unlikely(
!(ae->flags & HEALTH_ENTRY_FLAG_PROCESSED) &&
!(ae->flags & HEALTH_ENTRY_FLAG_UPDATED)
@@ -226,7 +225,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
}
// remember this for the next iteration
- stop_at_id = first_waiting;
+ host->health_last_processed_id = first_waiting;
netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
@@ -323,6 +322,23 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
return 1;
}
+static inline int check_if_resumed_from_suspention(void) {
+ static usec_t last_realtime = 0, last_monotonic = 0;
+ usec_t realtime = now_realtime_usec(), monotonic = now_monotonic_usec();
+ int ret = 0;
+
+ // detect if monotonic and realtime have twice the difference
+ // in which case we assume the system was just waken from hibernation
+
+ if(last_realtime && last_monotonic && realtime - last_realtime > 2 * (monotonic - last_monotonic))
+ ret = 1;
+
+ last_realtime = realtime;
+ last_monotonic = monotonic;
+
+ return ret;
+}
+
void *health_main(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
@@ -339,11 +355,8 @@ void *health_main(void *ptr) {
BUFFER *wb = buffer_create(100);
- time_t now = now_realtime_sec();
- time_t now_boottime = now_boottime_sec();
- time_t last_now = now;
- time_t last_now_boottime = now_boottime;
- time_t hibernation_delay = config_get_number(CONFIG_SECTION_HEALTH, "postpone alarms during hibernation for seconds", 60);
+ time_t now = now_realtime_sec();
+ time_t hibernation_delay = config_get_number(CONFIG_SECTION_HEALTH, "postpone alarms during hibernation for seconds", 60);
unsigned int loop = 0;
while(!netdata_exit) {
@@ -354,21 +367,14 @@ void *health_main(void *ptr) {
time_t next_run = now + min_run_every;
RRDCALC *rc;
- // detect if boottime and realtime have twice the difference
- // in which case we assume the system was just waken from hibernation
- if(unlikely(now - last_now > 2 * (now_boottime - last_now_boottime))) {
+ if(unlikely(check_if_resumed_from_suspention())) {
apply_hibernation_delay = 1;
- info("Postponing alarm checks for %ld seconds, due to boottime discrepancy (realtime dt: %ld, boottime dt: %ld)."
+ info("Postponing alarm checks for %ld seconds, because it seems that the system was just resumed from suspension."
, hibernation_delay
- , (long)(now - last_now)
- , (long)(now_boottime - last_now_boottime)
);
}
- last_now = now;
- last_now_boottime = now_boottime;
-
if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
error("Cannot set pthread cancel state to DISABLE.");
@@ -381,7 +387,7 @@ void *health_main(void *ptr) {
if(unlikely(apply_hibernation_delay)) {
- info("Postponing alarm checks for %ld seconds, on host '%s'."
+ info("Postponing health checks for %ld seconds, on host '%s'."
, hibernation_delay
, host->hostname
);
@@ -389,8 +395,13 @@ void *health_main(void *ptr) {
host->health_delay_up_to = now + hibernation_delay;
}
- if(unlikely(!host->health_enabled || now < host->health_delay_up_to))
- continue;
+ if(unlikely(host->health_delay_up_to)) {
+ if(unlikely(now < host->health_delay_up_to))
+ continue;
+
+ info("Resuming health checks on host '%s'.", host->hostname);
+ host->health_delay_up_to = 0;
+ }
rrdhost_rdlock(host);
@@ -726,8 +737,6 @@ void *health_main(void *ptr) {
else
debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration now", loop);
- now_boottime = now_boottime_sec();
-
} // forever
buffer_free(wb);
diff --git a/src/health_config.c b/src/health_config.c
index b4655dc7..2ead82ef 100644
--- a/src/health_config.c
+++ b/src/health_config.c
@@ -6,6 +6,8 @@
#define HEALTH_ALARM_KEY "alarm"
#define HEALTH_TEMPLATE_KEY "template"
#define HEALTH_ON_KEY "on"
+#define HEALTH_HOST_KEY "hosts"
+#define HEALTH_OS_KEY "os"
#define HEALTH_FAMILIES_KEY "families"
#define HEALTH_LOOKUP_KEY "lookup"
#define HEALTH_CALC_KEY "calc"
@@ -88,7 +90,10 @@ static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCAL
RRDCALCTEMPLATE *t, *last = NULL;
for (t = host->templates; t ; last = t, t = t->next) {
- if(unlikely(t->hash_name == rt->hash_name && !strcmp(t->name, rt->name))) {
+ if(unlikely(t->hash_name == rt->hash_name
+ && !strcmp(t->name, rt->name)
+ && !strcmp(t->family_match?t->family_match:"*", rt->family_match?rt->family_match:"*")
+ )) {
error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
return 0;
}
@@ -400,7 +405,9 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
static uint32_t
hash_alarm = 0,
hash_template = 0,
+ hash_os = 0,
hash_on = 0,
+ hash_host = 0,
hash_families = 0,
hash_calc = 0,
hash_green = 0,
@@ -422,6 +429,8 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
hash_on = simple_uhash(HEALTH_ON_KEY);
+ hash_os = simple_uhash(HEALTH_OS_KEY);
+ hash_host = simple_uhash(HEALTH_HOST_KEY);
hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
hash_calc = simple_uhash(HEALTH_CALC_KEY);
hash_lookup = simple_uhash(HEALTH_LOOKUP_KEY);
@@ -448,6 +457,7 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
RRDCALC *rc = NULL;
RRDCALCTEMPLATE *rt = NULL;
+ int ignore_this = 0;
size_t line = 0, append = 0;
char *s;
while((s = fgets(&buffer[append], (int)(HEALTH_CONF_MAX_LINE - append), fp)) || append) {
@@ -494,11 +504,11 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
uint32_t hash = simple_uhash(key);
if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
- if(rc && !rrdcalc_add_alarm_from_config(host, rc))
+ if (rc && (ignore_this || !rrdcalc_add_alarm_from_config(host, rc)))
rrdcalc_free(host, rc);
if(rt) {
- if (!rrdcalctemplate_add_template_from_config(host, rt))
+ if (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt))
rrdcalctemplate_free(host, rt);
rt = NULL;
}
@@ -516,15 +526,17 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
if(rrdvar_fix_name(rc->name))
error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
+
+ ignore_this = 0;
}
else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
if(rc) {
- if(!rrdcalc_add_alarm_from_config(host, rc))
+ if(ignore_this || !rrdcalc_add_alarm_from_config(host, rc))
rrdcalc_free(host, rc);
rc = NULL;
}
- if(rt && !rrdcalctemplate_add_template_from_config(host, rt))
+ if(rt && (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt)))
rrdcalctemplate_free(host, rt);
rt = callocz(1, sizeof(RRDCALCTEMPLATE));
@@ -537,6 +549,40 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
if(rrdvar_fix_name(rt->name))
error("Health configuration renamed template '%s' to '%s'", value, rt->name);
+
+ ignore_this = 0;
+ }
+ else if(hash == hash_os && !strcasecmp(key, HEALTH_OS_KEY)) {
+ char *os_match = value;
+ SIMPLE_PATTERN *os_pattern = simple_pattern_create(os_match, SIMPLE_PATTERN_EXACT);
+
+ if(!simple_pattern_matches(os_pattern, host->os)) {
+ if(rc)
+ debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s/%s: host O/S does not match '%s'", host->hostname, rc->name, line, path, filename, os_match);
+
+ if(rt)
+ debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s/%s: host O/S does not match '%s'", host->hostname, rt->name, line, path, filename, os_match);
+
+ ignore_this = 1;
+ }
+
+ simple_pattern_free(os_pattern);
+ }
+ else if(hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) {
+ char *host_match = value;
+ SIMPLE_PATTERN *host_pattern = simple_pattern_create(host_match, SIMPLE_PATTERN_EXACT);
+
+ if(!simple_pattern_matches(host_pattern, host->hostname)) {
+ if(rc)
+ debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s/%s: hostname does not match '%s'", host->hostname, rc->name, line, path, filename, host_match);
+
+ if(rt)
+ debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s/%s: hostname does not match '%s'", host->hostname, rt->name, line, path, filename, host_match);
+
+ ignore_this = 1;
+ }
+
+ simple_pattern_free(host_pattern);
}
else if(rc) {
if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
@@ -786,10 +832,10 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) {
}
}
- if(rc && !rrdcalc_add_alarm_from_config(host, rc))
+ if(rc && (ignore_this || !rrdcalc_add_alarm_from_config(host, rc)))
rrdcalc_free(host, rc);
- if(rt && !rrdcalctemplate_add_template_from_config(host, rt))
+ if(rt && (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt)))
rrdcalctemplate_free(host, rt);
fclose(fp);
diff --git a/src/health_log.c b/src/health_log.c
index 95abcfe5..9881d35d 100644
--- a/src/health_log.c
+++ b/src/health_log.c
@@ -121,8 +121,6 @@ inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
}
inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename) {
- static uint32_t max_unique_id = 0, max_alarm_id = 0;
-
errno = 0;
char *s, *buf = mallocz(65536 + 1);
@@ -271,7 +269,7 @@ inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filena
ae->new_value = str2l(pointers[25]);
ae->old_value = str2l(pointers[26]);
- static char value_string[100 + 1];
+ char value_string[100 + 1];
freez(ae->old_value_string);
freez(ae->new_value_string);
ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
@@ -285,11 +283,11 @@ inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filena
}
else updated++;
- if(unlikely(ae->unique_id > max_unique_id))
- max_unique_id = ae->unique_id;
+ if(unlikely(ae->unique_id > host->health_max_unique_id))
+ host->health_max_unique_id = ae->unique_id;
- if(unlikely(ae->alarm_id >= max_alarm_id))
- max_alarm_id = ae->alarm_id;
+ if(unlikely(ae->alarm_id >= host->health_max_alarm_id))
+ host->health_max_alarm_id = ae->alarm_id;
}
else {
error("HEALTH [%s]: line %zu of file '%s' is invalid (unrecognized entry type '%s').", host->hostname, line, filename, pointers[0]);
@@ -301,11 +299,11 @@ inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filena
freez(buf);
- if(!max_unique_id) max_unique_id = (uint32_t)now_realtime_sec();
- if(!max_alarm_id) max_alarm_id = (uint32_t)now_realtime_sec();
+ if(!host->health_max_unique_id) host->health_max_unique_id = (uint32_t)now_realtime_sec();
+ if(!host->health_max_alarm_id) host->health_max_alarm_id = (uint32_t)now_realtime_sec();
- host->health_log.next_log_id = max_unique_id + 1;
- host->health_log.next_alarm_id = max_alarm_id + 1;
+ host->health_log.next_log_id = host->health_max_unique_id + 1;
+ host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
debug(D_HEALTH, "HEALTH [%s]: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", host->hostname, filename, loaded, updated, errored, duplicate);
return loaded;
@@ -388,7 +386,7 @@ inline void health_alarm_log(
ae->old_value = old_value;
ae->new_value = new_value;
- static char value_string[100 + 1];
+ char value_string[100 + 1];
ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
diff --git a/src/inlined.h b/src/inlined.h
index f1812ba1..9ab2dca7 100644
--- a/src/inlined.h
+++ b/src/inlined.h
@@ -244,26 +244,48 @@ static inline char *strncpyz(char *dst, const char *src, size_t n) {
return p;
}
-static inline int read_single_number_file(const char *filename, unsigned long long *result) {
- char buffer[30 + 1];
-
+static inline int read_file(const char *filename, char *buffer, size_t size) {
int fd = open(filename, O_RDONLY, 0666);
- if(unlikely(fd == -1)) {
- *result = 0;
+ if(unlikely(fd == -1))
return 1;
- }
- ssize_t r = read(fd, buffer, 30);
+ ssize_t r = read(fd, buffer, size);
if(unlikely(r == -1)) {
- *result = 0;
close(fd);
return 2;
}
+ buffer[r] = '\0';
close(fd);
+ return 0;
+}
+
+static inline int read_single_number_file(const char *filename, unsigned long long *result) {
+ char buffer[30 + 1];
+
+ int ret = read_file(filename, buffer, 30);
+ if(unlikely(ret)) {
+ *result = 0;
+ return ret;
+ }
+
buffer[30] = '\0';
*result = str2ull(buffer);
return 0;
}
+static inline int read_single_signed_number_file(const char *filename, long long *result) {
+ char buffer[30 + 1];
+
+ int ret = read_file(filename, buffer, 30);
+ if(unlikely(ret)) {
+ *result = 0;
+ return ret;
+ }
+
+ buffer[30] = '\0';
+ *result = atoll(buffer);
+ return 0;
+}
+
#endif //NETDATA_INLINED_H
diff --git a/src/macos_fw.c b/src/macos_fw.c
index c47da52f..fa103e11 100644
--- a/src/macos_fw.c
+++ b/src/macos_fw.c
@@ -420,8 +420,8 @@ int do_macos_iokit(int update_every, usec_t dt) {
st = rrdset_create_localhost("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth"
, "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/macos_sysctl.c b/src/macos_sysctl.c
index af229fb6..843aceae 100644
--- a/src/macos_sysctl.c
+++ b/src/macos_sysctl.c
@@ -299,8 +299,8 @@ int do_macos_sysctl(int update_every, usec_t dt) {
st = rrdset_create_localhost("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s"
, 500, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -588,7 +588,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
if (likely(do_icmpmsg)) {
st = rrdset_find_localhost("ipv4.icmpmsg");
if (unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages"
+ st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messages"
, "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
diff --git a/src/main.c b/src/main.c
index bf5d787a..89ca828a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -172,7 +172,7 @@ void kill_childs()
// it is detached
// pthread_join(w->thread, NULL);
- w->obsolete = 1;
+ WEB_CLIENT_IS_OBSOLETE(w);
}
int i;
@@ -635,6 +635,7 @@ int main(int argc, char **argv) {
char* debug_flags_string = "debug_flags=";
if(strcmp(optarg, "unittest") == 0) {
+ if(unit_test_buffer()) exit(1);
if(unit_test_str2ld()) exit(1);
//default_rrd_update_every = 1;
//default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
@@ -854,47 +855,10 @@ int main(int argc, char **argv) {
// block signals while initializing threads.
// this causes the threads to block signals.
- sigset_t sigset;
- sigfillset(&sigset);
- if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
- error("Could not block signals for threads");
+ signals_block();
- // Catch signals which we want to use
- struct sigaction sa;
- sa.sa_flags = 0;
-
- // ingore all signals while we run in a signal handler
- sigfillset(&sa.sa_mask);
-
- // INFO: If we add signals here we have to unblock them
- // at popen.c when running a external plugin.
-
- // Ignore SIGPIPE completely.
- sa.sa_handler = SIG_IGN;
- if(sigaction(SIGPIPE, &sa, NULL) == -1)
- error("Failed to change signal handler for SIGPIPE");
-
- sa.sa_handler = sig_handler_exit;
- if(sigaction(SIGINT, &sa, NULL) == -1)
- error("Failed to change signal handler for SIGINT");
-
- sa.sa_handler = sig_handler_exit;
- if(sigaction(SIGTERM, &sa, NULL) == -1)
- error("Failed to change signal handler for SIGTERM");
-
- sa.sa_handler = sig_handler_logrotate;
- if(sigaction(SIGHUP, &sa, NULL) == -1)
- error("Failed to change signal handler for SIGHUP");
-
- // save database on SIGUSR1
- sa.sa_handler = sig_handler_save;
- if(sigaction(SIGUSR1, &sa, NULL) == -1)
- error("Failed to change signal handler for SIGUSR1");
-
- // reload health configuration on SIGUSR2
- sa.sa_handler = sig_handler_reload_health;
- if(sigaction(SIGUSR2, &sa, NULL) == -1)
- error("Failed to change signal handler for SIGUSR2");
+ // setup the signals we want to use
+ signals_init();
// --------------------------------------------------------------------
@@ -939,11 +903,6 @@ int main(int argc, char **argv) {
user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:"");
}
- // IMPORTANT: these have to run once, while single threaded
- web_files_uid(); // IMPORTANT: web_files_uid() before web_files_gid()
- web_files_gid();
-
-
// --------------------------------------------------------------------
// create the listening sockets
@@ -974,6 +933,11 @@ int main(int argc, char **argv) {
info("netdata started on pid %d.", getpid());
+ // IMPORTANT: these have to run once, while single threaded
+ // but after we have switched user
+ web_files_uid();
+ web_files_gid();
+
// ------------------------------------------------------------------------
// set default pthread stack size - after we have forked
@@ -1025,21 +989,12 @@ int main(int argc, char **argv) {
// ------------------------------------------------------------------------
- // block signals while initializing threads.
- sigset_t sigset;
- sigfillset(&sigset);
+ // unblock signals
- if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
- error("Could not unblock signals for threads");
- }
+ signals_unblock();
- // Handle flags set in the signal handler.
- while(1) {
- pause();
- if(netdata_exit) {
- debug(D_EXIT, "Exit main loop of netdata.");
- netdata_cleanup_and_exit(0);
- exit(0);
- }
- }
+ // ------------------------------------------------------------------------
+ // Handle signals
+
+ signals_handle();
}
diff --git a/src/plugin_freebsd.c b/src/plugin_freebsd.c
index 020fdb41..c09b28a5 100644
--- a/src/plugin_freebsd.c
+++ b/src/plugin_freebsd.c
@@ -36,6 +36,7 @@ static struct freebsd_module {
// CPU metrics
{ .name = "kern.cp_times", .dim = "cp_times", .enabled = 1, .func = do_kern_cp_times },
+ { .name = "dev.cpu.temperature", .dim = "cpu_temperature", .enabled = 1, .func = do_dev_cpu_temperature },
// disk metrics
{ .name = "kern.devstat", .dim = "kern_devstat", .enabled = 1, .func = do_kern_devstat },
diff --git a/src/plugin_freebsd.h b/src/plugin_freebsd.h
index 541bf852..78fe33d7 100644
--- a/src/plugin_freebsd.h
+++ b/src/plugin_freebsd.h
@@ -17,6 +17,7 @@ extern int do_vm_loadavg(int update_every, usec_t dt);
extern int do_vm_vmtotal(int update_every, usec_t dt);
extern int do_kern_cp_time(int update_every, usec_t dt);
extern int do_kern_cp_times(int update_every, usec_t dt);
+extern int do_dev_cpu_temperature(int update_every, usec_t dt);
extern int do_hw_intcnt(int update_every, usec_t dt);
extern int do_vm_stats_sys_v_intr(int update_every, usec_t dt);
extern int do_vm_stats_sys_v_soft(int update_every, usec_t dt);
diff --git a/src/plugin_proc.h b/src/plugin_proc.h
index 688b23de..72cfc6aa 100644
--- a/src/plugin_proc.h
+++ b/src/plugin_proc.h
@@ -32,4 +32,8 @@ extern int get_numa_node_count(void);
// metrics that need to be shared among data collectors
extern unsigned long long tcpext_TCPSynRetrans;
+// netdev renames
+extern void netdev_rename_device_add(const char *host_device, const char *container_device, const char *container_name);
+extern void netdev_rename_device_del(const char *host_device);
+
#endif /* NETDATA_PLUGIN_PROC_H */
diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c
index 750086a2..52c1f5ae 100644
--- a/src/plugin_proc_diskspace.c
+++ b/src/plugin_proc_diskspace.c
@@ -6,6 +6,7 @@
static struct mountinfo *disk_mountinfo_root = NULL;
static int check_for_new_mountpoints_every = 15;
+static int cleanup_mount_points = 1;
static inline void mountinfo_reload(int force) {
static time_t last_loaded = 0;
@@ -58,7 +59,7 @@ int mount_point_cleanup(void *entry, void *data) {
return 0;
}
- if(likely(mp->collected)) {
+ if(likely(cleanup_mount_points && mp->collected)) {
mp->collected = 0;
mp->updated = 0;
mp->shown_error = 0;
@@ -328,6 +329,8 @@ void *proc_diskspace_main(void *ptr) {
int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1);
+ cleanup_mount_points = config_get_boolean(CONFIG_SECTION_DISKSPACE, "remove charts of unmounted disks" , cleanup_mount_points);
+
int update_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "update every", localhost->rrd_update_every);
if(update_every < localhost->rrd_update_every)
update_every = localhost->rrd_update_every;
@@ -370,7 +373,8 @@ void *proc_diskspace_main(void *ptr) {
if(unlikely(netdata_exit)) break;
- dictionary_get_all(dict_mountpoints, mount_point_cleanup, NULL);
+ if(dict_mountpoints)
+ dictionary_get_all(dict_mountpoints, mount_point_cleanup, NULL);
if(vdo_cpu_netdata) {
static RRDSET *stcpu_thread = NULL, *st_duration = NULL;
diff --git a/src/plugin_tc.c b/src/plugin_tc.c
index 6bf5782a..c928e61b 100644
--- a/src/plugin_tc.c
+++ b/src/plugin_tc.c
@@ -392,7 +392,7 @@ static inline void tc_device_commit(struct tc_device *d) {
if(unlikely(!c->render)) continue;
if(unlikely(!c->rd_bytes))
- c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
else if(unlikely(c->name_updated))
rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
diff --git a/src/plugins_d.c b/src/plugins_d.c
index 9eb10277..42433b55 100644
--- a/src/plugins_d.c
+++ b/src/plugins_d.c
@@ -217,47 +217,63 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
st = NULL;
}
else if(likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) {
- int noname = 0;
st = NULL;
- if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
- noname = 1;
+ char *type = words[1];
+ char *name = words[2];
+ char *title = words[3];
+ char *units = words[4];
+ char *family = words[5];
+ char *context = words[6];
+ char *chart = words[7];
+ char *priority_s = words[8];
+ char *update_every_s = words[9];
+ char *options = words[10];
- char *type = words[1];
+ // parse the id from type
char *id = NULL;
- if(likely(type)) {
- id = strchr(type, '.');
- if(likely(id)) { *id = '\0'; id++; }
+ if(likely(type && (id = strchr(type, '.')))) {
+ *id = '\0';
+ id++;
}
- char *name = words[2];
- char *title = words[3];
- char *units = words[4];
- char *family = words[5];
- char *context = words[6];
- char *chart = words[7];
- char *priority_s = words[8];
- char *update_every_s = words[9];
- char *options = words[10];
+ // make sure we have the required variables
if(unlikely(!type || !*type || !id || !*id)) {
error("PLUGINSD: '%s' is requesting a CHART, without a type.id, on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
enabled = 0;
break;
}
+ // parse the name, and make sure it does not include 'type.'
+ if(unlikely(name && *name)) {
+ // when data are coming from slaves
+ // name will be type.name
+ // so we have to remove 'type.' from name too
+ size_t len = strlen(type);
+ if(strncmp(type, name, len) == 0 && name[len] == '.')
+ name = &name[len + 1];
+
+ // if the name is the same with the id,
+ // or is just 'NULL', clear it.
+ if(unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0))
+ name = NULL;
+ }
+
int priority = 1000;
- if(likely(priority_s)) priority = str2i(priority_s);
+ if(likely(priority_s && *priority_s)) priority = str2i(priority_s);
int update_every = cd->update_every;
- if(likely(update_every_s)) update_every = str2i(update_every_s);
+ if(likely(update_every_s && *update_every_s)) update_every = str2i(update_every_s);
if(unlikely(!update_every)) update_every = cd->update_every;
RRDSET_TYPE chart_type = RRDSET_TYPE_LINE;
if(unlikely(chart)) chart_type = rrdset_type_id(chart);
- if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
- if(unlikely(!family || !*family)) family = NULL;
- if(unlikely(!context || !*context)) context = NULL;
+ if(unlikely(name && !*name)) name = NULL;
+ if(unlikely(family && !*family)) family = NULL;
+ if(unlikely(context && !*context)) context = NULL;
+ if(unlikely(!title)) title = "";
+ if(unlikely(!units)) units = "unknown";
st = rrdset_find_bytype(host, type, id);
if(unlikely(!st)) {
diff --git a/src/popen.c b/src/popen.c
index 8448b731..27be6177 100644
--- a/src/popen.c
+++ b/src/popen.c
@@ -105,38 +105,8 @@ FILE *mypopen(const char *command, pid_t *pidptr)
#endif
// reset all signals
- {
- sigset_t sigset;
- sigfillset(&sigset);
-
- if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid());
-
- // We only need to reset ignored signals.
- // Signals with signal handlers are reset by default.
- struct sigaction sa;
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = 0;
-
- if(sigaction(SIGINT, &sa, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGINT.", command, getpid());
-
- if(sigaction(SIGTERM, &sa, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGTERM.", command, getpid());
-
- if(sigaction(SIGPIPE, &sa, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid());
-
- if(sigaction(SIGHUP, &sa, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGHUP.", command, getpid());
-
- if(sigaction(SIGUSR1, &sa, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid());
-
- if(sigaction(SIGUSR2, &sa, NULL) == -1)
- error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR2.", command, getpid());
- }
+ signals_unblock();
+ signals_reset();
debug(D_CHILDS, "executing command: '%s' on pid %d.", command, getpid());
execl("/bin/sh", "sh", "-c", command, NULL);
diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c
index d3fed5a6..4a32ec94 100644
--- a/src/proc_diskstats.c
+++ b/src/proc_diskstats.c
@@ -273,7 +273,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
global_do_qops = CONFIG_BOOLEAN_AUTO,
global_do_util = CONFIG_BOOLEAN_AUTO,
global_do_backlog = CONFIG_BOOLEAN_AUTO,
- globals_initialized = 0;
+ globals_initialized = 0,
+ global_cleanup_removed_disks = 1;
if(unlikely(!globals_initialized)) {
globals_initialized = 1;
@@ -291,6 +292,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
global_do_util = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "utilization percentage for all disks", global_do_util);
global_do_backlog = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "backlog for all disks", global_do_backlog);
+ global_cleanup_removed_disks = config_get_boolean(CONFIG_SECTION_DISKSTATS, "remove charts of removed disks" , global_cleanup_removed_disks);
+
char buffer[FILENAME_MAX + 1];
snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s");
@@ -806,7 +809,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
struct disk *d = disk_root, *last = NULL;
while(d) {
- if(unlikely(!d->updated)) {
+ if(unlikely(global_cleanup_removed_disks && !d->updated)) {
struct disk *t = d;
rrdset_obsolete_and_pointer_null(d->st_avgsz);
diff --git a/src/proc_interrupts.c b/src/proc_interrupts.c
index 082e1f57..b9f3941d 100644
--- a/src/proc_interrupts.c
+++ b/src/proc_interrupts.c
@@ -18,10 +18,10 @@ struct interrupt {
// since each interrupt is variable in size
// we use this to calculate its record size
-#define recordsize(cpus) (sizeof(struct interrupt) + (cpus * sizeof(struct cpu_interrupt)))
+#define recordsize(cpus) (sizeof(struct interrupt) + ((cpus) * sizeof(struct cpu_interrupt)))
// given a base, get a pointer to each record
-#define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
+#define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[(line) * recordsize(cpus)])
static inline struct interrupt *get_interrupts_array(size_t lines, int cpus) {
static struct interrupt *irrs = NULL;
@@ -142,68 +142,106 @@ int do_proc_interrupts(int update_every, usec_t dt) {
irr->used = 1;
}
- RRDSET *st;
-
// --------------------------------------------------------------------
- st = rrdset_find_bytype_localhost("system", "interrupts");
- if(unlikely(!st)) st = rrdset_create_localhost("system", "interrupts", NULL, "interrupts", NULL, "System interrupts"
- , "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
- else rrdset_next(st);
+ static RRDSET *st_system_interrupts = NULL;
+ if(unlikely(!st_system_interrupts))
+ st_system_interrupts = rrdset_create_localhost(
+ "system"
+ , "interrupts"
+ , NULL
+ , "interrupts"
+ , NULL
+ , "System interrupts"
+ , "interrupts/s"
+ , 1000
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+ else
+ rrdset_next(st_system_interrupts);
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
if(unlikely(!irr->used)) continue;
+
// some interrupt may have changed without changing the total number of lines
// if the same number of interrupts have been added and removed between two
// calls of this function.
if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
- irr->rd = rrddim_find(st, irr->id);
+ irr->rd = rrddim_find(st_system_interrupts, irr->id);
+
if(unlikely(!irr->rd))
- irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ irr->rd = rrddim_add(st_system_interrupts, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
- rrddim_set_name(st, irr->rd, irr->name);
+ rrddim_set_name(st_system_interrupts, irr->rd, irr->name);
// also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
if(likely(do_per_core)) {
int c;
- for (c = 0; c < cpus ;c++)
- irr->cpu[c].rd = NULL;
+ for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL;
}
}
- rrddim_set_by_pointer(st, irr->rd, irr->total);
+
+ rrddim_set_by_pointer(st_system_interrupts, irr->rd, irr->total);
}
- rrdset_done(st);
+
+ rrdset_done(st_system_interrupts);
+
+ // --------------------------------------------------------------------
if(likely(do_per_core)) {
+ static RRDSET **core_st = NULL;
+ static int old_cpus = 0;
+
+ if(old_cpus < cpus) {
+ core_st = reallocz(core_st, sizeof(RRDSET *) * cpus);
+ memset(&core_st[old_cpus], 0, sizeof(RRDSET *) * (cpus - old_cpus));
+ old_cpus = cpus;
+ }
+
int c;
for(c = 0; c < cpus ;c++) {
- char id[50+1];
- snprintfz(id, 50, "cpu%d_interrupts", c);
+ if(unlikely(!core_st[c])) {
+ char id[50+1];
+ snprintfz(id, 50, "cpu%d_interrupts", c);
- st = rrdset_find_bytype_localhost("cpu", id);
- if(unlikely(!st)) {
char title[100+1];
snprintfz(title, 100, "CPU%d Interrupts", c);
- st = rrdset_create_localhost("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s",
- 1100 + c, update_every, RRDSET_TYPE_STACKED);
+ core_st[c] = rrdset_create_localhost(
+ "cpu"
+ , id
+ , NULL
+ , "interrupts"
+ , "cpu.interrupts"
+ , title
+ , "interrupts/s"
+ , 1100 + c
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
- else rrdset_next(st);
+ else rrdset_next(core_st[c]);
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
+
if(unlikely(!irr->used)) continue;
+
if(unlikely(!irr->cpu[c].rd)) {
- irr->cpu[c].rd = rrddim_find(st, irr->id);
+ irr->cpu[c].rd = rrddim_find(core_st[c], irr->id);
+
if(unlikely(!irr->cpu[c].rd))
- irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
- rrddim_set_name(st, irr->cpu[c].rd, irr->name);
+ rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name);
}
- rrddim_set_by_pointer(st, irr->cpu[c].rd, irr->cpu[c].value);
+
+ rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
}
- rrdset_done(st);
+
+ rrdset_done(core_st[c]);
}
}
diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c
index a48801b3..54fc545a 100644
--- a/src/proc_loadavg.c
+++ b/src/proc_loadavg.c
@@ -7,7 +7,6 @@ int do_proc_loadavg(int update_every, usec_t dt) {
static procfile *ff = NULL;
static int do_loadavg = -1, do_all_processes = -1;
static usec_t next_loadavg_dt = 0;
- static RRDSET *load_chart = NULL, *processes_chart = NULL;
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
@@ -49,24 +48,33 @@ int do_proc_loadavg(int update_every, usec_t dt) {
if(next_loadavg_dt <= dt) {
if(likely(do_loadavg)) {
+ static RRDSET *load_chart = NULL;
+ static RRDDIM *rd_load1 = NULL, *rd_load5 = NULL, *rd_load15 = NULL;
+
if(unlikely(!load_chart)) {
- load_chart = rrdset_find_byname_localhost("system.load");
- if(unlikely(!load_chart)) {
- load_chart = rrdset_create_localhost("system", "load", NULL, "load", NULL, "System Load Average"
- , "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)
- ? MIN_LOADAVG_UPDATE_EVERY : update_every
- , RRDSET_TYPE_LINE);
- rrddim_add(load_chart, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(load_chart, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(load_chart, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
- }
+ load_chart = rrdset_create_localhost(
+ "system"
+ , "load"
+ , NULL
+ , "load"
+ , NULL
+ , "System Load Average"
+ , "load"
+ , 100
+ , (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_load1 = rrddim_add(load_chart, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rd_load5 = rrddim_add(load_chart, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rd_load15 = rrddim_add(load_chart, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(load_chart);
- rrddim_set(load_chart, "load1", (collected_number) (load1 * 1000));
- rrddim_set(load_chart, "load5", (collected_number) (load5 * 1000));
- rrddim_set(load_chart, "load15", (collected_number) (load15 * 1000));
+ rrddim_set_by_pointer(load_chart, rd_load1, (collected_number) (load1 * 1000));
+ rrddim_set_by_pointer(load_chart, rd_load5, (collected_number) (load5 * 1000));
+ rrddim_set_by_pointer(load_chart, rd_load15, (collected_number) (load15 * 1000));
rrdset_done(load_chart);
next_loadavg_dt = load_chart->update_every * USEC_PER_SEC;
@@ -78,18 +86,28 @@ int do_proc_loadavg(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_all_processes)) {
+ static RRDSET *processes_chart = NULL;
+ static RRDDIM *rd_active = NULL;
+
if(unlikely(!processes_chart)) {
- processes_chart = rrdset_find_byname_localhost("system.active_processes");
- if(unlikely(!processes_chart)) {
- processes_chart = rrdset_create_localhost("system", "active_processes", NULL, "processes", NULL
- , "System Active Processes", "processes", 750, update_every
- , RRDSET_TYPE_LINE);
- rrddim_add(processes_chart, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- }
+ processes_chart = rrdset_create_localhost(
+ "system"
+ , "active_processes"
+ , NULL
+ , "processes"
+ , NULL
+ , "System Active Processes"
+ , "processes"
+ , 750
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_active = rrddim_add(processes_chart, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(processes_chart);
- rrddim_set(processes_chart, "active", active_processes);
+ rrddim_set_by_pointer(processes_chart, rd_active, active_processes);
rrdset_done(processes_chart);
}
diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c
index 6b0219cc..152a6366 100644
--- a/src/proc_meminfo.c
+++ b/src/proc_meminfo.c
@@ -132,54 +132,79 @@ int do_proc_meminfo(int update_every, usec_t dt) {
procfile_lineword(ff, l, 1)))) break;
}
- RRDSET *st;
-
// --------------------------------------------------------------------
// http://stackoverflow.com/questions/3019748/how-to-reliably-measure-available-memory-in-linux
unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
if(do_ram) {
- st = rrdset_find_localhost("system.ram");
- if(!st) {
- st = rrdset_create_localhost("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every
- , RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "buffers", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_system_ram = NULL;
+ static RRDDIM *rd_free = NULL, *rd_used = NULL, *rd_cached = NULL, *rd_buffers = NULL;
+
+ if(unlikely(!st_system_ram)) {
+ st_system_ram = rrdset_create_localhost(
+ "system"
+ , "ram"
+ , NULL
+ , "ram"
+ , NULL
+ , "System RAM"
+ , "MB"
+ , 200
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_cached = rrddim_add(st_system_ram, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_buffers = rrddim_add(st_system_ram, "buffers", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_system_ram);
+
+ rrddim_set_by_pointer(st_system_ram, rd_free, MemFree);
+ rrddim_set_by_pointer(st_system_ram, rd_used, MemUsed);
+ rrddim_set_by_pointer(st_system_ram, rd_cached, Cached);
+ rrddim_set_by_pointer(st_system_ram, rd_buffers, Buffers);
- rrddim_set(st, "free", MemFree);
- rrddim_set(st, "used", MemUsed);
- rrddim_set(st, "cached", Cached);
- rrddim_set(st, "buffers", Buffers);
- rrdset_done(st);
+ rrdset_done(st_system_ram);
}
// --------------------------------------------------------------------
unsigned long long SwapUsed = SwapTotal - SwapFree;
- if(SwapTotal || SwapUsed || SwapFree || do_swap == CONFIG_BOOLEAN_YES) {
+ if(do_swap == CONFIG_BOOLEAN_YES || SwapTotal || SwapUsed || SwapFree) {
do_swap = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("system.swap");
- if(!st) {
- st = rrdset_create_localhost("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every
- , RRDSET_TYPE_STACKED);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_system_swap = NULL;
+ static RRDDIM *rd_free = NULL, *rd_used = NULL;
+
+ if(unlikely(!st_system_swap)) {
+ st_system_swap = rrdset_create_localhost(
+ "system"
+ , "swap"
+ , NULL
+ , "swap"
+ , NULL
+ , "System Swap"
+ , "MB"
+ , 201
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrdset_flag_set(st_system_swap, RRDSET_FLAG_DETAIL);
+
+ rd_free = rrddim_add(st_system_swap, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_used = rrddim_add(st_system_swap, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_system_swap);
- rrddim_set(st, "used", SwapUsed);
- rrddim_set(st, "free", SwapFree);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_system_swap, rd_used, SwapUsed);
+ rrddim_set_by_pointer(st_system_swap, rd_free, SwapFree);
+
+ rrdset_done(st_system_swap);
}
// --------------------------------------------------------------------
@@ -187,102 +212,171 @@ int do_proc_meminfo(int update_every, usec_t dt) {
if(arl_hwcorrupted->flags & ARL_ENTRY_FLAG_FOUND && (do_hwcorrupt == CONFIG_BOOLEAN_YES || (do_hwcorrupt == CONFIG_BOOLEAN_AUTO && HardwareCorrupted > 0))) {
do_hwcorrupt = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("mem.hwcorrupt");
- if(!st) {
- st = rrdset_create_localhost("mem", "hwcorrupt", NULL, "ecc", NULL, "Hardware Corrupted ECC", "MB", 9000
- , update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_mem_hwcorrupt = NULL;
+ static RRDDIM *rd_corrupted = NULL;
+
+ if(unlikely(!st_mem_hwcorrupt)) {
+ st_mem_hwcorrupt = rrdset_create_localhost(
+ "mem"
+ , "hwcorrupt"
+ , NULL
+ , "ecc"
+ , NULL
+ , "Corrupted Memory, detected by ECC"
+ , "MB"
+ , 9000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st_mem_hwcorrupt, RRDSET_FLAG_DETAIL);
+
+ rd_corrupted = rrddim_add(st_mem_hwcorrupt, "HardwareCorrupted", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_mem_hwcorrupt);
+
+ rrddim_set_by_pointer(st_mem_hwcorrupt, rd_corrupted, HardwareCorrupted);
- rrddim_set(st, "HardwareCorrupted", HardwareCorrupted);
- rrdset_done(st);
+ rrdset_done(st_mem_hwcorrupt);
}
// --------------------------------------------------------------------
if(do_committed) {
- st = rrdset_find_localhost("mem.committed");
- if(!st) {
- st = rrdset_create_localhost("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB"
- , 5000, update_every, RRDSET_TYPE_AREA);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_mem_committed = NULL;
+ static RRDDIM *rd_committed = NULL;
+
+ if(unlikely(!st_mem_committed)) {
+ st_mem_committed = rrdset_create_localhost(
+ "mem"
+ , "committed"
+ , NULL
+ , "system"
+ , NULL
+ , "Committed (Allocated) Memory"
+ , "MB"
+ , 5000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(st_mem_committed, RRDSET_FLAG_DETAIL);
+
+ rd_committed = rrddim_add(st_mem_committed, "Committed_AS", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_mem_committed);
+
+ rrddim_set_by_pointer(st_mem_committed, rd_committed, Committed_AS);
- rrddim_set(st, "Committed_AS", Committed_AS);
- rrdset_done(st);
+ rrdset_done(st_mem_committed);
}
// --------------------------------------------------------------------
if(do_writeback) {
- st = rrdset_find_localhost("mem.writeback");
- if(!st) {
- st = rrdset_create_localhost("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000
- , update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "Dirty", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "Writeback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "Bounce", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_mem_writeback = NULL;
+ static RRDDIM *rd_dirty = NULL, *rd_writeback = NULL, *rd_fusewriteback = NULL, *rd_nfs_writeback = NULL, *rd_bounce = NULL;
+
+ if(unlikely(!st_mem_writeback)) {
+ st_mem_writeback = rrdset_create_localhost(
+ "mem"
+ , "writeback"
+ , NULL
+ , "kernel"
+ , NULL
+ , "Writeback Memory"
+ , "MB"
+ , 4000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_mem_writeback, RRDSET_FLAG_DETAIL);
+
+ rd_dirty = rrddim_add(st_mem_writeback, "Dirty", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_writeback = rrddim_add(st_mem_writeback, "Writeback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_fusewriteback = rrddim_add(st_mem_writeback, "FuseWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_nfs_writeback = rrddim_add(st_mem_writeback, "NfsWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_bounce = rrddim_add(st_mem_writeback, "Bounce", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
-
- rrddim_set(st, "Dirty", Dirty);
- rrddim_set(st, "Writeback", Writeback);
- rrddim_set(st, "FuseWriteback", WritebackTmp);
- rrddim_set(st, "NfsWriteback", NFS_Unstable);
- rrddim_set(st, "Bounce", Bounce);
- rrdset_done(st);
+ else rrdset_next(st_mem_writeback);
+
+ rrddim_set_by_pointer(st_mem_writeback, rd_dirty, Dirty);
+ rrddim_set_by_pointer(st_mem_writeback, rd_writeback, Writeback);
+ rrddim_set_by_pointer(st_mem_writeback, rd_fusewriteback, WritebackTmp);
+ rrddim_set_by_pointer(st_mem_writeback, rd_nfs_writeback, NFS_Unstable);
+ rrddim_set_by_pointer(st_mem_writeback, rd_bounce, Bounce);
+
+ rrdset_done(st_mem_writeback);
}
// --------------------------------------------------------------------
if(do_kernel) {
- st = rrdset_find_localhost("mem.kernel");
- if(!st) {
- st = rrdset_create_localhost("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000
- , update_every, RRDSET_TYPE_STACKED);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "Slab", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "KernelStack", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "PageTables", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_mem_kernel = NULL;
+ static RRDDIM *rd_slab = NULL, *rd_kernelstack = NULL, *rd_pagetables = NULL, *rd_vmallocused = NULL;
+
+ if(unlikely(!st_mem_kernel)) {
+ st_mem_kernel = rrdset_create_localhost(
+ "mem"
+ , "kernel"
+ , NULL
+ , "kernel"
+ , NULL
+ , "Memory Used by Kernel"
+ , "MB"
+ , 6000
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrdset_flag_set(st_mem_kernel, RRDSET_FLAG_DETAIL);
+
+ rd_slab = rrddim_add(st_mem_kernel, "Slab", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_kernelstack = rrddim_add(st_mem_kernel, "KernelStack", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_pagetables = rrddim_add(st_mem_kernel, "PageTables", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_vmallocused = rrddim_add(st_mem_kernel, "VmallocUsed", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_mem_kernel);
+
+ rrddim_set_by_pointer(st_mem_kernel, rd_slab, Slab);
+ rrddim_set_by_pointer(st_mem_kernel, rd_kernelstack, KernelStack);
+ rrddim_set_by_pointer(st_mem_kernel, rd_pagetables, PageTables);
+ rrddim_set_by_pointer(st_mem_kernel, rd_vmallocused, VmallocUsed);
- rrddim_set(st, "KernelStack", KernelStack);
- rrddim_set(st, "Slab", Slab);
- rrddim_set(st, "PageTables", PageTables);
- rrddim_set(st, "VmallocUsed", VmallocUsed);
- rrdset_done(st);
+ rrdset_done(st_mem_kernel);
}
// --------------------------------------------------------------------
if(do_slab) {
- st = rrdset_find_localhost("mem.slab");
- if(!st) {
- st = rrdset_create_localhost("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500
- , update_every, RRDSET_TYPE_STACKED);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "reclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ static RRDSET *st_mem_slab = NULL;
+ static RRDDIM *rd_reclaimable = NULL, *rd_unreclaimable = NULL;
+
+ if(unlikely(!st_mem_slab)) {
+ st_mem_slab = rrdset_create_localhost(
+ "mem"
+ , "slab"
+ , NULL
+ , "slab"
+ , NULL
+ , "Reclaimable Kernel Memory"
+ , "MB"
+ , 6500
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrdset_flag_set(st_mem_slab, RRDSET_FLAG_DETAIL);
+
+ rd_reclaimable = rrddim_add(st_mem_slab, "reclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_unreclaimable = rrddim_add(st_mem_slab, "unreclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_mem_slab);
+
+ rrddim_set_by_pointer(st_mem_slab, rd_reclaimable, SReclaimable);
+ rrddim_set_by_pointer(st_mem_slab, rd_unreclaimable, SUnreclaim);
- rrddim_set(st, "reclaimable", SReclaimable);
- rrddim_set(st, "unreclaimable", SUnreclaim);
- rrdset_done(st);
+ rrdset_done(st_mem_slab);
}
return 0;
diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c
index ee758899..6e12fc5d 100644
--- a/src/proc_net_dev.c
+++ b/src/proc_net_dev.c
@@ -1,6 +1,9 @@
#include "common.h"
-struct netdev {
+// ----------------------------------------------------------------------------
+// netdev list
+
+static struct netdev {
char *name;
uint32_t hash;
size_t len;
@@ -18,6 +21,27 @@ struct netdev {
int do_compressed;
int do_events;
+ const char *chart_type_net_bytes;
+ const char *chart_type_net_packets;
+ const char *chart_type_net_errors;
+ const char *chart_type_net_fifo;
+ const char *chart_type_net_events;
+ const char *chart_type_net_drops;
+ const char *chart_type_net_compressed;
+
+ const char *chart_id_net_bytes;
+ const char *chart_id_net_packets;
+ const char *chart_id_net_errors;
+ const char *chart_id_net_fifo;
+ const char *chart_id_net_events;
+ const char *chart_id_net_drops;
+ const char *chart_id_net_compressed;
+
+ const char *chart_family;
+
+ int flipped;
+ unsigned long priority;
+
// data collected
kernel_uint_t rbytes;
kernel_uint_t rpackets;
@@ -66,13 +90,13 @@ struct netdev {
RRDDIM *rd_tcompressed;
struct netdev *next;
-};
-
-static struct netdev *netdev_root = NULL, *netdev_last_used = NULL;
+} *netdev_root = NULL, *netdev_last_used = NULL;
static size_t netdev_added = 0, netdev_found = 0;
-static void netdev_free(struct netdev *d) {
+// ----------------------------------------------------------------------------
+
+static void netdev_charts_release(struct netdev *d) {
if(d->st_bandwidth) rrdset_is_obsolete(d->st_bandwidth);
if(d->st_packets) rrdset_is_obsolete(d->st_packets);
if(d->st_errors) rrdset_is_obsolete(d->st_errors);
@@ -81,11 +105,229 @@ static void netdev_free(struct netdev *d) {
if(d->st_compressed) rrdset_is_obsolete(d->st_compressed);
if(d->st_events) rrdset_is_obsolete(d->st_events);
+ d->st_bandwidth = NULL;
+ d->st_compressed = NULL;
+ d->st_drops = NULL;
+ d->st_errors = NULL;
+ d->st_events = NULL;
+ d->st_fifo = NULL;
+ d->st_packets = NULL;
+
+ d->rd_rbytes = NULL;
+ d->rd_rpackets = NULL;
+ d->rd_rerrors = NULL;
+ d->rd_rdrops = NULL;
+ d->rd_rfifo = NULL;
+ d->rd_rframe = NULL;
+ d->rd_rcompressed = NULL;
+ d->rd_rmulticast = NULL;
+
+ d->rd_tbytes = NULL;
+ d->rd_tpackets = NULL;
+ d->rd_terrors = NULL;
+ d->rd_tdrops = NULL;
+ d->rd_tfifo = NULL;
+ d->rd_tcollisions = NULL;
+ d->rd_tcarrier = NULL;
+ d->rd_tcompressed = NULL;
+}
+
+static void netdev_free_strings(struct netdev *d) {
+ freez((void *)d->chart_type_net_bytes);
+ freez((void *)d->chart_type_net_compressed);
+ freez((void *)d->chart_type_net_drops);
+ freez((void *)d->chart_type_net_errors);
+ freez((void *)d->chart_type_net_events);
+ freez((void *)d->chart_type_net_fifo);
+ freez((void *)d->chart_type_net_packets);
+
+ freez((void *)d->chart_id_net_bytes);
+ freez((void *)d->chart_id_net_compressed);
+ freez((void *)d->chart_id_net_drops);
+ freez((void *)d->chart_id_net_errors);
+ freez((void *)d->chart_id_net_events);
+ freez((void *)d->chart_id_net_fifo);
+ freez((void *)d->chart_id_net_packets);
+
+ freez((void *)d->chart_family);
+}
+
+static void netdev_free(struct netdev *d) {
+ netdev_charts_release(d);
+ netdev_free_strings(d);
+
+ freez((void *)d->name);
+ freez((void *)d);
netdev_added--;
- freez(d->name);
- freez(d);
}
+
+// ----------------------------------------------------------------------------
+// netdev renames
+
+static struct netdev_rename {
+ const char *host_device;
+ uint32_t hash;
+
+ const char *container_device;
+ const char *container_name;
+
+ int processed;
+
+ struct netdev_rename *next;
+} *netdev_rename_root = NULL;
+
+static int netdev_pending_renames = 0;
+static netdata_mutex_t netdev_rename_mutex = NETDATA_MUTEX_INITIALIZER;
+
+static struct netdev_rename *netdev_rename_find(const char *host_device, uint32_t hash) {
+ struct netdev_rename *r;
+
+ for(r = netdev_rename_root; r ; r = r->next)
+ if(r->hash == hash && !strcmp(host_device, r->host_device))
+ return r;
+
+ return NULL;
+}
+
+// other threads can call this function to register a rename to a netdev
+void netdev_rename_device_add(const char *host_device, const char *container_device, const char *container_name) {
+ netdata_mutex_lock(&netdev_rename_mutex);
+
+ uint32_t hash = simple_hash(host_device);
+ struct netdev_rename *r = netdev_rename_find(host_device, hash);
+ if(!r) {
+ r = callocz(1, sizeof(struct netdev_rename));
+ r->host_device = strdupz(host_device);
+ r->container_device = strdupz(container_device);
+ r->container_name = strdupz(container_name);
+ r->hash = hash;
+ r->next = netdev_rename_root;
+ r->processed = 0;
+ netdev_rename_root = r;
+ netdev_pending_renames++;
+ info("CGROUP: registered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
+ }
+ else {
+ if(strcmp(r->container_device, container_device) != 0 || strcmp(r->container_name, container_name) != 0) {
+ freez((void *) r->container_device);
+ freez((void *) r->container_name);
+
+ r->container_device = strdupz(container_device);
+ r->container_name = strdupz(container_name);
+ r->processed = 0;
+ netdev_pending_renames++;
+ info("CGROUP: altered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
+ }
+ }
+
+ netdata_mutex_unlock(&netdev_rename_mutex);
+}
+
+// other threads can call this function to delete a rename to a netdev
+void netdev_rename_device_del(const char *host_device) {
+ netdata_mutex_lock(&netdev_rename_mutex);
+
+ struct netdev_rename *r, *last = NULL;
+
+ uint32_t hash = simple_hash(host_device);
+ for(r = netdev_rename_root; r ; last = r, r = r->next) {
+ if (r->hash == hash && !strcmp(host_device, r->host_device)) {
+ if (netdev_rename_root == r)
+ netdev_rename_root = r->next;
+ else if (last)
+ last->next = r->next;
+
+ if(!r->processed)
+ netdev_pending_renames--;
+
+ info("CGROUP: unregistered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
+
+ freez((void *) r->host_device);
+ freez((void *) r->container_name);
+ freez((void *) r->container_device);
+ freez((void *) r);
+ break;
+ }
+ }
+
+ netdata_mutex_unlock(&netdev_rename_mutex);
+}
+
+static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *r) {
+ info("CGROUP: renaming network interface '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
+
+ netdev_charts_release(d);
+ netdev_free_strings(d);
+
+ char buffer[RRD_ID_LENGTH_MAX + 1];
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "cgroup_%s", r->container_name);
+ d->chart_type_net_bytes = strdupz(buffer);
+ d->chart_type_net_compressed = strdupz(buffer);
+ d->chart_type_net_drops = strdupz(buffer);
+ d->chart_type_net_errors = strdupz(buffer);
+ d->chart_type_net_events = strdupz(buffer);
+ d->chart_type_net_fifo = strdupz(buffer);
+ d->chart_type_net_packets = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_%s", r->container_device);
+ d->chart_id_net_bytes = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_compressed_%s", r->container_device);
+ d->chart_id_net_compressed = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_drops_%s", r->container_device);
+ d->chart_id_net_drops = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_errors_%s", r->container_device);
+ d->chart_id_net_errors = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_events_%s", r->container_device);
+ d->chart_id_net_events = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_fifo_%s", r->container_device);
+ d->chart_id_net_fifo = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_packets_%s", r->container_device);
+ d->chart_id_net_packets = strdupz(buffer);
+
+ snprintfz(buffer, RRD_ID_LENGTH_MAX, "net %s", r->container_device);
+ d->chart_family = strdupz(buffer);
+
+ d->priority = 43000;
+ d->flipped = 1;
+}
+
+static inline void netdev_rename(struct netdev *d) {
+ struct netdev_rename *r = netdev_rename_find(d->name, d->hash);
+ if(unlikely(r && !r->processed)) {
+ netdev_rename_cgroup(d, r);
+ r->processed = 1;
+ netdev_pending_renames--;
+ }
+}
+
+static inline void netdev_rename_lock(struct netdev *d) {
+ netdata_mutex_lock(&netdev_rename_mutex);
+ netdev_rename(d);
+ netdata_mutex_unlock(&netdev_rename_mutex);
+}
+
+static inline void netdev_rename_all_lock(void) {
+ netdata_mutex_lock(&netdev_rename_mutex);
+
+ struct netdev *d;
+ for(d = netdev_root; d ; d = d->next)
+ netdev_rename(d);
+
+ netdev_pending_renames = 0;
+ netdata_mutex_unlock(&netdev_rename_mutex);
+}
+
+// ----------------------------------------------------------------------------
+// netdev data collection
+
static void netdev_cleanup() {
if(likely(netdev_found == netdev_added)) return;
@@ -144,6 +386,28 @@ static struct netdev *get_netdev(const char *name) {
d->name = strdupz(name);
d->hash = simple_hash(d->name);
d->len = strlen(d->name);
+
+ d->chart_type_net_bytes = strdupz("net");
+ d->chart_type_net_compressed = strdupz("net_compressed");
+ d->chart_type_net_drops = strdupz("net_drops");
+ d->chart_type_net_errors = strdupz("net_errors");
+ d->chart_type_net_events = strdupz("net_events");
+ d->chart_type_net_fifo = strdupz("net_fifo");
+ d->chart_type_net_packets = strdupz("net_packets");
+
+ d->chart_id_net_bytes = strdupz(d->name);
+ d->chart_id_net_compressed = strdupz(d->name);
+ d->chart_id_net_drops = strdupz(d->name);
+ d->chart_id_net_errors = strdupz(d->name);
+ d->chart_id_net_events = strdupz(d->name);
+ d->chart_id_net_fifo = strdupz(d->name);
+ d->chart_id_net_packets = strdupz(d->name);
+
+ d->chart_family = strdupz(d->name);
+ d->priority = 7000;
+
+ netdev_rename_lock(d);
+
netdev_added++;
// link it to the end
@@ -176,9 +440,7 @@ int do_proc_net_dev(int update_every, usec_t dt) {
do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_BOOLEAN_AUTO);
do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_BOOLEAN_AUTO);
- disabled_list = simple_pattern_create(
- config_get("plugin:proc:/proc/net/dev", "disable by default interfaces matching", "lo fireqos* *-ifb")
- , SIMPLE_PATTERN_EXACT);
+ disabled_list = simple_pattern_create(config_get("plugin:proc:/proc/net/dev", "disable by default interfaces matching", "lo fireqos* *-ifb"), SIMPLE_PATTERN_EXACT);
}
if(unlikely(!ff)) {
@@ -191,6 +453,10 @@ int do_proc_net_dev(int update_every, usec_t dt) {
ff = procfile_readall(ff);
if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
+ // rename all the devices, if we have pending renames
+ if(unlikely(netdev_pending_renames))
+ netdev_rename_all_lock();
+
netdev_found = 0;
size_t lines = procfile_lines(ff), l;
@@ -220,13 +486,13 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(d->enabled == CONFIG_BOOLEAN_NO)
continue;
- d->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth);
- d->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets);
- d->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors);
- d->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops);
- d->do_fifo = config_get_boolean_ondemand(var_name, "fifo", do_fifo);
+ d->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth);
+ d->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets);
+ d->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors);
+ d->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops);
+ d->do_fifo = config_get_boolean_ondemand(var_name, "fifo", do_fifo);
d->do_compressed = config_get_boolean_ondemand(var_name, "compressed", do_compressed);
- d->do_events = config_get_boolean_ondemand(var_name, "events", do_events);
+ d->do_events = config_get_boolean_ondemand(var_name, "events", do_events);
}
if(unlikely(!d->enabled))
@@ -278,20 +544,28 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_bandwidth)) {
d->st_bandwidth = rrdset_create_localhost(
- "net"
- , d->name
+ d->chart_type_net_bytes
+ , d->chart_id_net_bytes
, NULL
- , d->name
+ , d->chart_family
, "net.net"
, "Bandwidth"
, "kilobits/s"
- , 7000
+ , d->priority
, update_every
, RRDSET_TYPE_AREA
);
- d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+
+ if(d->flipped) {
+ // flip receive/trasmit
+
+ RRDDIM *td = d->rd_rbytes;
+ d->rd_rbytes = d->rd_tbytes;
+ d->rd_tbytes = td;
+ }
}
else rrdset_next(d->st_bandwidth);
@@ -309,23 +583,31 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_packets)) {
d->st_packets = rrdset_create_localhost(
- "net_packets"
- , d->name
+ d->chart_type_net_packets
+ , d->chart_id_net_packets
, NULL
- , d->name
+ , d->chart_family
, "net.packets"
, "Packets"
, "packets/s"
- , 7001
+ , d->priority + 1
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(d->st_packets, RRDSET_FLAG_DETAIL);
- d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(d->flipped) {
+ // flip receive/trasmit
+
+ RRDDIM *td = d->rd_rpackets;
+ d->rd_rpackets = d->rd_tpackets;
+ d->rd_tpackets = td;
+ }
}
else rrdset_next(d->st_packets);
@@ -344,22 +626,30 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_errors)) {
d->st_errors = rrdset_create_localhost(
- "net_errors"
- , d->name
+ d->chart_type_net_errors
+ , d->chart_id_net_errors
, NULL
- , d->name
+ , d->chart_family
, "net.errors"
, "Interface Errors"
, "errors/s"
- , 7002
+ , d->priority + 2
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(d->st_errors, RRDSET_FLAG_DETAIL);
- d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(d->flipped) {
+ // flip receive/trasmit
+
+ RRDDIM *td = d->rd_rerrors;
+ d->rd_rerrors = d->rd_terrors;
+ d->rd_terrors = td;
+ }
}
else rrdset_next(d->st_errors);
@@ -377,22 +667,30 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_drops)) {
d->st_drops = rrdset_create_localhost(
- "net_drops"
- , d->name
+ d->chart_type_net_drops
+ , d->chart_id_net_drops
, NULL
- , d->name
+ , d->chart_family
, "net.drops"
, "Interface Drops"
, "drops/s"
- , 7003
+ , d->priority + 3
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(d->st_drops, RRDSET_FLAG_DETAIL);
- d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(d->flipped) {
+ // flip receive/trasmit
+
+ RRDDIM *td = d->rd_rdrops;
+ d->rd_rdrops = d->rd_tdrops;
+ d->rd_tdrops = td;
+ }
}
else rrdset_next(d->st_drops);
@@ -410,22 +708,30 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_fifo)) {
d->st_fifo = rrdset_create_localhost(
- "net_fifo"
- , d->name
+ d->chart_type_net_fifo
+ , d->chart_id_net_fifo
, NULL
- , d->name
+ , d->chart_family
, "net.fifo"
, "Interface FIFO Buffer Errors"
, "errors"
- , 7004
+ , d->priority + 4
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(d->st_fifo, RRDSET_FLAG_DETAIL);
- d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(d->flipped) {
+ // flip receive/trasmit
+
+ RRDDIM *td = d->rd_rfifo;
+ d->rd_rfifo = d->rd_tfifo;
+ d->rd_tfifo = td;
+ }
}
else rrdset_next(d->st_fifo);
@@ -443,22 +749,30 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_compressed)) {
d->st_compressed = rrdset_create_localhost(
- "net_compressed"
- , d->name
+ d->chart_type_net_compressed
+ , d->chart_id_net_compressed
, NULL
- , d->name
+ , d->chart_family
, "net.compressed"
, "Compressed Packets"
, "packets/s"
- , 7005
+ , d->priority + 5
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(d->st_compressed, RRDSET_FLAG_DETAIL);
- d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(d->flipped) {
+ // flip receive/trasmit
+
+ RRDDIM *td = d->rd_rcompressed;
+ d->rd_rcompressed = d->rd_tcompressed;
+ d->rd_tcompressed = td;
+ }
}
else rrdset_next(d->st_compressed);
@@ -476,23 +790,23 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!d->st_events)) {
d->st_events = rrdset_create_localhost(
- "net_events"
- , d->name
+ d->chart_type_net_events
+ , d->chart_id_net_events
, NULL
- , d->name
+ , d->chart_family
, "net.events"
, "Network Interface Events"
, "events/s"
- , 7006
+ , d->priority + 6
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(d->st_events, RRDSET_FLAG_DETAIL);
- d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- d->rd_tcarrier = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tcarrier = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_events);
diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c
index 16a3234d..aa806b46 100644
--- a/src/proc_net_ip_vs_stats.c
+++ b/src/proc_net_ip_vs_stats.c
@@ -80,8 +80,8 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth"
, "kilobits/s", 3100, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c
index 322e51d1..e01b81d2 100644
--- a/src/proc_net_netstat.c
+++ b/src/proc_net_netstat.c
@@ -232,151 +232,255 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
parse_line_pair(ff, arl_ipext, h, l);
- RRDSET *st;
-
// --------------------------------------------------------------------
if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (ipext_InOctets || ipext_OutOctets))) {
do_bandwidth = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("system.ipv4");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s"
- , 500, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_system_ipv4 = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if(unlikely(!st_system_ipv4)) {
+ st_system_ipv4 = rrdset_create_localhost(
+ "system"
+ , "ipv4"
+ , NULL
+ , "network"
+ , NULL
+ , "IPv4 Bandwidth"
+ , "kilobits/s"
+ , 500
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st_system_ipv4, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_system_ipv4, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_system_ipv4);
- rrddim_set(st, "InOctets", ipext_InOctets);
- rrddim_set(st, "OutOctets", ipext_OutOctets);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_system_ipv4, rd_in, ipext_InOctets);
+ rrddim_set_by_pointer(st_system_ipv4, rd_out, ipext_OutOctets);
+
+ rrdset_done(st_system_ipv4);
}
// --------------------------------------------------------------------
if(do_inerrors == CONFIG_BOOLEAN_YES || (do_inerrors == CONFIG_BOOLEAN_AUTO && (ipext_InNoRoutes || ipext_InTruncatedPkts))) {
do_inerrors = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.inerrors");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors"
- , "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "InNoRoutes", "noroutes", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", "truncated", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_ipv4_inerrors = NULL;
+ static RRDDIM *rd_noroutes = NULL, *rd_truncated = NULL, *rd_checksum = NULL;
+
+ if(unlikely(!st_ipv4_inerrors)) {
+ st_ipv4_inerrors = rrdset_create_localhost(
+ "ipv4"
+ , "inerrors"
+ , NULL
+ , "errors"
+ , NULL
+ , "IPv4 Input Errors"
+ , "packets/s"
+ , 4000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st_ipv4_inerrors, RRDSET_FLAG_DETAIL);
+
+ rd_noroutes = rrddim_add(st_ipv4_inerrors, "InNoRoutes", "noroutes", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_truncated = rrddim_add(st_ipv4_inerrors, "InTruncatedPkts", "truncated", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_checksum = rrddim_add(st_ipv4_inerrors, "InCsumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_ipv4_inerrors);
+
+ rrddim_set_by_pointer(st_ipv4_inerrors, rd_noroutes, ipext_InNoRoutes);
+ rrddim_set_by_pointer(st_ipv4_inerrors, rd_truncated, ipext_InTruncatedPkts);
+ rrddim_set_by_pointer(st_ipv4_inerrors, rd_checksum, ipext_InCsumErrors);
- rrddim_set(st, "InNoRoutes", ipext_InNoRoutes);
- rrddim_set(st, "InTruncatedPkts", ipext_InTruncatedPkts);
- rrddim_set(st, "InCsumErrors", ipext_InCsumErrors);
- rrdset_done(st);
+ rrdset_done(st_ipv4_inerrors);
}
// --------------------------------------------------------------------
if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (ipext_InMcastOctets || ipext_OutMcastOctets))) {
do_mcast = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.mcast");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth"
- , "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "InMcastOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutMcastOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_ipv4_mcast = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if(unlikely(!st_ipv4_mcast)) {
+ st_ipv4_mcast = rrdset_create_localhost(
+ "ipv4"
+ , "mcast"
+ , NULL
+ , "multicast"
+ , NULL
+ , "IPv4 Multicast Bandwidth"
+ , "kilobits/s"
+ , 9000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(st_ipv4_mcast, RRDSET_FLAG_DETAIL);
+
+ rd_in = rrddim_add(st_ipv4_mcast, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ipv4_mcast, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_ipv4_mcast);
- rrddim_set(st, "InMcastOctets", ipext_InMcastOctets);
- rrddim_set(st, "OutMcastOctets", ipext_OutMcastOctets);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_ipv4_mcast, rd_in, ipext_InMcastOctets);
+ rrddim_set_by_pointer(st_ipv4_mcast, rd_out, ipext_OutMcastOctets);
+
+ rrdset_done(st_ipv4_mcast);
}
// --------------------------------------------------------------------
if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (ipext_InBcastOctets || ipext_OutBcastOctets))) {
do_bcast = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.bcast");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth"
- , "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "InBcastOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutBcastOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_ipv4_bcast = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if(unlikely(!st_ipv4_bcast)) {
+ st_ipv4_bcast = rrdset_create_localhost(
+ "ipv4"
+ , "bcast"
+ , NULL
+ , "broadcast"
+ , NULL
+ , "IPv4 Broadcast Bandwidth"
+ , "kilobits/s"
+ , 8000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(st_ipv4_bcast, RRDSET_FLAG_DETAIL);
+
+ rd_in = rrddim_add(st_ipv4_bcast, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ipv4_bcast, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_ipv4_bcast);
+
+ rrddim_set_by_pointer(st_ipv4_bcast, rd_in, ipext_InBcastOctets);
+ rrddim_set_by_pointer(st_ipv4_bcast, rd_out, ipext_OutBcastOctets);
- rrddim_set(st, "InBcastOctets", ipext_InBcastOctets);
- rrddim_set(st, "OutBcastOctets", ipext_OutBcastOctets);
- rrdset_done(st);
+ rrdset_done(st_ipv4_bcast);
}
// --------------------------------------------------------------------
if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InMcastPkts || ipext_OutMcastPkts))) {
do_mcast_p = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.mcastpkts");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets"
- , "packets/s", 8600, update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_ipv4_mcastpkts = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if(unlikely(!st_ipv4_mcastpkts)) {
+ st_ipv4_mcastpkts = rrdset_create_localhost(
+ "ipv4"
+ , "mcastpkts"
+ , NULL
+ , "multicast"
+ , NULL
+ , "IPv4 Multicast Packets"
+ , "packets/s"
+ , 8600
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st_ipv4_mcastpkts, RRDSET_FLAG_DETAIL);
+
+ rd_in = rrddim_add(st_ipv4_mcastpkts, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ipv4_mcastpkts, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(st_ipv4_mcastpkts);
+
+ rrddim_set_by_pointer(st_ipv4_mcastpkts, rd_in, ipext_InMcastPkts);
+ rrddim_set_by_pointer(st_ipv4_mcastpkts, rd_out, ipext_OutMcastPkts);
- rrddim_set(st, "InMcastPkts", ipext_InMcastPkts);
- rrddim_set(st, "OutMcastPkts", ipext_OutMcastPkts);
- rrdset_done(st);
+ rrdset_done(st_ipv4_mcastpkts);
}
// --------------------------------------------------------------------
if(do_bcast_p == CONFIG_BOOLEAN_YES || (do_bcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InBcastPkts || ipext_OutBcastPkts))) {
do_bcast_p = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.bcastpkts");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets"
- , "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_ipv4_bcastpkts = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if(unlikely(!st_ipv4_bcastpkts)) {
+ st_ipv4_bcastpkts = rrdset_create_localhost(
+ "ipv4"
+ , "bcastpkts"
+ , NULL
+ , "broadcast"
+ , NULL
+ , "IPv4 Broadcast Packets"
+ , "packets/s"
+ , 8500
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st_ipv4_bcastpkts, RRDSET_FLAG_DETAIL);
+
+ rd_in = rrddim_add(st_ipv4_bcastpkts, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_ipv4_bcastpkts, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_ipv4_bcastpkts);
- rrddim_set(st, "InBcastPkts", ipext_InBcastPkts);
- rrddim_set(st, "OutBcastPkts", ipext_OutBcastPkts);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_ipv4_bcastpkts, rd_in, ipext_InBcastPkts);
+ rrddim_set_by_pointer(st_ipv4_bcastpkts, rd_out, ipext_OutBcastPkts);
+
+ rrdset_done(st_ipv4_bcastpkts);
}
// --------------------------------------------------------------------
if(do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (ipext_InCEPkts || ipext_InECT0Pkts || ipext_InECT1Pkts || ipext_InNoECTPkts))) {
do_ecn = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.ecnpkts");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics"
- , "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_ecnpkts = NULL;
+ static RRDDIM *rd_cep = NULL, *rd_noectp = NULL, *rd_ectp0 = NULL, *rd_ectp1 = NULL;
+
+ if(unlikely(!st_ecnpkts)) {
+ st_ecnpkts = rrdset_create_localhost(
+ "ipv4"
+ , "ecnpkts"
+ , NULL
+ , "ecn"
+ , NULL
+ , "IPv4 ECN Statistics"
+ , "packets/s"
+ , 8700
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st_ecnpkts, RRDSET_FLAG_DETAIL);
+
+ rd_cep = rrddim_add(st_ecnpkts, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_noectp = rrddim_add(st_ecnpkts, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ectp0 = rrddim_add(st_ecnpkts, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ectp1 = rrddim_add(st_ecnpkts, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(st_ecnpkts);
+
+ rrddim_set_by_pointer(st_ecnpkts, rd_cep, ipext_InCEPkts);
+ rrddim_set_by_pointer(st_ecnpkts, rd_noectp, ipext_InNoECTPkts);
+ rrddim_set_by_pointer(st_ecnpkts, rd_ectp0, ipext_InECT0Pkts);
+ rrddim_set_by_pointer(st_ecnpkts, rd_ectp1, ipext_InECT1Pkts);
- rrddim_set(st, "InCEPkts", ipext_InCEPkts);
- rrddim_set(st, "InNoECTPkts", ipext_InNoECTPkts);
- rrddim_set(st, "InECT0Pkts", ipext_InECT0Pkts);
- rrddim_set(st, "InECT1Pkts", ipext_InECT1Pkts);
- rrdset_done(st);
+ rrdset_done(st_ecnpkts);
}
}
else if(unlikely(hash == hash_tcpext && strcmp(key, "TcpExt") == 0)) {
@@ -390,117 +494,192 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
parse_line_pair(ff, arl_tcpext, h, l);
- RRDSET *st;
-
// --------------------------------------------------------------------
if(do_tcpext_memory == CONFIG_BOOLEAN_YES || (do_tcpext_memory == CONFIG_BOOLEAN_AUTO && (tcpext_TCPMemoryPressures))) {
do_tcpext_memory = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.tcpmemorypressures");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "tcpmemorypressures", NULL, "tcp", NULL, "TCP Memory Pressures"
- , "events/s", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "TCPMemoryPressures", "pressures", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_tcpmemorypressures = NULL;
+ static RRDDIM *rd_pressures = NULL;
+
+ if(unlikely(!st_tcpmemorypressures)) {
+ st_tcpmemorypressures = rrdset_create_localhost(
+ "ipv4"
+ , "tcpmemorypressures"
+ , NULL
+ , "tcp"
+ , NULL
+ , "TCP Memory Pressures"
+ , "events/s"
+ , 3000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_pressures = rrddim_add(st_tcpmemorypressures, "TCPMemoryPressures", "pressures", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_tcpmemorypressures);
+
+ rrddim_set_by_pointer(st_tcpmemorypressures, rd_pressures, tcpext_TCPMemoryPressures);
- rrddim_set(st, "TCPMemoryPressures", tcpext_TCPMemoryPressures);
- rrdset_done(st);
+ rrdset_done(st_tcpmemorypressures);
}
// --------------------------------------------------------------------
if(do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpext_TCPAbortOnData || tcpext_TCPAbortOnClose || tcpext_TCPAbortOnMemory || tcpext_TCPAbortOnTimeout || tcpext_TCPAbortOnLinger || tcpext_TCPAbortFailed))) {
do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.tcpconnaborts");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts"
- , "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPAbortFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_tcpconnaborts = NULL;
+ static RRDDIM *rd_baddata = NULL, *rd_userclosed = NULL, *rd_nomemory = NULL, *rd_timeout = NULL, *rd_linger = NULL, *rd_failed = NULL;
+
+ if(unlikely(!st_tcpconnaborts)) {
+ st_tcpconnaborts = rrdset_create_localhost(
+ "ipv4"
+ , "tcpconnaborts"
+ , NULL
+ , "tcp"
+ , NULL
+ , "TCP Connection Aborts"
+ , "connections/s"
+ , 3010
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_baddata = rrddim_add(st_tcpconnaborts, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_userclosed = rrddim_add(st_tcpconnaborts, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_nomemory = rrddim_add(st_tcpconnaborts, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_timeout = rrddim_add(st_tcpconnaborts, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_linger = rrddim_add(st_tcpconnaborts, "TCPAbortOnLinger", "linger", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st_tcpconnaborts, "TCPAbortFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
-
- rrddim_set(st, "TCPAbortOnData", tcpext_TCPAbortOnData);
- rrddim_set(st, "TCPAbortOnClose", tcpext_TCPAbortOnClose);
- rrddim_set(st, "TCPAbortOnMemory", tcpext_TCPAbortOnMemory);
- rrddim_set(st, "TCPAbortOnTimeout", tcpext_TCPAbortOnTimeout);
- rrddim_set(st, "TCPAbortOnLinger", tcpext_TCPAbortOnLinger);
- rrddim_set(st, "TCPAbortFailed", tcpext_TCPAbortFailed);
- rrdset_done(st);
+ else
+ rrdset_next(st_tcpconnaborts);
+
+ rrddim_set_by_pointer(st_tcpconnaborts, rd_baddata, tcpext_TCPAbortOnData);
+ rrddim_set_by_pointer(st_tcpconnaborts, rd_userclosed, tcpext_TCPAbortOnClose);
+ rrddim_set_by_pointer(st_tcpconnaborts, rd_nomemory, tcpext_TCPAbortOnMemory);
+ rrddim_set_by_pointer(st_tcpconnaborts, rd_timeout, tcpext_TCPAbortOnTimeout);
+ rrddim_set_by_pointer(st_tcpconnaborts, rd_linger, tcpext_TCPAbortOnLinger);
+ rrddim_set_by_pointer(st_tcpconnaborts, rd_failed, tcpext_TCPAbortFailed);
+
+ rrdset_done(st_tcpconnaborts);
}
+
// --------------------------------------------------------------------
if(do_tcpext_reorder == CONFIG_BOOLEAN_YES || (do_tcpext_reorder == CONFIG_BOOLEAN_AUTO && (tcpext_TCPRenoReorder || tcpext_TCPFACKReorder || tcpext_TCPSACKReorder || tcpext_TCPTSReorder))) {
do_tcpext_reorder = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.tcpreorders");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "tcpreorders", NULL, "tcp", NULL
- , "TCP Reordered Packets by Detection Method", "packets/s", 3020
- , update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "TCPTSReorder", "timestamp", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPSACKReorder", "sack", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPFACKReorder", "fack", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPRenoReorder", "reno", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_tcpreorders = NULL;
+ static RRDDIM *rd_timestamp = NULL, *rd_sack = NULL, *rd_fack = NULL, *rd_reno = NULL;
+
+ if(unlikely(!st_tcpreorders)) {
+ st_tcpreorders = rrdset_create_localhost(
+ "ipv4"
+ , "tcpreorders"
+ , NULL
+ , "tcp"
+ , NULL
+ , "TCP Reordered Packets by Detection Method"
+ , "packets/s"
+ , 3020
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_timestamp = rrddim_add(st_tcpreorders, "TCPTSReorder", "timestamp", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sack = rrddim_add(st_tcpreorders, "TCPSACKReorder", "sack", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_fack = rrddim_add(st_tcpreorders, "TCPFACKReorder", "fack", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_reno = rrddim_add(st_tcpreorders, "TCPRenoReorder", "reno", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_tcpreorders);
+
+ rrddim_set_by_pointer(st_tcpreorders, rd_timestamp, tcpext_TCPTSReorder);
+ rrddim_set_by_pointer(st_tcpreorders, rd_sack, tcpext_TCPSACKReorder);
+ rrddim_set_by_pointer(st_tcpreorders, rd_fack, tcpext_TCPFACKReorder);
+ rrddim_set_by_pointer(st_tcpreorders, rd_reno, tcpext_TCPRenoReorder);
- rrddim_set(st, "TCPTSReorder", tcpext_TCPTSReorder);
- rrddim_set(st, "TCPSACKReorder", tcpext_TCPSACKReorder);
- rrddim_set(st, "TCPFACKReorder", tcpext_TCPFACKReorder);
- rrddim_set(st, "TCPRenoReorder", tcpext_TCPRenoReorder);
- rrdset_done(st);
+ rrdset_done(st_tcpreorders);
}
// --------------------------------------------------------------------
if(do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && (tcpext_TCPOFOQueue || tcpext_TCPOFODrop || tcpext_TCPOFOMerge))) {
do_tcpext_ofo = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.tcpofo");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue"
- , "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPOFODrop", "dropped", -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "TCPOFOMerge", "merged", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OfoPruned", "pruned", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_ipv4_tcpofo = NULL;
+ static RRDDIM *rd_inqueue = NULL, *rd_dropped = NULL, *rd_merged = NULL, *rd_pruned = NULL;
+
+ if(unlikely(!st_ipv4_tcpofo)) {
+
+ st_ipv4_tcpofo = rrdset_create_localhost(
+ "ipv4"
+ , "tcpofo"
+ , NULL
+ , "tcp"
+ , NULL
+ , "TCP Out-Of-Order Queue"
+ , "packets/s"
+ , 3050
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_inqueue = rrddim_add(st_ipv4_tcpofo, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_dropped = rrddim_add(st_ipv4_tcpofo, "TCPOFODrop", "dropped", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_merged = rrddim_add(st_ipv4_tcpofo, "TCPOFOMerge", "merged", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_pruned = rrddim_add(st_ipv4_tcpofo, "OfoPruned", "pruned", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_ipv4_tcpofo);
- rrddim_set(st, "TCPOFOQueue", tcpext_TCPOFOQueue);
- rrddim_set(st, "TCPOFODrop", tcpext_TCPOFODrop);
- rrddim_set(st, "TCPOFOMerge", tcpext_TCPOFOMerge);
- rrddim_set(st, "OfoPruned", tcpext_OfoPruned);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_ipv4_tcpofo, rd_inqueue, tcpext_TCPOFOQueue);
+ rrddim_set_by_pointer(st_ipv4_tcpofo, rd_dropped, tcpext_TCPOFODrop);
+ rrddim_set_by_pointer(st_ipv4_tcpofo, rd_merged, tcpext_TCPOFOMerge);
+ rrddim_set_by_pointer(st_ipv4_tcpofo, rd_pruned, tcpext_OfoPruned);
+
+ rrdset_done(st_ipv4_tcpofo);
}
// --------------------------------------------------------------------
if(do_tcpext_syscookies == CONFIG_BOOLEAN_YES || (do_tcpext_syscookies == CONFIG_BOOLEAN_AUTO && (tcpext_SyncookiesSent || tcpext_SyncookiesRecv || tcpext_SyncookiesFailed))) {
do_tcpext_syscookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find_localhost("ipv4.tcpsyncookies");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies"
- , "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ static RRDSET *st_syncookies = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_failed = NULL;
+
+ if(unlikely(!st_syncookies)) {
+
+ st_syncookies = rrdset_create_localhost(
+ "ipv4"
+ , "tcpsyncookies"
+ , NULL
+ , "tcp"
+ , NULL
+ , "TCP SYN Cookies"
+ , "packets/s"
+ , 3100
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st_syncookies, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st_syncookies, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st_syncookies, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st_syncookies);
+
+ rrddim_set_by_pointer(st_syncookies, rd_received, tcpext_SyncookiesRecv);
+ rrddim_set_by_pointer(st_syncookies, rd_sent, tcpext_SyncookiesSent);
+ rrddim_set_by_pointer(st_syncookies, rd_failed, tcpext_SyncookiesFailed);
- rrddim_set(st, "SyncookiesRecv", tcpext_SyncookiesRecv);
- rrddim_set(st, "SyncookiesSent", tcpext_SyncookiesSent);
- rrddim_set(st, "SyncookiesFailed", tcpext_SyncookiesFailed);
- rrdset_done(st);
+ rrdset_done(st_syncookies);
}
}
diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c
index 7c0fd9b4..817c964b 100644
--- a/src/proc_net_snmp.c
+++ b/src/proc_net_snmp.c
@@ -554,7 +554,7 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmpmsg");
if(!st) {
- st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages"
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messages"
, "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
for(i = 0; icmpmsg_data[i].name ;i++)
diff --git a/src/proc_net_snmp6.c b/src/proc_net_snmp6.c
index aa9ab220..6649b7af 100644
--- a/src/proc_net_snmp6.c
+++ b/src/proc_net_snmp6.c
@@ -283,8 +283,8 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
st = rrdset_create_localhost("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500
, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -536,8 +536,8 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, RRDSET_TYPE_AREA);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -557,8 +557,8 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
, RRDSET_TYPE_AREA);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_softirqs.c b/src/proc_softirqs.c
index 560e2acb..352407a4 100644
--- a/src/proc_softirqs.c
+++ b/src/proc_softirqs.c
@@ -124,77 +124,120 @@ int do_proc_softirqs(int update_every, usec_t dt) {
irr->used = 1;
}
- RRDSET *st;
-
// --------------------------------------------------------------------
- st = rrdset_find_bytype_localhost("system", "softirqs");
- if(unlikely(!st)) st = rrdset_create_localhost("system", "softirqs", NULL, "softirqs", NULL, "System softirqs"
- , "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
- else rrdset_next(st);
+ static RRDSET *st_system_softirqs = NULL;
+ if(unlikely(!st_system_softirqs))
+ st_system_softirqs = rrdset_create_localhost(
+ "system"
+ , "softirqs"
+ , NULL
+ , "softirqs"
+ , NULL
+ , "System softirqs"
+ , "softirqs/s"
+ , 950
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+ else
+ rrdset_next(st_system_softirqs);
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
+
if(unlikely(!irr->used)) continue;
+
// some interrupt may have changed without changing the total number of lines
// if the same number of interrupts have been added and removed between two
// calls of this function.
if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
- irr->rd = rrddim_find(st, irr->id);
+ irr->rd = rrddim_find(st_system_softirqs, irr->id);
+
if(unlikely(!irr->rd))
- irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ irr->rd = rrddim_add(st_system_softirqs, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
- rrddim_set_name(st, irr->rd, irr->name);
+ rrddim_set_name(st_system_softirqs, irr->rd, irr->name);
// also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
if(likely(do_per_core)) {
int c;
- for (c = 0; c < cpus ;c++)
- irr->cpu[c].rd = NULL;
+ for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL;
}
}
- rrddim_set_by_pointer(st, irr->rd, irr->total);
+
+ rrddim_set_by_pointer(st_system_softirqs, irr->rd, irr->total);
}
- rrdset_done(st);
+
+ rrdset_done(st_system_softirqs);
+
+ // --------------------------------------------------------------------
if(do_per_core) {
+ static RRDSET **core_st = NULL;
+ static int old_cpus = 0;
+
+ if(old_cpus < cpus) {
+ core_st = reallocz(core_st, sizeof(RRDSET *) * cpus);
+ memset(&core_st[old_cpus], 0, sizeof(RRDSET *) * (cpus - old_cpus));
+ old_cpus = cpus;
+ }
+
int c;
for(c = 0; c < cpus ; c++) {
- char id[50+1];
- snprintfz(id, 50, "cpu%d_softirqs", c);
-
- st = rrdset_find_bytype_localhost("cpu", id);
- if(unlikely(!st)) {
- // find if everything is zero
- unsigned long long core_sum = 0 ;
- for(l = 0; l < lines ;l++) {
+ if(unlikely(!core_st[c])) {
+ // find if everything is just zero
+ unsigned long long core_sum = 0;
+
+ for (l = 0; l < lines; l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
- if(unlikely(!irr->used)) continue;
+ if (unlikely(!irr->used)) continue;
core_sum += irr->cpu[c].value;
}
- if(unlikely(core_sum == 0)) continue; // try next core
- char title[100+1];
+ if (unlikely(core_sum == 0)) continue; // try next core
+
+ char id[50 + 1];
+ snprintfz(id, 50, "cpu%d_softirqs", c);
+
+ char title[100 + 1];
snprintfz(title, 100, "CPU%d softirqs", c);
- st = rrdset_create_localhost("cpu", id, NULL, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c
- , update_every, RRDSET_TYPE_STACKED);
+
+ core_st[c] = rrdset_create_localhost(
+ "cpu"
+ , id
+ , NULL
+ , "softirqs"
+ , "cpu.softirqs"
+ , title
+ , "softirqs/s"
+ , 3000 + c
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
- else rrdset_next(st);
+ else
+ rrdset_next(core_st[c]);
for(l = 0; l < lines ;l++) {
struct interrupt *irr = irrindex(irrs, l, cpus);
+
if(unlikely(!irr->used)) continue;
+
if(unlikely(!irr->cpu[c].rd)) {
- irr->cpu[c].rd = rrddim_find(st, irr->id);
+ irr->cpu[c].rd = rrddim_find(core_st[c], irr->id);
+
if(unlikely(!irr->cpu[c].rd))
- irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
- rrddim_set_name(st, irr->cpu[c].rd, irr->name);
+ rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name);
}
- rrddim_set_by_pointer(st, irr->cpu[c].rd, irr->cpu[c].value);
+
+ rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value);
}
- rrdset_done(st);
+
+ rrdset_done(core_st[c]);
}
}
diff --git a/src/proc_stat.c b/src/proc_stat.c
index 04f0896c..40bf5cfa 100644
--- a/src/proc_stat.c
+++ b/src/proc_stat.c
@@ -1,25 +1,171 @@
#include "common.h"
+struct per_core_single_number_file {
+ char found:1;
+ const char *filename;
+ int fd;
+ collected_number value;
+ RRDDIM *rd;
+};
+
+#define CORE_THROTTLE_COUNT_INDEX 0
+#define PACKAGE_THROTTLE_COUNT_INDEX 1
+#define SCALING_CUR_FREQ_INDEX 2
+#define PER_CORE_FILES 3
+
+struct cpu_chart {
+ const char *id;
+
+ RRDSET *st;
+ RRDDIM *rd_user;
+ RRDDIM *rd_nice;
+ RRDDIM *rd_system;
+ RRDDIM *rd_idle;
+ RRDDIM *rd_iowait;
+ RRDDIM *rd_irq;
+ RRDDIM *rd_softirq;
+ RRDDIM *rd_steal;
+ RRDDIM *rd_guest;
+ RRDDIM *rd_guest_nice;
+
+ struct per_core_single_number_file files[PER_CORE_FILES];
+};
+
+static int keep_per_core_fds_open = CONFIG_BOOLEAN_YES;
+
+static int read_per_core_files(struct cpu_chart *all_cpu_charts, size_t len, size_t index) {
+ char buf[50 + 1];
+ size_t x, files_read = 0, files_nonzero = 0;
+
+ for(x = 0; x < len ; x++) {
+ struct per_core_single_number_file *f = &all_cpu_charts[x].files[index];
+
+ f->found = 0;
+
+ if(unlikely(!f->filename))
+ continue;
+
+ if(unlikely(f->fd == -1)) {
+ f->fd = open(f->filename, O_RDONLY);
+ if (unlikely(f->fd == -1)) {
+ error("Cannot open file '%s'", f->filename);
+ continue;
+ }
+ }
+
+ ssize_t ret = read(f->fd, buf, 50);
+ if(unlikely(ret == -1)) {
+ // cannot read that file
+
+ error("Cannot read file '%s'", f->filename);
+ close(f->fd);
+ f->fd = -1;
+ continue;
+ }
+ else {
+ // successful read
+
+ // terminate the buffer
+ buf[ret] = '\0';
+
+ if(unlikely(keep_per_core_fds_open != CONFIG_BOOLEAN_YES)) {
+ close(f->fd);
+ f->fd = -1;
+ }
+ else if(lseek(f->fd, 0, SEEK_SET) == -1) {
+ error("Cannot seek in file '%s'", f->filename);
+ close(f->fd);
+ f->fd = -1;
+ }
+ }
+
+ files_read++;
+ f->found = 1;
+
+ f->value = str2ll(buf, NULL);
+ // info("read '%s', parsed as " COLLECTED_NUMBER_FORMAT, buf, f->value);
+ if(likely(f->value != 0))
+ files_nonzero++;
+ }
+
+ if(files_read == 0)
+ return -1;
+
+ if(files_nonzero == 0)
+ return 0;
+
+ return (int)files_nonzero;
+}
+
+static void chart_per_core_files(struct cpu_chart *all_cpu_charts, size_t len, size_t index, RRDSET *st, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm) {
+ size_t x;
+ for(x = 0; x < len ; x++) {
+ struct per_core_single_number_file *f = &all_cpu_charts[x].files[index];
+
+ if(unlikely(!f->found))
+ continue;
+
+ if(unlikely(!f->rd))
+ f->rd = rrddim_add(st, all_cpu_charts[x].id, NULL, multiplier, divisor, algorithm);
+
+ rrddim_set_by_pointer(st, f->rd, f->value);
+ }
+}
+
int do_proc_stat(int update_every, usec_t dt) {
(void)dt;
+ static struct cpu_chart *all_cpu_charts = NULL;
+ static size_t all_cpu_charts_size = 0;
static procfile *ff = NULL;
- static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
+ static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1, do_core_throttle_count = -1, do_package_throttle_count = -1, do_scaling_cur_freq = -1;
static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
+ static char *core_throttle_count_filename = NULL, *package_throttle_count_filename = NULL, *scaling_cur_freq_filename = NULL;
if(unlikely(do_cpu == -1)) {
- do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
- do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
- do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
- do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
- do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
- do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
+ do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", CONFIG_BOOLEAN_YES);
+ do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", CONFIG_BOOLEAN_YES);
+ do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", CONFIG_BOOLEAN_YES);
+ do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", CONFIG_BOOLEAN_YES);
+ do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", CONFIG_BOOLEAN_YES);
+ do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", CONFIG_BOOLEAN_YES);
+
+ // give sane defaults based on the number of processors
+ if(processors > 50) {
+ // the system has too many processors
+ keep_per_core_fds_open = CONFIG_BOOLEAN_NO;
+ do_core_throttle_count = CONFIG_BOOLEAN_NO;
+ do_package_throttle_count = CONFIG_BOOLEAN_NO;
+ do_scaling_cur_freq = CONFIG_BOOLEAN_NO;
+ }
+ else {
+ // the system has a reasonable number of processors
+ keep_per_core_fds_open = CONFIG_BOOLEAN_YES;
+ do_core_throttle_count = CONFIG_BOOLEAN_AUTO;
+ do_package_throttle_count = CONFIG_BOOLEAN_NO;
+ do_scaling_cur_freq = CONFIG_BOOLEAN_NO;
+ }
+
+ keep_per_core_fds_open = config_get_boolean("plugin:proc:/proc/stat", "keep per core files open", keep_per_core_fds_open);
+ do_core_throttle_count = config_get_boolean_ondemand("plugin:proc:/proc/stat", "core_throttle_count", do_core_throttle_count);
+ do_package_throttle_count = config_get_boolean_ondemand("plugin:proc:/proc/stat", "package_throttle_count", do_package_throttle_count);
+ do_scaling_cur_freq = config_get_boolean_ondemand("plugin:proc:/proc/stat", "scaling_cur_freq", do_scaling_cur_freq);
hash_intr = simple_hash("intr");
hash_ctxt = simple_hash("ctxt");
hash_processes = simple_hash("processes");
hash_procs_running = simple_hash("procs_running");
hash_procs_blocked = simple_hash("procs_blocked");
+
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/thermal_throttle/core_throttle_count");
+ core_throttle_count_filename = config_get("plugin:proc:/proc/stat", "core_throttle_count filename to monitor", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/thermal_throttle/package_throttle_count");
+ package_throttle_count_filename = config_get("plugin:proc:/proc/stat", "package_throttle_count filename to monitor", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/cpufreq/scaling_cur_freq");
+ scaling_cur_freq_filename = config_get("plugin:proc:/proc/stat", "scaling_cur_freq filename to monitor", filename);
}
if(unlikely(!ff)) {
@@ -36,7 +182,6 @@ int do_proc_stat(int update_every, usec_t dt) {
size_t words;
unsigned long long processes = 0, running = 0 , blocked = 0;
- RRDSET *st;
for(l = 0; l < lines ;l++) {
char *row_key = procfile_lineword(ff, l, 0);
@@ -50,120 +195,189 @@ int do_proc_stat(int update_every, usec_t dt) {
continue;
}
- char *id;
- unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
-
- id = row_key;
- user = str2ull(procfile_lineword(ff, l, 1));
- nice = str2ull(procfile_lineword(ff, l, 2));
- system = str2ull(procfile_lineword(ff, l, 3));
- idle = str2ull(procfile_lineword(ff, l, 4));
- iowait = str2ull(procfile_lineword(ff, l, 5));
- irq = str2ull(procfile_lineword(ff, l, 6));
- softirq = str2ull(procfile_lineword(ff, l, 7));
- steal = str2ull(procfile_lineword(ff, l, 8));
-
- guest = str2ull(procfile_lineword(ff, l, 9));
- user -= guest;
-
- guest_nice = str2ull(procfile_lineword(ff, l, 10));
- nice -= guest_nice;
-
- char *title, *type, *context, *family;
- long priority;
- int isthistotal;
-
- if(unlikely(strcmp(id, "cpu")) == 0) {
- title = "Total CPU utilization";
- type = "system";
- context = "system.cpu";
- family = id;
- priority = 100;
- isthistotal = 1;
- }
- else {
- title = "Core utilization";
- type = "cpu";
- context = "cpu.cpu";
- family = "utilization";
- priority = 1000;
- isthistotal = 0;
- }
+ size_t core = (row_key[3] == '\0') ? 0 : str2ul(&row_key[3]) + 1;
+
+ if(likely((core == 0 && do_cpu) || (core > 0 && do_cpu_cores))) {
+ char *id;
+ unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
- if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
- st = rrdset_find_bytype_localhost(type, id);
- if(unlikely(!st)) {
- st = rrdset_create_localhost(type, id, NULL, family, context, title, "percentage", priority
- , update_every, RRDSET_TYPE_STACKED);
+ id = row_key;
+ user = str2ull(procfile_lineword(ff, l, 1));
+ nice = str2ull(procfile_lineword(ff, l, 2));
+ system = str2ull(procfile_lineword(ff, l, 3));
+ idle = str2ull(procfile_lineword(ff, l, 4));
+ iowait = str2ull(procfile_lineword(ff, l, 5));
+ irq = str2ull(procfile_lineword(ff, l, 6));
+ softirq = str2ull(procfile_lineword(ff, l, 7));
+ steal = str2ull(procfile_lineword(ff, l, 8));
+
+ guest = str2ull(procfile_lineword(ff, l, 9));
+ user -= guest;
+
+ guest_nice = str2ull(procfile_lineword(ff, l, 10));
+ nice -= guest_nice;
+
+ char *title, *type, *context, *family;
+ long priority;
+
+ if(core >= all_cpu_charts_size) {
+ size_t old_cpu_charts_size = all_cpu_charts_size;
+ all_cpu_charts_size = core + 1;
+ all_cpu_charts = reallocz(all_cpu_charts, sizeof(struct cpu_chart) * all_cpu_charts_size);
+ memset(&all_cpu_charts[old_cpu_charts_size], 0, sizeof(struct cpu_chart) * (all_cpu_charts_size - old_cpu_charts_size));
+ }
+ struct cpu_chart *cpu_chart = &all_cpu_charts[core];
+
+ if(unlikely(!cpu_chart->st)) {
+ cpu_chart->id = strdupz(id);
+
+ if(core == 0) {
+ title = "Total CPU utilization";
+ type = "system";
+ context = "system.cpu";
+ family = id;
+ priority = 100;
+ }
+ else {
+ title = "Core utilization";
+ type = "cpu";
+ context = "cpu.cpu";
+ family = "utilization";
+ priority = 1000;
+
+ // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
+ // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state
+
+ char filename[FILENAME_MAX + 1];
+ struct stat stbuf;
+
+ if(do_core_throttle_count != CONFIG_BOOLEAN_NO) {
+ snprintfz(filename, FILENAME_MAX, core_throttle_count_filename, id);
+ if (stat(filename, &stbuf) == 0) {
+ cpu_chart->files[CORE_THROTTLE_COUNT_INDEX].filename = strdupz(filename);
+ cpu_chart->files[CORE_THROTTLE_COUNT_INDEX].fd = -1;
+ do_core_throttle_count = CONFIG_BOOLEAN_YES;
+ }
+ }
+
+ if(do_package_throttle_count != CONFIG_BOOLEAN_NO) {
+ snprintfz(filename, FILENAME_MAX, package_throttle_count_filename, id);
+ if (stat(filename, &stbuf) == 0) {
+ cpu_chart->files[PACKAGE_THROTTLE_COUNT_INDEX].filename = strdupz(filename);
+ cpu_chart->files[PACKAGE_THROTTLE_COUNT_INDEX].fd = -1;
+ do_package_throttle_count = CONFIG_BOOLEAN_YES;
+ }
+ }
+
+ if(do_scaling_cur_freq != CONFIG_BOOLEAN_NO) {
+ snprintfz(filename, FILENAME_MAX, scaling_cur_freq_filename, id);
+ if (stat(filename, &stbuf) == 0) {
+ cpu_chart->files[SCALING_CUR_FREQ_INDEX].filename = strdupz(filename);
+ cpu_chart->files[SCALING_CUR_FREQ_INDEX].fd = -1;
+ do_scaling_cur_freq = CONFIG_BOOLEAN_YES;
+ }
+ }
+ }
+
+ cpu_chart->st = rrdset_create_localhost(
+ type
+ , id
+ , NULL
+ , family
+ , context
+ , title
+ , "percentage"
+ , priority
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
long multiplier = 1;
long divisor = 1; // sysconf(_SC_CLK_TCK);
- rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "guest", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "steal", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "softirq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "irq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "user", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "iowait", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-
- rrddim_add(st, "idle", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
- rrddim_hide(st, "idle");
+ cpu_chart->rd_guest_nice = rrddim_add(cpu_chart->st, "guest_nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_guest = rrddim_add(cpu_chart->st, "guest", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_steal = rrddim_add(cpu_chart->st, "steal", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_softirq = rrddim_add(cpu_chart->st, "softirq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_irq = rrddim_add(cpu_chart->st, "irq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_user = rrddim_add(cpu_chart->st, "user", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_system = rrddim_add(cpu_chart->st, "system", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_nice = rrddim_add(cpu_chart->st, "nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_iowait = rrddim_add(cpu_chart->st, "iowait", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ cpu_chart->rd_idle = rrddim_add(cpu_chart->st, "idle", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_hide(cpu_chart->st, "idle");
}
- else rrdset_next(st);
-
- rrddim_set(st, "user", user);
- rrddim_set(st, "nice", nice);
- rrddim_set(st, "system", system);
- rrddim_set(st, "idle", idle);
- rrddim_set(st, "iowait", iowait);
- rrddim_set(st, "irq", irq);
- rrddim_set(st, "softirq", softirq);
- rrddim_set(st, "steal", steal);
- rrddim_set(st, "guest", guest);
- rrddim_set(st, "guest_nice", guest_nice);
- rrdset_done(st);
+ else rrdset_next(cpu_chart->st);
+
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_user, user);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_nice, nice);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_system, system);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_idle, idle);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_iowait, iowait);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_irq, irq);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_softirq, softirq);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_steal, steal);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_guest, guest);
+ rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_guest_nice, guest_nice);
+ rrdset_done(cpu_chart->st);
}
}
else if(unlikely(hash == hash_intr && strcmp(row_key, "intr") == 0)) {
- unsigned long long value = str2ull(procfile_lineword(ff, l, 1));
-
- // --------------------------------------------------------------------
-
if(likely(do_interrupts)) {
- st = rrdset_find_bytype_localhost("system", "intr");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts"
- , "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_intr = NULL;
+ static RRDDIM *rd_interrupts = NULL;
+ unsigned long long value = str2ull(procfile_lineword(ff, l, 1));
+
+ if(unlikely(!st_intr)) {
+ st_intr = rrdset_create_localhost(
+ "system"
+ , "intr"
+ , NULL
+ , "interrupts"
+ , NULL
+ , "CPU Interrupts"
+ , "interrupts/s"
+ , 900
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL);
+
+ rd_interrupts = rrddim_add(st_intr, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(st_intr);
- rrddim_set(st, "interrupts", value);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_intr, rd_interrupts, value);
+ rrdset_done(st_intr);
}
}
else if(unlikely(hash == hash_ctxt && strcmp(row_key, "ctxt") == 0)) {
- unsigned long long value = str2ull(procfile_lineword(ff, l, 1));
-
- // --------------------------------------------------------------------
-
if(likely(do_context)) {
- st = rrdset_find_bytype_localhost("system", "ctxt");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches"
- , "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_ctxt = NULL;
+ static RRDDIM *rd_switches = NULL;
+ unsigned long long value = str2ull(procfile_lineword(ff, l, 1));
+
+ if(unlikely(!st_ctxt)) {
+ st_ctxt = rrdset_create_localhost(
+ "system"
+ , "ctxt"
+ , NULL
+ , "processes"
+ , NULL
+ , "CPU Context Switches"
+ , "context switches/s"
+ , 800
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_switches = rrddim_add(st_ctxt, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(st_ctxt);
- rrddim_set(st, "switches", value);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_ctxt, rd_switches, value);
+ rrdset_done(st_ctxt);
}
}
else if(unlikely(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0)) {
@@ -180,36 +394,147 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_forks)) {
- st = rrdset_find_bytype_localhost("system", "forks");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s"
- , 700, update_every, RRDSET_TYPE_LINE);
- rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
- rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ static RRDSET *st_forks = NULL;
+ static RRDDIM *rd_started = NULL;
+
+ if(unlikely(!st_forks)) {
+ st_forks = rrdset_create_localhost(
+ "system"
+ , "forks"
+ , NULL
+ , "processes"
+ , NULL
+ , "Started Processes"
+ , "processes/s"
+ , 700
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_forks, RRDSET_FLAG_DETAIL);
+
+ rd_started = rrddim_add(st_forks, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(st_forks);
- rrddim_set(st, "started", processes);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_forks, rd_started, processes);
+ rrdset_done(st_forks);
}
// --------------------------------------------------------------------
if(likely(do_processes)) {
- st = rrdset_find_bytype_localhost("system", "processes");
- if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "processes", NULL, "processes", NULL, "System Processes", "processes"
- , 600, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st_processes = NULL;
+ static RRDDIM *rd_running = NULL;
+ static RRDDIM *rd_blocked = NULL;
+
+ if(unlikely(!st_processes)) {
+ st_processes = rrdset_create_localhost(
+ "system"
+ , "processes"
+ , NULL
+ , "processes"
+ , NULL
+ , "System Processes"
+ , "processes"
+ , 600
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_running = rrddim_add(st_processes, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rd_blocked = rrddim_add(st_processes, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_processes);
+
+ rrddim_set_by_pointer(st_processes, rd_running, running);
+ rrddim_set_by_pointer(st_processes, rd_blocked, blocked);
+ rrdset_done(st_processes);
+ }
- rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+ if(likely(all_cpu_charts_size > 1)) {
+ if(likely(do_core_throttle_count != CONFIG_BOOLEAN_NO)) {
+ int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, CORE_THROTTLE_COUNT_INDEX);
+ if(likely(r != -1 && (do_core_throttle_count == CONFIG_BOOLEAN_YES || r > 0))) {
+ do_core_throttle_count = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st_core_throttle_count = NULL;
+
+ if (unlikely(!st_core_throttle_count))
+ st_core_throttle_count = rrdset_create_localhost(
+ "cpu"
+ , "core_throttling"
+ , NULL
+ , "throttling"
+ , "cpu.core_throttling"
+ , "Core Thermal Throttling Events"
+ , "events/s"
+ , 5001
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ else
+ rrdset_next(st_core_throttle_count);
+
+ chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, CORE_THROTTLE_COUNT_INDEX, st_core_throttle_count, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrdset_done(st_core_throttle_count);
+ }
}
- else rrdset_next(st);
- rrddim_set(st, "running", running);
- rrddim_set(st, "blocked", blocked);
- rrdset_done(st);
+ if(likely(do_package_throttle_count != CONFIG_BOOLEAN_NO)) {
+ int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, PACKAGE_THROTTLE_COUNT_INDEX);
+ if(likely(r != -1 && (do_package_throttle_count == CONFIG_BOOLEAN_YES || r > 0))) {
+ do_package_throttle_count = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st_package_throttle_count = NULL;
+
+ if(unlikely(!st_package_throttle_count))
+ st_package_throttle_count = rrdset_create_localhost(
+ "cpu"
+ , "package_throttling"
+ , NULL
+ , "throttling"
+ , "cpu.package_throttling"
+ , "Package Thermal Throttling Events"
+ , "events/s"
+ , 5002
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ else
+ rrdset_next(st_package_throttle_count);
+
+ chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, PACKAGE_THROTTLE_COUNT_INDEX, st_package_throttle_count, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrdset_done(st_package_throttle_count);
+ }
+ }
+
+ if(likely(do_scaling_cur_freq != CONFIG_BOOLEAN_NO)) {
+ int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, SCALING_CUR_FREQ_INDEX);
+ if(likely(r != -1 && (do_scaling_cur_freq == CONFIG_BOOLEAN_YES || r > 0))) {
+ do_scaling_cur_freq = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st_scaling_cur_freq = NULL;
+
+ if(unlikely(!st_scaling_cur_freq))
+ st_scaling_cur_freq = rrdset_create_localhost(
+ "cpu"
+ , "scaling_cur_freq"
+ , NULL
+ , "cpufreq"
+ , "cpu.scaling_cur_freq"
+ , "Per CPU Core, Current CPU Scaling Frequency"
+ , "MHz"
+ , 5003
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+ else
+ rrdset_next(st_scaling_cur_freq);
+
+ chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, SCALING_CUR_FREQ_INDEX, st_scaling_cur_freq, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrdset_done(st_scaling_cur_freq);
+ }
+ }
}
return 0;
diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/src/proc_sys_kernel_random_entropy_avail.c
index fea8900d..267ea271 100644
--- a/src/proc_sys_kernel_random_entropy_avail.c
+++ b/src/proc_sys_kernel_random_entropy_avail.c
@@ -17,15 +17,28 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
unsigned long long entropy = str2ull(procfile_lineword(ff, 0, 0));
- RRDSET *st = rrdset_find_bytype_localhost("system", "entropy");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
+
if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000
- , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "entropy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ st = rrdset_create_localhost(
+ "system"
+ , "entropy"
+ , NULL
+ , "entropy"
+ , NULL
+ , "Available Entropy"
+ , "entropy"
+ , 1000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "entropy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "entropy", entropy);
+ rrddim_set_by_pointer(st, rd, entropy);
rrdset_done(st);
return 0;
diff --git a/src/proc_uptime.c b/src/proc_uptime.c
index f74cccb9..fb05b5cb 100644
--- a/src/proc_uptime.c
+++ b/src/proc_uptime.c
@@ -3,7 +3,6 @@
int do_proc_uptime(int update_every, usec_t dt) {
(void)dt;
- static RRDSET *st = NULL;
collected_number uptime = 0;
#ifdef CLOCK_BOOTTIME_IS_AVAILABLE
@@ -38,17 +37,31 @@ int do_proc_uptime(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(unlikely(!st))
- st = rrdset_find_localhost("system.uptime");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
if(unlikely(!st)) {
- st = rrdset_create_localhost("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000
- , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+
+ st = rrdset_create_localhost(
+ "system"
+ , "uptime"
+ , NULL
+ , "uptime"
+ , NULL
+ , "System Uptime"
+ , "seconds"
+ , 1000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "uptime", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd, uptime);
- rrddim_set(st, "uptime", uptime);
rrdset_done(st);
return 0;
diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c
index a2416313..2382116f 100644
--- a/src/proc_vmstat.c
+++ b/src/proc_vmstat.c
@@ -91,17 +91,29 @@ int do_proc_vmstat(int update_every, usec_t dt) {
do_swapio = CONFIG_BOOLEAN_YES;
static RRDSET *st_swapio = NULL;
- if(unlikely(!st_swapio)) {
- st_swapio = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250
- , update_every, RRDSET_TYPE_AREA);
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL);
+ if(unlikely(!st_swapio)) {
+ st_swapio = rrdset_create_localhost(
+ "system"
+ , "swapio"
+ , NULL
+ , "swap"
+ , NULL
+ , "Swap I/O"
+ , "kilobytes/s"
+ , 250
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_swapio);
- rrddim_set(st_swapio, "in", pswpin);
- rrddim_set(st_swapio, "out", pswpout);
+ rrddim_set_by_pointer(st_swapio, rd_in, pswpin);
+ rrddim_set_by_pointer(st_swapio, rd_out, pswpout);
rrdset_done(st_swapio);
}
@@ -109,17 +121,29 @@ int do_proc_vmstat(int update_every, usec_t dt) {
if(do_io) {
static RRDSET *st_io = NULL;
- if(unlikely(!st_io)) {
- st_io = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150
- , update_every, RRDSET_TYPE_AREA);
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ if(unlikely(!st_io)) {
+ st_io = rrdset_create_localhost(
+ "system"
+ , "io"
+ , NULL
+ , "disk"
+ , NULL
+ , "Disk I/O"
+ , "kilobytes/s"
+ , 150
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_io);
- rrddim_set(st_io, "in", pgpgin);
- rrddim_set(st_io, "out", pgpgout);
+ rrddim_set_by_pointer(st_io, rd_in, pgpgin);
+ rrddim_set_by_pointer(st_io, rd_out, pgpgout);
rrdset_done(st_io);
}
@@ -127,18 +151,31 @@ int do_proc_vmstat(int update_every, usec_t dt) {
if(do_pgfaults) {
static RRDSET *st_pgfaults = NULL;
+ static RRDDIM *rd_minor = NULL, *rd_major = NULL;
+
if(unlikely(!st_pgfaults)) {
- st_pgfaults = rrdset_create_localhost("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults"
- , "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
+ st_pgfaults = rrdset_create_localhost(
+ "mem"
+ , "pgfaults"
+ , NULL
+ , "system"
+ , NULL
+ , "Memory Page Faults"
+ , "page faults/s"
+ , 500
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL);
- rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_minor = rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_major = rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_pgfaults);
- rrddim_set(st_pgfaults, "minor", pgfault);
- rrddim_set(st_pgfaults, "major", pgmajfault);
+ rrddim_set_by_pointer(st_pgfaults, rd_minor, pgfault);
+ rrddim_set_by_pointer(st_pgfaults, rd_major, pgmajfault);
rrdset_done(st_pgfaults);
}
@@ -149,6 +186,7 @@ int do_proc_vmstat(int update_every, usec_t dt) {
// single-node systems have uninteresting statistics (since all accesses
// are local).
if(unlikely(has_numa == -1))
+
has_numa = (numa_local || numa_foreign || numa_interleave || numa_other || numa_pte_updates ||
numa_huge_pte_updates || numa_hint_faults || numa_hint_faults_local || numa_pages_migrated) ? 1 : 0;
@@ -156,37 +194,50 @@ int do_proc_vmstat(int update_every, usec_t dt) {
do_numa = CONFIG_BOOLEAN_YES;
static RRDSET *st_numa = NULL;
+ static RRDDIM *rd_local = NULL, *rd_foreign = NULL, *rd_interleave = NULL, *rd_other = NULL, *rd_pte_updates = NULL, *rd_huge_pte_updates = NULL, *rd_hint_faults = NULL, *rd_hint_faults_local = NULL, *rd_pages_migrated = NULL;
+
if(unlikely(!st_numa)) {
- st_numa = rrdset_create_localhost("mem", "numa", NULL, "numa", NULL, "NUMA events", "events/s", 800
- , update_every, RRDSET_TYPE_LINE);
+ st_numa = rrdset_create_localhost(
+ "mem"
+ , "numa"
+ , NULL
+ , "numa"
+ , NULL
+ , "NUMA events"
+ , "events/s"
+ , 800
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
rrdset_flag_set(st_numa, RRDSET_FLAG_DETAIL);
// These depend on CONFIG_NUMA in the kernel.
- rrddim_add(st_numa, "local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "foreign", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "interleave", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "other", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_local = rrddim_add(st_numa, "local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_foreign = rrddim_add(st_numa, "foreign", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_interleave = rrddim_add(st_numa, "interleave", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_other = rrddim_add(st_numa, "other", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
// The following stats depend on CONFIG_NUMA_BALANCING in the
// kernel.
- rrddim_add(st_numa, "pte_updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "huge_pte_updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "hint_faults", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "hint_faults_local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st_numa, "pages_migrated", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_pte_updates = rrddim_add(st_numa, "pte_updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_huge_pte_updates = rrddim_add(st_numa, "huge_pte_updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_hint_faults = rrddim_add(st_numa, "hint_faults", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_hint_faults_local = rrddim_add(st_numa, "hint_faults_local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_pages_migrated = rrddim_add(st_numa, "pages_migrated", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_numa);
- rrddim_set(st_numa, "local", numa_local);
- rrddim_set(st_numa, "foreign", numa_foreign);
- rrddim_set(st_numa, "interleave", numa_interleave);
- rrddim_set(st_numa, "other", numa_other);
+ rrddim_set_by_pointer(st_numa, rd_local, numa_local);
+ rrddim_set_by_pointer(st_numa, rd_foreign, numa_foreign);
+ rrddim_set_by_pointer(st_numa, rd_interleave, numa_interleave);
+ rrddim_set_by_pointer(st_numa, rd_other, numa_other);
- rrddim_set(st_numa, "pte_updates", numa_pte_updates);
- rrddim_set(st_numa, "huge_pte_updates", numa_huge_pte_updates);
- rrddim_set(st_numa, "hint_faults", numa_hint_faults);
- rrddim_set(st_numa, "hint_faults_local", numa_hint_faults_local);
- rrddim_set(st_numa, "pages_migrated", numa_pages_migrated);
+ rrddim_set_by_pointer(st_numa, rd_pte_updates, numa_pte_updates);
+ rrddim_set_by_pointer(st_numa, rd_huge_pte_updates, numa_huge_pte_updates);
+ rrddim_set_by_pointer(st_numa, rd_hint_faults, numa_hint_faults);
+ rrddim_set_by_pointer(st_numa, rd_hint_faults_local, numa_hint_faults_local);
+ rrddim_set_by_pointer(st_numa, rd_pages_migrated, numa_pages_migrated);
rrdset_done(st_numa);
}
diff --git a/src/rrd.h b/src/rrd.h
index 5bc61dcb..1ebb89e5 100644
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -462,6 +462,9 @@ struct rrdhost {
RRDCALC *alarms;
ALARM_LOG health_log; // alarms historical events (event log)
+ uint32_t health_last_processed_id; // the last processed health id from the log
+ uint32_t health_max_unique_id; // the max alarm log unique id given for the host
+ uint32_t health_max_alarm_id; // the max alarm id given for the host
// templates of alarms
// these are used to create alarms when charts
diff --git a/src/rrd2json.c b/src/rrd2json.c
index 98080139..84d90448 100644
--- a/src/rrd2json.c
+++ b/src/rrd2json.c
@@ -213,14 +213,14 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, st->units);
else {
if(rd->multiplier < 0 || rd->divisor < 0) n = -n;
- n = roundl(n);
+ n = calculated_number_round(n);
if(!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) total += n;
buffer_sprintf(wb, "NETDATA_%s_%s=\"%0.0Lf\" # %s\n", chart, dimension, n, st->units);
}
}
}
- total = roundl(total);
+ total = calculated_number_round(total);
buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"%0.0Lf\" # %s\n", chart, total, st->units);
rrdset_unlock(st);
}
@@ -243,7 +243,7 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
if(isnan(n) || isinf(n))
buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rc->units);
else {
- n = roundl(n);
+ n = calculated_number_round(n);
buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"%0.0Lf\" # %s\n", chart, alarm, n, rc->units);
}
@@ -1573,13 +1573,13 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
switch(group_method) {
case GROUP_MIN:
if(unlikely(isnan(group_values[c])) ||
- fabsl(value) < fabsl(group_values[c]))
+ calculated_number_fabs(value) < calculated_number_fabs(group_values[c]))
group_values[c] = value;
break;
case GROUP_MAX:
if(unlikely(isnan(group_values[c])) ||
- fabsl(value) > fabsl(group_values[c]))
+ calculated_number_fabs(value) > calculated_number_fabs(group_values[c]))
group_values[c] = value;
break;
diff --git a/src/rrddim.c b/src/rrddim.c
index e75aa3fd..8df54839 100644
--- a/src/rrddim.c
+++ b/src/rrddim.c
@@ -167,11 +167,11 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
}
if(rd->multiplier != multiplier) {
- info("File %s does not have the expected multiplier (expected " COLLECTED_NUMBER_FORMAT ", found " COLLECTED_NUMBER_FORMAT ". Previous values may be wrong.", fullfilename, multiplier, rd->multiplier);
+ info("File %s does not have the expected multiplier (expected " COLLECTED_NUMBER_FORMAT ", found " COLLECTED_NUMBER_FORMAT "). Previous values may be wrong.", fullfilename, multiplier, rd->multiplier);
}
if(rd->divisor != divisor) {
- info("File %s does not have the expected divisor (expected " COLLECTED_NUMBER_FORMAT ", found " COLLECTED_NUMBER_FORMAT ". Previous values may be wrong.", fullfilename, divisor, rd->divisor);
+ info("File %s does not have the expected divisor (expected " COLLECTED_NUMBER_FORMAT ", found " COLLECTED_NUMBER_FORMAT "). Previous values may be wrong.", fullfilename, divisor, rd->divisor);
}
}
}
diff --git a/src/rrdpush.c b/src/rrdpush.c
index 6def90fe..c1d052fd 100644
--- a/src/rrdpush.c
+++ b/src/rrdpush.c
@@ -113,12 +113,12 @@ static inline void send_chart_definition(RRDSET *st) {
// sends the current chart dimensions
static inline void send_chart_metrics(RRDSET *st) {
- buffer_sprintf(st->rrdhost->rrdpush_buffer, "BEGIN %s %llu\n", st->id, (st->upstream_resync_time > st->last_collected_time.tv_sec)?st->usec_since_last_update:0);
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "BEGIN \"%s\" %llu\n", st->id, (st->upstream_resync_time > st->last_collected_time.tv_sec)?st->usec_since_last_update:0);
RRDDIM *rd;
rrddim_foreach_read(rd, st) {
if(rd->updated && rd->exposed)
- buffer_sprintf(st->rrdhost->rrdpush_buffer, "SET %s = " COLLECTED_NUMBER_FORMAT "\n"
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "SET \"%s\" = " COLLECTED_NUMBER_FORMAT "\n"
, rd->id
, rd->collected_value
);
@@ -380,7 +380,7 @@ void *rrdpush_sender_thread(void *ptr) {
// allow appending data into rrdpush_buffer
host->rrdpush_connected = 1;
- debug(D_STREAM, "Connected...");
+ debug(D_STREAM, "STREAM: Connected on fd %d...", host->rrdpush_socket);
}
ifd->fd = host->rrdpush_pipe[PIPE_READ];
@@ -389,13 +389,13 @@ void *rrdpush_sender_thread(void *ptr) {
ofd->fd = host->rrdpush_socket;
ofd->revents = 0;
- if(begin < buffer_strlen(host->rrdpush_buffer)) {
- debug(D_STREAM, "STREAM: Requesting data output on streaming socket...");
+ if(ofd->fd != -1 && begin < buffer_strlen(host->rrdpush_buffer)) {
+ debug(D_STREAM, "STREAM: Requesting data output on streaming socket %d...", ofd->fd);
ofd->events = POLLOUT;
fdmax = 2;
}
else {
- debug(D_STREAM, "STREAM: Not requesting data output on streaming socket (nothing to send now)...");
+ debug(D_STREAM, "STREAM: Not requesting data output on streaming socket %d (nothing to send now)...", ofd->fd);
ofd->events = 0;
fdmax = 1;
}
@@ -419,7 +419,7 @@ void *rrdpush_sender_thread(void *ptr) {
break;
}
else if(likely(retval)) {
- if (ifd->revents & POLLIN) {
+ if (ifd->revents & POLLIN || ifd->revents & POLLPRI) {
debug(D_STREAM, "STREAM: Data added to send buffer (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_buffer));
char buffer[1000 + 1];
@@ -427,67 +427,98 @@ void *rrdpush_sender_thread(void *ptr) {
error("STREAM %s [send to %s]: cannot read from internal pipe.", host->hostname, connected_to);
}
- if (ofd->revents & POLLOUT && begin < buffer_strlen(host->rrdpush_buffer)) {
- debug(D_STREAM, "STREAM: Sending data (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_buffer));
-
- // BEGIN RRDPUSH LOCKED SESSION
-
- // during this session, data collectors
- // will not be able to append data to our buffer
- // but the socket is in non-blocking mode
- // so, we will not block at send()
-
- if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
- error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname);
-
- debug(D_STREAM, "STREAM: Getting exclusive lock on host...");
- rrdpush_lock(host);
-
- debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_buffer));
- ssize_t ret = send(host->rrdpush_socket, &host->rrdpush_buffer->buffer[begin], buffer_strlen(host->rrdpush_buffer) - begin, MSG_DONTWAIT);
- if (unlikely(ret == -1)) {
- if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
- debug(D_STREAM, "STREAM: Send failed - closing socket...");
- error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection);
- close(host->rrdpush_socket);
- host->rrdpush_socket = -1;
+ if (ofd->revents & POLLOUT) {
+ if (begin < buffer_strlen(host->rrdpush_buffer)) {
+ debug(D_STREAM, "STREAM: Sending data (current buffer length %zu bytes, begin = %zu)...", buffer_strlen(host->rrdpush_buffer), begin);
+
+ // BEGIN RRDPUSH LOCKED SESSION
+
+ // during this session, data collectors
+ // will not be able to append data to our buffer
+ // but the socket is in non-blocking mode
+ // so, we will not block at send()
+
+ if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname);
+
+ debug(D_STREAM, "STREAM: Getting exclusive lock on host...");
+ rrdpush_lock(host);
+
+ debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_buffer));
+ ssize_t ret = send(host->rrdpush_socket, &host->rrdpush_buffer->buffer[begin], buffer_strlen(host->rrdpush_buffer) - begin, MSG_DONTWAIT);
+ if (unlikely(ret == -1)) {
+ if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
+ debug(D_STREAM, "STREAM: Send failed - closing socket...");
+ error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+ else {
+ debug(D_STREAM, "STREAM: Send failed - will retry...");
+ }
+ }
+ else if (likely(ret > 0)) {
+ // DEBUG - dump the scring to see it
+ //char c = host->rrdpush_buffer->buffer[begin + ret];
+ //host->rrdpush_buffer->buffer[begin + ret] = '\0';
+ //debug(D_STREAM, "STREAM: sent from %zu to %zd:\n%s\n", begin, ret, &host->rrdpush_buffer->buffer[begin]);
+ //host->rrdpush_buffer->buffer[begin + ret] = c;
+
+ sent_connection += ret;
+ sent_bytes += ret;
+ begin += ret;
+
+ if (begin == buffer_strlen(host->rrdpush_buffer)) {
+ // we send it all
+
+ debug(D_STREAM, "STREAM: Sent %zd bytes (the whole buffer)...", ret);
+ buffer_flush(host->rrdpush_buffer);
+ begin = 0;
+ }
+ else {
+ debug(D_STREAM, "STREAM: Sent %zd bytes (part of the data buffer)...", ret);
+ }
+
+ last_sent_t = now_monotonic_sec();
}
else {
- debug(D_STREAM, "STREAM: Send failed - will retry...");
+ debug(D_STREAM, "STREAM: send() returned %zd - closing the socket...", ret);
+ error("STREAM %s [send to %s]: failed to send metrics (send() returned %zd) - closing connection - we have sent %zu bytes on this connection.",
+ host->hostname, connected_to, ret, sent_connection);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
}
- }
- else if(likely(ret > 0)) {
- sent_connection += ret;
- sent_bytes += ret;
- begin += ret;
- if (begin == buffer_strlen(host->rrdpush_buffer)) {
- // we send it all
+ debug(D_STREAM, "STREAM: Releasing exclusive lock on host...");
+ rrdpush_unlock(host);
- debug(D_STREAM, "STREAM: Sent %zd bytes (the whole buffer)...", ret);
- buffer_flush(host->rrdpush_buffer);
- begin = 0;
- }
- else {
- debug(D_STREAM, "STREAM: Sent %zd bytes (part of the data buffer)...", ret);
- }
+ if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname);
- last_sent_t = now_monotonic_sec();
+ // END RRDPUSH LOCKED SESSION
}
else {
- debug(D_STREAM, "STREAM: send() returned %zd - closing the socket...", ret);
- error("STREAM %s [send to %s]: failed to send metrics (send() returned %zd) - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, ret, sent_connection);
- close(host->rrdpush_socket);
- host->rrdpush_socket = -1;
+ debug(D_STREAM, "STREAM: we have sent the entire buffer, but we received POLLOUT...");
}
+ }
- debug(D_STREAM, "STREAM: Releasing exclusive lock on host...");
- rrdpush_unlock(host);
-
- if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
- error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname);
-
- // END RRDPUSH LOCKED SESSION
+ if(unlikely(ofd->revents & POLLERR)) {
+ debug(D_STREAM, "STREAM: Send failed (POLLERR) - closing socket...");
+ error("STREAM %s [send to %s]: connection reports errors (POLLERR), closing it - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+ else if(unlikely(ofd->revents & POLLHUP)) {
+ debug(D_STREAM, "STREAM: Send failed (POLLHUP) - closing socket...");
+ error("STREAM %s [send to %s]: connection closed by remote end (POLLHUP) - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+ else if(unlikely(ofd->revents & POLLNVAL)) {
+ debug(D_STREAM, "STREAM: Send failed (POLLNVAL) - closing socket...");
+ error("STREAM %s [send to %s]: connection is invalid (POLLNVAL), closing it - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
}
}
else {
@@ -602,7 +633,7 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const
, host->rrd_history_entries
, rrd_memory_mode_name(host->rrd_memory_mode)
, (health_enabled == CONFIG_BOOLEAN_NO)?"disabled":((health_enabled == CONFIG_BOOLEAN_YES)?"enabled":"auto")
- , host->tags
+ , host->tags?host->tags:""
);
#endif // NETDATA_INTERNAL_CHECKS
@@ -648,8 +679,15 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const
host->connected_senders++;
rrdhost_flag_clear(host, RRDHOST_ORPHAN);
- if(health_enabled != CONFIG_BOOLEAN_NO)
- host->health_delay_up_to = now_realtime_sec() + alarms_delay;
+ if(health_enabled != CONFIG_BOOLEAN_NO) {
+ if(alarms_delay > 0) {
+ host->health_delay_up_to = now_realtime_sec() + alarms_delay;
+ info("Postponing health checks for %ld seconds, on host '%s', because it was just connected."
+ , alarms_delay
+ , host->hostname
+ );
+ }
+ }
rrdhost_unlock(host);
// call the plugins.d processor to receive the metrics
diff --git a/src/rrdset.c b/src/rrdset.c
index caa427ff..c5168f02 100644
--- a/src/rrdset.c
+++ b/src/rrdset.c
@@ -582,10 +582,15 @@ RRDSET *rrdset_create_custom(
st->chart_type = rrdset_type_id(config_get(st->config_section, "chart type", rrdset_type_name(chart_type)));
st->type = config_get(st->config_section, "type", type);
+
st->family = config_get(st->config_section, "family", family?family:st->type);
+ json_fix_string(st->family);
+
st->units = config_get(st->config_section, "units", units?units:"");
+ json_fix_string(st->units);
st->context = config_get(st->config_section, "context", context?context:st->id);
+ json_fix_string(st->context);
st->hash_context = simple_hash(st->context);
st->priority = config_get_number(st->config_section, "priority", priority);
diff --git a/src/signals.c b/src/signals.c
new file mode 100644
index 00000000..331e8035
--- /dev/null
+++ b/src/signals.c
@@ -0,0 +1,168 @@
+#include "common.h"
+
+typedef enum signal_action {
+ NETDATA_SIGNAL_END_OF_LIST,
+ NETDATA_SIGNAL_IGNORE,
+ NETDATA_SIGNAL_EXIT_CLEANLY,
+ NETDATA_SIGNAL_SAVE_DATABASE,
+ NETDATA_SIGNAL_LOG_ROTATE,
+ NETDATA_SIGNAL_RELOAD_HEALTH,
+ NETDATA_SIGNAL_FATAL,
+} SIGNAL_ACTION;
+
+static struct {
+ int signo; // the signal
+ const char *name; // the name of the signal
+ size_t count; // the number of signals received
+ SIGNAL_ACTION action; // the action to take
+} signals_waiting[] = {
+ { SIGPIPE, "SIGPIPE", 0, NETDATA_SIGNAL_IGNORE },
+ { SIGINT , "SIGINT", 0, NETDATA_SIGNAL_EXIT_CLEANLY },
+ { SIGQUIT, "SIGQUIT", 0, NETDATA_SIGNAL_EXIT_CLEANLY },
+ { SIGTERM, "SIGTERM", 0, NETDATA_SIGNAL_EXIT_CLEANLY },
+ { SIGHUP, "SIGHUP", 0, NETDATA_SIGNAL_LOG_ROTATE },
+ { SIGUSR1, "SIGUSR1", 0, NETDATA_SIGNAL_SAVE_DATABASE },
+ { SIGUSR2, "SIGUSR2", 0, NETDATA_SIGNAL_RELOAD_HEALTH },
+ { SIGBUS, "SIGBUS", 0, NETDATA_SIGNAL_FATAL },
+
+ // terminator
+ { 0, "NONE", 0, NETDATA_SIGNAL_END_OF_LIST }
+};
+
+static void signal_handler(int signo) {
+ // find the entry in the list
+ int i;
+ for(i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST ; i++) {
+ if(unlikely(signals_waiting[i].signo == signo)) {
+ signals_waiting[i].count++;
+
+ if(signals_waiting[i].action == NETDATA_SIGNAL_FATAL) {
+ char buffer[200 + 1];
+ snprintfz(buffer, 200, "\nSIGNAL HANLDER: received: %s. Oops! This is bad!\n", signals_waiting[i].name);
+ if(write(STDERR_FILENO, buffer, strlen(buffer)) == -1) {
+ // nothing to do - we cannot write but there is no way to complaint about it
+ ;
+ }
+ }
+
+ return;
+ }
+ }
+}
+
+void signals_block(void) {
+ sigset_t sigset;
+ sigfillset(&sigset);
+
+ if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
+ error("SIGNAL: Could not block signals for threads");
+}
+
+void signals_unblock(void) {
+ sigset_t sigset;
+ sigfillset(&sigset);
+
+ if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
+ error("SIGNAL: Could not unblock signals for threads");
+ }
+}
+
+void signals_init(void) {
+ // Catch signals which we want to use
+ struct sigaction sa;
+ sa.sa_flags = 0;
+
+ // ignore all signals while we run in a signal handler
+ sigfillset(&sa.sa_mask);
+
+ int i;
+ for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) {
+ if(signals_waiting[i].action == NETDATA_SIGNAL_IGNORE)
+ sa.sa_handler = SIG_IGN;
+ else
+ sa.sa_handler = signal_handler;
+
+ if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1)
+ error("SIGNAL: Failed to change signal handler for: %s", signals_waiting[i].name);
+ }
+}
+
+void signals_reset(void) {
+ struct sigaction sa;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = 0;
+
+ int i;
+ for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) {
+ if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1)
+ error("SIGNAL: Failed to reset signal handler for: %s", signals_waiting[i].name);
+ }
+}
+
+void signals_handle(void) {
+ while(1) {
+
+ // pause() causes the calling process (or thread) to sleep until a signal
+ // is delivered that either terminates the process or causes the invocation
+ // of a signal-catching function.
+ if(pause() == -1 && errno == EINTR) {
+
+ // loop once, but keep looping while signals are coming in
+ // this is needed because a few operations may take some time
+ // so we need to check for new signals before pausing again
+ int found = 1;
+ while(found) {
+ found = 0;
+
+ // execute the actions of the signals
+ int i;
+ for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) {
+ if (signals_waiting[i].count) {
+ found = 1;
+ signals_waiting[i].count = 0;
+ const char *name = signals_waiting[i].name;
+
+ switch (signals_waiting[i].action) {
+ case NETDATA_SIGNAL_RELOAD_HEALTH:
+ error_log_limit_unlimited();
+ info("SIGNAL: Received %s. Reloading HEALTH configuration...", name);
+ health_reload();
+ error_log_limit_reset();
+ break;
+
+ case NETDATA_SIGNAL_SAVE_DATABASE:
+ error_log_limit_unlimited();
+ info("SIGNAL: Received %s. Saving databases...", name);
+ rrdhost_save_all();
+ info("Databases saved.");
+ error_log_limit_reset();
+ break;
+
+ case NETDATA_SIGNAL_LOG_ROTATE:
+ error_log_limit_unlimited();
+ info("SIGNAL: Received %s. Reopening all log files...", name);
+ reopen_all_log_files();
+ error_log_limit_reset();
+ break;
+
+ case NETDATA_SIGNAL_EXIT_CLEANLY:
+ info("SIGNAL: Received %s. Cleaning up to exit...", name);
+ netdata_cleanup_and_exit(0);
+ exit(0);
+
+ case NETDATA_SIGNAL_FATAL:
+ fatal("SIGNAL: Received %s. netdata now exits.", name);
+
+ default:
+ info("SIGNAL: Received %s. No signal handler configured. Ignoring it.", name);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ error("SIGNAL: pause() returned but it was not interrupted by a signal.");
+ }
+}
diff --git a/src/signals.h b/src/signals.h
new file mode 100644
index 00000000..d8611ede
--- /dev/null
+++ b/src/signals.h
@@ -0,0 +1,10 @@
+#ifndef NETDATA_SIGNALS_H
+#define NETDATA_SIGNALS_H
+
+extern void signals_init(void);
+extern void signals_block(void);
+extern void signals_unblock(void);
+extern void signals_handle(void);
+extern void signals_reset(void);
+
+#endif //NETDATA_SIGNALS_H
diff --git a/src/socket.c b/src/socket.c
index 2b382119..d28df81a 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -46,9 +46,10 @@ int sock_setreuse(int fd, int reuse) {
int sock_setreuse_port(int fd, int reuse) {
int ret = -1;
+
#ifdef SO_REUSEPORT
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
- if(ret == -1)
+ if(ret == -1 && errno != ENOPROTOOPT)
error("failed to set SO_REUSEPORT on socket %d", fd);
#endif
@@ -80,6 +81,50 @@ int sock_enlarge_out(int fd) {
// --------------------------------------------------------------------------------------------------------------------
// listening sockets
+int create_listen_socket_unix(const char *path, int listen_backlog) {
+ int sock;
+
+ debug(D_LISTENER, "LISTENER: UNIX creating new listening socket on path '%s'", path);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(sock < 0) {
+ error("LISTENER: UNIX socket() on path '%s' failed.", path);
+ return -1;
+ }
+
+ sock_setnonblock(sock);
+ sock_enlarge_in(sock);
+
+ struct sockaddr_un name;
+ memset(&name, 0, sizeof(struct sockaddr_un));
+ name.sun_family = AF_UNIX;
+ strncpy(name.sun_path, path, sizeof(name.sun_path)-1);
+
+ errno = 0;
+ if (unlink(path) == -1 && errno != ENOENT)
+ error("LISTENER: failed to remove existing (probably obsolete or left-over) file on UNIX socket path '%s'.", path);
+
+ if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
+ close(sock);
+ error("LISTENER: UNIX bind() on path '%s' failed.", path);
+ return -1;
+ }
+
+ // we have to chmod this to 0777 so that the client will be able
+ // to read from and write to this socket.
+ if(chmod(path, 0777) == -1)
+ error("LISTENER: failed to chmod() socket file '%s'.", path);
+
+ if(listen(sock, listen_backlog) < 0) {
+ close(sock);
+ error("LISTENER: UNIX listen() on path '%s' failed.", path);
+ return -1;
+ }
+
+ debug(D_LISTENER, "LISTENER: Listening on UNIX path '%s'", path);
+ return sock;
+}
+
int create_listen_socket4(int socktype, const char *ip, int port, int listen_backlog) {
int sock;
@@ -176,7 +221,7 @@ int create_listen_socket6(int socktype, uint32_t scope_id, const char *ip, int p
return sock;
}
-static inline int listen_sockets_add(LISTEN_SOCKETS *sockets, int fd, int socktype, const char *protocol, const char *ip, int port) {
+static inline int listen_sockets_add(LISTEN_SOCKETS *sockets, int fd, int family, int socktype, const char *protocol, const char *ip, int port) {
if(sockets->opened >= MAX_LISTEN_FDS) {
error("LISTENER: Too many listening sockets. Failed to add listening %s socket at ip '%s' port %d, protocol %s, socktype %d", protocol, ip, port, protocol, socktype);
close(fd);
@@ -184,11 +229,27 @@ static inline int listen_sockets_add(LISTEN_SOCKETS *sockets, int fd, int sockty
}
sockets->fds[sockets->opened] = fd;
+ sockets->fds_types[sockets->opened] = socktype;
+ sockets->fds_families[sockets->opened] = family;
char buffer[100 + 1];
- snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port);
+
+ switch(family) {
+ case AF_INET:
+ snprintfz(buffer, 100, "%s:%s:%d", protocol, ip, port);
+ break;
+
+ case AF_INET6:
+ default:
+ snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port);
+ break;
+
+ case AF_UNIX:
+ snprintfz(buffer, 100, "%s:%s", protocol, ip);
+ break;
+ }
+
sockets->fds_names[sockets->opened] = strdupz(buffer);
- sockets->fds_types[sockets->opened] = socktype;
sockets->opened++;
return 0;
@@ -230,7 +291,7 @@ void listen_sockets_close(LISTEN_SOCKETS *sockets) {
sockets->failed = 0;
}
-static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) {
+static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) {
int added = 0;
struct addrinfo hints;
struct addrinfo *result = NULL, *rp = NULL;
@@ -258,6 +319,22 @@ static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, i
socktype = SOCK_DGRAM;
protocol_str = "udp";
}
+ else if(strncmp(ip, "unix:", 5) == 0) {
+ char *path = ip + 5;
+ socktype = SOCK_STREAM;
+ protocol_str = "unix";
+
+ int fd = create_listen_socket_unix(path, listen_backlog);
+ if (fd == -1) {
+ error("LISTENER: Cannot create unix socket '%s'", path);
+ sockets->failed++;
+ }
+ else {
+ listen_sockets_add(sockets, fd, AF_UNIX, socktype, protocol_str, path, 0);
+ added++;
+ }
+ return added;
+ }
char *e = ip;
if(*e == '[') {
@@ -314,11 +391,13 @@ static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, i
for (rp = result; rp != NULL; rp = rp->ai_next) {
int fd = -1;
+ int family = -1;
char rip[INET_ADDRSTRLEN + INET6_ADDRSTRLEN] = "INVALID";
int rport = default_port;
- switch (rp->ai_addr->sa_family) {
+ family = rp->ai_addr->sa_family;
+ switch (family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *) rp->ai_addr;
inet_ntop(AF_INET, &sin->sin_addr, rip, INET_ADDRSTRLEN);
@@ -338,7 +417,7 @@ static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, i
}
default:
- debug(D_LISTENER, "LISTENER: Unknown socket family %d", rp->ai_addr->sa_family);
+ debug(D_LISTENER, "LISTENER: Unknown socket family %d", family);
break;
}
@@ -347,7 +426,7 @@ static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, i
sockets->failed++;
}
else {
- listen_sockets_add(sockets, fd, socktype, protocol_str, rip, rport);
+ listen_sockets_add(sockets, fd, family, socktype, protocol_str, rip, rport);
added++;
}
}
@@ -385,7 +464,7 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
char buf[e - s + 1];
strncpyz(buf, s, e - s);
- bind_to_one(sockets, buf, sockets->default_port, sockets->backlog);
+ bind_to_this(sockets, buf, sockets->default_port, sockets->backlog);
s = e;
}
@@ -403,7 +482,39 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
// --------------------------------------------------------------------------------------------------------------------
// connect to another host/port
-// _connect_to()
+// connect_to_this_unix()
+// path the path of the unix socket
+// timeout the timeout for establishing a connection
+
+static inline int connect_to_unix(const char *path, struct timeval *timeout) {
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd == -1) {
+ error("Failed to create UNIX socket() for '%s'", path);
+ return -1;
+ }
+
+ if(timeout) {
+ if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0)
+ error("Failed to set timeout on UNIX socket '%s'", path);
+ }
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+
+ if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ error("Cannot connect to UNIX socket on path '%s'.", path);
+ close(fd);
+ return -1;
+ }
+
+ debug(D_CONNECT_TO, "Connected to UNIX socket on path '%s'.", path);
+
+ return fd;
+}
+
+// connect_to_this_ip46()
// protocol IPPROTO_TCP, IPPROTO_UDP
// socktype SOCK_STREAM, SOCK_DGRAM
// host the destination hostname or IP address (IPv4 or IPv6) to connect to
@@ -413,7 +524,7 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
// service the service name or port to connect to
// timeout the timeout for establishing a connection
-static inline int _connect_to(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) {
+static inline int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) {
struct addrinfo hints;
struct addrinfo *ai_head = NULL, *ai = NULL;
@@ -519,7 +630,7 @@ static inline int _connect_to(int protocol, int socktype, const char *host, uint
return fd;
}
-// connect_to()
+// connect_to_this()
//
// definition format:
//
@@ -530,7 +641,7 @@ static inline int _connect_to(int protocol, int socktype, const char *host, uint
// INTERFACE = for IPv6 only, the network interface to use
// PORT = port number or service name
-int connect_to(const char *definition, int default_port, struct timeval *timeout) {
+int connect_to_this(const char *definition, int default_port, struct timeval *timeout) {
char buffer[strlen(definition) + 1];
strcpy(buffer, definition);
@@ -551,6 +662,10 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
protocol = IPPROTO_UDP;
socktype = SOCK_DGRAM;
}
+ else if(strncmp(host, "unix:", 5) == 0) {
+ char *path = host + 5;
+ return connect_to_unix(path, timeout);
+ }
char *e = host;
if(*e == '[') {
@@ -595,7 +710,7 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
service = default_service;
- return _connect_to(protocol, socktype, host, scope_id, service, timeout);
+ return connect_to_this_ip46(protocol, socktype, host, scope_id, service, timeout);
}
int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) {
@@ -617,7 +732,7 @@ int connect_to_one_of(const char *destination, int default_port, struct timeval
char buf[e - s + 1];
strncpyz(buf, s, e - s);
if(reconnects_counter) *reconnects_counter += 1;
- sock = connect_to(buf, default_port, timeout);
+ sock = connect_to_this(buf, default_port, timeout);
if(sock != -1) {
if(connected_to && connected_to_size) {
strncpy(connected_to, buf, connected_to_size);
@@ -747,7 +862,7 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien
socklen_t addrlen = sizeof(sadr);
int nfd = accept4(fd, (struct sockaddr *)&sadr, &addrlen, flags);
- if (nfd >= 0) {
+ if (likely(nfd >= 0)) {
if (getnameinfo((struct sockaddr *)&sadr, addrlen, client_ip, (socklen_t)ipsize, client_port, (socklen_t)portsize, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
error("LISTENER: cannot getnameinfo() on received client connection.");
strncpyz(client_ip, "UNKNOWN", ipsize - 1);
@@ -775,6 +890,10 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien
break;
}
}
+#ifdef HAVE_ACCEPT4
+ else if(errno == ENOSYS)
+ error("netdata has been compiled with the assumption that the system has the accept4() call, but it is not here. Recompile netdata like this: ./configure --disable-accept4 ...");
+#endif
return nfd;
}
diff --git a/src/socket.h b/src/socket.h
index bb95347a..8ca7288c 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -15,13 +15,14 @@ typedef struct listen_sockets {
size_t failed; // the number of sockets attempted to open, but failed
int fds[MAX_LISTEN_FDS]; // the open sockets
char *fds_names[MAX_LISTEN_FDS]; // descriptions for the open sockets
- int fds_types[MAX_LISTEN_FDS]; // the socktype for the open sockets
+ int fds_types[MAX_LISTEN_FDS]; // the socktype for the open sockets (SOCK_STREAM, SOCK_DGRAM)
+ int fds_families[MAX_LISTEN_FDS]; // the family of the open sockets (AF_UNIX, AF_INET, AF_INET6)
} LISTEN_SOCKETS;
extern int listen_sockets_setup(LISTEN_SOCKETS *sockets);
extern void listen_sockets_close(LISTEN_SOCKETS *sockets);
-extern int connect_to(const char *definition, int default_port, struct timeval *timeout);
+extern int connect_to_this(const char *definition, int default_port, struct timeval *timeout);
extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size);
extern ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
diff --git a/src/statsd.c b/src/statsd.c
index 4dd04757..08ce3e2f 100644
--- a/src/statsd.c
+++ b/src/statsd.c
@@ -232,6 +232,7 @@ static struct statsd {
int update_every;
SIMPLE_PATTERN *charts_for;
+ size_t decimal_detail;
size_t private_charts;
size_t max_private_charts;
size_t max_private_charts_hard;
@@ -250,6 +251,7 @@ static struct statsd {
.max_private_charts = 200,
.max_private_charts_hard = 1000,
.recvmmsg_size = 10,
+ .decimal_detail = STATSD_DECIMAL_DETAIL,
.gauges = {
.name = "gauge",
@@ -443,7 +445,7 @@ static inline void statsd_process_counter(STATSD_METRIC *m, const char *value, c
if(unlikely(m->reset)) statsd_reset_metric(m);
- m->counter.value += roundl((long double)statsd_parse_int(value, 1) / statsd_parse_float(sampling, 1.0));
+ m->counter.value += llrintl((long double)statsd_parse_int(value, 1) / statsd_parse_float(sampling, 1.0));
m->events++;
m->count++;
@@ -1286,7 +1288,7 @@ static inline void statsd_private_chart_gauge(STATSD_METRIC *m) {
, RRDSET_TYPE_LINE
);
- m->rd_value = rrddim_add(m->st, "gauge", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_value = rrddim_add(m->st, "gauge", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT)
m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -1394,13 +1396,13 @@ static inline void statsd_private_chart_timer_or_histogram(STATSD_METRIC *m, con
, RRDSET_TYPE_AREA
);
- m->histogram.ext->rd_min = rrddim_add(m->st, "min", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
- m->histogram.ext->rd_max = rrddim_add(m->st, "max", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
- m->rd_value = rrddim_add(m->st, "average", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
- m->histogram.ext->rd_percentile = rrddim_add(m->st, statsd.histogram_percentile_str, NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
- m->histogram.ext->rd_median = rrddim_add(m->st, "median", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
- m->histogram.ext->rd_stddev = rrddim_add(m->st, "stddev", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
- m->histogram.ext->rd_sum = rrddim_add(m->st, "sum", NULL, 1, STATSD_DECIMAL_DETAIL, RRD_ALGORITHM_ABSOLUTE);
+ m->histogram.ext->rd_min = rrddim_add(m->st, "min", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
+ m->histogram.ext->rd_max = rrddim_add(m->st, "max", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_value = rrddim_add(m->st, "average", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
+ m->histogram.ext->rd_percentile = rrddim_add(m->st, statsd.histogram_percentile_str, NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
+ m->histogram.ext->rd_median = rrddim_add(m->st, "median", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
+ m->histogram.ext->rd_stddev = rrddim_add(m->st, "stddev", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
+ m->histogram.ext->rd_sum = rrddim_add(m->st, "sum", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE);
if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT)
m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -1429,7 +1431,7 @@ static inline void statsd_flush_gauge(STATSD_METRIC *m) {
int updated = 0;
if(m->count && !m->reset) {
- m->last = (collected_number) (m->gauge.value * STATSD_DECIMAL_DETAIL);
+ m->last = (collected_number) (m->gauge.value * statsd.decimal_detail);
m->reset = 1;
updated = 1;
@@ -1488,18 +1490,18 @@ static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char
long double *series = m->histogram.ext->values;
sort_series(series, len);
- m->histogram.ext->last_min = (collected_number)roundl(series[0] * STATSD_DECIMAL_DETAIL);
- m->histogram.ext->last_max = (collected_number)roundl(series[len - 1] * STATSD_DECIMAL_DETAIL);
- m->last = (collected_number)roundl(average(series, len) * STATSD_DECIMAL_DETAIL);
- m->histogram.ext->last_median = (collected_number)roundl(median_on_sorted_series(series, len) * STATSD_DECIMAL_DETAIL);
- m->histogram.ext->last_stddev = (collected_number)roundl(standard_deviation(series, len) * STATSD_DECIMAL_DETAIL);
- m->histogram.ext->last_sum = (collected_number)roundl(sum(series, len) * STATSD_DECIMAL_DETAIL);
+ m->histogram.ext->last_min = (collected_number)roundl(series[0] * statsd.decimal_detail);
+ m->histogram.ext->last_max = (collected_number)roundl(series[len - 1] * statsd.decimal_detail);
+ m->last = (collected_number)roundl(average(series, len) * statsd.decimal_detail);
+ m->histogram.ext->last_median = (collected_number)roundl(median_on_sorted_series(series, len) * statsd.decimal_detail);
+ m->histogram.ext->last_stddev = (collected_number)roundl(standard_deviation(series, len) * statsd.decimal_detail);
+ m->histogram.ext->last_sum = (collected_number)roundl(sum(series, len) * statsd.decimal_detail);
size_t pct_len = (size_t)floor((double)len * statsd.histogram_percentile / 100.0);
if(pct_len < 1)
- m->histogram.ext->last_percentile = (collected_number)(series[0] * STATSD_DECIMAL_DETAIL);
+ m->histogram.ext->last_percentile = (collected_number)(series[0] * statsd.decimal_detail);
else
- m->histogram.ext->last_percentile = (collected_number)roundl(average(series, pct_len) * STATSD_DECIMAL_DETAIL);
+ m->histogram.ext->last_percentile = (collected_number)roundl(series[pct_len - 1] * statsd.decimal_detail);
debug(D_STATSD, "STATSD %s metric %s: min " COLLECTED_NUMBER_FORMAT ", max " COLLECTED_NUMBER_FORMAT ", last " COLLECTED_NUMBER_FORMAT ", pcent " COLLECTED_NUMBER_FORMAT ", median " COLLECTED_NUMBER_FORMAT ", stddev " COLLECTED_NUMBER_FORMAT ", sum " COLLECTED_NUMBER_FORMAT,
dim, m->name, m->histogram.ext->last_min, m->histogram.ext->last_max, m->last, m->histogram.ext->last_percentile, m->histogram.ext->last_median, m->histogram.ext->last_stddev, m->histogram.ext->last_sum);
@@ -1574,7 +1576,7 @@ static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC
}
else if(m->type == STATSD_METRIC_TYPE_HISTOGRAM || m->type == STATSD_METRIC_TYPE_TIMER) {
dim->algorithm = RRD_ALGORITHM_ABSOLUTE;
- dim->divisor *= STATSD_DECIMAL_DETAIL;
+ dim->divisor *= statsd.decimal_detail;
switch(dim->value_type) {
case STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS:
@@ -1619,7 +1621,7 @@ static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC
dim->algorithm = statsd_algorithm_for_metric(m);
if(m->type == STATSD_METRIC_TYPE_GAUGE)
- dim->divisor *= STATSD_DECIMAL_DETAIL;
+ dim->divisor *= statsd.decimal_detail;
}
if(unlikely(chart->st && dim->rd)) {
@@ -1776,6 +1778,7 @@ void *statsd_main(void *ptr) {
statsd.max_private_charts_hard = (size_t)config_get_number(CONFIG_SECTION_STATSD, "max private charts hard limit", (long long)statsd.max_private_charts * 5);
statsd.private_charts_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_STATSD, "private charts memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));
statsd.private_charts_rrd_history_entries = (int)config_get_number(CONFIG_SECTION_STATSD, "private charts history", default_rrd_history_entries);
+ statsd.decimal_detail = (size_t)config_get_number(CONFIG_SECTION_STATSD, "decimal detail", (long long int)statsd.decimal_detail);
statsd.histogram_percentile = (double)config_get_float(CONFIG_SECTION_STATSD, "histograms and timers percentile (percentThreshold)", statsd.histogram_percentile);
if(isless(statsd.histogram_percentile, 0) || isgreater(statsd.histogram_percentile, 100)) {
@@ -1922,13 +1925,13 @@ void *statsd_main(void *ptr) {
, "statsd"
, NULL
, "Bytes read by the netdata statsd server"
- , "kbps"
+ , "kilobits/s"
, 132003
, statsd.update_every
, RRDSET_TYPE_STACKED
);
- RRDDIM *rd_bytes_tcp = rrddim_add(st_bytes, "tcp", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
- RRDDIM *rd_bytes_udp = rrddim_add(st_bytes, "udp", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ RRDDIM *rd_bytes_tcp = rrddim_add(st_bytes, "tcp", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ RRDDIM *rd_bytes_udp = rrddim_add(st_bytes, "udp", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
RRDSET *st_packets = rrdset_create_localhost(
"netdata"
diff --git a/src/storage_number.c b/src/storage_number.c
index 27fe5f2c..05494120 100644
--- a/src/storage_number.c
+++ b/src/storage_number.c
@@ -2,12 +2,13 @@
extern char *print_number_lu_r(char *str, unsigned long uvalue);
extern char *print_number_llu_r(char *str, unsigned long long uvalue);
+extern char *print_number_llu_r_smart(char *str, unsigned long long uvalue);
storage_number pack_storage_number(calculated_number value, uint32_t flags)
{
// bit 32 = sign 0:positive, 1:negative
// bit 31 = 0:divide, 1:multiply
- // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
+ // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
// bit 27, 26, 25 flags
// bit 24 to bit 1 = the value
@@ -105,6 +106,7 @@ calculated_number unpack_storage_number(storage_number value)
return n;
}
+/*
int print_calculated_number(char *str, calculated_number value)
{
char *wstr = str;
@@ -113,21 +115,14 @@ int print_calculated_number(char *str, calculated_number value)
if(sign) value = -value;
#ifdef STORAGE_WITH_MATH
- // without llrint() there are rounding problems
+ // without llrintl() there are rounding problems
// for example 0.9 becomes 0.89
- unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
+ unsigned long long uvalue = (unsigned long long int) llrintl(value * (calculated_number)100000);
#else
unsigned long long uvalue = value * (calculated_number)100000;
#endif
-#ifdef ENVIRONMENT32
- if(uvalue > (unsigned long long)0xffffffff)
- wstr = print_number_llu_r(str, uvalue);
- else
- wstr = print_number_lu_r(str, uvalue);
-#else
- do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
-#endif
+ wstr = print_number_llu_r_smart(str, uvalue);
// make sure we have 6 bytes at least
while((wstr - str) < 6) *wstr++ = '0';
@@ -166,3 +161,62 @@ int print_calculated_number(char *str, calculated_number value)
// return the buffer length
return (int) ((wstr - str) + 2 + decimal );
}
+*/
+
+int print_calculated_number(char *str, calculated_number value) {
+ char integral_str[50], fractional_str[50];
+
+ char *wstr = str;
+
+ if(unlikely(value < 0)) {
+ *wstr++ = '-';
+ value = -value;
+ }
+
+ calculated_number integral, fractional;
+
+#ifdef STORAGE_WITH_MATH
+ fractional = modfl(value, &integral) * 10000000.0;
+#else
+ fractional = ((unsigned long long)(value * 10000000ULL) % 10000000ULL);
+#endif
+
+ char *istre;
+ if(integral == 0.0) {
+ integral_str[0] = '0';
+ istre = &integral_str[1];
+ }
+ else
+ // convert the integral part to string (reversed)
+ istre = print_number_llu_r_smart(integral_str, (unsigned long long)integral);
+
+ // copy reversed the integral string
+ istre--;
+ while( istre >= integral_str ) *wstr++ = *istre--;
+
+ if(fractional != 0.0) {
+ // add a dot
+ *wstr++ = '.';
+
+ // convert the fractional part to string (reversed)
+ char *fstre = print_number_llu_r_smart(fractional_str, (unsigned long long)calculated_number_llrint(fractional));
+
+ // prepend zeros to reach 7 digits length
+ int decimal = 7;
+ int len = (int)(fstre - fractional_str);
+ while(len < decimal) {
+ *wstr++ = '0';
+ len++;
+ }
+
+ char *begin = fractional_str;
+ while(begin < fstre && *begin == '0') begin++;
+
+ // copy reversed the fractional string
+ fstre--;
+ while( fstre >= begin ) *wstr++ = *fstre--;
+ }
+
+ *wstr = '\0';
+ return (int)(wstr - str);
+}
diff --git a/src/storage_number.h b/src/storage_number.h
index 34ed0d89..3c1b6bab 100644
--- a/src/storage_number.h
+++ b/src/storage_number.h
@@ -14,6 +14,10 @@ typedef long double collected_number;
#define COLLECTED_NUMBER_FORMAT "%0.7Lf"
*/
+#define calculated_number_llrint(x) llrintl(x)
+#define calculated_number_round(x) roundl(x)
+#define calculated_number_fabs(x) fabsl(x)
+
typedef uint32_t storage_number;
#define STORAGE_NUMBER_FORMAT "%u"
@@ -28,7 +32,7 @@ typedef uint32_t storage_number;
#define SN_FLAGS_MASK (~(0x6 << 24))
// extract the flags
-#define get_storage_number_flags(value) ((((storage_number)value) & (1 << 24)) | (((storage_number)value) & (2 << 24)) | (((storage_number)value) & (4 << 24)))
+#define get_storage_number_flags(value) ((((storage_number)(value)) & (1 << 24)) | (((storage_number)(value)) & (2 << 24)) | (((storage_number)(value)) & (4 << 24)))
#define SN_EMPTY_SLOT 0x00000000
// checks
@@ -40,13 +44,13 @@ calculated_number unpack_storage_number(storage_number value);
int print_calculated_number(char *str, calculated_number value);
-#define STORAGE_NUMBER_POSITIVE_MAX 167772150000000.0
-#define STORAGE_NUMBER_POSITIVE_MIN 0.00001
-#define STORAGE_NUMBER_NEGATIVE_MAX -0.00001
-#define STORAGE_NUMBER_NEGATIVE_MIN -167772150000000.0
+#define STORAGE_NUMBER_POSITIVE_MAX (167772150000000.0)
+#define STORAGE_NUMBER_POSITIVE_MIN (0.0000001)
+#define STORAGE_NUMBER_NEGATIVE_MAX (-0.0000001)
+#define STORAGE_NUMBER_NEGATIVE_MIN (-167772150000000.0)
// accepted accuracy loss
#define ACCURACY_LOSS 0.0001
-#define accuracy_loss(t1, t2) ((t1 == t2 || t1 == 0.0 || t2 == 0.0) ? 0.0 : (100.0 - ((t1 > t2) ? (t2 * 100.0 / t1 ) : (t1 * 100.0 / t2))))
+#define accuracy_loss(t1, t2) (((t1) == (t2) || (t1) == 0.0 || (t2) == 0.0) ? 0.0 : (100.0 - (((t1) > (t2)) ? ((t2) * 100.0 / (t1) ) : ((t1) * 100.0 / (t2)))))
#endif /* NETDATA_STORAGE_NUMBER_H */
diff --git a/src/sys_devices_system_edac_mc.c b/src/sys_devices_system_edac_mc.c
index c41ad7fa..7ec98943 100644
--- a/src/sys_devices_system_edac_mc.c
+++ b/src/sys_devices_system_edac_mc.c
@@ -27,7 +27,7 @@ static void find_all_mc() {
char *dirname = config_get("plugin:proc:/sys/devices/system/edac/mc", "directory to monitor", name);
DIR *dir = opendir(dirname);
- if(!dir) {
+ if(unlikely(!dir)) {
error("Cannot read ECC memory errors directory '%s'", dirname);
return;
}
@@ -132,21 +132,30 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
static RRDSET *ce_st = NULL;
if(unlikely(!ce_st)) {
- ce_st = rrdset_find_localhost("mem.ecc_ce");
- if(unlikely(!ce_st))
- ce_st = rrdset_create_localhost("mem", "ecc_ce", NULL, "ecc", NULL, "ECC Memory Correctable Errors"
- , "errors", 6600, update_every, RRDSET_TYPE_LINE);
-
- for(m = mc_root; m; m = m->next)
- if(m->ce_count_filename)
- m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ ce_st = rrdset_create_localhost(
+ "mem"
+ , "ecc_ce"
+ , NULL
+ , "ecc"
+ , NULL
+ , "ECC Memory Correctable Errors"
+ , "errors"
+ , 6600
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
}
else
rrdset_next(ce_st);
- for(m = mc_root; m; m = m->next)
- if(m->ce_count_filename && m->ce_updated)
+ for(m = mc_root; m; m = m->next) {
+ if (m->ce_count_filename && m->ce_updated) {
+ if(unlikely(!m->ce_rd))
+ m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(ce_st, m->ce_rd, m->ce_count);
+ }
+ }
rrdset_done(ce_st);
}
@@ -159,22 +168,30 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
static RRDSET *ue_st = NULL;
if(unlikely(!ue_st)) {
- ue_st = rrdset_find_localhost("mem.ecc_ue");
-
- if(unlikely(!ue_st))
- ue_st = rrdset_create_localhost("mem", "ecc_ue", NULL, "ecc", NULL, "ECC Memory Uncorrectable Errors"
- , "errors", 6610, update_every, RRDSET_TYPE_LINE);
-
- for(m = mc_root; m; m = m->next)
- if(m->ue_count_filename)
- m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ ue_st = rrdset_create_localhost(
+ "mem"
+ , "ecc_ue"
+ , NULL
+ , "ecc"
+ , NULL
+ , "ECC Memory Uncorrectable Errors"
+ , "errors"
+ , 6610
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
}
else
rrdset_next(ue_st);
- for(m = mc_root; m; m = m->next)
- if(m->ue_count_filename && m->ue_updated)
+ for(m = mc_root; m; m = m->next) {
+ if (m->ue_count_filename && m->ue_updated) {
+ if(unlikely(!m->ue_rd))
+ m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(ue_st, m->ue_rd, m->ue_count);
+ }
+ }
rrdset_done(ue_st);
}
diff --git a/src/sys_fs_cgroup.c b/src/sys_fs_cgroup.c
index 0f9c8854..c047547e 100644
--- a/src/sys_fs_cgroup.c
+++ b/src/sys_fs_cgroup.c
@@ -41,7 +41,7 @@ static char *cgroup_memory_base = NULL;
static char *cgroup_devices_base = NULL;
static int cgroup_root_count = 0;
-static int cgroup_root_max = 500;
+static int cgroup_root_max = 1000;
static int cgroup_max_depth = 0;
static SIMPLE_PATTERN *enabled_cgroup_patterns = NULL;
@@ -50,6 +50,7 @@ static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
static char *cgroups_rename_script = NULL;
+static char *cgroups_network_interface_script = NULL;
static int cgroups_check = 0;
@@ -103,7 +104,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
if(!mi) {
- error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
+ error("CGROUP: cannot find cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
s = "/sys/fs/cgroup/cpuacct";
}
else s = mi->mount_point;
@@ -113,7 +114,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
if(!mi) {
- error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
+ error("CGROUP: cannot find blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
s = "/sys/fs/cgroup/blkio";
}
else s = mi->mount_point;
@@ -123,7 +124,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
if(!mi) {
- error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
+ error("CGROUP: cannot find memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
s = "/sys/fs/cgroup/memory";
}
else s = mi->mount_point;
@@ -133,7 +134,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
if(!mi) {
- error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
+ error("CGROUP: cannot find devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
s = "/sys/fs/cgroup/devices";
}
else s = mi->mount_point;
@@ -166,7 +167,7 @@ void read_cgroup_plugin_configuration() {
" !/docker "
" !/libvirt "
" !/lxc "
- " !/lxc/*/ns " // #1397
+ " !/lxc/*/* " // #1397 #2649
" !/machine "
" !/qemu "
" !/system "
@@ -184,13 +185,16 @@ void read_cgroup_plugin_configuration() {
" !/systemd "
" !/user "
" !/user.slice "
- " !/lxc/*/ns/* " // #2161
+ " !/lxc/*/* " // #2161 #2649
" * "
), SIMPLE_PATTERN_EXACT);
snprintfz(filename, FILENAME_MAX, "%s/cgroup-name.sh", netdata_configured_plugins_dir);
cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", filename);
+ snprintfz(filename, FILENAME_MAX, "%s/cgroup-network", netdata_configured_plugins_dir);
+ cgroups_network_interface_script = config_get("plugin:cgroups", "script to get cgroup network interfaces", filename);
+
enabled_cgroup_renames = simple_pattern_create(
config_get("plugin:cgroups", "run script to rename cgroups matching",
" *.scope "
@@ -329,6 +333,12 @@ struct cpuacct_usage {
unsigned long long *cpu_percpu;
};
+struct cgroup_network_interface {
+ const char *host_device;
+ const char *container_device;
+ struct cgroup_network_interface *next;
+};
+
#define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001
#define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
@@ -360,6 +370,8 @@ struct cgroup {
struct blkio io_merged; // operations
struct blkio io_queued; // operations
+ struct cgroup_network_interface *interfaces;
+
// per cgroup charts
RRDSET *st_cpu;
RRDSET *st_cpu_per_core;
@@ -433,7 +445,7 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
unsigned long i, lines = procfile_lines(ff);
if(unlikely(lines < 1)) {
- error("File '%s' should have 1+ lines.", cp->filename);
+ error("CGROUP: file '%s' should have 1+ lines.", cp->filename);
cp->updated = 0;
return;
}
@@ -475,7 +487,7 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
}
if(unlikely(procfile_lines(ff) < 1)) {
- error("File '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff));
+ error("CGROUP: file '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff));
ca->updated = 0;
return;
}
@@ -539,7 +551,7 @@ static inline void cgroup_read_blkio(struct blkio *io) {
unsigned long i, lines = procfile_lines(ff);
if(unlikely(lines < 1)) {
- error("File '%s' should have 1+ lines.", io->filename);
+ error("CGROUP: file '%s' should have 1+ lines.", io->filename);
io->updated = 0;
return;
}
@@ -612,7 +624,7 @@ static inline void cgroup_read_memory(struct memory *mem) {
unsigned long i, lines = procfile_lines(ff);
if(unlikely(lines < 1)) {
- error("File '%s' should have 1+ lines.", mem->filename_detailed);
+ error("CGROUP: file '%s' should have 1+ lines.", mem->filename_detailed);
mem->updated_detailed = 0;
goto memory_next;
}
@@ -718,6 +730,77 @@ static inline void read_all_cgroups(struct cgroup *root) {
}
// ----------------------------------------------------------------------------
+// cgroup network interfaces
+
+#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048
+static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
+ debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
+
+ pid_t cgroup_pid;
+ char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
+
+ snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id);
+
+ debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
+ FILE *fp = mypopen(buffer, &cgroup_pid);
+ if(fp) {
+ char *s;
+ while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
+ trim(s);
+
+ if(*s && *s != '\n') {
+ char *t = s;
+ while(*t && *t != ' ') t++;
+ if(*t == ' ') {
+ *t = '\0';
+ t++;
+ }
+
+ if(!*s) {
+ error("CGROUP: empty host interface returned by script");
+ continue;
+ }
+
+ if(!*t) {
+ error("CGROUP: empty container interface returned by script");
+ continue;
+ }
+
+ struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
+ i->host_device = strdupz(s);
+ i->container_device = strdupz(t);
+ i->next = cg->interfaces;
+ cg->interfaces = i;
+
+ info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
+
+ // register a device rename to proc_net_dev.c
+ netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id);
+ }
+ }
+
+ mypclose(fp, cgroup_pid);
+ // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
+ }
+ else
+ error("CGROUP: cannot popen(\"%s\", \"r\").", buffer);
+}
+
+static inline void free_cgroup_network_interfaces(struct cgroup *cg) {
+ while(cg->interfaces) {
+ struct cgroup_network_interface *i = cg->interfaces;
+ cg->interfaces = i->next;
+
+ // delete the registration of proc_net_dev rename
+ netdev_rename_device_del(i->host_device);
+
+ freez((void *)i->host_device);
+ freez((void *)i->container_device);
+ freez((void *)i);
+ }
+}
+
+// ----------------------------------------------------------------------------
// add/remove/find cgroup objects
#define CGROUP_CHARTID_LINE_MAX 1024
@@ -775,7 +858,7 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) {
}
}
else
- error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
+ error("CGROUP: cannot popen(\"%s\", \"r\").", buffer);
}
static inline struct cgroup *cgroup_add(const char *id) {
@@ -783,7 +866,7 @@ static inline struct cgroup *cgroup_add(const char *id) {
debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
if(cgroup_root_count >= cgroup_root_max) {
- info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
+ info("CGROUP: maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
return NULL;
}
@@ -872,7 +955,7 @@ static inline struct cgroup *cgroup_add(const char *id) {
for (t = cgroup_root; t; t = t->next) {
if (t != cg && t->enabled && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) {
if (!strncmp(t->chart_id, "/system.slice/", 14) && !strncmp(cg->chart_id, "/init.scope/system.slice/", 25)) {
- error("Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
+ error("CGROUP: chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id, t->id);
debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id, t->id);
@@ -880,7 +963,7 @@ static inline struct cgroup *cgroup_add(const char *id) {
t->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
}
else {
- error("Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
+ error("CGROUP: chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id);
debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id);
@@ -893,6 +976,9 @@ static inline struct cgroup *cgroup_add(const char *id) {
}
}
+ if(cg->enabled && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))
+ read_cgroup_network_interfaces(cg);
+
debug(D_CGROUP, "ADDED CGROUP: '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
return cg;
@@ -916,6 +1002,8 @@ static inline void cgroup_free(struct cgroup *cg) {
if(cg->st_queued_ops) rrdset_is_obsolete(cg->st_queued_ops);
if(cg->st_merged_ops) rrdset_is_obsolete(cg->st_merged_ops);
+ free_cgroup_network_interfaces(cg);
+
freez(cg->cpuacct_usage.cpu_percpu);
freez(cg->cpuacct_stat.filename);
@@ -979,7 +1067,7 @@ static inline void found_subdir_in_dir(const char *dir) {
depth++;
if(depth > cgroup_max_depth) {
- info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
+ info("CGROUP: '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
return;
}
}
@@ -1004,7 +1092,7 @@ static inline int find_dir_in_subdirs(const char *base, const char *this, void (
DIR *dir = opendir(this);
if(!dir) {
- error("Cannot read cgroups directory '%s'", base);
+ error("CGROUP: cannot read directory '%s'", base);
return ret;
}
ret = 1;
@@ -1110,7 +1198,7 @@ static inline void find_all_cgroups() {
if(find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
cgroup_enable_cpuacct_stat =
cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
- error("disabled CGROUP cpu statistics.");
+ error("CGROUP: disabled cpu statistics.");
}
}
@@ -1122,7 +1210,7 @@ static inline void find_all_cgroups() {
cgroup_enable_blkio_throttle_ops =
cgroup_enable_blkio_merged_ops =
cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_NO;
- error("disabled CGROUP blkio statistics.");
+ error("CGROUP: disabled blkio statistics.");
}
}
@@ -1132,14 +1220,14 @@ static inline void find_all_cgroups() {
cgroup_enable_detailed_memory =
cgroup_enable_swap =
cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_NO;
- error("disabled CGROUP memory statistics.");
+ error("CGROUP: disabled memory statistics.");
}
}
if(cgroup_search_in_devices) {
if(find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir) == -1) {
cgroup_search_in_devices = 0;
- error("disabled CGROUP devices statistics.");
+ error("CGROUP: disabled devices statistics.");
}
}
@@ -2508,13 +2596,13 @@ void update_cgroup_charts(int update_every) {
void *cgroups_main(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
- info("CGROUP Plugin thread created with task id %d", gettid());
+ info("CGROUP plugin thread created with task id %d", gettid());
if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
- error("Cannot set pthread cancel type to DEFERRED.");
+ error("CGROUP: cannot set pthread cancel type to DEFERRED.");
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
- error("Cannot set pthread cancel state to ENABLE.");
+ error("CGROUP: cannot set pthread cancel state to ENABLE.");
struct rusage thread;
diff --git a/src/sys_kernel_mm_ksm.c b/src/sys_kernel_mm_ksm.c
index 76d80853..6b04ef28 100644
--- a/src/sys_kernel_mm_ksm.c
+++ b/src/sys_kernel_mm_ksm.c
@@ -5,18 +5,18 @@ typedef struct ksm_name_value {
unsigned long long value;
} KSM_NAME_VALUE;
-#define PAGES_SHARED 0
-#define PAGES_SHARING 1
+#define PAGES_SHARED 0
+#define PAGES_SHARING 1
#define PAGES_UNSHARED 2
#define PAGES_VOLATILE 3
-#define PAGES_TO_SCAN 4
+#define PAGES_TO_SCAN 4
KSM_NAME_VALUE values[] = {
- [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
- [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
+ [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
+ [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
[PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL },
[PAGES_VOLATILE] = { "/sys/kernel/mm/ksm/pages_volatile", 0ULL },
- [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL },
+ [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL },
};
int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
@@ -24,117 +24,168 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
static procfile *ff_pages_shared = NULL, *ff_pages_sharing = NULL, *ff_pages_unshared = NULL, *ff_pages_volatile = NULL, *ff_pages_to_scan = NULL;
static long page_size = -1;
- if(page_size == -1)
+ if(unlikely(page_size == -1))
page_size = sysconf(_SC_PAGESIZE);
- if(!ff_pages_shared) {
+ if(unlikely(!ff_pages_shared)) {
snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename));
ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
- if(!ff_pages_sharing) {
+ if(unlikely(!ff_pages_sharing)) {
snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename));
ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
- if(!ff_pages_unshared) {
+ if(unlikely(!ff_pages_unshared)) {
snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename));
ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
- if(!ff_pages_volatile) {
+ if(unlikely(!ff_pages_volatile)) {
snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename));
ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
- if(!ff_pages_to_scan) {
+ if(unlikely(!ff_pages_to_scan)) {
snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename));
ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
- if(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile || !ff_pages_to_scan) return 1;
+ if(unlikely(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile || !ff_pages_to_scan))
+ return 1;
unsigned long long pages_shared = 0, pages_sharing = 0, pages_unshared = 0, pages_volatile = 0, pages_to_scan = 0, offered = 0, saved = 0;
ff_pages_shared = procfile_readall(ff_pages_shared);
- if(!ff_pages_shared) return 0; // we return 0, so that we will retry to open it next time
+ if(unlikely(!ff_pages_shared)) return 0; // we return 0, so that we will retry to open it next time
pages_shared = str2ull(procfile_lineword(ff_pages_shared, 0, 0));
ff_pages_sharing = procfile_readall(ff_pages_sharing);
- if(!ff_pages_sharing) return 0; // we return 0, so that we will retry to open it next time
+ if(unlikely(!ff_pages_sharing)) return 0; // we return 0, so that we will retry to open it next time
pages_sharing = str2ull(procfile_lineword(ff_pages_sharing, 0, 0));
ff_pages_unshared = procfile_readall(ff_pages_unshared);
- if(!ff_pages_unshared) return 0; // we return 0, so that we will retry to open it next time
+ if(unlikely(!ff_pages_unshared)) return 0; // we return 0, so that we will retry to open it next time
pages_unshared = str2ull(procfile_lineword(ff_pages_unshared, 0, 0));
ff_pages_volatile = procfile_readall(ff_pages_volatile);
- if(!ff_pages_volatile) return 0; // we return 0, so that we will retry to open it next time
+ if(unlikely(!ff_pages_volatile)) return 0; // we return 0, so that we will retry to open it next time
pages_volatile = str2ull(procfile_lineword(ff_pages_volatile, 0, 0));
ff_pages_to_scan = procfile_readall(ff_pages_to_scan);
- if(!ff_pages_to_scan) return 0; // we return 0, so that we will retry to open it next time
+ if(unlikely(!ff_pages_to_scan)) return 0; // we return 0, so that we will retry to open it next time
pages_to_scan = str2ull(procfile_lineword(ff_pages_to_scan, 0, 0));
offered = pages_sharing + pages_shared + pages_unshared + pages_volatile;
saved = pages_sharing - pages_shared;
- if(!offered || !pages_to_scan) return 0;
-
- RRDSET *st;
+ if(unlikely(!offered || !pages_to_scan)) return 0;
// --------------------------------------------------------------------
- st = rrdset_find_localhost("mem.ksm");
- if(!st) {
- st = rrdset_create_localhost("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000
- , update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ {
+ static RRDSET *st_mem_ksm = NULL;
+ static RRDDIM *rd_shared = NULL, *rd_unshared = NULL, *rd_sharing = NULL, *rd_volatile = NULL, *rd_to_scan = NULL;
+
+ if (unlikely(!st_mem_ksm)) {
+ st_mem_ksm = rrdset_create_localhost(
+ "mem"
+ , "ksm"
+ , NULL
+ , "ksm"
+ , NULL
+ , "Kernel Same Page Merging"
+ , "MB"
+ , 5000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_shared = rrddim_add(st_mem_ksm, "shared", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_unshared = rrddim_add(st_mem_ksm, "unshared", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_sharing = rrddim_add(st_mem_ksm, "sharing", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_volatile = rrddim_add(st_mem_ksm, "volatile", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_to_scan = rrddim_add(st_mem_ksm, "to_scan", "to scan", -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else
+ rrdset_next(st_mem_ksm);
+
+ rrddim_set_by_pointer(st_mem_ksm, rd_shared, pages_shared * page_size);
+ rrddim_set_by_pointer(st_mem_ksm, rd_unshared, pages_unshared * page_size);
+ rrddim_set_by_pointer(st_mem_ksm, rd_sharing, pages_sharing * page_size);
+ rrddim_set_by_pointer(st_mem_ksm, rd_volatile, pages_volatile * page_size);
+ rrddim_set_by_pointer(st_mem_ksm, rd_to_scan, pages_to_scan * page_size);
+
+ rrdset_done(st_mem_ksm);
}
- else rrdset_next(st);
-
- rrddim_set(st, "shared", pages_shared * page_size);
- rrddim_set(st, "unshared", pages_unshared * page_size);
- rrddim_set(st, "sharing", pages_sharing * page_size);
- rrddim_set(st, "volatile", pages_volatile * page_size);
- rrddim_set(st, "to_scan", pages_to_scan * page_size);
- rrdset_done(st);
-
- st = rrdset_find_localhost("mem.ksm_savings");
- if(!st) {
- st = rrdset_create_localhost("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB"
- , 5001, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "savings", saved * page_size);
- rrddim_set(st, "offered", offered * page_size);
- rrdset_done(st);
- st = rrdset_find_localhost("mem.ksm_ratios");
- if(!st) {
- st = rrdset_create_localhost("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness"
- , "percentage", 5002, update_every, RRDSET_TYPE_LINE);
+ // --------------------------------------------------------------------
- rrddim_add(st, "savings", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
+ {
+ static RRDSET *st_mem_ksm_savings = NULL;
+ static RRDDIM *rd_savings = NULL, *rd_offered = NULL;
+
+ if (unlikely(!st_mem_ksm_savings)) {
+ st_mem_ksm_savings = rrdset_create_localhost(
+ "mem"
+ , "ksm_savings"
+ , NULL
+ , "ksm"
+ , NULL
+ , "Kernel Same Page Merging Savings"
+ , "MB"
+ , 5001
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_savings = rrddim_add(st_mem_ksm_savings, "savings", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rd_offered = rrddim_add(st_mem_ksm_savings, "offered", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else
+ rrdset_next(st_mem_ksm_savings);
+
+ rrddim_set_by_pointer(st_mem_ksm_savings, rd_savings, saved * page_size);
+ rrddim_set_by_pointer(st_mem_ksm_savings, rd_offered, offered * page_size);
+
+ rrdset_done(st_mem_ksm_savings);
}
- else rrdset_next(st);
- rrddim_set(st, "savings", (saved * 1000000) / offered);
- rrdset_done(st);
+ // --------------------------------------------------------------------
+
+ {
+ static RRDSET *st_mem_ksm_ratios = NULL;
+ static RRDDIM *rd_savings = NULL;
+
+ if (unlikely(!st_mem_ksm_ratios)) {
+ st_mem_ksm_ratios = rrdset_create_localhost(
+ "mem"
+ , "ksm_ratios"
+ , NULL
+ , "ksm"
+ , NULL
+ , "Kernel Same Page Merging Effectiveness"
+ , "percentage"
+ , 5002
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_savings = rrddim_add(st_mem_ksm_ratios, "savings", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else
+ rrdset_next(st_mem_ksm_ratios);
+
+ rrddim_set_by_pointer(st_mem_ksm_ratios, rd_savings, (saved * 1000000) / offered);
+
+ rrdset_done(st_mem_ksm_ratios);
+ }
return 0;
}
diff --git a/src/unit_test.c b/src/unit_test.c
index 9b008138..3c963211 100644
--- a/src/unit_test.c
+++ b/src/unit_test.c
@@ -31,8 +31,8 @@ int check_storage_number(calculated_number n, int debug) {
CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
n,
d, s, ddiff, dcdiff,
- buffer,
- len, p, pdiff, pcdiff
+ buffer, len,
+ p, pdiff, pcdiff
);
if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
@@ -45,6 +45,19 @@ int check_storage_number(calculated_number n, int debug) {
return 0;
}
+calculated_number storage_number_min(calculated_number n) {
+ calculated_number r = 1, last;
+
+ do {
+ last = n;
+ n /= 2.0;
+ storage_number t = pack_storage_number(n, SN_EXISTS);
+ r = unpack_storage_number(t);
+ } while(r != 0.0 && r != last);
+
+ return last;
+}
+
void benchmark_storage_number(int loop, int multiplier) {
int i, j;
calculated_number n, d;
@@ -73,10 +86,10 @@ void benchmark_storage_number(int loop, int multiplier) {
}
fprintf(stderr, "\nNETDATA FLOATING POINT\n");
- fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
+ fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", storage_number_min(1));
fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
- fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
+ fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", -storage_number_min(1));
fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
// ------------------------------------------------------------------------
@@ -231,7 +244,7 @@ int unit_test_storage()
int unit_test_str2ld() {
char *values[] = {
- "1.234567", "-35.6", "0.00123", "23842384234234.2", ".1", "1.2e-10",
+ "1.2345678", "-35.6", "0.00123", "23842384234234.2", ".1", "1.2e-10",
"hello", "1wrong", "nan", "inf", NULL
};
@@ -269,6 +282,36 @@ int unit_test_str2ld() {
return 0;
}
+int unit_test_buffer() {
+ BUFFER *wb = buffer_create(1);
+ char string[2048 + 1];
+ char final[9000 + 1];
+ int i;
+
+ for(i = 0; i < 2048; i++)
+ string[i] = (char)((i % 24) + 'a');
+ string[2048] = '\0';
+
+ const char *fmt = "string1: %s\nstring2: %s\nstring3: %s\nstring4: %s";
+ buffer_sprintf(wb, fmt, string, string, string, string);
+ snprintfz(final, 9000, fmt, string, string, string, string);
+
+ const char *s = buffer_tostring(wb);
+
+ if(buffer_strlen(wb) != strlen(final) || strcmp(s, final) != 0) {
+ fprintf(stderr, "\nbuffer_sprintf() is faulty.\n");
+ fprintf(stderr, "\nstring : %s (length %zu)\n", string, strlen(string));
+ fprintf(stderr, "\nbuffer : %s (length %zu)\n", s, buffer_strlen(wb));
+ fprintf(stderr, "\nexpected: %s (length %zu)\n", final, strlen(final));
+ buffer_free(wb);
+ return -1;
+ }
+
+ fprintf(stderr, "buffer_sprintf() works as expected.\n");
+ buffer_free(wb);
+ return 0;
+}
+
// --------------------------------------------------------------------------------------------------------------------
struct feed_values {
@@ -994,7 +1037,7 @@ int run_test(struct test *test)
for(c = 0 ; c < max ; c++) {
calculated_number v = unpack_storage_number(rd->values[c]);
calculated_number n = test->results[c];
- int same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
+ int same = (calculated_number_round(v * 10000000.0) == calculated_number_round(n * 10000000.0))?1:0;
fprintf(stderr, " %s/%s: checking position %lu (at %lu secs), expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n",
test->name, rd->name, c+1,
(rrdset_first_entry_t(st) + c * st->update_every) - time_start,
@@ -1005,7 +1048,7 @@ int run_test(struct test *test)
if(rd2) {
v = unpack_storage_number(rd2->values[c]);
n = test->results2[c];
- same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
+ same = (calculated_number_round(v * 10000000.0) == calculated_number_round(n * 10000000.0))?1:0;
fprintf(stderr, " %s/%s: checking position %lu (at %lu secs), expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n",
test->name, rd2->name, c+1,
(rrdset_first_entry_t(st) + c * st->update_every) - time_start,
@@ -1019,8 +1062,7 @@ int run_test(struct test *test)
static int test_variable_renames(void) {
fprintf(stderr, "Creating chart\n");
- RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1
- , RRDSET_TYPE_LINE);
+ RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
fprintf(stderr, "Created chart with id '%s', name '%s'\n", st->id, st->name);
fprintf(stderr, "Creating dimension DIM1\n");
diff --git a/src/unit_test.h b/src/unit_test.h
index 3240b5f0..68ed61fc 100644
--- a/src/unit_test.h
+++ b/src/unit_test.h
@@ -5,5 +5,6 @@ extern int unit_test_storage(void);
extern int unit_test(long delay, long shift);
extern int run_all_mockup_tests(void);
extern int unit_test_str2ld(void);
+extern int unit_test_buffer(void);
#endif /* NETDATA_UNIT_TEST_H */
diff --git a/src/web_api_v1.c b/src/web_api_v1.c
index 3ffd8c32..9514f8db 100644
--- a/src/web_api_v1.c
+++ b/src/web_api_v1.c
@@ -816,7 +816,7 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
#endif /* NETDATA_INTERNAL_CHECKS */
}
- if(respect_web_browser_do_not_track_policy && w->donottrack) {
+ if(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w)) {
buffer_flush(w->response.data);
buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
return 400;
@@ -853,19 +853,19 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
switch(action) {
case 'A':
- w->tracking_required = 1;
+ web_client_enable_tracking_required(w);
return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
case 'D':
- w->tracking_required = 1;
+ web_client_enable_tracking_required(w);
return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
case 'S':
- w->tracking_required = 1;
+ web_client_enable_tracking_required(w);
return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec());
case 'W':
- w->tracking_required = 1;
+ web_client_enable_tracking_required(w);
return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
case 'H':
diff --git a/src/web_buffer.c b/src/web_buffer.c
index 9f9ceda6..f5452452 100644
--- a/src/web_buffer.c
+++ b/src/web_buffer.c
@@ -84,6 +84,19 @@ inline char *print_number_llu_r(char *str, unsigned long long uvalue) {
return wstr;
}
+inline char *print_number_llu_r_smart(char *str, unsigned long long uvalue) {
+#ifdef ENVIRONMENT32
+ if(uvalue > (unsigned long long)0xffffffff)
+ str = print_number_llu_r(str, uvalue);
+ else
+ str = print_number_lu_r(str, uvalue);
+#else
+ do *str++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
+#endif
+
+ return str;
+}
+
void buffer_print_llu(BUFFER *wb, unsigned long long uvalue)
{
buffer_need_bytes(wb, 50);
@@ -201,29 +214,25 @@ void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
{
if(unlikely(!fmt || !*fmt)) return;
- buffer_need_bytes(wb, 2);
-
- size_t len = wb->size - wb->len - 1;
- size_t wrote;
-
va_list args;
- va_start(args, fmt);
- wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
- va_end(args);
+ size_t wrote = 0, need = 2, multiplier = 0, len;
+
+ do {
+ need += wrote + multiplier * WEB_DATA_LENGTH_INCREASE_STEP;
+ multiplier++;
- if(unlikely(wrote >= len)) {
- // truncated
- buffer_overflow_check(wb);
+ debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu, by %zu bytes (wrote = %zu)\n", wb->len, wb->size, need, wrote);
+ buffer_need_bytes(wb, need);
- debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
- buffer_need_bytes(wb, len + WEB_DATA_LENGTH_INCREASE_STEP);
+ len = wb->size - wb->len - 1;
va_start(args, fmt);
- buffer_vsprintf(wb, fmt, args);
+ wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
va_end(args);
- }
- else
- wb->len += wrote;
+
+ } while(wrote >= len);
+
+ wb->len += wrote;
// the buffer is \0 terminated by vsnprintf
}
diff --git a/src/web_buffer.h b/src/web_buffer.h
index 8f0d29cd..177abc0a 100644
--- a/src/web_buffer.h
+++ b/src/web_buffer.h
@@ -71,6 +71,7 @@ extern void buffer_char_replace(BUFFER *wb, char from, char to);
extern char *print_number_lu_r(char *str, unsigned long uvalue);
extern char *print_number_llu_r(char *str, unsigned long long uvalue);
+extern char *print_number_llu_r_smart(char *str, unsigned long long uvalue);
extern void buffer_print_llu(BUFFER *wb, unsigned long long uvalue);
diff --git a/src/web_buffer_svg.c b/src/web_buffer_svg.c
index 2591799d..287bbd6b 100644
--- a/src/web_buffer_svg.c
+++ b/src/web_buffer_svg.c
@@ -389,10 +389,13 @@ static inline char *format_value_with_precision_and_unit(char *value_string, siz
len = snprintfz(value_string, value_string_len, "%0.0Lf", (long double) value);
trim_zeros = 0;
}
- else if(isgreaterequal(abs, 10)) len = snprintfz(value_string, value_string_len, "%0.1Lf", (long double) value);
- else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
- else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
- else len = snprintfz(value_string, value_string_len, "%0.4Lf", (long double) value);
+ else if(isgreaterequal(abs, 10)) len = snprintfz(value_string, value_string_len, "%0.1Lf", (long double) value);
+ else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
+ else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
+ else if(isgreaterequal(abs, 0.01)) len = snprintfz(value_string, value_string_len, "%0.4Lf", (long double) value);
+ else if(isgreaterequal(abs, 0.001)) len = snprintfz(value_string, value_string_len, "%0.5Lf", (long double) value);
+ else if(isgreaterequal(abs, 0.0001)) len = snprintfz(value_string, value_string_len, "%0.6Lf", (long double) value);
+ else len = snprintfz(value_string, value_string_len, "%0.7Lf", (long double) value);
if(unlikely(trim_zeros)) {
int l;
diff --git a/src/web_client.c b/src/web_client.c
index 7da08070..6ec3e11e 100644
--- a/src/web_client.c
+++ b/src/web_client.c
@@ -17,10 +17,11 @@ unsigned long long web_clients_count = 0;
static inline int web_client_crock_socket(struct web_client *w) {
#ifdef TCP_CORK
- if(likely(!w->tcp_cork && w->ofd != -1)) {
+ if(likely(web_client_is_corkable(w) && !w->tcp_cork && w->ofd != -1)) {
w->tcp_cork = 1;
if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
error("%llu: failed to enable TCP_CORK on socket.", w->id);
+
w->tcp_cork = 0;
return -1;
}
@@ -78,7 +79,7 @@ struct web_client *web_client_create(int listener) {
w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
w->origin[0] = '*';
- w->wait_receive = 1;
+ web_client_enable_wait_receive(w);
if(web_clients) web_clients->prev = w;
w->next = web_clients;
@@ -150,9 +151,9 @@ void web_client_reset(struct web_client *w) {
w->mode = WEB_CLIENT_MODE_NORMAL;
w->tcp_cork = 0;
- w->donottrack = 0;
- w->tracking_required = 0;
- w->keepalive = 0;
+ web_client_disable_donottrack(w);
+ web_client_disable_tracking_required(w);
+ web_client_disable_keepalive(w);
w->decoded_url[0] = '\0';
buffer_reset(w->response.header_output);
@@ -162,8 +163,8 @@ void web_client_reset(struct web_client *w) {
w->response.sent = 0;
w->response.code = 0;
- w->wait_receive = 1;
- w->wait_send = 0;
+ web_client_enable_wait_receive(w);
+ web_client_disable_wait_send(w);
w->response.zoutput = 0;
@@ -210,14 +211,18 @@ uid_t web_files_uid(void) {
static uid_t owner_uid = 0;
if(unlikely(!web_owner)) {
- web_owner = config_get(CONFIG_SECTION_WEB, "web files owner", config_get(CONFIG_SECTION_GLOBAL, "run as user", ""));
+ // getpwuid() is not thread safe,
+ // but we have called this function once
+ // while single threaded
+ struct passwd *pw = getpwuid(geteuid());
+ web_owner = config_get(CONFIG_SECTION_WEB, "web files owner", (pw)?(pw->pw_name?pw->pw_name:""):"");
if(!web_owner || !*web_owner)
owner_uid = geteuid();
else {
// getpwnam() is not thread safe,
// but we have called this function once
// while single threaded
- struct passwd *pw = getpwnam(web_owner);
+ pw = getpwnam(web_owner);
if(!pw) {
error("User '%s' is not present. Ignoring option.", web_owner);
owner_uid = geteuid();
@@ -237,14 +242,18 @@ gid_t web_files_gid(void) {
static gid_t owner_gid = 0;
if(unlikely(!web_group)) {
- web_group = config_get(CONFIG_SECTION_WEB, "web files group", config_get(CONFIG_SECTION_WEB, "web files owner", ""));
+ // getgrgid() is not thread safe,
+ // but we have called this function once
+ // while single threaded
+ struct group *gr = getgrgid(getegid());
+ web_group = config_get(CONFIG_SECTION_WEB, "web files group", (gr)?(gr->gr_name?gr->gr_name:""):"");
if(!web_group || !*web_group)
owner_gid = getegid();
else {
// getgrnam() is not thread safe,
// but we have called this function once
// while single threaded
- struct group *gr = getgrnam(web_group);
+ gr = getgrnam(web_group);
if(!gr) {
error("Group '%s' is not present. Ignoring option.", web_group);
owner_gid = getegid();
@@ -383,8 +392,8 @@ int mysendfile(struct web_client *w, char *filename) {
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, stat.st_size, w->ifd, w->ofd);
w->mode = WEB_CLIENT_MODE_FILECOPY;
- w->wait_receive = 1;
- w->wait_send = 0;
+ web_client_enable_wait_receive(w);
+ web_client_disable_wait_send(w);
buffer_flush(w->response.data);
w->response.rlen = stat.st_size;
#ifdef __APPLE__
@@ -723,11 +732,11 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
if(strcasestr(v, "keep-alive"))
- w->keepalive = 1;
+ web_client_enable_keepalive(w);
}
else if(respect_web_browser_do_not_track_policy && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
- if(*v == '0') w->donottrack = 0;
- else if(*v == '1') w->donottrack = 1;
+ if(*v == '0') web_client_disable_donottrack(w);
+ else if(*v == '1') web_client_enable_donottrack(w);
}
#ifdef NETDATA_WITH_ZLIB
else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
@@ -776,7 +785,7 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
w->mode = WEB_CLIENT_MODE_STREAM;
}
else {
- w->wait_receive = 0;
+ web_client_disable_wait_receive(w);
return HTTP_VALIDATION_NOT_SUPPORTED;
}
@@ -792,7 +801,7 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
// incomplete requests
if(unlikely(!*s)) {
- w->wait_receive = 1;
+ web_client_enable_wait_receive(w);
return HTTP_VALIDATION_INCOMPLETE;
}
@@ -823,7 +832,7 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
// FIXME -- we should avoid it
strncpyz(w->last_url, w->decoded_url, URL_MAX);
- w->wait_receive = 0;
+ web_client_disable_wait_receive(w);
return HTTP_VALIDATION_OK;
}
@@ -833,7 +842,7 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
}
// incomplete request
- w->wait_receive = 1;
+ web_client_enable_wait_receive(w);
return HTTP_VALIDATION_INCOMPLETE;
}
@@ -876,7 +885,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
"Content-Type: %s\r\n"
"Date: %s\r\n"
, w->response.code, code_msg
- , w->keepalive?"keep-alive":"close"
+ , web_client_has_keepalive(w)?"keep-alive":"close"
, w->origin
, content_type_string
, date
@@ -904,7 +913,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
}
else {
if(respect_web_browser_do_not_track_policy) {
- if(w->tracking_required)
+ if(web_client_has_tracking_required(w))
buffer_sprintf(w->response.header_output,
"Tk: T;cookies\r\n");
else
@@ -946,7 +955,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
}
else {
// we don't know the content length, disable keep-alive
- w->keepalive = 0;
+ web_client_disable_keepalive(w);
}
}
@@ -1234,8 +1243,8 @@ void web_client_process_request(struct web_client *w) {
web_client_send_http_header(w);
// enable sending immediately if we have data
- if(w->response.data->len) w->wait_send = 1;
- else w->wait_send = 0;
+ if(w->response.data->len) web_client_enable_wait_send(w);
+ else web_client_disable_wait_send(w);
switch(w->mode) {
case WEB_CLIENT_MODE_STREAM:
@@ -1253,7 +1262,7 @@ void web_client_process_request(struct web_client *w) {
case WEB_CLIENT_MODE_FILECOPY:
if(w->response.rlen) {
debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen);
- w->wait_receive = 1;
+ web_client_enable_wait_receive(w);
/*
// utilize the kernel sendfile() for copying the file to the socket.
@@ -1368,14 +1377,14 @@ ssize_t web_client_send_deflate(struct web_client *w)
if(t < 0) return t;
}
- if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
+ if(w->mode == WEB_CLIENT_MODE_FILECOPY && web_client_has_wait_receive(w) && w->response.rlen && w->response.rlen > w->response.data->len) {
// we have to wait, more data will come
debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
- w->wait_send = 0;
+ web_client_disable_wait_send(w);
return t;
}
- if(unlikely(!w->keepalive)) {
+ if(unlikely(!web_client_has_keepalive(w))) {
debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
WEB_CLIENT_IS_DEAD(w);
return t;
@@ -1411,7 +1420,7 @@ ssize_t web_client_send_deflate(struct web_client *w)
// ask for FINISH if we have all the input
int flush = Z_SYNC_FLUSH;
if(w->mode == WEB_CLIENT_MODE_NORMAL
- || (w->mode == WEB_CLIENT_MODE_FILECOPY && !w->wait_receive && w->response.data->len == w->response.rlen)) {
+ || (w->mode == WEB_CLIENT_MODE_FILECOPY && !web_client_has_wait_receive(w) && w->response.data->len == w->response.rlen)) {
flush = Z_FINISH;
debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id);
}
@@ -1480,14 +1489,14 @@ ssize_t web_client_send(struct web_client *w) {
// A. we have done everything
// B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
- if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
+ if(w->mode == WEB_CLIENT_MODE_FILECOPY && web_client_has_wait_receive(w) && w->response.rlen && w->response.rlen > w->response.data->len) {
// we have to wait, more data will come
debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
- w->wait_send = 0;
+ web_client_disable_wait_send(w);
return 0;
}
- if(unlikely(!w->keepalive)) {
+ if(unlikely(!web_client_has_keepalive(w))) {
debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
WEB_CLIENT_IS_DEAD(w);
return 0;
@@ -1541,10 +1550,10 @@ ssize_t web_client_receive(struct web_client *w)
debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
- w->wait_send = 1;
+ web_client_enable_wait_send(w);
if(w->response.rlen && w->response.data->len >= w->response.rlen)
- w->wait_receive = 0;
+ web_client_disable_wait_receive(w);
}
}
else if(likely(bytes == 0)) {
@@ -1557,7 +1566,7 @@ ssize_t web_client_receive(struct web_client *w)
if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
// we are copying data from ifd to ofd
// let it finish copying...
- w->wait_receive = 0;
+ web_client_disable_wait_receive(w);
debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id);
if(w->ifd != w->ofd) close(w->ifd);
@@ -1603,11 +1612,11 @@ void *web_client_main(void *ptr)
for(;;) {
if(unlikely(netdata_exit)) break;
- if(unlikely(w->dead)) {
+ if(unlikely(web_client_check_dead(w))) {
debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
break;
}
- else if(unlikely(!w->wait_receive && !w->wait_send)) {
+ else if(unlikely(!web_client_has_wait_receive(w) && !web_client_has_wait_send(w))) {
debug(D_WEB_CLIENT, "%llu: client is not set for neither receiving nor sending data.", w->id);
break;
}
@@ -1622,8 +1631,8 @@ void *web_client_main(void *ptr)
fds[0].events = 0;
fds[0].revents = 0;
- if(w->wait_receive) fds[0].events |= POLLIN;
- if(w->wait_send) fds[0].events |= POLLOUT;
+ if(web_client_has_wait_receive(w)) fds[0].events |= POLLIN;
+ if(web_client_has_wait_send(w)) fds[0].events |= POLLOUT;
fds[1].fd = -1;
fds[1].events = 0;
@@ -1637,19 +1646,19 @@ void *web_client_main(void *ptr)
fds[0].fd = w->ifd;
fds[0].events = 0;
fds[0].revents = 0;
- if(w->wait_receive) fds[0].events |= POLLIN;
+ if(web_client_has_wait_receive(w)) fds[0].events |= POLLIN;
ifd = &fds[0];
fds[1].fd = w->ofd;
fds[1].events = 0;
fds[1].revents = 0;
- if(w->wait_send) fds[1].events |= POLLOUT;
+ if(web_client_has_wait_send(w)) fds[1].events |= POLLOUT;
ofd = &fds[1];
fdmax = 2;
}
- debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
+ debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, web_client_has_wait_receive(w)?"INPUT":"", web_client_has_wait_send(w)?"OUTPUT":"");
errno = 0;
timeout = web_client_timeout * 1000;
retval = poll(fds, fdmax, timeout);
@@ -1666,14 +1675,14 @@ void *web_client_main(void *ptr)
break;
}
else if(unlikely(!retval)) {
- debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
+ debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, web_client_has_wait_receive(w)?"INPUT":"", web_client_has_wait_send(w)?"OUTPUT":"");
break;
}
if(unlikely(netdata_exit)) break;
int used = 0;
- if(w->wait_send && ofd->revents & POLLOUT) {
+ if(web_client_has_wait_send(w) && ofd->revents & POLLOUT) {
used++;
if(web_client_send(w) < 0) {
debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
@@ -1683,7 +1692,7 @@ void *web_client_main(void *ptr)
if(unlikely(netdata_exit)) break;
- if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
+ if(web_client_has_wait_receive(w) && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
used++;
if(web_client_receive(w) < 0) {
debug(D_WEB_CLIENT, "%llu: Cannot receive data from client. Closing client.", w->id);
@@ -1724,7 +1733,7 @@ void *web_client_main(void *ptr)
w->ifd = -1;
w->ofd = -1;
- w->obsolete = 1;
+ WEB_CLIENT_IS_OBSOLETE(w);
pthread_exit(NULL);
return NULL;
diff --git a/src/web_client.h b/src/web_client.h
index 617917df..126a494f 100644
--- a/src/web_client.h
+++ b/src/web_client.h
@@ -20,6 +20,66 @@ typedef enum web_client_mode {
WEB_CLIENT_MODE_STREAM = 3
} WEB_CLIENT_MODE;
+typedef enum web_client_flags {
+ WEB_CLIENT_FLAG_OBSOLETE = 1 << 0, // if set, the listener will remove this client
+ // after setting this, you should not touch
+ // this web_client
+
+ WEB_CLIENT_FLAG_DEAD = 1 << 1, // if set, this client is dead
+
+ WEB_CLIENT_FLAG_KEEPALIVE = 1 << 2, // if set, the web client will be re-used
+
+ WEB_CLIENT_FLAG_WAIT_RECEIVE = 1 << 3, // if set, we are waiting more input data
+ WEB_CLIENT_FLAG_WAIT_SEND = 1 << 4, // if set, we have data to send to the client
+
+ WEB_CLIENT_FLAG_DO_NOT_TRACK = 1 << 5, // if set, we should not set cookies on this client
+ WEB_CLIENT_FLAG_TRACKING_REQUIRED = 1 << 6, // if set, we need to send cookies
+
+ WEB_CLIENT_FLAG_TCP_CLIENT = 1 << 7, // if set, the client is using a TCP socket
+ WEB_CLIENT_FLAG_UNIX_CLIENT = 1 << 8 // if set, the client is using a UNIX socket
+} WEB_CLIENT_FLAGS;
+
+//#ifdef HAVE_C___ATOMIC
+//#define web_client_flag_check(w, flag) (__atomic_load_n(&((w)->flags), __ATOMIC_SEQ_CST) & flag)
+//#define web_client_flag_set(w, flag) __atomic_or_fetch(&((w)->flags), flag, __ATOMIC_SEQ_CST)
+//#define web_client_flag_clear(w, flag) __atomic_and_fetch(&((w)->flags), ~flag, __ATOMIC_SEQ_CST)
+//#else
+#define web_client_flag_check(w, flag) ((w)->flags & flag)
+#define web_client_flag_set(w, flag) (w)->flags |= flag
+#define web_client_flag_clear(w, flag) (w)->flags &= ~flag
+//#endif
+
+#define WEB_CLIENT_IS_OBSOLETE(w) web_client_flag_set(w, WEB_CLIENT_FLAG_OBSOLETE)
+#define web_client_check_obsolete(w) web_client_flag_check(w, WEB_CLIENT_FLAG_OBSOLETE)
+
+#define WEB_CLIENT_IS_DEAD(w) web_client_flag_set(w, WEB_CLIENT_FLAG_DEAD)
+#define web_client_check_dead(w) web_client_flag_check(w, WEB_CLIENT_FLAG_DEAD)
+
+#define web_client_has_keepalive(w) web_client_flag_check(w, WEB_CLIENT_FLAG_KEEPALIVE)
+#define web_client_enable_keepalive(w) web_client_flag_set(w, WEB_CLIENT_FLAG_KEEPALIVE)
+#define web_client_disable_keepalive(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_KEEPALIVE)
+
+#define web_client_has_donottrack(w) web_client_flag_check(w, WEB_CLIENT_FLAG_DO_NOT_TRACK)
+#define web_client_enable_donottrack(w) web_client_flag_set(w, WEB_CLIENT_FLAG_DO_NOT_TRACK)
+#define web_client_disable_donottrack(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_DO_NOT_TRACK)
+
+#define web_client_has_tracking_required(w) web_client_flag_check(w, WEB_CLIENT_FLAG_TRACKING_REQUIRED)
+#define web_client_enable_tracking_required(w) web_client_flag_set(w, WEB_CLIENT_FLAG_TRACKING_REQUIRED)
+#define web_client_disable_tracking_required(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_TRACKING_REQUIRED)
+
+#define web_client_has_wait_receive(w) web_client_flag_check(w, WEB_CLIENT_FLAG_WAIT_RECEIVE)
+#define web_client_enable_wait_receive(w) web_client_flag_set(w, WEB_CLIENT_FLAG_WAIT_RECEIVE)
+#define web_client_disable_wait_receive(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_WAIT_RECEIVE)
+
+#define web_client_has_wait_send(w) web_client_flag_check(w, WEB_CLIENT_FLAG_WAIT_SEND)
+#define web_client_enable_wait_send(w) web_client_flag_set(w, WEB_CLIENT_FLAG_WAIT_SEND)
+#define web_client_disable_wait_send(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_WAIT_SEND)
+
+#define web_client_set_tcp(w) web_client_flag_set(w, WEB_CLIENT_FLAG_TCP_CLIENT)
+#define web_client_set_unix(w) web_client_flag_set(w, WEB_CLIENT_FLAG_UNIX_CLIENT)
+
+#define web_client_is_corkable(w) web_client_flag_check(w, WEB_CLIENT_FLAG_TCP_CLIENT)
+
#define URL_MAX 8192
#define ZLIB_CHUNK 16384
#define HTTP_RESPONSE_HEADER_SIZE 4096
@@ -50,20 +110,7 @@ struct response {
struct web_client {
unsigned long long id;
- uint8_t obsolete:1; // if set to 1, the listener will remove this client
- // after setting this to 1, you should not touch
- // this web_client
-
- uint8_t dead:1; // if set to 1, this client is dead
-
- uint8_t keepalive:1; // if set to 1, the web client will be re-used
-
- uint8_t wait_receive:1; // 1 = we are waiting more input data
- uint8_t wait_send:1; // 1 = we have data to send to the client
-
- uint8_t donottrack:1; // 1 = we should not set cookies on this client
- uint8_t tracking_required:1; // 1 = if the request requires cookies
-
+ WEB_CLIENT_FLAGS flags; // status flags for the client
WEB_CLIENT_MODE mode; // the operational mode of the client
int tcp_cork; // 1 = we have a cork on the socket
@@ -94,8 +141,6 @@ struct web_client {
struct web_client *next;
};
-#define WEB_CLIENT_IS_DEAD(w) (w)->dead=1
-
extern struct web_client *web_clients;
extern uid_t web_files_uid(void);
diff --git a/src/web_server.c b/src/web_server.c
index 491cd11a..72168d15 100644
--- a/src/web_server.c
+++ b/src/web_server.c
@@ -89,7 +89,7 @@ static inline void cleanup_web_clients(void) {
struct web_client *w;
for (w = web_clients; w;) {
- if (w->obsolete) {
+ if (web_client_check_obsolete(w)) {
debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
// pthread_cancel(w->thread);
// pthread_join(w->thread, NULL);
@@ -170,11 +170,11 @@ void *socket_listen_main_multi_threaded(void *ptr) {
if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
error("%llu: failed to create new thread for web client.", w->id);
- w->obsolete = 1;
+ WEB_CLIENT_IS_OBSOLETE(w);
}
else if(pthread_detach(w->thread) != 0) {
error("%llu: Cannot request detach of newly created web client thread.", w->id);
- w->obsolete = 1;
+ WEB_CLIENT_IS_OBSOLETE(w);
}
}
}
@@ -200,7 +200,7 @@ void *socket_listen_main_multi_threaded(void *ptr) {
struct web_client *single_threaded_clients[FD_SETSIZE];
static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) {
- if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
+ if(unlikely(web_client_check_obsolete(w) || web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w))))
return 1;
if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) {
@@ -216,8 +216,8 @@ static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds
FD_SET(w->ofd, efds);
}
- if(w->wait_receive) FD_SET(w->ifd, ifds);
- if(w->wait_send) FD_SET(w->ofd, ofds);
+ if(web_client_has_wait_receive(w)) FD_SET(w->ifd, ifds);
+ if(web_client_has_wait_send(w)) FD_SET(w->ofd, ofds);
single_threaded_clients[w->ifd] = w;
single_threaded_clients[w->ofd] = w;
@@ -229,13 +229,13 @@ static inline int single_threaded_unlink_client(struct web_client *w, fd_set *if
FD_CLR(w->ifd, efds);
if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);
- if(w->wait_receive) FD_CLR(w->ifd, ifds);
- if(w->wait_send) FD_CLR(w->ofd, ofds);
+ if(web_client_has_wait_receive(w)) FD_CLR(w->ifd, ifds);
+ if(web_client_has_wait_send(w)) FD_CLR(w->ofd, ofds);
single_threaded_clients[w->ifd] = NULL;
single_threaded_clients[w->ofd] = NULL;
- if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
+ if(unlikely(web_client_check_obsolete(w) || web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w))))
return 1;
return 0;
@@ -302,6 +302,12 @@ void *socket_listen_main_single_threaded(void *ptr) {
if (FD_ISSET(api_sockets.fds[i], &rifds)) {
debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
w = web_client_create(api_sockets.fds[i]);
+
+ if(api_sockets.fds_families[i] == AF_UNIX)
+ web_client_set_unix(w);
+ else
+ web_client_set_tcp(w);
+
if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
web_client_free(w);
}
@@ -326,7 +332,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
continue;
}
- if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
+ if (unlikely(web_client_has_wait_receive(w) && FD_ISSET(w->ifd, &rifds))) {
if (unlikely(web_client_receive(w) < 0)) {
web_client_free(w);
continue;
@@ -338,7 +344,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
}
}
- if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
+ if (unlikely(web_client_has_wait_send(w) && FD_ISSET(w->ofd, &rofds))) {
if (unlikely(web_client_send(w) < 0)) {
debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
web_client_free(w);