diff options
Diffstat (limited to '')
65 files changed, 3480 insertions, 1225 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 601d3204f..feddc326d 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 3ce869b0d..bc73c7125 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 91c4c5c54..2c7721b8c 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 ecb6aaeac..c0eb5c083 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 000000000..8894d60ee --- /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 aa75c198d..5a953672d 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 efeebf16f..51d2bba55 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 bc02446e0..5c5333a36 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 b193602d6..150d74e3a 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 7355fac9e..1a4448bd3 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 d2f0eaa82..a87b872d9 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 146268a53..42a1ac01d 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 8575061ac..886889086 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 cc470f81f..136a1ecd7 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 b4655dc78..2ead82ef5 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 95abcfe5f..9881d35d4 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 f1812ba1c..9ab2dca73 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 c47da52f1..fa103e110 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 af229fb61..843aceae0 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 bf5d787ad..89ca828a1 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 020fdb41c..c09b28a5f 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 541bf852f..78fe33d7e 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 688b23de9..72cfc6aa9 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 750086a2c..52c1f5ae6 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 6bf5782a9..c928e61ba 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 9eb102770..42433b552 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 8448b7311..27be61774 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 d3fed5a6d..4a32ec949 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 082e1f57b..b9f3941d2 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 a48801b37..54fc545a5 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 6b0219cc9..152a6366e 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 ee7588990..6e12fc5dd 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 16a3234df..aa806b460 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 322e51d13..e01b81d28 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 7c0fd9b4a..817c964b4 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 aa9ab2209..6649b7afe 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 560e2acb2..352407a4f 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 04f0896cd..40bf5cfad 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 fea8900d3..267ea271a 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 f74cccb97..fb05b5cb3 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 a2416313a..2382116f1 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); } @@ -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 98080139c..84d904485 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 e75aa3fd2..8df548397 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 6def90fe5..c1d052fd8 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 caa427ff6..c5168f02e 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 000000000..331e80358 --- /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 000000000..d8611edea --- /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 2b3821190..d28df81a6 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 bb95347ab..8ca7288c9 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 4dd04757b..08ce3e2f5 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 27fe5f2c7..054941202 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 34ed0d89c..3c1b6bab3 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 c41ad7faa..7ec989434 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 0f9c8854a..c047547e7 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 76d808538..6b04ef280 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 9b008138f..3c9632119 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 3240b5f0e..68ed61fcb 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 3ffd8c324..9514f8dbd 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 9f9ceda63..f5452452f 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 8f0d29cd2..177abc0a8 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 2591799d4..287bbd6b8 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 7da080705..6ec3e11e3 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 617917df0..126a494f0 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 491cd11aa..72168d15b 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); |