summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am201
-rw-r--r--src/Makefile.in526
-rw-r--r--src/adaptive_resortable_list.c40
-rw-r--r--src/appconfig.c310
-rw-r--r--src/appconfig.h67
-rw-r--r--src/apps_plugin.c2089
-rw-r--r--src/avl.c16
-rw-r--r--src/avl.h8
-rw-r--r--src/backends.c556
-rw-r--r--src/clocks.c114
-rw-r--r--src/clocks.h94
-rw-r--r--src/common.c81
-rw-r--r--src/common.h41
-rw-r--r--src/daemon.c154
-rw-r--r--src/dictionary.c14
-rw-r--r--src/dictionary.h2
-rw-r--r--src/freebsd_sysctl.c4861
-rw-r--r--src/freeipmi_plugin.c1621
-rw-r--r--src/global_statistics.c83
-rw-r--r--[-rwxr-xr-x]src/health.c3133
-rw-r--r--src/health.h88
-rw-r--r--src/health_config.c877
-rw-r--r--src/health_json.c256
-rw-r--r--src/health_log.c465
-rw-r--r--src/inlined.h47
-rw-r--r--src/ipc.c22
-rw-r--r--src/locks.h294
-rw-r--r--src/log.c6
-rw-r--r--src/log.h56
-rw-r--r--src/macos_fw.c179
-rw-r--r--src/macos_mach_smi.c72
-rw-r--r--src/macos_sysctl.c566
-rw-r--r--src/main.c474
-rw-r--r--src/main.h2
-rw-r--r--src/plugin_checks.c31
-rw-r--r--src/plugin_freebsd.c156
-rw-r--r--src/plugin_freebsd.h113
-rw-r--r--src/plugin_idlejitter.c15
-rw-r--r--src/plugin_macos.c30
-rw-r--r--src/plugin_macos.h4
-rw-r--r--src/plugin_nfacct.c855
-rw-r--r--src/plugin_proc.c34
-rw-r--r--src/plugin_proc_diskspace.c233
-rw-r--r--src/plugin_tc.c679
-rw-r--r--src/plugins_d.c506
-rw-r--r--src/plugins_d.h3
-rw-r--r--src/proc_diskstats.c556
-rw-r--r--src/proc_interrupts.c16
-rw-r--r--src/proc_loadavg.c31
-rw-r--r--src/proc_meminfo.c103
-rw-r--r--src/proc_net_dev.c434
-rw-r--r--src/proc_net_ip_vs_stats.c31
-rw-r--r--src/proc_net_netstat.c254
-rw-r--r--src/proc_net_rpc_nfs.c47
-rw-r--r--src/proc_net_rpc_nfsd.c171
-rw-r--r--src/proc_net_snmp.c203
-rw-r--r--src/proc_net_snmp6.c465
-rw-r--r--src/proc_net_softnet_stat.c16
-rw-r--r--src/proc_net_stat_conntrack.c94
-rw-r--r--src/proc_net_stat_synproxy.c62
-rw-r--r--src/proc_self_mountinfo.c8
-rw-r--r--src/proc_softirqs.c16
-rw-r--r--src/proc_stat.c63
-rw-r--r--src/proc_sys_kernel_random_entropy_avail.c9
-rw-r--r--src/proc_uptime.c9
-rw-r--r--src/proc_vmstat.c64
-rw-r--r--src/procfile.c298
-rw-r--r--src/procfile.h16
-rw-r--r--src/registry.c98
-rw-r--r--src/registry.h13
-rw-r--r--src/registry_init.c41
-rw-r--r--src/registry_internals.c36
-rw-r--r--src/registry_internals.h8
-rw-r--r--src/registry_machine.c2
-rw-r--r--src/registry_person.c2
-rw-r--r--src/rrd.c1642
-rw-r--r--src/rrd.h460
-rw-r--r--src/rrd2json.c755
-rw-r--r--src/rrd2json.h29
-rw-r--r--src/rrd2json_api_old.c487
-rw-r--r--src/rrd2json_api_old.h14
-rw-r--r--src/rrdcalc.c415
-rw-r--r--src/rrdcalctemplate.c62
-rw-r--r--src/rrddim.c313
-rw-r--r--src/rrddimvar.c210
-rw-r--r--src/rrdfamily.c58
-rw-r--r--src/rrdhost.c583
-rw-r--r--src/rrdpush.c761
-rw-r--r--src/rrdpush.h15
-rw-r--r--src/rrdset.c1310
-rw-r--r--src/rrdsetvar.c120
-rw-r--r--src/rrdvar.c265
-rw-r--r--src/simple_pattern.c8
-rw-r--r--src/socket.c101
-rw-r--r--src/socket.h4
-rw-r--r--src/sys_devices_system_edac_mc.c34
-rw-r--r--src/sys_devices_system_node.c90
-rw-r--r--src/sys_fs_cgroup.c1081
-rw-r--r--src/sys_kernel_mm_ksm.c46
-rw-r--r--src/unit_test.c67
-rw-r--r--src/web_api_old.c237
-rw-r--r--src/web_api_old.h13
-rw-r--r--src/web_api_v1.c903
-rw-r--r--src/web_api_v1.h21
-rw-r--r--src/web_buffer.c5
-rw-r--r--src/web_buffer_svg.c332
-rw-r--r--src/web_buffer_svg.h3
-rw-r--r--src/web_client.c1759
-rw-r--r--src/web_client.h25
-rw-r--r--src/web_server.c42
-rw-r--r--src/web_server.h14
111 files changed, 22605 insertions, 12919 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d8274d255..1c1dd3385 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,11 +12,14 @@ AM_CPPFLAGS = \
-DRUN_DIR="\"$(localstatedir)/run/netdata\"" \
-DWEB_DIR="\"$(webdir)\"" \
$(NULL)
+
AM_CFLAGS = \
$(OPTIONAL_MATH_CFLAGS) \
$(OPTIONAL_NFACCT_CLFAGS) \
$(OPTIONAL_ZLIB_CFLAGS) \
$(OPTIONAL_UUID_CFLAGS) \
+ $(OPTIONAL_LIBCAP_CFLAGS) \
+ $(OPTIONAL_IPMIMONITORING_CFLAGS)\
$(NULL)
sbin_PROGRAMS = netdata
@@ -24,66 +27,131 @@ dist_cache_DATA = .keep
dist_varlib_DATA = .keep
dist_registry_DATA = .keep
dist_log_DATA = .keep
-if !MACOS
-plugins_PROGRAMS = apps.plugin
+plugins_PROGRAMS =
+
+if ENABLE_PLUGIN_APPS
+plugins_PROGRAMS += apps.plugin
+endif
+
+if ENABLE_PLUGIN_FREEIPMI
+plugins_PROGRAMS += freeipmi.plugin
endif
netdata_SOURCES = \
- appconfig.c appconfig.h \
- adaptive_resortable_list.c adaptive_resortable_list.h \
- avl.c avl.h \
- backends.c backends.h \
- clocks.c clocks.h \
- common.c common.h \
- daemon.c daemon.h \
- dictionary.c dictionary.h \
- eval.c eval.h \
- global_statistics.c global_statistics.h \
- health.c health.h \
+ adaptive_resortable_list.c \
+ adaptive_resortable_list.h \
+ appconfig.c \
+ appconfig.h \
+ avl.c \
+ avl.h \
+ backends.c \
+ backends.h \
+ clocks.c \
+ clocks.h \
+ common.c \
+ common.h \
+ daemon.c \
+ daemon.h \
+ dictionary.c \
+ dictionary.h \
+ eval.c \
+ eval.h \
+ global_statistics.c \
+ global_statistics.h \
+ health.c \
+ health.h \
+ health_config.c \
+ health_json.c \
+ health_log.c \
inlined.h \
- log.c log.h \
- main.c main.h \
- plugin_checks.c plugin_checks.h \
- plugin_idlejitter.c plugin_idlejitter.h \
- plugin_nfacct.c plugin_nfacct.h \
- plugin_tc.c plugin_tc.h \
- plugins_d.c plugins_d.h \
- popen.c popen.h \
- socket.c socket.h \
- simple_pattern.c simple_pattern.h \
- sys_fs_cgroup.c \
- sys_devices_system_edac_mc.c \
- sys_devices_system_node.c \
- procfile.c procfile.h \
- proc_self_mountinfo.c proc_self_mountinfo.h \
- registry.c registry.h \
- registry_internals.c registry_internals.h \
- registry_url.c registry_url.h \
- registry_person.c registry_person.h \
- registry_machine.c registry_machine.h \
- registry_init.c \
+ locks.h \
+ log.c \
+ log.h \
+ main.c \
+ main.h \
+ plugin_checks.c \
+ plugin_checks.h \
+ plugin_idlejitter.c \
+ plugin_idlejitter.h \
+ plugin_nfacct.c \
+ plugin_nfacct.h \
+ plugin_tc.c \
+ plugin_tc.h \
+ plugins_d.c \
+ plugins_d.h \
+ popen.c \
+ popen.h \
+ proc_self_mountinfo.c \
+ proc_self_mountinfo.h \
+ procfile.c \
+ procfile.h \
+ registry.c \
+ registry.h \
registry_db.c \
+ registry_init.c \
+ registry_internals.c \
+ registry_internals.h \
registry_log.c \
- rrd.c rrd.h \
- rrd2json.c rrd2json.h \
- storage_number.c storage_number.h \
- unit_test.c unit_test.h \
+ registry_machine.c \
+ registry_machine.h \
+ registry_person.c \
+ registry_person.h \
+ 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 \
+ 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_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 \
+ 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)
if FREEBSD
netdata_SOURCES += \
- plugin_freebsd.c plugin_freebsd.h \
+ plugin_freebsd.c \
+ plugin_freebsd.h \
freebsd_sysctl.c \
$(NULL)
else
if MACOS
netdata_SOURCES += \
- plugin_macos.c plugin_macos.h \
+ plugin_macos.c \
+ plugin_macos.h \
macos_sysctl.c \
macos_mach_smi.c \
macos_fw.c \
@@ -91,8 +159,10 @@ netdata_SOURCES += \
else
netdata_SOURCES += \
ipc.c ipc.h \
- plugin_proc.c plugin_proc.h \
- plugin_proc_diskspace.c plugin_proc_diskspace.h \
+ plugin_proc.c \
+ plugin_proc.h \
+ plugin_proc_diskspace.c \
+ plugin_proc_diskspace.h \
proc_diskstats.c \
proc_interrupts.c \
proc_softirqs.c \
@@ -135,19 +205,26 @@ apps_plugin_SOURCES = \
web_buffer.c web_buffer.h \
$(NULL)
-install-data-hook:
- if [ `id -u` == 0 ]; then \
- chown root '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- ( setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin' || \
- chmod 4755 '$(DESTDIR)$(pluginsdir)/apps.plugin' ); \
- else \
- echo; \
- echo "ATTENTION"; \
- echo; \
- echo "$(pluginsdir)/apps.plugin requires escalated capabilities:"; \
- echo "sudo chown root '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo; \
- fi
+if FREEBSD
+apps_plugin_SOURCES += \
+ plugin_freebsd.h \
+ $(NULL)
+endif
+
+apps_plugin_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_LIBCAP_LIBS) \
+ $(NULL)
+
+freeipmi_plugin_SOURCES = \
+ freeipmi_plugin.c \
+ clocks.c clocks.h \
+ common.c common.h \
+ inlined.h \
+ log.c log.h \
+ procfile.c procfile.h \
+ $(NULL)
+
+freeipmi_plugin_LDADD = \
+ $(OPTIONAL_IPMIMONITORING_LIBS) \
+ $(NULL)
diff --git a/src/Makefile.in b/src/Makefile.in
index f94646363..d7229d18a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,23 +36,29 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = netdata$(EXEEXT)
-@MACOS_FALSE@plugins_PROGRAMS = apps.plugin$(EXEEXT)
-@FREEBSD_TRUE@am__append_1 = \
-@FREEBSD_TRUE@ plugin_freebsd.c plugin_freebsd.h \
+plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
+@ENABLE_PLUGIN_APPS_TRUE@am__append_1 = apps.plugin
+@ENABLE_PLUGIN_FREEIPMI_TRUE@am__append_2 = freeipmi.plugin
+@FREEBSD_TRUE@am__append_3 = \
+@FREEBSD_TRUE@ plugin_freebsd.c \
+@FREEBSD_TRUE@ plugin_freebsd.h \
@FREEBSD_TRUE@ freebsd_sysctl.c \
@FREEBSD_TRUE@ $(NULL)
-@FREEBSD_FALSE@@MACOS_TRUE@am__append_2 = \
-@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.c plugin_macos.h \
+@FREEBSD_FALSE@@MACOS_TRUE@am__append_4 = \
+@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.c \
+@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.h \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_sysctl.c \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_mach_smi.c \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_fw.c \
@FREEBSD_FALSE@@MACOS_TRUE@ $(NULL)
-@FREEBSD_FALSE@@MACOS_FALSE@am__append_3 = \
+@FREEBSD_FALSE@@MACOS_FALSE@am__append_5 = \
@FREEBSD_FALSE@@MACOS_FALSE@ ipc.c ipc.h \
-@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.c plugin_proc.h \
-@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.c plugin_proc_diskspace.h \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.c \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.h \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.c \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.h \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_diskstats.c \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_interrupts.c \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_softirqs.c \
@@ -129,10 +81,17 @@ sbin_PROGRAMS = netdata$(EXEEXT)
@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.c \
@FREEBSD_FALSE@@MACOS_FALSE@ $(NULL)
+@FREEBSD_TRUE@am__append_6 = \
+@FREEBSD_TRUE@ plugin_freebsd.h \
+@FREEBSD_TRUE@ $(NULL)
+
subdir = src
+DIST_COMMON = $(dist_cache_DATA) $(dist_log_DATA) \
+ $(dist_registry_DATA) $(dist_varlib_DATA) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -141,43 +100,56 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_cache_DATA) \
- $(dist_log_DATA) $(dist_registry_DATA) $(dist_varlib_DATA) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
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)
am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" \
"$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)" \
"$(DESTDIR)$(registrydir)" "$(DESTDIR)$(varlibdir)"
PROGRAMS = $(plugins_PROGRAMS) $(sbin_PROGRAMS)
+am__apps_plugin_SOURCES_DIST = 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 plugin_freebsd.h
+am__objects_1 =
am_apps_plugin_OBJECTS = apps_plugin.$(OBJEXT) avl.$(OBJEXT) \
clocks.$(OBJEXT) common.$(OBJEXT) log.$(OBJEXT) \
- procfile.$(OBJEXT) web_buffer.$(OBJEXT)
+ procfile.$(OBJEXT) web_buffer.$(OBJEXT) $(am__objects_1)
apps_plugin_OBJECTS = $(am_apps_plugin_OBJECTS)
-apps_plugin_LDADD = $(LDADD)
-am__netdata_SOURCES_DIST = appconfig.c appconfig.h \
- adaptive_resortable_list.c adaptive_resortable_list.h avl.c \
- avl.h backends.c backends.h clocks.c clocks.h common.c \
- common.h daemon.c daemon.h dictionary.c dictionary.h eval.c \
- eval.h global_statistics.c global_statistics.h health.c \
- health.h inlined.h log.c log.h main.c main.h plugin_checks.c \
- plugin_checks.h plugin_idlejitter.c plugin_idlejitter.h \
- plugin_nfacct.c plugin_nfacct.h plugin_tc.c plugin_tc.h \
- plugins_d.c plugins_d.h popen.c popen.h socket.c socket.h \
- simple_pattern.c simple_pattern.h sys_fs_cgroup.c \
- sys_devices_system_edac_mc.c sys_devices_system_node.c \
- procfile.c procfile.h proc_self_mountinfo.c \
- proc_self_mountinfo.h registry.c registry.h \
- registry_internals.c registry_internals.h registry_url.c \
- registry_url.h registry_person.c registry_person.h \
- registry_machine.c registry_machine.h registry_init.c \
- registry_db.c registry_log.c rrd.c rrd.h rrd2json.c rrd2json.h \
- storage_number.c storage_number.h unit_test.c unit_test.h \
- url.c url.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 \
+am__DEPENDENCIES_1 =
+apps_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_freeipmi_plugin_OBJECTS = freeipmi_plugin.$(OBJEXT) \
+ clocks.$(OBJEXT) common.$(OBJEXT) log.$(OBJEXT) \
+ procfile.$(OBJEXT)
+freeipmi_plugin_OBJECTS = $(am_freeipmi_plugin_OBJECTS)
+freeipmi_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__netdata_SOURCES_DIST = adaptive_resortable_list.c \
+ adaptive_resortable_list.h appconfig.c appconfig.h avl.c avl.h \
+ backends.c backends.h clocks.c clocks.h common.c common.h \
+ daemon.c daemon.h dictionary.c dictionary.h eval.c eval.h \
+ global_statistics.c global_statistics.h health.c health.h \
+ health_config.c health_json.c health_log.c inlined.h locks.h \
+ log.c log.h main.c main.h plugin_checks.c plugin_checks.h \
+ plugin_idlejitter.c plugin_idlejitter.h plugin_nfacct.c \
+ plugin_nfacct.h plugin_tc.c plugin_tc.h plugins_d.c \
+ plugins_d.h popen.c popen.h proc_self_mountinfo.c \
+ proc_self_mountinfo.h procfile.c procfile.h registry.c \
+ registry.h registry_db.c registry_init.c registry_internals.c \
+ registry_internals.h registry_log.c registry_machine.c \
+ registry_machine.h registry_person.c registry_person.h \
+ 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 \
+ 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 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 \
@@ -189,13 +161,13 @@ am__netdata_SOURCES_DIST = appconfig.c appconfig.h \
proc_net_stat_synproxy.c proc_stat.c \
proc_sys_kernel_random_entropy_avail.c proc_vmstat.c \
proc_uptime.c sys_kernel_mm_ksm.c
-@FREEBSD_TRUE@am__objects_1 = plugin_freebsd.$(OBJEXT) \
+@FREEBSD_TRUE@am__objects_2 = plugin_freebsd.$(OBJEXT) \
@FREEBSD_TRUE@ freebsd_sysctl.$(OBJEXT)
-@FREEBSD_FALSE@@MACOS_TRUE@am__objects_2 = plugin_macos.$(OBJEXT) \
+@FREEBSD_FALSE@@MACOS_TRUE@am__objects_3 = plugin_macos.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_sysctl.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_mach_smi.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_fw.$(OBJEXT)
-@FREEBSD_FALSE@@MACOS_FALSE@am__objects_3 = ipc.$(OBJEXT) \
+@FREEBSD_FALSE@@MACOS_FALSE@am__objects_4 = ipc.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_diskstats.$(OBJEXT) \
@@ -218,65 +190,48 @@ am__netdata_SOURCES_DIST = appconfig.c appconfig.h \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_vmstat.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_uptime.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.$(OBJEXT)
-am_netdata_OBJECTS = appconfig.$(OBJEXT) \
- adaptive_resortable_list.$(OBJEXT) avl.$(OBJEXT) \
- backends.$(OBJEXT) clocks.$(OBJEXT) common.$(OBJEXT) \
- daemon.$(OBJEXT) dictionary.$(OBJEXT) eval.$(OBJEXT) \
- global_statistics.$(OBJEXT) health.$(OBJEXT) log.$(OBJEXT) \
- main.$(OBJEXT) plugin_checks.$(OBJEXT) \
- plugin_idlejitter.$(OBJEXT) plugin_nfacct.$(OBJEXT) \
- plugin_tc.$(OBJEXT) plugins_d.$(OBJEXT) popen.$(OBJEXT) \
- socket.$(OBJEXT) simple_pattern.$(OBJEXT) \
- sys_fs_cgroup.$(OBJEXT) sys_devices_system_edac_mc.$(OBJEXT) \
- sys_devices_system_node.$(OBJEXT) procfile.$(OBJEXT) \
- proc_self_mountinfo.$(OBJEXT) registry.$(OBJEXT) \
- registry_internals.$(OBJEXT) registry_url.$(OBJEXT) \
- registry_person.$(OBJEXT) registry_machine.$(OBJEXT) \
- registry_init.$(OBJEXT) registry_db.$(OBJEXT) \
- registry_log.$(OBJEXT) rrd.$(OBJEXT) rrd2json.$(OBJEXT) \
- storage_number.$(OBJEXT) unit_test.$(OBJEXT) url.$(OBJEXT) \
- web_buffer.$(OBJEXT) web_buffer_svg.$(OBJEXT) \
- web_client.$(OBJEXT) web_server.$(OBJEXT) $(am__objects_1) \
- $(am__objects_2) $(am__objects_3)
+am_netdata_OBJECTS = adaptive_resortable_list.$(OBJEXT) \
+ appconfig.$(OBJEXT) avl.$(OBJEXT) backends.$(OBJEXT) \
+ clocks.$(OBJEXT) common.$(OBJEXT) daemon.$(OBJEXT) \
+ dictionary.$(OBJEXT) eval.$(OBJEXT) \
+ global_statistics.$(OBJEXT) health.$(OBJEXT) \
+ health_config.$(OBJEXT) health_json.$(OBJEXT) \
+ health_log.$(OBJEXT) log.$(OBJEXT) main.$(OBJEXT) \
+ plugin_checks.$(OBJEXT) plugin_idlejitter.$(OBJEXT) \
+ plugin_nfacct.$(OBJEXT) plugin_tc.$(OBJEXT) \
+ plugins_d.$(OBJEXT) popen.$(OBJEXT) \
+ proc_self_mountinfo.$(OBJEXT) procfile.$(OBJEXT) \
+ registry.$(OBJEXT) registry_db.$(OBJEXT) \
+ registry_init.$(OBJEXT) registry_internals.$(OBJEXT) \
+ registry_log.$(OBJEXT) registry_machine.$(OBJEXT) \
+ registry_person.$(OBJEXT) registry_url.$(OBJEXT) rrd.$(OBJEXT) \
+ rrd2json.$(OBJEXT) rrd2json_api_old.$(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) \
+ 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)
netdata_OBJECTS = $(am_netdata_OBJECTS)
-am__DEPENDENCIES_1 =
netdata_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo " GEN " $@;
-am__v_GEN_1 =
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-AM_V_CC = $(am__v_CC_@AM_V@)
-am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
-am__v_CC_0 = @echo " CC " $@;
-am__v_CC_1 =
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-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) $(netdata_SOURCES)
-DIST_SOURCES = $(apps_plugin_SOURCES) $(am__netdata_SOURCES_DIST)
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
+SOURCES = $(apps_plugin_SOURCES) $(freeipmi_plugin_SOURCES) \
+ $(netdata_SOURCES)
+DIST_SOURCES = $(am__apps_plugin_SOURCES_DIST) \
+ $(freeipmi_plugin_SOURCES) $(am__netdata_SOURCES_DIST)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -306,30 +261,11 @@ am__uninstall_files_from_dir = { \
}
DATA = $(dist_cache_DATA) $(dist_log_DATA) $(dist_registry_DATA) \
$(dist_varlib_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates. Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
- BEGIN { nonempty = 0; } \
- { items[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique. This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
- list='$(am__tagged_files)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -353,7 +289,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -367,6 +307,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -483,33 +427,40 @@ AM_CFLAGS = \
$(OPTIONAL_NFACCT_CLFAGS) \
$(OPTIONAL_ZLIB_CFLAGS) \
$(OPTIONAL_UUID_CFLAGS) \
+ $(OPTIONAL_LIBCAP_CFLAGS) \
+ $(OPTIONAL_IPMIMONITORING_CFLAGS)\
$(NULL)
dist_cache_DATA = .keep
dist_varlib_DATA = .keep
dist_registry_DATA = .keep
dist_log_DATA = .keep
-netdata_SOURCES = appconfig.c appconfig.h adaptive_resortable_list.c \
- adaptive_resortable_list.h avl.c avl.h backends.c backends.h \
- clocks.c clocks.h common.c common.h daemon.c daemon.h \
- dictionary.c dictionary.h eval.c eval.h global_statistics.c \
- global_statistics.h health.c health.h inlined.h log.c log.h \
- main.c main.h plugin_checks.c plugin_checks.h \
+netdata_SOURCES = adaptive_resortable_list.c \
+ adaptive_resortable_list.h appconfig.c appconfig.h avl.c avl.h \
+ backends.c backends.h clocks.c clocks.h common.c common.h \
+ daemon.c daemon.h dictionary.c dictionary.h eval.c eval.h \
+ global_statistics.c global_statistics.h health.c health.h \
+ health_config.c health_json.c health_log.c inlined.h locks.h \
+ log.c log.h main.c main.h plugin_checks.c plugin_checks.h \
plugin_idlejitter.c plugin_idlejitter.h plugin_nfacct.c \
plugin_nfacct.h plugin_tc.c plugin_tc.h plugins_d.c \
- plugins_d.h popen.c popen.h socket.c socket.h simple_pattern.c \
- simple_pattern.h sys_fs_cgroup.c sys_devices_system_edac_mc.c \
- sys_devices_system_node.c procfile.c procfile.h \
- proc_self_mountinfo.c proc_self_mountinfo.h registry.c \
- registry.h registry_internals.c registry_internals.h \
- registry_url.c registry_url.h registry_person.c \
- registry_person.h registry_machine.c registry_machine.h \
- registry_init.c registry_db.c registry_log.c rrd.c rrd.h \
- rrd2json.c rrd2json.h storage_number.c storage_number.h \
- unit_test.c unit_test.h url.c url.h web_buffer.c web_buffer.h \
+ plugins_d.h popen.c popen.h proc_self_mountinfo.c \
+ proc_self_mountinfo.h procfile.c procfile.h registry.c \
+ registry.h registry_db.c registry_init.c registry_internals.c \
+ registry_internals.h registry_log.c registry_machine.c \
+ registry_machine.h registry_person.c registry_person.h \
+ 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 \
+ 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_1) \
- $(am__append_2) $(am__append_3)
+ web_server.c web_server.h $(NULL) $(am__append_3) \
+ $(am__append_4) $(am__append_5)
netdata_LDADD = \
$(OPTIONAL_MATH_LIBS) \
$(OPTIONAL_NFACCT_LIBS) \
@@ -517,15 +468,25 @@ netdata_LDADD = \
$(OPTIONAL_UUID_LIBS) \
$(NULL)
-apps_plugin_SOURCES = \
- apps_plugin.c \
- avl.c avl.h \
+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)
+apps_plugin_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_LIBCAP_LIBS) \
+ $(NULL)
+
+freeipmi_plugin_SOURCES = \
+ freeipmi_plugin.c \
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)
+
+freeipmi_plugin_LDADD = \
+ $(OPTIONAL_IPMIMONITORING_LIBS) \
$(NULL)
all: all-am
@@ -544,6 +505,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -563,18 +525,14 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-pluginsPROGRAMS: $(plugins_PROGRAMS)
@$(NORMAL_INSTALL)
+ test -z "$(pluginsdir)" || $(MKDIR_P) "$(DESTDIR)$(pluginsdir)"
@list='$(plugins_PROGRAMS)'; test -n "$(pluginsdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pluginsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pluginsdir)" || exit 1; \
- fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
- while read p p1; do if test -f $$p \
- ; then echo "$$p"; echo "$$p"; else :; fi; \
+ while read p p1; do if test -f $$p; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
done | \
- sed -e 'p;s,.*/,,;n;h' \
- -e 's|.*|.|' \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
@@ -595,8 +553,7 @@ uninstall-pluginsPROGRAMS:
@list='$(plugins_PROGRAMS)'; test -n "$(pluginsdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
- -e 's/$$/$(EXEEXT)/' \
- `; \
+ -e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pluginsdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pluginsdir)" && rm -f $$files
@@ -605,18 +562,14 @@ clean-pluginsPROGRAMS:
-test -z "$(plugins_PROGRAMS)" || rm -f $(plugins_PROGRAMS)
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
- fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
- while read p p1; do if test -f $$p \
- ; then echo "$$p"; echo "$$p"; else :; fi; \
+ while read p p1; do if test -f $$p; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
done | \
- sed -e 'p;s,.*/,,;n;h' \
- -e 's|.*|.|' \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
@@ -637,22 +590,22 @@ uninstall-sbinPROGRAMS:
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
- -e 's/$$/$(EXEEXT)/' \
- `; \
+ -e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(sbindir)" && rm -f $$files
clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
-
apps.plugin$(EXEEXT): $(apps_plugin_OBJECTS) $(apps_plugin_DEPENDENCIES) $(EXTRA_apps_plugin_DEPENDENCIES)
@rm -f apps.plugin$(EXEEXT)
- $(AM_V_CCLD)$(LINK) $(apps_plugin_OBJECTS) $(apps_plugin_LDADD) $(LIBS)
-
+ $(LINK) $(apps_plugin_OBJECTS) $(apps_plugin_LDADD) $(LIBS)
+freeipmi.plugin$(EXEEXT): $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_DEPENDENCIES) $(EXTRA_freeipmi_plugin_DEPENDENCIES)
+ @rm -f freeipmi.plugin$(EXEEXT)
+ $(LINK) $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_LDADD) $(LIBS)
netdata$(EXEEXT): $(netdata_OBJECTS) $(netdata_DEPENDENCIES) $(EXTRA_netdata_DEPENDENCIES)
@rm -f netdata$(EXEEXT)
- $(AM_V_CCLD)$(LINK) $(netdata_OBJECTS) $(netdata_LDADD) $(LIBS)
+ $(LINK) $(netdata_OBJECTS) $(netdata_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -671,8 +624,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dictionary.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_sysctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freeipmi_plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global_statistics.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health_json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health_log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macos_fw.Po@am__quote@
@@ -720,6 +677,17 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_url.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd2json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd2json_api_old.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdcalc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdcalctemplate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrddim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrddimvar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdfamily.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdhost.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdpush.Po@am__quote@
+@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)/simple_pattern.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_number.Po@am__quote@
@@ -729,31 +697,30 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_kernel_mm_ksm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_api_old.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_api_v1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_buffer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_buffer_svg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_client.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_server.Po@am__quote@
.c.o:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
install-dist_cacheDATA: $(dist_cache_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(cachedir)" || $(MKDIR_P) "$(DESTDIR)$(cachedir)"
@list='$(dist_cache_DATA)'; test -n "$(cachedir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(cachedir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(cachedir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -770,11 +737,8 @@ uninstall-dist_cacheDATA:
dir='$(DESTDIR)$(cachedir)'; $(am__uninstall_files_from_dir)
install-dist_logDATA: $(dist_log_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(logdir)" || $(MKDIR_P) "$(DESTDIR)$(logdir)"
@list='$(dist_log_DATA)'; test -n "$(logdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(logdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(logdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -791,11 +755,8 @@ uninstall-dist_logDATA:
dir='$(DESTDIR)$(logdir)'; $(am__uninstall_files_from_dir)
install-dist_registryDATA: $(dist_registry_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(registrydir)" || $(MKDIR_P) "$(DESTDIR)$(registrydir)"
@list='$(dist_registry_DATA)'; test -n "$(registrydir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(registrydir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(registrydir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -812,11 +773,8 @@ uninstall-dist_registryDATA:
dir='$(DESTDIR)$(registrydir)'; $(am__uninstall_files_from_dir)
install-dist_varlibDATA: $(dist_varlib_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(varlibdir)" || $(MKDIR_P) "$(DESTDIR)$(varlibdir)"
@list='$(dist_varlib_DATA)'; test -n "$(varlibdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(varlibdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(varlibdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -832,15 +790,26 @@ uninstall-dist_varlibDATA:
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(varlibdir)'; $(am__uninstall_files_from_dir)
-ID: $(am__tagged_files)
- $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
- $(am__define_uniq_tagged_files); \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
@@ -852,11 +821,15 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$$unique; \
fi; \
fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
- $(am__define_uniq_tagged_files); \
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
@@ -865,21 +838,6 @@ GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
- list='$(am__tagged_files)'; \
- case "$(srcdir)" in \
- [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
- *) sdir=$(subdir)/$(srcdir) ;; \
- esac; \
- for i in $$list; do \
- if test -f "$$i"; then \
- echo "$(subdir)/$$i"; \
- else \
- echo "$$sdir/$$i"; \
- fi; \
- done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
@@ -978,8 +936,7 @@ info-am:
install-data-am: install-dist_cacheDATA install-dist_logDATA \
install-dist_registryDATA install-dist_varlibDATA \
install-pluginsPROGRAMS
- @$(NORMAL_INSTALL)
- $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+
install-dvi: install-dvi-am
install-dvi-am:
@@ -1027,45 +984,26 @@ uninstall-am: uninstall-dist_cacheDATA uninstall-dist_logDATA \
uninstall-dist_registryDATA uninstall-dist_varlibDATA \
uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS
-.MAKE: install-am install-data-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
- clean-pluginsPROGRAMS clean-sbinPROGRAMS cscopelist-am ctags \
- ctags-am distclean distclean-compile distclean-generic \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am \
- install-data-hook install-dist_cacheDATA install-dist_logDATA \
- install-dist_registryDATA install-dist_varlibDATA install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-pluginsPROGRAMS install-ps \
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-pluginsPROGRAMS clean-sbinPROGRAMS ctags distclean \
+ distclean-compile distclean-generic distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_cacheDATA \
+ install-dist_logDATA install-dist_registryDATA \
+ install-dist_varlibDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pluginsPROGRAMS install-ps \
install-ps-am install-sbinPROGRAMS install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
- mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am uninstall-dist_cacheDATA uninstall-dist_logDATA \
uninstall-dist_registryDATA uninstall-dist_varlibDATA \
uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS
-.PRECIOUS: Makefile
-
-
-install-data-hook:
- if [ `id -u` == 0 ]; then \
- chown root '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- ( setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin' || \
- chmod 4755 '$(DESTDIR)$(pluginsdir)/apps.plugin' ); \
- else \
- echo; \
- echo "ATTENTION"; \
- echo; \
- echo "$(pluginsdir)/apps.plugin requires escalated capabilities:"; \
- echo "sudo chown root '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo; \
- fi
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/adaptive_resortable_list.c b/src/adaptive_resortable_list.c
index a37c396fa..f74c53eae 100644
--- a/src/adaptive_resortable_list.c
+++ b/src/adaptive_resortable_list.c
@@ -52,7 +52,6 @@ void arl_free(ARL_BASE *arl_base) {
}
void arl_begin(ARL_BASE *base) {
- ARL_ENTRY *e;
#ifdef NETDATA_INTERNAL_CHECKS
if(likely(base->iteration > 10)) {
@@ -66,6 +65,7 @@ void arl_begin(ARL_BASE *base) {
info("ARL '%s' has %zu fast searches and %zu slow searches. Is the source really changing so fast?"
, base->name, base->fast, base->slow);
+ /*
if(unlikely(base->iteration % 60 == 0)) {
info("ARL '%s' statistics: iteration %zu, expected %zu, wanted %zu, allocated %zu, fred %zu, relinkings %zu, found %zu, added %zu, fast %zu, slow %zu"
, base->name
@@ -83,13 +83,15 @@ void arl_begin(ARL_BASE *base) {
// for(e = base->head; e; e = e->next) fprintf(stderr, "%s ", e->name);
// fprintf(stderr, "\n");
}
+ */
}
#endif
if(unlikely(base->added || base->iteration % base->rechecks) == 1) {
base->added = 0;
base->wanted = 0;
- for(e = base->head; e ; e = e->next) {
+ ARL_ENTRY *e = base->head;
+ while(e) {
if(e->flags & ARL_ENTRY_FLAG_FOUND) {
// remove the found flag
@@ -98,25 +100,48 @@ void arl_begin(ARL_BASE *base) {
// count it in wanted
if(e->flags & ARL_ENTRY_FLAG_EXPECTED)
base->wanted++;
+
}
- else if(e->flags & ARL_ENTRY_FLAG_DYNAMIC) {
+ else if(e->flags & ARL_ENTRY_FLAG_DYNAMIC && !(base->head == e && !e->next)) { // not last entry
// we can remove this entry
// it is not found, and it was created because
// it was found in the source file
+
+ // remember the next one
+ ARL_ENTRY *t = e->next;
+
+ // remove it from the list
if(e->next) e->next->prev = e->prev;
if(e->prev) e->prev->next = e->next;
if(base->head == e) base->head = e->next;
+
+ // free it
freez(e->name);
freez(e);
+ // count it
base->fred++;
+
+ // continue
+ e = t;
+ continue;
}
+
+ e = e->next;
}
}
+ if(unlikely(!base->head)) {
+ // hm... no nodes at all in the list #1700
+ // add a fake one to prevent a crash
+ // this is better than checking for the existence of nodes all the time
+ arl_expect(base, "a-really-not-existing-source-keyword", NULL);
+ }
+
base->iteration++;
base->next_keyword = base->head;
base->found = 0;
+
}
// register an expected keyword to the ARL
@@ -153,7 +178,7 @@ int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *val
break;
#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(e == base->next_keyword))
+ if(unlikely(base->next_keyword && e == base->next_keyword))
fatal("Internal Error: e == base->last");
#endif
@@ -208,9 +233,14 @@ int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *val
if(base->head == base->next_keyword)
base->head = e;
}
- else
+ else {
e->prev = NULL;
+ if(!base->head)
+ base->head = e;
+ }
+
+ // prepare the next iteration
base->next_keyword = e->next;
if(unlikely(!base->next_keyword))
base->next_keyword = base->head;
diff --git a/src/appconfig.c b/src/appconfig.c
index 81ab01be2..71ff4b75e 100644
--- a/src/appconfig.c
+++ b/src/appconfig.c
@@ -2,8 +2,6 @@
#define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2)
-pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
-
// ----------------------------------------------------------------------------
// definitions
@@ -12,7 +10,7 @@ pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
#define CONFIG_VALUE_CHANGED 0x04 // has been changed from the loaded value
#define CONFIG_VALUE_CHECKED 0x08 // has been checked if the value is different from the default
-struct config_value {
+struct config_option {
avl avl; // the index - this has to be first!
uint8_t flags;
@@ -22,10 +20,10 @@ struct config_value {
char *name;
char *value;
- struct config_value *next; // config->mutex protects just this
+ struct config_option *next; // config->mutex protects just this
};
-struct config {
+struct section {
avl avl;
uint32_t hash; // a simple hash to speed up searching
@@ -33,111 +31,124 @@ struct config {
char *name;
- struct config *next; // gloabl config_mutex protects just this
+ struct section *next; // gloabl config_mutex protects just this
- struct config_value *values;
+ struct config_option *values;
avl_tree_lock values_index;
- pthread_mutex_t mutex; // this locks only the writers, to ensure atomic updates
+ netdata_mutex_t mutex; // this locks only the writers, to ensure atomic updates
// readers are protected using the rwlock in avl_tree_lock
-} *config_root = NULL;
+};
+
+static int appconfig_section_compare(void *a, void *b);
+
+struct config netdata_config = {
+ .sections = NULL,
+ .mutex = NETDATA_MUTEX_INITIALIZER,
+ .index = {
+ { NULL, appconfig_section_compare },
+ AVL_LOCK_INITIALIZER
+ }
+};
+struct config stream_config = {
+ .sections = NULL,
+ .mutex = NETDATA_MUTEX_INITIALIZER,
+ .index = {
+ { NULL, appconfig_section_compare },
+ AVL_LOCK_INITIALIZER
+ }
+};
// ----------------------------------------------------------------------------
// locking
-static inline void config_global_write_lock(void) {
- pthread_mutex_lock(&config_mutex);
+static inline void appconfig_wrlock(struct config *root) {
+ netdata_mutex_lock(&root->mutex);
}
-static inline void config_global_unlock(void) {
- pthread_mutex_unlock(&config_mutex);
+static inline void appconfig_unlock(struct config *root) {
+ netdata_mutex_unlock(&root->mutex);
}
-static inline void config_section_write_lock(struct config *co) {
- pthread_mutex_lock(&co->mutex);
+static inline void config_section_wrlock(struct section *co) {
+ netdata_mutex_lock(&co->mutex);
}
-static inline void config_section_unlock(struct config *co) {
- pthread_mutex_unlock(&co->mutex);
+static inline void config_section_unlock(struct section *co) {
+ netdata_mutex_unlock(&co->mutex);
}
// ----------------------------------------------------------------------------
// config name-value index
-static int config_value_compare(void* a, void* b) {
- if(((struct config_value *)a)->hash < ((struct config_value *)b)->hash) return -1;
- else if(((struct config_value *)a)->hash > ((struct config_value *)b)->hash) return 1;
- else return strcmp(((struct config_value *)a)->name, ((struct config_value *)b)->name);
+static int appconfig_option_compare(void *a, void *b) {
+ if(((struct config_option *)a)->hash < ((struct config_option *)b)->hash) return -1;
+ else if(((struct config_option *)a)->hash > ((struct config_option *)b)->hash) return 1;
+ else return strcmp(((struct config_option *)a)->name, ((struct config_option *)b)->name);
}
-#define config_value_index_add(co, cv) (struct config_value *)avl_insert_lock(&((co)->values_index), (avl *)(cv))
-#define config_value_index_del(co, cv) (struct config_value *)avl_remove_lock(&((co)->values_index), (avl *)(cv))
+#define appconfig_option_index_add(co, cv) (struct config_option *)avl_insert_lock(&((co)->values_index), (avl *)(cv))
+#define appconfig_option_index_del(co, cv) (struct config_option *)avl_remove_lock(&((co)->values_index), (avl *)(cv))
-static struct config_value *config_value_index_find(struct config *co, const char *name, uint32_t hash) {
- struct config_value tmp;
+static struct config_option *appconfig_option_index_find(struct section *co, const char *name, uint32_t hash) {
+ struct config_option tmp;
tmp.hash = (hash)?hash:simple_hash(name);
tmp.name = (char *)name;
- return (struct config_value *)avl_search_lock(&(co->values_index), (avl *) &tmp);
+ return (struct config_option *)avl_search_lock(&(co->values_index), (avl *) &tmp);
}
// ----------------------------------------------------------------------------
// config sections index
-static int config_compare(void* a, void* b) {
- if(((struct config *)a)->hash < ((struct config *)b)->hash) return -1;
- else if(((struct config *)a)->hash > ((struct config *)b)->hash) return 1;
- else return strcmp(((struct config *)a)->name, ((struct config *)b)->name);
+static int appconfig_section_compare(void *a, void *b) {
+ if(((struct section *)a)->hash < ((struct section *)b)->hash) return -1;
+ else if(((struct section *)a)->hash > ((struct section *)b)->hash) return 1;
+ else return strcmp(((struct section *)a)->name, ((struct section *)b)->name);
}
-avl_tree_lock config_root_index = {
- { NULL, config_compare },
- AVL_LOCK_INITIALIZER
-};
-
-#define config_index_add(cfg) (struct config *)avl_insert_lock(&config_root_index, (avl *)(cfg))
-#define config_index_del(cfg) (struct config *)avl_remove_lock(&config_root_index, (avl *)(cfg))
+#define appconfig_index_add(root, cfg) (struct section *)avl_insert_lock(&root->index, (avl *)(cfg))
+#define appconfig_index_del(root, cfg) (struct section *)avl_remove_lock(&root->index, (avl *)(cfg))
-static struct config *config_index_find(const char *name, uint32_t hash) {
- struct config tmp;
+static struct section *appconfig_index_find(struct config *root, const char *name, uint32_t hash) {
+ struct section tmp;
tmp.hash = (hash)?hash:simple_hash(name);
tmp.name = (char *)name;
- return (struct config *)avl_search_lock(&config_root_index, (avl *) &tmp);
+ return (struct section *)avl_search_lock(&root->index, (avl *) &tmp);
}
// ----------------------------------------------------------------------------
// config section methods
-static inline struct config *config_section_find(const char *section) {
- return config_index_find(section, 0);
+static inline struct section *appconfig_section_find(struct config *root, const char *section) {
+ return appconfig_index_find(root, section, 0);
}
-static inline struct config *config_section_create(const char *section)
-{
+static inline struct section *appconfig_section_create(struct config *root, const char *section) {
debug(D_CONFIG, "Creating section '%s'.", section);
- struct config *co = callocz(1, sizeof(struct config));
+ struct section *co = callocz(1, sizeof(struct section));
co->name = strdupz(section);
co->hash = simple_hash(co->name);
- avl_init_lock(&co->values_index, config_value_compare);
+ avl_init_lock(&co->values_index, appconfig_option_compare);
- if(unlikely(config_index_add(co) != co))
+ if(unlikely(appconfig_index_add(root, co) != co))
error("INTERNAL ERROR: indexing of section '%s', already exists.", co->name);
- config_global_write_lock();
- struct config *co2 = config_root;
+ appconfig_wrlock(root);
+ struct section *co2 = root->sections;
if(co2) {
while (co2->next) co2 = co2->next;
co2->next = co;
}
- else config_root = co;
- config_global_unlock();
+ else root->sections = co;
+ appconfig_unlock(root);
return co;
}
@@ -146,20 +157,25 @@ static inline struct config *config_section_create(const char *section)
// ----------------------------------------------------------------------------
// config name-value methods
-static inline struct config_value *config_value_create(struct config *co, const char *name, const char *value)
-{
+static inline struct config_option *appconfig_value_create(struct section *co, const char *name, const char *value) {
debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
- struct config_value *cv = callocz(1, sizeof(struct config_value));
+ struct config_option *cv = callocz(1, sizeof(struct config_option));
cv->name = strdupz(name);
cv->hash = simple_hash(cv->name);
cv->value = strdupz(value);
- if(unlikely(config_value_index_add(co, cv) != cv))
- error("INTERNAL ERROR: indexing of config '%s' in section '%s': already exists.", cv->name, co->name);
+ struct config_option *found = appconfig_option_index_add(co, cv);
+ if(found != cv) {
+ error("indexing of config '%s' in section '%s': already exists - using the existing one.", cv->name, co->name);
+ freez(cv->value);
+ freez(cv->name);
+ freez(cv);
+ return found;
+ }
- config_section_write_lock(co);
- struct config_value *cv2 = co->values;
+ config_section_wrlock(co);
+ struct config_option *cv2 = co->values;
if(cv2) {
while (cv2->next) cv2 = cv2->next;
cv2->next = cv;
@@ -170,66 +186,87 @@ static inline struct config_value *config_value_create(struct config *co, const
return cv;
}
-int config_exists(const char *section, const char *name) {
- struct config_value *cv;
+int appconfig_exists(struct config *root, const char *section, const char *name) {
+ struct config_option *cv;
debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
- struct config *co = config_section_find(section);
+ struct section *co = appconfig_section_find(root, section);
if(!co) return 0;
- cv = config_value_index_find(co, name, 0);
+ cv = appconfig_option_index_find(co, name, 0);
if(!cv) return 0;
return 1;
}
-int config_rename(const char *section, const char *old, const char *new) {
- struct config_value *cv, *cv2;
+int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) {
+ struct config_option *cv_old, *cv_new;
+ int ret = -1;
- debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
+ debug(D_CONFIG, "request to rename config in section '%s', old name '%s', to section '%s', new name '%s'", section_old, name_old, section_new, name_new);
- struct config *co = config_section_find(section);
- if(!co) return -1;
+ struct section *co_old = appconfig_section_find(root, section_old);
+ if(!co_old) return ret;
- config_section_write_lock(co);
+ struct section *co_new = appconfig_section_find(root, section_new);
+ if(!co_new) co_new = appconfig_section_create(root, section_new);
- cv = config_value_index_find(co, old, 0);
- if(!cv) goto cleanup;
+ config_section_wrlock(co_old);
+ config_section_wrlock(co_new);
- cv2 = config_value_index_find(co, new, 0);
- if(cv2) goto cleanup;
+ cv_old = appconfig_option_index_find(co_old, name_old, 0);
+ if(!cv_old) goto cleanup;
- if(unlikely(config_value_index_del(co, cv) != cv))
- error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted tge wrong config entry.", cv->name, co->name);
+ cv_new = appconfig_option_index_find(co_new, name_new, 0);
+ if(cv_new) goto cleanup;
- freez(cv->name);
- cv->name = strdupz(new);
- cv->hash = simple_hash(cv->name);
- if(unlikely(config_value_index_add(co, cv) != cv))
- error("INTERNAL ERROR: indexing of config '%s' in section '%s', already exists.", cv->name, co->name);
+ if(unlikely(appconfig_option_index_del(co_old, cv_old) != cv_old))
+ error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted tge wrong config entry.", cv_old->name, co_old->name);
- config_section_unlock(co);
+ if(co_old->values == cv_old) {
+ co_old->values = cv_old->next;
+ }
+ else {
+ struct config_option *t;
+ for(t = co_old->values; t && t->next != cv_old ;t = t->next) ;
+ if(!t || t->next != cv_old)
+ error("INTERNAL ERROR: cannot find variable '%s' in section '%s' of the config - but it should be there.", cv_old->name, co_old->name);
+ else
+ t->next = cv_old->next;
+ }
- return 0;
+ freez(cv_old->name);
+ cv_old->name = strdupz(name_new);
+ cv_old->hash = simple_hash(cv_old->name);
+
+ cv_new = cv_old;
+ cv_new->next = co_new->values;
+ co_new->values = cv_new;
+
+ if(unlikely(appconfig_option_index_add(co_new, cv_old) != cv_old))
+ error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.", cv_old->name, co_new->name);
+
+ ret = 0;
cleanup:
- config_section_unlock(co);
- return -1;
+ config_section_unlock(co_new);
+ config_section_unlock(co_old);
+ return ret;
}
-char *config_get(const char *section, const char *name, const char *default_value)
+char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value)
{
- struct config_value *cv;
+ struct config_option *cv;
debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
- struct config *co = config_section_find(section);
- if(!co) co = config_section_create(section);
+ struct section *co = appconfig_section_find(root, section);
+ if(!co) co = appconfig_section_create(root, section);
- cv = config_value_index_find(co, name, 0);
+ cv = appconfig_option_index_find(co, name, 0);
if(!cv) {
- cv = config_value_create(co, name, default_value);
+ cv = appconfig_value_create(co, name, default_value);
if(!cv) return NULL;
}
cv->flags |= CONFIG_VALUE_USED;
@@ -246,67 +283,67 @@ char *config_get(const char *section, const char *name, const char *default_valu
return(cv->value);
}
-long long config_get_number(const char *section, const char *name, long long value)
+long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value)
{
char buffer[100], *s;
sprintf(buffer, "%lld", value);
- s = config_get(section, name, buffer);
+ s = appconfig_get(root, section, name, buffer);
if(!s) return value;
return strtoll(s, NULL, 0);
}
-int config_get_boolean(const char *section, const char *name, int value)
+int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value)
{
char *s;
if(value) s = "yes";
else s = "no";
- s = config_get(section, name, s);
+ s = appconfig_get(root, section, name, s);
if(!s) return value;
if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
return 0;
}
-int config_get_boolean_ondemand(const char *section, const char *name, int value)
+int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value)
{
char *s;
- if(value == CONFIG_ONDEMAND_ONDEMAND)
+ if(value == CONFIG_BOOLEAN_AUTO)
s = "auto";
- else if(value == CONFIG_ONDEMAND_NO)
+ else if(value == CONFIG_BOOLEAN_NO)
s = "no";
else
s = "yes";
- s = config_get(section, name, s);
+ s = appconfig_get(root, section, name, s);
if(!s) return value;
if(!strcmp(s, "yes"))
- return CONFIG_ONDEMAND_YES;
+ return CONFIG_BOOLEAN_YES;
else if(!strcmp(s, "no"))
- return CONFIG_ONDEMAND_NO;
+ return CONFIG_BOOLEAN_NO;
else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
- return CONFIG_ONDEMAND_ONDEMAND;
+ return CONFIG_BOOLEAN_AUTO;
return value;
}
-const char *config_set_default(const char *section, const char *name, const char *value)
+const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value)
{
- struct config_value *cv;
+ struct config_option *cv;
debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
- struct config *co = config_section_find(section);
- if(!co) return config_set(section, name, value);
+ struct section *co = appconfig_section_find(root, section);
+ if(!co) return appconfig_set(root, section, name, value);
- cv = config_value_index_find(co, name, 0);
- if(!cv) return config_set(section, name, value);
+ cv = appconfig_option_index_find(co, name, 0);
+ if(!cv) return appconfig_set(root, section, name, value);
cv->flags |= CONFIG_VALUE_USED;
@@ -323,17 +360,17 @@ const char *config_set_default(const char *section, const char *name, const char
return cv->value;
}
-const char *config_set(const char *section, const char *name, const char *value)
+const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value)
{
- struct config_value *cv;
+ struct config_option *cv;
debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
- struct config *co = config_section_find(section);
- if(!co) co = config_section_create(section);
+ struct section *co = appconfig_section_find(root, section);
+ if(!co) co = appconfig_section_create(root, section);
- cv = config_value_index_find(co, name, 0);
- if(!cv) cv = config_value_create(co, name, value);
+ cv = appconfig_option_index_find(co, name, 0);
+ if(!cv) cv = appconfig_value_create(co, name, value);
cv->flags |= CONFIG_VALUE_USED;
if(strcmp(cv->value, value) != 0) {
@@ -346,23 +383,23 @@ const char *config_set(const char *section, const char *name, const char *value)
return value;
}
-long long config_set_number(const char *section, const char *name, long long value)
+long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value)
{
char buffer[100];
sprintf(buffer, "%lld", value);
- config_set(section, name, buffer);
+ appconfig_set(root, section, name, buffer);
return value;
}
-int config_set_boolean(const char *section, const char *name, int value)
+int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value)
{
char *s;
if(value) s = "yes";
else s = "no";
- config_set(section, name, s);
+ appconfig_set(root, section, name, s);
return value;
}
@@ -371,10 +408,10 @@ int config_set_boolean(const char *section, const char *name, int value)
// ----------------------------------------------------------------------------
// config load/save
-int load_config(char *filename, int overwrite_used)
+int appconfig_load(struct config *root, char *filename, int overwrite_used)
{
int line = 0;
- struct config *co = NULL;
+ struct section *co = NULL;
char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
@@ -404,8 +441,8 @@ int load_config(char *filename, int overwrite_used)
s[len - 1] = '\0';
s++;
- co = config_section_find(s);
- if(!co) co = config_section_create(s);
+ co = appconfig_section_find(root, s);
+ if(!co) co = appconfig_section_create(root, s);
continue;
}
@@ -437,9 +474,9 @@ int load_config(char *filename, int overwrite_used)
continue;
}
- struct config_value *cv = config_value_index_find(co, name, 0);
+ struct config_option *cv = appconfig_option_index_find(co, name, 0);
- if(!cv) cv = config_value_create(co, name, value);
+ if(!cv) cv = appconfig_value_create(co, name, value);
else {
if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
@@ -457,11 +494,11 @@ int load_config(char *filename, int overwrite_used)
return 1;
}
-void generate_config(BUFFER *wb, int only_changed)
+void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
{
int i, pri;
- struct config *co;
- struct config_value *cv;
+ struct section *co;
+ struct config_option *cv;
for(i = 0; i < 3 ;i++) {
switch(i) {
@@ -490,13 +527,16 @@ void generate_config(BUFFER *wb, int only_changed)
break;
}
- config_global_write_lock();
- for(co = config_root; co ; co = co->next) {
- if(!strcmp(co->name, "global") ||
- !strcmp(co->name, "plugins") ||
- !strcmp(co->name, "registry") ||
- !strcmp(co->name, "health") ||
- !strcmp(co->name, "backend"))
+ appconfig_wrlock(root);
+ for(co = root->sections; co ; co = co->next) {
+ if(!strcmp(co->name, CONFIG_SECTION_GLOBAL)
+ || !strcmp(co->name, CONFIG_SECTION_WEB)
+ || !strcmp(co->name, CONFIG_SECTION_PLUGINS)
+ || !strcmp(co->name, CONFIG_SECTION_REGISTRY)
+ || !strcmp(co->name, CONFIG_SECTION_HEALTH)
+ || !strcmp(co->name, CONFIG_SECTION_BACKEND)
+ || !strcmp(co->name, CONFIG_SECTION_STREAM)
+ )
pri = 0;
else if(!strncmp(co->name, "plugin:", 7)) pri = 1;
else pri = 2;
@@ -506,7 +546,7 @@ void generate_config(BUFFER *wb, int only_changed)
int changed = 0;
int count = 0;
- config_section_write_lock(co);
+ config_section_wrlock(co);
for(cv = co->values; cv ; cv = cv->next) {
used += (cv->flags & CONFIG_VALUE_USED)?1:0;
changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
@@ -523,7 +563,7 @@ void generate_config(BUFFER *wb, int only_changed)
buffer_sprintf(wb, "\n[%s]\n", co->name);
- config_section_write_lock(co);
+ config_section_wrlock(co);
for(cv = co->values; cv ; cv = cv->next) {
if(used && !(cv->flags & CONFIG_VALUE_USED)) {
@@ -534,6 +574,6 @@ void generate_config(BUFFER *wb, int only_changed)
config_section_unlock(co);
}
}
- config_global_unlock();
+ appconfig_unlock(root);
}
}
diff --git a/src/appconfig.h b/src/appconfig.h
index 08aae8348..45cc8cfd5 100644
--- a/src/appconfig.h
+++ b/src/appconfig.h
@@ -3,30 +3,67 @@
#define CONFIG_FILENAME "netdata.conf"
+#define CONFIG_SECTION_GLOBAL "global"
+#define CONFIG_SECTION_WEB "web"
+#define CONFIG_SECTION_PLUGINS "plugins"
+#define CONFIG_SECTION_REGISTRY "registry"
+#define CONFIG_SECTION_HEALTH "health"
+#define CONFIG_SECTION_BACKEND "backend"
+#define CONFIG_SECTION_STREAM "stream"
+
// these are used to limit the configuration names and values lengths
// they are not enforced by config.c functions (they will strdup() all strings, no matter of their length)
#define CONFIG_MAX_NAME 1024
#define CONFIG_MAX_VALUE 2048
-extern int load_config(char *filename, int overwrite_used);
+struct config {
+ struct section *sections;
+ netdata_mutex_t mutex;
+ avl_tree_lock index;
+};
+
+extern struct config
+ netdata_config,
+ stream_config;
+
+#define CONFIG_BOOLEAN_NO 0
+#define CONFIG_BOOLEAN_YES 1
+#define CONFIG_BOOLEAN_AUTO 2
+
+extern int appconfig_load(struct config *root, char *filename, int overwrite_used);
+
+extern char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value);
+extern long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value);
+extern int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value);
+extern int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value);
+
+extern const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value);
+extern const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value);
+extern long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value);
+extern int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value);
+
+extern int appconfig_exists(struct config *root, const char *section, const char *name);
+extern int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new);
+
+extern void appconfig_generate(struct config *root, BUFFER *wb, int only_changed);
-extern char *config_get(const char *section, const char *name, const char *default_value);
-extern long long config_get_number(const char *section, const char *name, long long value);
-extern int config_get_boolean(const char *section, const char *name, int value);
+// ----------------------------------------------------------------------------
+// shortcuts for the default netdata configuration
-#define CONFIG_ONDEMAND_NO 0
-#define CONFIG_ONDEMAND_YES 1
-#define CONFIG_ONDEMAND_ONDEMAND 2
-extern int config_get_boolean_ondemand(const char *section, const char *name, int value);
+#define config_load(filename, overwrite_used) appconfig_load(&netdata_config, filename, overwrite_used)
+#define config_get(section, name, default_value) appconfig_get(&netdata_config, section, name, default_value)
+#define config_get_number(section, name, value) appconfig_get_number(&netdata_config, section, name, value)
+#define config_get_boolean(section, name, value) appconfig_get_boolean(&netdata_config, section, name, value)
+#define config_get_boolean_ondemand(section, name, value) appconfig_get_boolean_ondemand(&netdata_config, section, name, value)
-extern const char *config_set(const char *section, const char *name, const char *value);
-extern const char *config_set_default(const char *section, const char *name, const char *value);
-extern long long config_set_number(const char *section, const char *name, long long value);
-extern int config_set_boolean(const char *section, const char *name, int value);
+#define config_set(section, name, default_value) appconfig_get(&netdata_config, section, name, default_value)
+#define config_set_default(section, name, value) appconfig_set_default(&netdata_config, section, name, value)
+#define config_set_number(section, name, value) appconfig_set_number(&netdata_config, section, name, value)
+#define config_set_boolean(section, name, value) appconfig_set_boolean(&netdata_config, section, name, value)
-extern int config_exists(const char *section, const char *name);
-extern int config_rename(const char *section, const char *old, const char *new);
+#define config_exists(section, name) appconfig_exists(&netdata_config, section, name)
+#define config_move(section_old, name_old, section_new, name_new) appconfig_move(&netdata_config, section_old, name_old, section_new, name_new)
-extern void generate_config(BUFFER *wb, int only_changed);
+#define config_generate(buffer, only_changed) appconfig_generate(&netdata_config, buffer, only_changed)
#endif /* NETDATA_CONFIG_H */
diff --git a/src/apps_plugin.c b/src/apps_plugin.c
index 0a72190aa..b1bf06bee 100644
--- a/src/apps_plugin.c
+++ b/src/apps_plugin.c
@@ -1,50 +1,141 @@
+
+/*
+ * netdata apps.plugin
+ * (C) Copyright 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
+ * Released under GPL v3+
+ */
+
#include "common.h"
+#ifdef __FreeBSD__
+#include <sys/user.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// per O/S configuration
+
+// the minimum PID of the system
+// this is also the pid of the init process
+#define INIT_PID 1
+
+// if the way apps.plugin will work, will read the entire process list,
+// including the resource utilization of each process, instantly
+// set this to 1
+// when set to 0, apps.plugin builds a sort list of processes, in order
+// to process children processes, before parent processes
+#ifdef __FreeBSD__
+#define ALL_PIDS_ARE_READ_INSTANTLY 1
+#else
+#define ALL_PIDS_ARE_READ_INSTANTLY 0
+#endif
+
+// ----------------------------------------------------------------------------
+// string lengths
+
#define MAX_COMPARE_NAME 100
#define MAX_NAME 100
#define MAX_CMDLINE 1024
-// the rates we are going to send to netdata
-// will have this detail
-// a value of:
-// 1 will send just integer parts to netdata
-// 100 will send 2 decimal points
-// 1000 will send 3 decimal points
+
+// ----------------------------------------------------------------------------
+// the rates we are going to send to netdata will have this detail a value of:
+// - 1 will send just integer parts to netdata
+// - 100 will send 2 decimal points
+// - 1000 will send 3 decimal points
// etc.
#define RATES_DETAIL 10000ULL
+
+// ----------------------------------------------------------------------------
+// to avoid reallocating too frequently, we can increase the number of spare
+// file descriptors used by processes.
+// IMPORTANT:
+// having a lot of spares, increases the CPU utilization of the plugin.
#define MAX_SPARE_FDS 1
-int debug = 0;
-int update_every = 1;
-unsigned long long global_iterations_counter = 1;
-unsigned long long file_counter = 0;
-int proc_pid_cmdline_is_needed = 0;
-int include_exited_childs = 1;
-char *config_dir = CONFIG_DIR;
+// ----------------------------------------------------------------------------
+// command line options
+
+static int
+ debug = 0,
+ update_every = 1,
+ enable_guest_charts = 0,
+#ifdef __FreeBSD__
+ enable_file_charts = 0,
+#else
+ enable_file_charts = 1,
+#endif
+ enable_users_charts = 1,
+ enable_groups_charts = 1,
+ include_exited_childs = 1;
-pid_t *all_pids_sortlist = NULL;
-// will be automatically set to 1, if guest values are collected
-int show_guest_time = 0;
-int show_guest_time_old = 0;
+// will be changed to getenv(NETDATA_CONFIG_DIR) if it exists
+static char *config_dir = CONFIG_DIR;
+
+// ----------------------------------------------------------------------------
+// internal flags
+// handled in code (automatically set)
+
+static int
+ show_guest_time = 0, // 1 when guest values are collected
+ show_guest_time_old = 0,
+ proc_pid_cmdline_is_needed = 0; // 1 when we need to read /proc/cmdline
-int enable_guest_charts = 0;
-int enable_file_charts = 1;
-int enable_users_charts = 1;
-int enable_groups_charts = 1;
// ----------------------------------------------------------------------------
+// internal counters
+
+static size_t
+ global_iterations_counter = 1,
+ calls_counter = 0,
+ file_counter = 0,
+ targets_assignment_counter = 0;
+
+
+// ----------------------------------------------------------------------------
+// Normalization
+//
+// With normalization we lower the collected metrics by a factor to make them
+// match the total utilization of the system.
+// The discrepancy exists because apps.plugin needs some time to collect all
+// the metrics. This results in utilization that exceeds the total utilization
+// of the system.
+//
+// With normalization we align the per-process utilization, to the total of
+// the system. We first consume the exited children utilization and it the
+// collected values is above the total, we proportionally scale each reported
+// metric.
+
+// the total system time, as reported by /proc/stat
+static kernel_uint_t
+ global_utime = 0,
+ global_stime = 0,
+ global_gtime = 0;
-void netdata_cleanup_and_exit(int ret) {
- exit(ret);
-}
+
+// the normalization ratios, as calculated by normalize_utilization()
+double utime_fix_ratio = 1.0,
+ stime_fix_ratio = 1.0,
+ gtime_fix_ratio = 1.0,
+ minflt_fix_ratio = 1.0,
+ majflt_fix_ratio = 1.0,
+ cutime_fix_ratio = 1.0,
+ cstime_fix_ratio = 1.0,
+ cgtime_fix_ratio = 1.0,
+ cminflt_fix_ratio = 1.0,
+ cmajflt_fix_ratio = 1.0;
// ----------------------------------------------------------------------------
// target
-// target is the structure that process data are aggregated
+//
+// target is the structure that processes are aggregated to be reported
+// to netdata.
+//
+// - Each entry in /etc/apps_groups.conf creates a target.
+// - Each user and group used by a process in the system, creates a target.
struct target {
char compare[MAX_COMPARE_NAME + 1];
@@ -59,74 +150,281 @@ struct target {
uid_t uid;
gid_t gid;
- unsigned long long minflt;
- unsigned long long cminflt;
- unsigned long long majflt;
- unsigned long long cmajflt;
- unsigned long long utime;
- unsigned long long stime;
- unsigned long long gtime;
- unsigned long long cutime;
- unsigned long long cstime;
- unsigned long long cgtime;
- unsigned long long num_threads;
- // unsigned long long rss;
-
- unsigned long long statm_size;
- unsigned long long statm_resident;
- unsigned long long statm_share;
- // unsigned long long statm_text;
- // unsigned long long statm_lib;
- // unsigned long long statm_data;
- // unsigned long long statm_dirty;
-
- unsigned long long io_logical_bytes_read;
- unsigned long long io_logical_bytes_written;
- // unsigned long long io_read_calls;
- // unsigned long long io_write_calls;
- unsigned long long io_storage_bytes_read;
- unsigned long long io_storage_bytes_written;
- // unsigned long long io_cancelled_write_bytes;
+ kernel_uint_t minflt;
+ kernel_uint_t cminflt;
+ kernel_uint_t majflt;
+ kernel_uint_t cmajflt;
+ kernel_uint_t utime;
+ kernel_uint_t stime;
+ kernel_uint_t gtime;
+ kernel_uint_t cutime;
+ kernel_uint_t cstime;
+ kernel_uint_t cgtime;
+ kernel_uint_t num_threads;
+ // kernel_uint_t rss;
+
+ kernel_uint_t statm_size;
+ kernel_uint_t statm_resident;
+ kernel_uint_t statm_share;
+ // kernel_uint_t statm_text;
+ // kernel_uint_t statm_lib;
+ // kernel_uint_t statm_data;
+ // kernel_uint_t statm_dirty;
+
+ kernel_uint_t io_logical_bytes_read;
+ kernel_uint_t io_logical_bytes_written;
+ // kernel_uint_t io_read_calls;
+ // kernel_uint_t io_write_calls;
+ kernel_uint_t io_storage_bytes_read;
+ kernel_uint_t io_storage_bytes_written;
+ // kernel_uint_t io_cancelled_write_bytes;
int *target_fds;
int target_fds_size;
- unsigned long long openfiles;
- unsigned long long openpipes;
- unsigned long long opensockets;
- unsigned long long openinotifies;
- unsigned long long openeventfds;
- unsigned long long opentimerfds;
- unsigned long long opensignalfds;
- unsigned long long openeventpolls;
- unsigned long long openother;
-
- unsigned long processes; // how many processes have been merged to this
- int exposed; // if set, we have sent this to netdata
- int hidden; // if set, we set the hidden flag on the dimension
+ kernel_uint_t openfiles;
+ kernel_uint_t openpipes;
+ kernel_uint_t opensockets;
+ kernel_uint_t openinotifies;
+ kernel_uint_t openeventfds;
+ kernel_uint_t opentimerfds;
+ kernel_uint_t opensignalfds;
+ kernel_uint_t openeventpolls;
+ kernel_uint_t openother;
+
+ unsigned int processes; // how many processes have been merged to this
+ int exposed; // if set, we have sent this to netdata
+ int hidden; // if set, we set the hidden flag on the dimension
int debug;
int ends_with;
- int starts_with; // if set, the compare string matches only the
- // beginning of the command
+ int starts_with; // if set, the compare string matches only the
+ // beginning of the command
- struct target *target; // the one that will be reported to netdata
+ struct target *target; // the one that will be reported to netdata
struct target *next;
};
+struct target
+ *apps_groups_default_target = NULL, // the default target
+ *apps_groups_root_target = NULL, // apps_groups.conf defined
+ *users_root_target = NULL, // users
+ *groups_root_target = NULL; // user groups
+
+size_t
+ apps_groups_targets_count = 0; // # of apps_groups.conf targets
+
// ----------------------------------------------------------------------------
-// apps_groups.conf
-// aggregate all processes in groups, to have a limited number of dimensions
+// pid_stat
+//
+// structure to store data for each process running
+// see: man proc for the description of the fields
+
+struct pid_stat {
+ int32_t pid;
+ char comm[MAX_COMPARE_NAME + 1];
+ char cmdline[MAX_CMDLINE + 1];
-struct target *apps_groups_root_target = NULL;
-struct target *apps_groups_default_target = NULL;
-long apps_groups_targets = 0;
+ uint32_t log_thrown;
-struct target *users_root_target = NULL;
-struct target *groups_root_target = NULL;
+ // char state;
+ int32_t ppid;
+ // int32_t pgrp;
+ // int32_t session;
+ // int32_t tty_nr;
+ // int32_t tpgid;
+ // uint64_t flags;
-static struct target *get_users_target(uid_t uid)
-{
+ // these are raw values collected
+ kernel_uint_t minflt_raw;
+ kernel_uint_t cminflt_raw;
+ kernel_uint_t majflt_raw;
+ kernel_uint_t cmajflt_raw;
+ kernel_uint_t utime_raw;
+ kernel_uint_t stime_raw;
+ kernel_uint_t gtime_raw; // guest_time
+ kernel_uint_t cutime_raw;
+ kernel_uint_t cstime_raw;
+ kernel_uint_t cgtime_raw; // cguest_time
+
+ // these are rates
+ kernel_uint_t minflt;
+ kernel_uint_t cminflt;
+ kernel_uint_t majflt;
+ kernel_uint_t cmajflt;
+ kernel_uint_t utime;
+ kernel_uint_t stime;
+ kernel_uint_t gtime;
+ kernel_uint_t cutime;
+ kernel_uint_t cstime;
+ kernel_uint_t cgtime;
+
+ // int64_t priority;
+ // int64_t nice;
+ int32_t num_threads;
+ // int64_t itrealvalue;
+ // kernel_uint_t starttime;
+ // kernel_uint_t vsize;
+ // kernel_uint_t rss;
+ // kernel_uint_t rsslim;
+ // kernel_uint_t starcode;
+ // kernel_uint_t endcode;
+ // kernel_uint_t startstack;
+ // kernel_uint_t kstkesp;
+ // kernel_uint_t kstkeip;
+ // uint64_t signal;
+ // uint64_t blocked;
+ // uint64_t sigignore;
+ // uint64_t sigcatch;
+ // uint64_t wchan;
+ // uint64_t nswap;
+ // uint64_t cnswap;
+ // int32_t exit_signal;
+ // int32_t processor;
+ // uint32_t rt_priority;
+ // uint32_t policy;
+ // kernel_uint_t delayacct_blkio_ticks;
+
+ uid_t uid;
+ gid_t gid;
+
+ kernel_uint_t statm_size;
+ kernel_uint_t statm_resident;
+ kernel_uint_t statm_share;
+ // kernel_uint_t statm_text;
+ // kernel_uint_t statm_lib;
+ // kernel_uint_t statm_data;
+ // kernel_uint_t statm_dirty;
+
+ kernel_uint_t io_logical_bytes_read_raw;
+ kernel_uint_t io_logical_bytes_written_raw;
+ // kernel_uint_t io_read_calls_raw;
+ // kernel_uint_t io_write_calls_raw;
+ kernel_uint_t io_storage_bytes_read_raw;
+ kernel_uint_t io_storage_bytes_written_raw;
+ // kernel_uint_t io_cancelled_write_bytes_raw;
+
+ kernel_uint_t io_logical_bytes_read;
+ kernel_uint_t io_logical_bytes_written;
+ // kernel_uint_t io_read_calls;
+ // kernel_uint_t io_write_calls;
+ kernel_uint_t io_storage_bytes_read;
+ kernel_uint_t io_storage_bytes_written;
+ // kernel_uint_t io_cancelled_write_bytes;
+
+ int *fds; // array of fds it uses
+ int fds_size; // the size of the fds array
+
+ int children_count; // number of processes directly referencing this
+ char keep:1; // 1 when we need to keep this process in memory even after it exited
+ int keeploops; // increases by 1 every time keep is 1 and updated 0
+ char updated:1; // 1 when the process is currently running
+ char merged:1; // 1 when it has been merged to its parent
+ char read:1; // 1 when we have already read this process for this iteration
+
+ int sortlist; // higher numbers = top on the process tree
+ // each process gets a unique number
+
+ struct target *target; // app_groups.conf targets
+ struct target *user_target; // uid based targets
+ struct target *group_target; // gid based targets
+
+ usec_t stat_collected_usec;
+ usec_t last_stat_collected_usec;
+
+ usec_t io_collected_usec;
+ usec_t last_io_collected_usec;
+
+ char *fds_dirname; // the full directory name in /proc/PID/fd
+
+ char *stat_filename;
+ char *statm_filename;
+ char *io_filename;
+ char *cmdline_filename;
+
+ struct pid_stat *parent;
+ struct pid_stat *prev;
+ struct pid_stat *next;
+};
+
+// log each problem once per process
+// log flood protection flags (log_thrown)
+#define PID_LOG_IO 0x00000001
+#define PID_LOG_STATM 0x00000002
+#define PID_LOG_CMDLINE 0x00000004
+#define PID_LOG_FDS 0x00000008
+#define PID_LOG_STAT 0x00000010
+
+static struct pid_stat
+ *root_of_pids = NULL, // global list of all processes running
+ **all_pids = NULL; // to avoid allocations, we pre-allocate the
+ // the entire pid space.
+
+static size_t
+ all_pids_count = 0; // the number of processes running
+
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
+// Another pre-allocated list of all possible pids.
+// We need it to pids and assign them a unique sortlist id, so that we
+// read parents before children. This is needed to prevent a situation where
+// a child is found running, but until we read its parent, it has exited and
+// its parent has accumulated its resources.
+static pid_t
+ *all_pids_sortlist = NULL;
+#endif
+
+// ----------------------------------------------------------------------------
+// file descriptor
+//
+// this is used to keep a global list of all open files of the system.
+// it is needed in order to calculate the unique files processes have open.
+
+#define FILE_DESCRIPTORS_INCREASE_STEP 100
+
+// types for struct file_descriptor->type
+typedef enum fd_filetype {
+ FILETYPE_OTHER,
+ FILETYPE_FILE,
+ FILETYPE_PIPE,
+ FILETYPE_SOCKET,
+ FILETYPE_INOTIFY,
+ FILETYPE_EVENTFD,
+ FILETYPE_EVENTPOLL,
+ FILETYPE_TIMERFD,
+ FILETYPE_SIGNALFD
+} FD_FILETYPE;
+
+struct file_descriptor {
+ avl avl;
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ uint32_t magic;
+#endif /* NETDATA_INTERNAL_CHECKS */
+
+ const char *name;
+ uint32_t hash;
+
+ FD_FILETYPE type;
+ int count;
+ int pos;
+} *all_files = NULL;
+
+static int
+ all_files_len = 0,
+ all_files_size = 0;
+
+// ----------------------------------------------------------------------------
+// callback required by fatal()
+
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+// ----------------------------------------------------------------------------
+// apps_groups.conf
+// aggregate all processes in groups, to have a limited number of dimensions
+
+static struct target *get_users_target(uid_t uid) {
struct target *w;
for(w = users_root_target ; w ; w = w->next)
if(w->uid == uid) return w;
@@ -221,10 +519,12 @@ static struct target *get_apps_groups_target(const char *id, struct target *targ
if(*name == '-') thidden = 1;
name++;
}
- for(target = apps_groups_root_target ; target ; target = target->next) {
+
+ for(target = apps_groups_root_target ; target != NULL ; target = target->next) {
if(!target->target && strcmp(name, target->name) == 0)
break;
}
+
if(unlikely(debug)) {
if(unlikely(target))
fprintf(stderr, "apps.plugin: REUSING TARGET NAME '%s' on ID '%s'\n", target->name, target->id);
@@ -302,10 +602,10 @@ static int read_apps_groups_conf(const char *file)
if(!ff)
return 1;
- unsigned long line, lines = procfile_lines(ff);
+ size_t line, lines = procfile_lines(ff);
for(line = 0; line < lines ;line++) {
- unsigned long word, words = procfile_linewords(ff, line);
+ size_t word, words = procfile_linewords(ff, line);
if(!words) continue;
char *name = procfile_lineword(ff, line, 0);
@@ -326,7 +626,7 @@ static int read_apps_groups_conf(const char *file)
// add this target
struct target *n = get_apps_groups_target(s, w, name);
if(!n) {
- error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
+ error("Cannot create target '%s' (line %zu, word %zu)", s, line, word);
continue;
}
@@ -351,186 +651,135 @@ static int read_apps_groups_conf(const char *file)
// ----------------------------------------------------------------------------
-// data to store for each pid
-// see: man proc
+// struct pid_stat management
-#define PID_LOG_IO 0x00000001
-#define PID_LOG_STATM 0x00000002
-#define PID_LOG_CMDLINE 0x00000004
-#define PID_LOG_FDS 0x00000008
-#define PID_LOG_STAT 0x00000010
+static inline struct pid_stat *get_pid_entry(pid_t pid) {
+ if(unlikely(all_pids[pid]))
+ return all_pids[pid];
-struct pid_stat {
- int32_t pid;
- char comm[MAX_COMPARE_NAME + 1];
- char cmdline[MAX_CMDLINE + 1];
+ struct pid_stat *p = callocz(sizeof(struct pid_stat), 1);
+ p->fds = callocz(sizeof(int), MAX_SPARE_FDS);
+ p->fds_size = MAX_SPARE_FDS;
- uint32_t log_thrown;
+ if(likely(root_of_pids))
+ root_of_pids->prev = p;
- // char state;
- int32_t ppid;
- // int32_t pgrp;
- // int32_t session;
- // int32_t tty_nr;
- // int32_t tpgid;
- // uint64_t flags;
+ p->next = root_of_pids;
+ root_of_pids = p;
- // these are raw values collected
- unsigned long long minflt_raw;
- unsigned long long cminflt_raw;
- unsigned long long majflt_raw;
- unsigned long long cmajflt_raw;
- unsigned long long utime_raw;
- unsigned long long stime_raw;
- unsigned long long gtime_raw; // guest_time
- unsigned long long cutime_raw;
- unsigned long long cstime_raw;
- unsigned long long cgtime_raw; // cguest_time
+ p->pid = pid;
- // these are rates
- unsigned long long minflt;
- unsigned long long cminflt;
- unsigned long long majflt;
- unsigned long long cmajflt;
- unsigned long long utime;
- unsigned long long stime;
- unsigned long long gtime;
- unsigned long long cutime;
- unsigned long long cstime;
- unsigned long long cgtime;
+ all_pids[pid] = p;
+ all_pids_count++;
- // int64_t priority;
- // int64_t nice;
- int32_t num_threads;
- // int64_t itrealvalue;
- // unsigned long long starttime;
- // unsigned long long vsize;
- // unsigned long long rss;
- // unsigned long long rsslim;
- // unsigned long long starcode;
- // unsigned long long endcode;
- // unsigned long long startstack;
- // unsigned long long kstkesp;
- // unsigned long long kstkeip;
- // uint64_t signal;
- // uint64_t blocked;
- // uint64_t sigignore;
- // uint64_t sigcatch;
- // uint64_t wchan;
- // uint64_t nswap;
- // uint64_t cnswap;
- // int32_t exit_signal;
- // int32_t processor;
- // uint32_t rt_priority;
- // uint32_t policy;
- // unsigned long long delayacct_blkio_ticks;
+ return p;
+}
- uid_t uid;
- gid_t gid;
+static inline void del_pid_entry(pid_t pid) {
+ struct pid_stat *p = all_pids[pid];
- unsigned long long statm_size;
- unsigned long long statm_resident;
- unsigned long long statm_share;
- // unsigned long long statm_text;
- // unsigned long long statm_lib;
- // unsigned long long statm_data;
- // unsigned long long statm_dirty;
-
- unsigned long long io_logical_bytes_read_raw;
- unsigned long long io_logical_bytes_written_raw;
- // unsigned long long io_read_calls_raw;
- // unsigned long long io_write_calls_raw;
- unsigned long long io_storage_bytes_read_raw;
- unsigned long long io_storage_bytes_written_raw;
- // unsigned long long io_cancelled_write_bytes_raw;
-
- unsigned long long io_logical_bytes_read;
- unsigned long long io_logical_bytes_written;
- // unsigned long long io_read_calls;
- // unsigned long long io_write_calls;
- unsigned long long io_storage_bytes_read;
- unsigned long long io_storage_bytes_written;
- // unsigned long long io_cancelled_write_bytes;
+ if(unlikely(!p)) {
+ error("attempted to free pid %d that is not allocated.", pid);
+ return;
+ }
- int *fds; // array of fds it uses
- int fds_size; // the size of the fds array
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, p->comm);
- int children_count; // number of processes directly referencing this
- int keep; // 1 when we need to keep this process in memory even after it exited
- int keeploops; // increases by 1 every time keep is 1 and updated 0
- int updated; // 1 when the process is currently running
- int merged; // 1 when it has been merged to its parent
- int new_entry; // 1 when this is a new process, just saw for the first time
- int read; // 1 when we have already read this process for this iteration
- int sortlist; // higher numbers = top on the process tree
- // each process gets a unique number
+ if(root_of_pids == p)
+ root_of_pids = p->next;
- struct target *target; // app_groups.conf targets
- struct target *user_target; // uid based targets
- struct target *group_target; // gid based targets
+ if(p->next) p->next->prev = p->prev;
+ if(p->prev) p->prev->next = p->next;
- unsigned long long stat_collected_usec;
- unsigned long long last_stat_collected_usec;
+ freez(p->fds);
+ freez(p->fds_dirname);
+ freez(p->stat_filename);
+ freez(p->statm_filename);
+ freez(p->io_filename);
+ freez(p->cmdline_filename);
+ freez(p);
- unsigned long long io_collected_usec;
- unsigned long long last_io_collected_usec;
+ all_pids[pid] = NULL;
+ all_pids_count--;
+}
- char *stat_filename;
- char *statm_filename;
- char *io_filename;
- char *cmdline_filename;
+// ----------------------------------------------------------------------------
- struct pid_stat *parent;
- struct pid_stat *prev;
- struct pid_stat *next;
-} *root_of_pids = NULL, **all_pids;
+static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
+ if(unlikely(!status)) {
+ // error("command failed log %u, errno %d", log, errno);
-long all_pids_count = 0;
+ if(unlikely(debug || errno != ENOENT)) {
+ if(unlikely(debug || !(p->log_thrown & log))) {
+ p->log_thrown |= log;
+ switch(log) {
+ case PID_LOG_IO:
+ error("Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
-static inline struct pid_stat *get_pid_entry(pid_t pid) {
- if(all_pids[pid]) {
- all_pids[pid]->new_entry = 0;
- return all_pids[pid];
- }
+ case PID_LOG_STATM:
+ error("Cannot process %s/proc/%d/statm (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
- all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
- all_pids[pid]->fds = callocz(sizeof(int), MAX_SPARE_FDS);
- all_pids[pid]->fds_size = MAX_SPARE_FDS;
+ case PID_LOG_CMDLINE:
+ error("Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
- if(root_of_pids) root_of_pids->prev = all_pids[pid];
- all_pids[pid]->next = root_of_pids;
- root_of_pids = all_pids[pid];
+ case PID_LOG_FDS:
+ error("Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
- all_pids[pid]->pid = pid;
- all_pids[pid]->new_entry = 1;
+ case PID_LOG_STAT:
+ break;
- all_pids_count++;
+ default:
+ error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
+ break;
+ }
+ }
+ }
+ errno = 0;
+ }
+ else if(unlikely(p->log_thrown & log)) {
+ // error("unsetting log %u on pid %d", log, p->pid);
+ p->log_thrown &= ~log;
+ }
- return all_pids[pid];
+ return status;
}
-static inline void del_pid_entry(pid_t pid) {
- if(!all_pids[pid]) {
- error("attempted to free pid %d that is not allocated.", pid);
- return;
- }
+static inline void assign_target_to_pid(struct pid_stat *p) {
+ targets_assignment_counter++;
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
+ uint32_t hash = simple_hash(p->comm);
+ size_t pclen = strlen(p->comm);
- if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
- if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
- if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
+ struct target *w;
+ for(w = apps_groups_root_target; w ; w = w->next) {
+ // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
- if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
- if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
- if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
- if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
- if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
- freez(all_pids[pid]);
+ // find it - 4 cases:
+ // 1. the target is not a pattern
+ // 2. the target has the prefix
+ // 3. the target has the suffix
+ // 4. the target is something inside cmdline
- all_pids[pid] = NULL;
- all_pids_count--;
+ if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
+ || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
+ || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
+ || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
+ ))) {
+
+ if(w->target) p->target = w->target;
+ else p->target = w;
+
+ if(debug || (p->target && p->target->debug))
+ fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
+
+ break;
+ }
+ }
}
@@ -539,9 +788,20 @@ static inline void del_pid_entry(pid_t pid) {
static inline int read_proc_pid_cmdline(struct pid_stat *p) {
+#ifdef __FreeBSD__
+ size_t i, bytes = MAX_CMDLINE;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ARGS;
+ mib[3] = p->pid;
+ if (unlikely(sysctl(mib, 4, p->cmdline, &bytes, NULL, 0)))
+ goto cleanup;
+#else
if(unlikely(!p->cmdline_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
p->cmdline_filename = strdupz(filename);
}
@@ -552,6 +812,7 @@ static inline int read_proc_pid_cmdline(struct pid_stat *p) {
close(fd);
if(unlikely(bytes < 0)) goto cleanup;
+#endif
p->cmdline[bytes] = '\0';
for(i = 0; i < bytes ; i++)
@@ -568,7 +829,16 @@ cleanup:
return 0;
}
-static inline int read_proc_pid_ownership(struct pid_stat *p) {
+static inline int read_proc_pid_ownership(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+
+ p->uid = proc_info->ki_uid;
+ p->gid = proc_info->ki_groups[0];
+
+ return 1;
+#else
if(unlikely(!p->stat_filename)) {
error("pid %d does not have a stat_filename", p->pid);
return 0;
@@ -587,14 +857,41 @@ static inline int read_proc_pid_ownership(struct pid_stat *p) {
p->gid = st.st_gid;
return 1;
+#endif
}
-static inline int read_proc_pid_stat(struct pid_stat *p) {
+// ----------------------------------------------------------------------------
+// macro to calculate the incremental rate of a value
+// each parameter is accessed only ONCE - so it is safe to pass function calls
+// or other macros as parameters
+
+#define incremental_rate(rate_variable, last_kernel_variable, new_kernel_value, collected_usec, last_collected_usec) { \
+ kernel_uint_t _new_tmp = new_kernel_value; \
+ rate_variable = (_new_tmp - last_kernel_variable) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); \
+ last_kernel_variable = _new_tmp; \
+ }
+
+// the same macro for struct pid members
+#define pid_incremental_rate(type, var, value) \
+ incremental_rate(var, var##_raw, value, p->type##_collected_usec, p->last_##type##_collected_usec)
+
+
+// ----------------------------------------------------------------------------
+
+static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+
+ if (unlikely(proc_info->ki_tdflags & TDF_IDLETD))
+ goto cleanup;
+#else
static procfile *ff = NULL;
if(unlikely(!p->stat_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", netdata_configured_host_prefix, p->pid);
p->stat_filename = strdupz(filename);
}
@@ -604,95 +901,104 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
if(unlikely(!ff)) goto cleanup;
// if(set_quotes) procfile_set_quotes(ff, "()");
- if(set_quotes) procfile_set_open_close(ff, "(", ")");
+ if(unlikely(set_quotes))
+ procfile_set_open_close(ff, "(", ")");
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
p->last_stat_collected_usec = p->stat_collected_usec;
- p->stat_collected_usec = now_realtime_usec();
- file_counter++;
+ p->stat_collected_usec = now_monotonic_usec();
+ calls_counter++;
+
+#ifdef __FreeBSD__
+ char *comm = proc_info->ki_comm;
+ p->ppid = proc_info->ki_ppid;
+#else
+ // p->pid = str2pid_t(procfile_lineword(ff, 0, 0));
+ char *comm = procfile_lineword(ff, 0, 1);
+ // p->state = *(procfile_lineword(ff, 0, 2));
+ p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
+ // p->pgrp = (int32_t)str2pid_t(procfile_lineword(ff, 0, 4));
+ // p->session = (int32_t)str2pid_t(procfile_lineword(ff, 0, 5));
+ // p->tty_nr = (int32_t)str2pid_t(procfile_lineword(ff, 0, 6));
+ // p->tpgid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 7));
+ // p->flags = str2uint64_t(procfile_lineword(ff, 0, 8));
+#endif
- // p->pid = str2ul(procfile_lineword(ff, 0, 0+i));
+ if(strcmp(p->comm, comm)) {
+ if(unlikely(debug)) {
+ if(p->comm[0])
+ fprintf(stderr, "apps.plugin: \tpid %d (%s) changed name to '%s'\n", p->pid, p->comm, comm);
+ else
+ fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", p->pid, comm);
+ }
- strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
+ strncpyz(p->comm, comm, MAX_COMPARE_NAME);
- // p->state = *(procfile_lineword(ff, 0, 2));
- p->ppid = (int32_t)str2ul(procfile_lineword(ff, 0, 3));
- // p->pgrp = str2ul(procfile_lineword(ff, 0, 4));
- // p->session = str2ul(procfile_lineword(ff, 0, 5));
- // p->tty_nr = str2ul(procfile_lineword(ff, 0, 6));
- // p->tpgid = str2ul(procfile_lineword(ff, 0, 7));
- // p->flags = str2ull(procfile_lineword(ff, 0, 8));
-
- unsigned long long last;
-
- last = p->minflt_raw;
- p->minflt_raw = str2ull(procfile_lineword(ff, 0, 9));
- p->minflt = (p->minflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cminflt_raw;
- p->cminflt_raw = str2ull(procfile_lineword(ff, 0, 10));
- p->cminflt = (p->cminflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->majflt_raw;
- p->majflt_raw = str2ull(procfile_lineword(ff, 0, 11));
- p->majflt = (p->majflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cmajflt_raw;
- p->cmajflt_raw = str2ull(procfile_lineword(ff, 0, 12));
- p->cmajflt = (p->cmajflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->utime_raw;
- p->utime_raw = str2ull(procfile_lineword(ff, 0, 13));
- p->utime = (p->utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->stime_raw;
- p->stime_raw = str2ull(procfile_lineword(ff, 0, 14));
- p->stime = (p->stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cutime_raw;
- p->cutime_raw = str2ull(procfile_lineword(ff, 0, 15));
- p->cutime = (p->cutime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cstime_raw;
- p->cstime_raw = str2ull(procfile_lineword(ff, 0, 16));
- p->cstime = (p->cstime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- // p->priority = str2ull(procfile_lineword(ff, 0, 17));
- // p->nice = str2ull(procfile_lineword(ff, 0, 18));
- p->num_threads = (int32_t)str2ul(procfile_lineword(ff, 0, 19));
- // p->itrealvalue = str2ull(procfile_lineword(ff, 0, 20));
- // p->starttime = str2ull(procfile_lineword(ff, 0, 21));
- // p->vsize = str2ull(procfile_lineword(ff, 0, 22));
- // p->rss = str2ull(procfile_lineword(ff, 0, 23));
- // p->rsslim = str2ull(procfile_lineword(ff, 0, 24));
- // p->starcode = str2ull(procfile_lineword(ff, 0, 25));
- // p->endcode = str2ull(procfile_lineword(ff, 0, 26));
- // p->startstack = str2ull(procfile_lineword(ff, 0, 27));
- // p->kstkesp = str2ull(procfile_lineword(ff, 0, 28));
- // p->kstkeip = str2ull(procfile_lineword(ff, 0, 29));
- // p->signal = str2ull(procfile_lineword(ff, 0, 30));
- // p->blocked = str2ull(procfile_lineword(ff, 0, 31));
- // p->sigignore = str2ull(procfile_lineword(ff, 0, 32));
- // p->sigcatch = str2ull(procfile_lineword(ff, 0, 33));
- // p->wchan = str2ull(procfile_lineword(ff, 0, 34));
- // p->nswap = str2ull(procfile_lineword(ff, 0, 35));
- // p->cnswap = str2ull(procfile_lineword(ff, 0, 36));
- // p->exit_signal = str2ul(procfile_lineword(ff, 0, 37));
- // p->processor = str2ul(procfile_lineword(ff, 0, 38));
- // p->rt_priority = str2ul(procfile_lineword(ff, 0, 39));
- // p->policy = str2ul(procfile_lineword(ff, 0, 40));
- // p->delayacct_blkio_ticks = str2ull(procfile_lineword(ff, 0, 41));
+ // /proc/<pid>/cmdline
+ if(likely(proc_pid_cmdline_is_needed))
+ managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
+
+ assign_target_to_pid(p);
+ }
+
+#ifdef __FreeBSD__
+ pid_incremental_rate(stat, p->minflt, (kernel_uint_t)proc_info->ki_rusage.ru_minflt);
+ pid_incremental_rate(stat, p->cminflt, (kernel_uint_t)proc_info->ki_rusage_ch.ru_minflt);
+ pid_incremental_rate(stat, p->majflt, (kernel_uint_t)proc_info->ki_rusage.ru_majflt);
+ pid_incremental_rate(stat, p->cmajflt, (kernel_uint_t)proc_info->ki_rusage_ch.ru_majflt);
+ pid_incremental_rate(stat, p->utime, (kernel_uint_t)proc_info->ki_rusage.ru_utime.tv_sec * 100 + proc_info->ki_rusage.ru_utime.tv_usec / 10000);
+ pid_incremental_rate(stat, p->stime, (kernel_uint_t)proc_info->ki_rusage.ru_stime.tv_sec * 100 + proc_info->ki_rusage.ru_stime.tv_usec / 10000);
+ pid_incremental_rate(stat, p->cutime, (kernel_uint_t)proc_info->ki_rusage_ch.ru_utime.tv_sec * 100 + proc_info->ki_rusage_ch.ru_utime.tv_usec / 10000);
+ pid_incremental_rate(stat, p->cstime, (kernel_uint_t)proc_info->ki_rusage_ch.ru_stime.tv_sec * 100 + proc_info->ki_rusage_ch.ru_utime.tv_usec / 10000);
+
+ p->num_threads = proc_info->ki_numthreads;
if(enable_guest_charts) {
- last = p->gtime_raw;
- p->gtime_raw = str2ull(procfile_lineword(ff, 0, 42));
- p->gtime = (p->gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ enable_guest_charts = 0;
+ info("Guest charts aren't supported by FreeBSD");
+ }
+#else
+ pid_incremental_rate(stat, p->minflt, str2kernel_uint_t(procfile_lineword(ff, 0, 9)));
+ pid_incremental_rate(stat, p->cminflt, str2kernel_uint_t(procfile_lineword(ff, 0, 10)));
+ pid_incremental_rate(stat, p->majflt, str2kernel_uint_t(procfile_lineword(ff, 0, 11)));
+ pid_incremental_rate(stat, p->cmajflt, str2kernel_uint_t(procfile_lineword(ff, 0, 12)));
+ pid_incremental_rate(stat, p->utime, str2kernel_uint_t(procfile_lineword(ff, 0, 13)));
+ pid_incremental_rate(stat, p->stime, str2kernel_uint_t(procfile_lineword(ff, 0, 14)));
+ pid_incremental_rate(stat, p->cutime, str2kernel_uint_t(procfile_lineword(ff, 0, 15)));
+ pid_incremental_rate(stat, p->cstime, str2kernel_uint_t(procfile_lineword(ff, 0, 16)));
+ // p->priority = str2kernel_uint_t(procfile_lineword(ff, 0, 17));
+ // p->nice = str2kernel_uint_t(procfile_lineword(ff, 0, 18));
+ p->num_threads = (int32_t)str2uint32_t(procfile_lineword(ff, 0, 19));
+ // p->itrealvalue = str2kernel_uint_t(procfile_lineword(ff, 0, 20));
+ // p->starttime = str2kernel_uint_t(procfile_lineword(ff, 0, 21));
+ // p->vsize = str2kernel_uint_t(procfile_lineword(ff, 0, 22));
+ // p->rss = str2kernel_uint_t(procfile_lineword(ff, 0, 23));
+ // p->rsslim = str2kernel_uint_t(procfile_lineword(ff, 0, 24));
+ // p->starcode = str2kernel_uint_t(procfile_lineword(ff, 0, 25));
+ // p->endcode = str2kernel_uint_t(procfile_lineword(ff, 0, 26));
+ // p->startstack = str2kernel_uint_t(procfile_lineword(ff, 0, 27));
+ // p->kstkesp = str2kernel_uint_t(procfile_lineword(ff, 0, 28));
+ // p->kstkeip = str2kernel_uint_t(procfile_lineword(ff, 0, 29));
+ // p->signal = str2kernel_uint_t(procfile_lineword(ff, 0, 30));
+ // p->blocked = str2kernel_uint_t(procfile_lineword(ff, 0, 31));
+ // p->sigignore = str2kernel_uint_t(procfile_lineword(ff, 0, 32));
+ // p->sigcatch = str2kernel_uint_t(procfile_lineword(ff, 0, 33));
+ // p->wchan = str2kernel_uint_t(procfile_lineword(ff, 0, 34));
+ // p->nswap = str2kernel_uint_t(procfile_lineword(ff, 0, 35));
+ // p->cnswap = str2kernel_uint_t(procfile_lineword(ff, 0, 36));
+ // p->exit_signal = str2kernel_uint_t(procfile_lineword(ff, 0, 37));
+ // p->processor = str2kernel_uint_t(procfile_lineword(ff, 0, 38));
+ // p->rt_priority = str2kernel_uint_t(procfile_lineword(ff, 0, 39));
+ // p->policy = str2kernel_uint_t(procfile_lineword(ff, 0, 40));
+ // p->delayacct_blkio_ticks = str2kernel_uint_t(procfile_lineword(ff, 0, 41));
- last = p->cgtime_raw;
- p->cgtime_raw = str2ull(procfile_lineword(ff, 0, 43));
- p->cgtime = (p->cgtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ if(enable_guest_charts) {
+
+ pid_incremental_rate(stat, p->gtime, str2kernel_uint_t(procfile_lineword(ff, 0, 42)));
+ pid_incremental_rate(stat, p->cgtime, str2kernel_uint_t(procfile_lineword(ff, 0, 43)));
if (show_guest_time || p->gtime || p->cgtime) {
p->utime -= (p->utime >= p->gtime) ? p->gtime : p->utime;
@@ -700,9 +1006,10 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
show_guest_time = 1;
}
}
+#endif
if(unlikely(debug || (p->target && p->target->debug)))
- fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", global_host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+ fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT ", threads=%d\n", netdata_configured_host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
if(unlikely(global_iterations_counter == 1)) {
p->minflt = 0;
@@ -735,12 +1042,16 @@ cleanup:
return 0;
}
-static inline int read_proc_pid_statm(struct pid_stat *p) {
+static inline int read_proc_pid_statm(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+#else
static procfile *ff = NULL;
if(unlikely(!p->statm_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", netdata_configured_host_prefix, p->pid);
p->statm_filename = strdupz(filename);
}
@@ -749,19 +1060,27 @@ static inline int read_proc_pid_statm(struct pid_stat *p) {
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
- file_counter++;
+ calls_counter++;
- p->statm_size = str2ull(procfile_lineword(ff, 0, 0));
- p->statm_resident = str2ull(procfile_lineword(ff, 0, 1));
- p->statm_share = str2ull(procfile_lineword(ff, 0, 2));
- // p->statm_text = str2ull(procfile_lineword(ff, 0, 3));
- // p->statm_lib = str2ull(procfile_lineword(ff, 0, 4));
- // p->statm_data = str2ull(procfile_lineword(ff, 0, 5));
- // p->statm_dirty = str2ull(procfile_lineword(ff, 0, 6));
+#ifdef __FreeBSD__
+ p->statm_size = proc_info->ki_size / sysconf(_SC_PAGESIZE);
+ p->statm_resident = proc_info->ki_rssize;
+ p->statm_share = 0; // do we have to use ru_ixrss here?
+#else
+ p->statm_size = str2kernel_uint_t(procfile_lineword(ff, 0, 0));
+ p->statm_resident = str2kernel_uint_t(procfile_lineword(ff, 0, 1));
+ p->statm_share = str2kernel_uint_t(procfile_lineword(ff, 0, 2));
+ // p->statm_text = str2kernel_uint_t(procfile_lineword(ff, 0, 3));
+ // p->statm_lib = str2kernel_uint_t(procfile_lineword(ff, 0, 4));
+ // p->statm_data = str2kernel_uint_t(procfile_lineword(ff, 0, 5));
+ // p->statm_dirty = str2kernel_uint_t(procfile_lineword(ff, 0, 6));
+#endif
return 1;
+#ifndef __FreeBSD__
cleanup:
p->statm_size = 0;
p->statm_resident = 0;
@@ -771,14 +1090,19 @@ cleanup:
// p->statm_data = 0;
// p->statm_dirty = 0;
return 0;
+#endif
}
-static inline int read_proc_pid_io(struct pid_stat *p) {
+static inline int read_proc_pid_io(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+#else
static procfile *ff = NULL;
if(unlikely(!p->io_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", netdata_configured_host_prefix, p->pid);
p->io_filename = strdupz(filename);
}
@@ -788,41 +1112,25 @@ static inline int read_proc_pid_io(struct pid_stat *p) {
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
- file_counter++;
+ calls_counter++;
p->last_io_collected_usec = p->io_collected_usec;
- p->io_collected_usec = now_realtime_usec();
-
- unsigned long long last;
-
- last = p->io_logical_bytes_read_raw;
- p->io_logical_bytes_read_raw = str2ull(procfile_lineword(ff, 0, 1));
- p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- last = p->io_logical_bytes_written_raw;
- p->io_logical_bytes_written_raw = str2ull(procfile_lineword(ff, 1, 1));
- p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- // last = p->io_read_calls_raw;
- // p->io_read_calls_raw = str2ull(procfile_lineword(ff, 2, 1));
- // p->io_read_calls = (p->io_read_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- // last = p->io_write_calls_raw;
- // p->io_write_calls_raw = str2ull(procfile_lineword(ff, 3, 1));
- // p->io_write_calls = (p->io_write_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+ p->io_collected_usec = now_monotonic_usec();
- last = p->io_storage_bytes_read_raw;
- p->io_storage_bytes_read_raw = str2ull(procfile_lineword(ff, 4, 1));
- p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- last = p->io_storage_bytes_written_raw;
- p->io_storage_bytes_written_raw = str2ull(procfile_lineword(ff, 5, 1));
- p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- // last = p->io_cancelled_write_bytes_raw;
- // p->io_cancelled_write_bytes_raw = str2ull(procfile_lineword(ff, 6, 1));
- // p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+#ifdef __FreeBSD__
+ pid_incremental_rate(io, p->io_storage_bytes_read, proc_info->ki_rusage.ru_inblock);
+ pid_incremental_rate(io, p->io_storage_bytes_written, proc_info->ki_rusage.ru_oublock);
+#else
+ pid_incremental_rate(io, p->io_logical_bytes_read, str2kernel_uint_t(procfile_lineword(ff, 0, 1)));
+ pid_incremental_rate(io, p->io_logical_bytes_written, str2kernel_uint_t(procfile_lineword(ff, 1, 1)));
+ // pid_incremental_rate(io, p->io_read_calls, str2kernel_uint_t(procfile_lineword(ff, 2, 1)));
+ // pid_incremental_rate(io, p->io_write_calls, str2kernel_uint_t(procfile_lineword(ff, 3, 1)));
+ pid_incremental_rate(io, p->io_storage_bytes_read, str2kernel_uint_t(procfile_lineword(ff, 4, 1)));
+ pid_incremental_rate(io, p->io_storage_bytes_written, str2kernel_uint_t(procfile_lineword(ff, 5, 1)));
+ // pid_incremental_rate(io, p->io_cancelled_write_bytes, str2kernel_uint_t(procfile_lineword(ff, 6, 1)));
+#endif
if(unlikely(global_iterations_counter == 1)) {
p->io_logical_bytes_read = 0;
@@ -836,6 +1144,7 @@ static inline int read_proc_pid_io(struct pid_stat *p) {
return 1;
+#ifndef __FreeBSD__
cleanup:
p->io_logical_bytes_read = 0;
p->io_logical_bytes_written = 0;
@@ -845,60 +1154,77 @@ cleanup:
p->io_storage_bytes_written = 0;
// p->io_cancelled_write_bytes = 0;
return 0;
+#endif
}
-unsigned long long global_utime = 0;
-unsigned long long global_stime = 0;
-unsigned long long global_gtime = 0;
-
static inline int read_proc_stat() {
+#ifdef __FreeBSD__
+ long cp_time[CPUSTATES];
+ static kernel_uint_t utime_raw = 0, stime_raw = 0, ntime_raw = 0;
+
+ if (unlikely(CPUSTATES != 5)) {
+ error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+ goto cleanup;
+ }
+ if (unlikely(GETSYSCTL_BY_NAME("kern.cp_time", cp_time))) goto cleanup;
+#else
static char filename[FILENAME_MAX + 1] = "";
static procfile *ff = NULL;
- static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
+ static kernel_uint_t utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
+#endif
static usec_t collected_usec = 0, last_collected_usec = 0;
+#ifndef __FreeBSD__
if(unlikely(!ff)) {
- snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix);
ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) goto cleanup;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
last_collected_usec = collected_usec;
- collected_usec = now_realtime_usec();
-
- file_counter++;
+ collected_usec = now_monotonic_usec();
- unsigned long long last;
+ calls_counter++;
- last = utime_raw;
- utime_raw = str2ull(procfile_lineword(ff, 0, 1));
- global_utime = (utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+ // temporary - it is added global_ntime;
+ kernel_uint_t global_ntime = 0;
- // nice time, on user time
- last = ntime_raw;
- ntime_raw = str2ull(procfile_lineword(ff, 0, 2));
- global_utime += (ntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
-
- last = stime_raw;
- stime_raw = str2ull(procfile_lineword(ff, 0, 3));
- global_stime = (stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+#ifdef __FreeBSD__
+ incremental_rate(global_utime, utime_raw, cp_time[0], collected_usec, last_collected_usec);
+ incremental_rate(global_ntime, ntime_raw, cp_time[1], collected_usec, last_collected_usec);
+ incremental_rate(global_stime, stime_raw, cp_time[2], collected_usec, last_collected_usec);
+#else
+ incremental_rate(global_utime, utime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 1)), collected_usec, last_collected_usec);
+ incremental_rate(global_ntime, ntime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 2)), collected_usec, last_collected_usec);
+ incremental_rate(global_stime, stime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 3)), collected_usec, last_collected_usec);
+ incremental_rate(global_gtime, gtime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 10)), collected_usec, last_collected_usec);
+#endif
- last = gtime_raw;
- gtime_raw = str2ull(procfile_lineword(ff, 0, 10));
- global_gtime = (gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+ global_utime += global_ntime;
+#ifdef __FreeBSD__
+ if(enable_guest_charts) {
+ enable_guest_charts = 0;
+ info("Guest charts aren't supported by FreeBSD");
+ }
+#else
if(enable_guest_charts) {
+ // temporary - it is added global_ntime;
+ kernel_uint_t global_gntime = 0;
+
// guest nice time, on guest time
- last = gntime_raw;
- gntime_raw = str2ull(procfile_lineword(ff, 0, 11));
- global_gtime += (gntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+ incremental_rate(global_gntime, gntime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 11)), collected_usec, last_collected_usec);
+
+ global_gtime += global_gntime;
// remove guest time from user time
global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime;
}
+#endif
if(unlikely(global_iterations_counter == 1)) {
global_utime = 0;
@@ -917,26 +1243,6 @@ cleanup:
// ----------------------------------------------------------------------------
-// file descriptor
-// this is used to keep a global list of all open files of the system
-// it is needed in order to calculate the unique files processes have open
-
-#define FILE_DESCRIPTORS_INCREASE_STEP 100
-
-struct file_descriptor {
- avl avl;
-#ifdef NETDATA_INTERNAL_CHECKS
- uint32_t magic;
-#endif /* NETDATA_INTERNAL_CHECKS */
- uint32_t hash;
- const char *name;
- int type;
- int count;
- int pos;
-} *all_files = NULL;
-
-int all_files_len = 0;
-int all_files_size = 0;
int file_descriptor_compare(void* a, void* b) {
#ifdef NETDATA_INTERNAL_CHECKS
@@ -977,15 +1283,7 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h
#define file_descriptor_add(fd) avl_insert(&all_files_index, (avl *)(fd))
#define file_descriptor_remove(fd) avl_remove(&all_files_index, (avl *)(fd))
-#define FILETYPE_OTHER 0
-#define FILETYPE_FILE 1
-#define FILETYPE_PIPE 2
-#define FILETYPE_SOCKET 3
-#define FILETYPE_INOTIFY 4
-#define FILETYPE_EVENTFD 5
-#define FILETYPE_EVENTPOLL 6
-#define FILETYPE_TIMERFD 7
-#define FILETYPE_SIGNALFD 8
+// ----------------------------------------------------------------------------
static inline void file_descriptor_not_used(int id)
{
@@ -1066,7 +1364,7 @@ static inline void all_files_grow() {
all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
}
-static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t hash, int type) {
+static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t hash, FD_FILETYPE type) {
// check we have enough memory to add it
if(!all_files || all_files_len == all_files_size)
all_files_grow();
@@ -1147,21 +1445,26 @@ static inline int file_descriptor_find_or_add(const char *name)
}
// not found
- int type;
- if(name[0] == '/') type = FILETYPE_FILE;
- else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
- else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
- else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
- else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
- else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
- else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
- else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
- else if(strncmp(name, "anon_inode:", 11) == 0) {
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
+ FD_FILETYPE type;
+ if(likely(name[0] == '/')) type = FILETYPE_FILE;
+ else if(likely(strncmp(name, "pipe:", 5) == 0)) type = FILETYPE_PIPE;
+ else if(likely(strncmp(name, "socket:", 7) == 0)) type = FILETYPE_SOCKET;
+ else if(likely(strncmp(name, "anon_inode:", 11) == 0)) {
+ const char *t = &name[11];
+
+ if(strcmp(t, "inotify") == 0) type = FILETYPE_INOTIFY;
+ else if(strcmp(t, "[eventfd]") == 0) type = FILETYPE_EVENTFD;
+ else if(strcmp(t, "[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
+ else if(strcmp(t, "[timerfd]") == 0) type = FILETYPE_TIMERFD;
+ else if(strcmp(t, "[signalfd]") == 0) type = FILETYPE_SIGNALFD;
+ else {
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
- type = FILETYPE_OTHER;
+ type = FILETYPE_OTHER;
+ }
}
+ else if(likely(strcmp(name, "inotify") == 0)) type = FILETYPE_INOTIFY;
else {
if(unlikely(debug))
fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
@@ -1172,81 +1475,243 @@ static inline int file_descriptor_find_or_add(const char *name)
return file_descriptor_set_on_empty_slot(name, hash, type);
}
-static inline int read_pid_file_descriptors(struct pid_stat *p) {
- char dirname[FILENAME_MAX+1];
+static inline void make_all_pid_fds_negative(struct pid_stat *p) {
+ int *fd = p->fds, *end = &p->fds[p->fds_size];
+ while(fd < end) {
+ *fd = -(*fd);
+ fd++;
+ }
+}
- snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
- DIR *fds = opendir(dirname);
- if(fds) {
- int c;
- struct dirent *de;
- char fdname[FILENAME_MAX + 1];
- char linkname[FILENAME_MAX + 1];
+static inline void cleanup_negative_pid_fds(struct pid_stat *p) {
+ int *fd = p->fds, *fdend = &p->fds[p->fds_size];
- // make the array negative
- for(c = 0 ; c < p->fds_size ; c++)
- p->fds[c] = -p->fds[c];
+ while(fd < fdend) {
+ if(unlikely(*fd < 0)) {
+ file_descriptor_not_used(-(*fd));
+ *fd++ = 0;
+ }
+ else
+ fd++;
+ }
+}
- while((de = readdir(fds))) {
- if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
- continue;
+static inline void zero_pid_fds(struct pid_stat *p, int first, int size) {
+ int *fd = &p->fds[first], *end = &p->fds[first + size];
+ while(fd < end) *fd++ = 0;
+}
- // check if the fds array is small
- int fdid = (int)str2l(de->d_name);
- if(fdid < 0) continue;
- if(fdid >= p->fds_size) {
- // it is small, extend it
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
+static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ int mib[4];
+ size_t size;
+ struct kinfo_file *fds;
+ static char *fdsbuf;
+ char *bfdsbuf, *efdsbuf;
+ char fdsname[FILENAME_MAX + 1];
+
+ // we make all pid fds negative, so that
+ // we can detect unused file descriptors
+ // at the end, to free them
+ make_all_pid_fds_negative(p);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_FILEDESC;
+ mib[3] = p->pid;
+
+ if (unlikely(sysctl(mib, 4, NULL, &size, NULL, 0))) {
+ error("sysctl error: Can't get file descriptors data size for pid %d", p->pid);
+ return 0;
+ }
+ if (likely(size > 0))
+ fdsbuf = reallocz(fdsbuf, size);
+ if (unlikely(sysctl(mib, 4, fdsbuf, &size, NULL, 0))) {
+ error("sysctl error: Can't get file descriptors data for pid %d", p->pid);
+ return 0;
+ }
- p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+ bfdsbuf = fdsbuf;
+ efdsbuf = fdsbuf + size;
+ while (bfdsbuf < efdsbuf) {
+ fds = (struct kinfo_file *)(uintptr_t)bfdsbuf;
+ if (unlikely(fds->kf_structsize == 0))
+ break;
- // and initialize it
- for(c = p->fds_size ; c < (fdid + MAX_SPARE_FDS) ; c++) p->fds[c] = 0;
- p->fds_size = fdid + MAX_SPARE_FDS;
- }
+ // do not process file descriptors for current working directory, root directory,
+ // jail directory, ktrace vnode, text vnode and controlling terminal
+ if (unlikely(fds->kf_fd < 0)) {
+ bfdsbuf += fds->kf_structsize;
+ continue;
+ }
- if(p->fds[fdid] == 0) {
- // we don't know this fd, get it
+ // get file descriptors array index
+ int fdid = fds->kf_fd;
- sprintf(fdname, "%s/proc/%d/fd/%s", global_host_prefix, p->pid, de->d_name);
- ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
- if(l == -1) {
- if(debug || (p->target && p->target->debug)) {
- if(debug || (p->target && p->target->debug))
- error("Cannot read link %s", fdname);
- }
- continue;
- }
- linkname[l] = '\0';
- file_counter++;
+ // check if the fds array is small
+ if (unlikely(fdid >= p->fds_size)) {
+ // it is small, extend it
+
+ if (unlikely(debug))
+ fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
+
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
- // if another process already has this, we will get
- // the same id
- p->fds[fdid] = file_descriptor_find_or_add(linkname);
+ // and initialize it
+ zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+ p->fds_size = fdid + MAX_SPARE_FDS;
+ }
+
+ if (unlikely(p->fds[fdid] == 0)) {
+ // we don't know this fd, get it
+
+ switch (fds->kf_type) {
+ case KF_TYPE_FIFO:
+ case KF_TYPE_VNODE:
+ if (unlikely(!fds->kf_path[0])) {
+ sprintf(fdsname, "other: inode: %lu", fds->kf_un.kf_file.kf_file_fileid);
+ break;
+ }
+ sprintf(fdsname, "%s", fds->kf_path);
+ break;
+ case KF_TYPE_SOCKET:
+ switch (fds->kf_sock_domain) {
+ case AF_INET:
+ case AF_INET6:
+ if (fds->kf_sock_protocol == IPPROTO_TCP)
+ sprintf(fdsname, "socket: %d %lx", fds->kf_sock_protocol, fds->kf_un.kf_sock.kf_sock_inpcb);
+ else
+ sprintf(fdsname, "socket: %d %lx", fds->kf_sock_protocol, fds->kf_un.kf_sock.kf_sock_pcb);
+ break;
+ case AF_UNIX:
+ /* print address of pcb and connected pcb */
+ sprintf(fdsname, "socket: %lx %lx", fds->kf_un.kf_sock.kf_sock_pcb, fds->kf_un.kf_sock.kf_sock_unpconn);
+ break;
+ default:
+ /* print protocol number and socket address */
+ sprintf(fdsname, "socket: other: %d %s %s", fds->kf_sock_protocol, fds->kf_sa_local.__ss_pad1, fds->kf_sa_local.__ss_pad2);
+ }
+ break;
+ case KF_TYPE_PIPE:
+ sprintf(fdsname, "pipe: %lu %lu", fds->kf_un.kf_pipe.kf_pipe_addr, fds->kf_un.kf_pipe.kf_pipe_peer);
+ break;
+ case KF_TYPE_PTS:
+ sprintf(fdsname, "other: pts: %u", fds->kf_un.kf_pts.kf_pts_dev);
+ break;
+ case KF_TYPE_SHM:
+ sprintf(fdsname, "other: shm: %s size: %lu", fds->kf_path, fds->kf_un.kf_file.kf_file_size);
+ break;
+ case KF_TYPE_SEM:
+ sprintf(fdsname, "other: sem: %u", fds->kf_un.kf_sem.kf_sem_value);
+ break;
+ default:
+ sprintf(fdsname, "other: pid: %d fd: %d", fds->kf_un.kf_proc.kf_pid, fds->kf_fd);
}
+ // if another process already has this, we will get
+ // the same id
+ p->fds[fdid] = file_descriptor_find_or_add(fdsname);
+ }
+
// else make it positive again, we need it
// of course, the actual file may have changed, but we don't care so much
// FIXME: we could compare the inode as returned by readdir dirent structure
- else p->fds[fdid] = -p->fds[fdid];
+
+ else
+ p->fds[fdid] = -p->fds[fdid];
+
+ bfdsbuf += fds->kf_structsize;
+ }
+#else
+ if(unlikely(!p->fds_dirname)) {
+ char dirname[FILENAME_MAX+1];
+ snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", netdata_configured_host_prefix, p->pid);
+ p->fds_dirname = strdupz(dirname);
+ }
+
+ DIR *fds = opendir(p->fds_dirname);
+ if(unlikely(!fds)) return 0;
+
+ struct dirent *de;
+ char fdname[FILENAME_MAX + 1];
+ char linkname[FILENAME_MAX + 1];
+
+ // we make all pid fds negative, so that
+ // we can detect unused file descriptors
+ // at the end, to free them
+ make_all_pid_fds_negative(p);
+
+ while((de = readdir(fds))) {
+ // we need only files with numeric names
+
+ if(unlikely(de->d_name[0] < '0' || de->d_name[0] > '9'))
+ continue;
+
+ // get its number
+ int fdid = (int) str2l(de->d_name);
+ if(unlikely(fdid < 0)) continue;
+
+ // check if the fds array is small
+ if(unlikely(fdid >= p->fds_size)) {
+ // it is small, extend it
+
+ if(unlikely(debug))
+ fprintf(stderr
+ , "apps.plugin: extending fd memory slots for %s from %d to %d\n"
+ , p->comm
+ , p->fds_size
+ , fdid + MAX_SPARE_FDS
+ );
+
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+
+ // and initialize it
+ zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+ p->fds_size = fdid + MAX_SPARE_FDS;
}
- closedir(fds);
- // remove all the negative file descriptors
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
- file_descriptor_not_used(-p->fds[c]);
- p->fds[c] = 0;
+ if(unlikely(p->fds[fdid] == 0)) {
+ // we don't know this fd, get it
+
+ sprintf(fdname, "%s/proc/%d/fd/%s", netdata_configured_host_prefix, p->pid, de->d_name);
+ ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
+ if(unlikely(l == -1)) {
+ if(debug || (p->target && p->target->debug)) {
+ if(debug || (p->target && p->target->debug))
+ error("Cannot read link %s", fdname);
+ }
+ continue;
+ }
+ else
+ linkname[l] = '\0';
+
+ file_counter++;
+
+ // if another process already has this, we will get
+ // the same id
+ p->fds[fdid] = file_descriptor_find_or_add(linkname);
}
+
+ // else make it positive again, we need it
+ // of course, the actual file may have changed, but we don't care so much
+ // FIXME: we could compare the inode as returned by readdir dirent structure
+ // UPDATE: no we cannot use inodes - under /proc inodes don't change when the link is changed
+
+ else
+ p->fds[fdid] = -p->fds[fdid];
}
- else return 0;
+
+ closedir(fds);
+#endif
+ cleanup_negative_pid_fds(p);
return 1;
}
// ----------------------------------------------------------------------------
-static inline int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
+static inline int print_process_and_parents(struct pid_stat *p, usec_t time) {
char *prefix = "\\_ ";
int indent = 0;
@@ -1261,25 +1726,25 @@ static inline int print_process_and_parents(struct pid_stat *p, unsigned long lo
for(i = 0; i < indent ;i++) buffer[i] = ' ';
buffer[i] = '\0';
- fprintf(stderr, " %s %s%s (%d %s %lld"
+ fprintf(stderr, " %s %s%s (%d %s %llu"
, buffer
, prefix
, p->comm
, p->pid
, p->updated?"running":"exited"
- , (long long)p->stat_collected_usec - (long long)time
+ , p->stat_collected_usec - time
);
- if(p->utime) fprintf(stderr, " utime=%llu", p->utime);
- if(p->stime) fprintf(stderr, " stime=%llu", p->stime);
- if(p->gtime) fprintf(stderr, " gtime=%llu", p->gtime);
- if(p->cutime) fprintf(stderr, " cutime=%llu", p->cutime);
- if(p->cstime) fprintf(stderr, " cstime=%llu", p->cstime);
- if(p->cgtime) fprintf(stderr, " cgtime=%llu", p->cgtime);
- if(p->minflt) fprintf(stderr, " minflt=%llu", p->minflt);
- if(p->cminflt) fprintf(stderr, " cminflt=%llu", p->cminflt);
- if(p->majflt) fprintf(stderr, " majflt=%llu", p->majflt);
- if(p->cmajflt) fprintf(stderr, " cmajflt=%llu", p->cmajflt);
+ if(p->utime) fprintf(stderr, " utime=" KERNEL_UINT_FORMAT, p->utime);
+ if(p->stime) fprintf(stderr, " stime=" KERNEL_UINT_FORMAT, p->stime);
+ if(p->gtime) fprintf(stderr, " gtime=" KERNEL_UINT_FORMAT, p->gtime);
+ if(p->cutime) fprintf(stderr, " cutime=" KERNEL_UINT_FORMAT, p->cutime);
+ if(p->cstime) fprintf(stderr, " cstime=" KERNEL_UINT_FORMAT, p->cstime);
+ if(p->cgtime) fprintf(stderr, " cgtime=" KERNEL_UINT_FORMAT, p->cgtime);
+ if(p->minflt) fprintf(stderr, " minflt=" KERNEL_UINT_FORMAT, p->minflt);
+ if(p->cminflt) fprintf(stderr, " cminflt=" KERNEL_UINT_FORMAT, p->cminflt);
+ if(p->majflt) fprintf(stderr, " majflt=" KERNEL_UINT_FORMAT, p->majflt);
+ if(p->cmajflt) fprintf(stderr, " cmajflt=" KERNEL_UINT_FORMAT, p->cmajflt);
fprintf(stderr, ")\n");
return indent + 1;
@@ -1291,7 +1756,7 @@ static inline void print_process_tree(struct pid_stat *p, char *msg) {
print_process_and_parents(p, p->stat_collected_usec);
}
-static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) {
+static inline void find_lost_child_debug(struct pid_stat *pe, kernel_uint_t lost, int type) {
int found = 0;
struct pid_stat *p = NULL;
@@ -1301,35 +1766,35 @@ static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long
switch(type) {
case 1:
if(p->cminflt > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child minflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 2:
if(p->cmajflt > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child majflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 3:
if(p->cutime > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child utime " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 4:
if(p->cstime > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child stime " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 5:
if(p->cgtime > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child gtime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child gtime " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
@@ -1339,30 +1804,30 @@ static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long
if(!found) {
switch(type) {
case 1:
- fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child minflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 2:
- fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child majflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 3:
- fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child utime " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 4:
- fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child stime " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 5:
- fprintf(stderr, " > cannot find any process to use the lost exited child gtime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child gtime " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
}
}
}
-static inline unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) {
- unsigned long long absorbed = 0;
+static inline kernel_uint_t remove_exited_child_from_parent(kernel_uint_t *field, kernel_uint_t *pfield) {
+ kernel_uint_t absorbed = 0;
if(*field > *pfield) {
absorbed += *pfield;
@@ -1385,20 +1850,18 @@ static inline void process_exited_processes() {
if(p->updated || !p->stat_collected_usec)
continue;
- struct pid_stat *pp = p->parent;
-
- unsigned long long utime = (p->utime_raw + p->cutime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long stime = (p->stime_raw + p->cstime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long gtime = (p->gtime_raw + p->cgtime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long minflt = (p->minflt_raw + p->cminflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long majflt = (p->majflt_raw + p->cmajflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t utime = (p->utime_raw + p->cutime_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t stime = (p->stime_raw + p->cstime_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t gtime = (p->gtime_raw + p->cgtime_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t minflt = (p->minflt_raw + p->cminflt_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t majflt = (p->majflt_raw + p->cmajflt_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
if(utime + stime + gtime + minflt + majflt == 0)
continue;
if(unlikely(debug)) {
log_date(stderr);
- fprintf(stderr, "Absorb %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
+ fprintf(stderr, "Absorb %s (%d %s total resources: utime=" KERNEL_UINT_FORMAT " stime=" KERNEL_UINT_FORMAT " gtime=" KERNEL_UINT_FORMAT " minflt=" KERNEL_UINT_FORMAT " majflt=" KERNEL_UINT_FORMAT ")\n"
, p->comm
, p->pid
, p->updated?"running":"exited"
@@ -1411,29 +1874,30 @@ static inline void process_exited_processes() {
print_process_tree(p, "Searching parents");
}
+ struct pid_stat *pp;
for(pp = p->parent; pp ; pp = pp->parent) {
if(!pp->updated) continue;
- unsigned long long absorbed;
+ kernel_uint_t absorbed;
absorbed = remove_exited_child_from_parent(&utime, &pp->cutime);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu utime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " utime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
absorbed = remove_exited_child_from_parent(&stime, &pp->cstime);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu stime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " stime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
absorbed = remove_exited_child_from_parent(&gtime, &pp->cgtime);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu gtime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " gtime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu minflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " minflt (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu majflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " majflt (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
}
if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
@@ -1448,7 +1912,7 @@ static inline void process_exited_processes() {
p->keep = 1;
if(unlikely(debug))
- fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
+ fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=" KERNEL_UINT_FORMAT " stime=" KERNEL_UINT_FORMAT " gtime=" KERNEL_UINT_FORMAT " minflt=" KERNEL_UINT_FORMAT " majflt=" KERNEL_UINT_FORMAT ")\n"
, p->comm
, p->pid
, p->updated?"running":"exited"
@@ -1513,7 +1977,7 @@ static inline void link_all_processes_to_their_parents(void) {
pp->children_count++;
if(unlikely(debug || (p->target && p->target->debug)))
- fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, gtime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
+ fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
}
else {
p->parent = NULL;
@@ -1540,6 +2004,7 @@ static inline void link_all_processes_to_their_parents(void) {
// to avoid filling up all disk space
// if debug is enabled, all errors are printed
+#ifndef __FreeBSD__
static int compar_pid(const void *pid1, const void *pid2) {
struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
@@ -1550,53 +2015,11 @@ static int compar_pid(const void *pid1, const void *pid2) {
else
return 1;
}
+#endif
-static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
- if(unlikely(!status)) {
- // error("command failed log %u, errno %d", log, errno);
-
- if(unlikely(debug || errno != ENOENT)) {
- if(unlikely(debug || !(p->log_thrown & log))) {
- p->log_thrown |= log;
- switch(log) {
- case PID_LOG_IO:
- error("Cannot process %s/proc/%d/io (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_STATM:
- error("Cannot process %s/proc/%d/statm (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_CMDLINE:
- error("Cannot process %s/proc/%d/cmdline (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_FDS:
- error("Cannot process entries in %s/proc/%d/fd (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_STAT:
- break;
-
- default:
- error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
- break;
- }
- }
- }
- errno = 0;
- }
- else if(unlikely(p->log_thrown & log)) {
- // error("unsetting log %u on pid %d", log, p->pid);
- p->log_thrown &= ~log;
- }
-
- return status;
-}
-
-static inline int collect_data_for_pid(pid_t pid) {
- if(unlikely(pid <= 0 || pid > pid_max)) {
- error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
+static inline int collect_data_for_pid(pid_t pid, void *ptr) {
+ if(unlikely(pid < INIT_PID || pid > pid_max)) {
+ error("Invalid pid %d read (expected %d to %d). Ignoring process.", pid, INIT_PID, pid_max);
return 0;
}
@@ -1609,11 +2032,11 @@ static inline int collect_data_for_pid(pid_t pid) {
// --------------------------------------------------------------------
// /proc/<pid>/stat
- if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p))))
+ if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p, ptr))))
// there is no reason to proceed if we cannot get its status
return 0;
- read_proc_pid_ownership(p);
+ read_proc_pid_ownership(p, ptr);
// check its parent pid
if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
@@ -1624,61 +2047,20 @@ static inline int collect_data_for_pid(pid_t pid) {
// --------------------------------------------------------------------
// /proc/<pid>/io
- managed_log(p, PID_LOG_IO, read_proc_pid_io(p));
+ managed_log(p, PID_LOG_IO, read_proc_pid_io(p, ptr));
// --------------------------------------------------------------------
// /proc/<pid>/statm
- if(unlikely(!managed_log(p, PID_LOG_STATM, read_proc_pid_statm(p))))
+ if(unlikely(!managed_log(p, PID_LOG_STATM, read_proc_pid_statm(p, ptr))))
// there is no reason to proceed if we cannot get its memory status
return 0;
// --------------------------------------------------------------------
- // link it
-
- // check if it is target
- // we do this only once, the first time this pid is loaded
- if(unlikely(p->new_entry)) {
- // /proc/<pid>/cmdline
- if(likely(proc_pid_cmdline_is_needed))
- managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
-
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
-
- uint32_t hash = simple_hash(p->comm);
- size_t pclen = strlen(p->comm);
-
- struct target *w;
- for(w = apps_groups_root_target; w ; w = w->next) {
- // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
-
- // find it - 4 cases:
- // 1. the target is not a pattern
- // 2. the target has the prefix
- // 3. the target has the suffix
- // 4. the target is something inside cmdline
- if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
- || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
- || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
- || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
- ) {
- if(w->target) p->target = w->target;
- else p->target = w;
-
- if(debug || (p->target && p->target->debug))
- fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
-
- break;
- }
- }
- }
-
- // --------------------------------------------------------------------
// /proc/<pid>/fd
if(enable_file_charts)
- managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p));
+ managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p, ptr));
// --------------------------------------------------------------------
// done!
@@ -1694,71 +2076,116 @@ static inline int collect_data_for_pid(pid_t pid) {
return 1;
}
-static int collect_data_for_all_processes_from_proc(void) {
+static int collect_data_for_all_processes(void) {
struct pid_stat *p = NULL;
- if(all_pids_count) {
- // read parents before childs
- // this is needed to prevent a situation where
- // a child is found running, but until we read
- // its parent, it has exited and its parent
- // has accumulated its resources
+#ifdef __FreeBSD__
+ int i, procnum;
+ size_t procbase_size;
+ static struct kinfo_proc *procbase;
- long slc = 0;
+ int mib[3];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PROC;
+ if (unlikely(sysctl(mib, 3, NULL, &procbase_size, NULL, 0))) {
+ error("sysctl error: Can't get processes data size");
+ return 0;
+ }
+ procbase = reallocz(procbase, procbase_size);
+ if (unlikely(sysctl(mib, 3, procbase, &procbase_size, NULL, 0))) {
+ error("sysctl error: Can't get processes data");
+ return 0;
+ }
+ procnum = procbase_size / sizeof(struct kinfo_proc);
+#endif
+
+ if(all_pids_count) {
+#ifndef __FreeBSD__
+ size_t slc = 0;
+#endif
for(p = root_of_pids; p ; p = p->next) {
- p->read = 0;
+ p->read = 0; // mark it as not read, so that collect_data_for_pid() will read it
p->updated = 0;
- p->new_entry = 0;
p->merged = 0;
p->children_count = 0;
p->parent = NULL;
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
all_pids_sortlist[slc++] = p->pid;
+#endif
}
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
if(unlikely(slc != all_pids_count)) {
- error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
+ error("Internal error: I was thinking I had %zu processes in my arrays, but it seems there are more.", all_pids_count);
all_pids_count = slc;
}
if(include_exited_childs) {
+ // Read parents before childs
+ // This is needed to prevent a situation where
+ // a child is found running, but until we read
+ // its parent, it has exited and its parent
+ // has accumulated its resources.
+
qsort((void *)all_pids_sortlist, (size_t)all_pids_count, sizeof(pid_t), compar_pid);
+
+ // we forward read all running processes
+ // collect_data_for_pid() is smart enough,
+ // not to read the same pid twice per iteration
for(slc = 0; slc < all_pids_count; slc++)
- collect_data_for_pid(all_pids_sortlist[slc]);
+ collect_data_for_pid(all_pids_sortlist[slc], NULL);
}
+#endif
}
+#ifdef __FreeBSD__
+ for (i = INIT_PID; i < procnum - INIT_PID; ++i) {
+ pid_t pid = procbase[i].ki_pid;
+ collect_data_for_pid(pid, &procbase[i]);
+ }
+#else
char dirname[FILENAME_MAX + 1];
- snprintfz(dirname, FILENAME_MAX, "%s/proc", global_host_prefix);
+ snprintfz(dirname, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
DIR *dir = opendir(dirname);
if(!dir) return 0;
- struct dirent *file = NULL;
+ struct dirent *de = NULL;
+
+ while((de = readdir(dir))) {
+ char *endptr = de->d_name;
+
+ if(unlikely(de->d_type != DT_DIR || de->d_name[0] < '0' || de->d_name[0] > '9'))
+ continue;
- while((file = readdir(dir))) {
- char *endptr = file->d_name;
- pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
+ pid_t pid = (pid_t) strtoul(de->d_name, &endptr, 10);
// make sure we read a valid number
- if(unlikely(endptr == file->d_name || *endptr != '\0'))
+ if(unlikely(endptr == de->d_name || *endptr != '\0'))
continue;
- collect_data_for_pid(pid);
+ collect_data_for_pid(pid, NULL);
}
closedir(dir);
+#endif
if(!all_pids_count)
return 0;
+ // we need /proc/stat to normalize the cpu consumption of the exited childs
+ read_proc_stat();
+
+ // build the process tree
+ link_all_processes_to_their_parents();
+
// normally this is done
// however we may have processes exited while we collected values
// so let's find the exited ones
// we do this by collecting the ownership of process
// if we manage to get the ownership, the process still runs
-
- read_proc_stat();
- link_all_processes_to_their_parents();
process_exited_processes();
return 1;
@@ -1786,15 +2213,14 @@ static void cleanup_exited_pids(void) {
for(p = root_of_pids; p ;) {
if(!p->updated && (!p->keep || p->keeploops > 0)) {
-// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
-
if(unlikely(debug && (p->keep || p->keeploops)))
fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
- file_descriptor_not_used(p->fds[c]);
- p->fds[c] = 0;
- }
+ for(c = 0; c < p->fds_size; c++)
+ if(p->fds[c] > 0) {
+ file_descriptor_not_used(p->fds[c]);
+ p->fds[c] = 0;
+ }
pid_t r = p->pid;
p = p->next;
@@ -1857,7 +2283,7 @@ static void apply_apps_groups_targets_inheritance(void) {
&& p->parent
&& p->parent->children_count
&& (p->target == p->parent->target || !p->parent->target)
- && p->ppid != 1
+ && p->ppid != INIT_PID
)) {
p->parent->children_count--;
p->merged = 1;
@@ -1879,8 +2305,8 @@ static void apply_apps_groups_targets_inheritance(void) {
}
// init goes always to default target
- if(all_pids[1])
- all_pids[1]->target = apps_groups_default_target;
+ if(all_pids[INIT_PID])
+ all_pids[INIT_PID]->target = apps_groups_default_target;
// give a default target on all top level processes
if(unlikely(debug)) loops++;
@@ -1918,9 +2344,9 @@ static void apply_apps_groups_targets_inheritance(void) {
fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
}
-static long zero_all_targets(struct target *root) {
+static size_t zero_all_targets(struct target *root) {
struct target *w;
- long count = 0;
+ size_t count = 0;
for (w = root; w ; w = w->next) {
count++;
@@ -2032,7 +2458,7 @@ static inline void aggregate_fd_on_target(int fd, struct target *w) {
w->openeventpolls++;
break;
- default:
+ case FILETYPE_OTHER:
w->openother++;
break;
}
@@ -2111,7 +2537,7 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
w->num_threads += p->num_threads;
if(unlikely(debug || w->debug))
- fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+ fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
}
static void calculate_netdata_statistics(void) {
@@ -2120,7 +2546,7 @@ static void calculate_netdata_statistics(void) {
zero_all_targets(users_root_target);
zero_all_targets(groups_root_target);
- apps_groups_targets = zero_all_targets(apps_groups_root_target);
+ apps_groups_targets_count = zero_all_targets(apps_groups_root_target);
// this has to be done, before the cleanup
struct pid_stat *p = NULL;
@@ -2182,21 +2608,18 @@ static void calculate_netdata_statistics(void) {
int print_calculated_number(char *str, calculated_number value) { (void)str; (void)value; return 0; }
-static inline void send_BEGIN(const char *type, const char *id, unsigned long long usec) {
+static inline void send_BEGIN(const char *type, const char *id, usec_t usec) {
fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
}
-static inline void send_SET(const char *name, unsigned long long value) {
- fprintf(stdout, "SET %s = %llu\n", name, value);
+static inline void send_SET(const char *name, kernel_uint_t value) {
+ fprintf(stdout, "SET %s = " KERNEL_UINT_FORMAT "\n", name, value);
}
static inline void send_END(void) {
fprintf(stdout, "END\n");
}
-double utime_fix_ratio = 1.0, stime_fix_ratio = 1.0, gtime_fix_ratio = 1.0, cutime_fix_ratio = 1.0, cstime_fix_ratio = 1.0, cgtime_fix_ratio = 1.0;
-double minflt_fix_ratio = 1.0, majflt_fix_ratio = 1.0, cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0;
-
static usec_t send_resource_usage_to_netdata() {
static struct timeval last = { 0, 0 };
static struct rusage me_last;
@@ -2209,7 +2632,7 @@ static usec_t send_resource_usage_to_netdata() {
usec_t cpusyst;
if(!last.tv_sec) {
- now_realtime_timeval(&last);
+ now_monotonic_timeval(&last);
getrusage(RUSAGE_SELF, &me_last);
// the first time, give a zero to allow
@@ -2220,7 +2643,7 @@ static usec_t send_resource_usage_to_netdata() {
cpusyst = 0;
}
else {
- now_realtime_timeval(&now);
+ now_monotonic_timeval(&now);
getrusage(RUSAGE_SELF, &me);
usec = dt_usec(&now, &last);
@@ -2231,73 +2654,115 @@ static usec_t send_resource_usage_to_netdata() {
memmove(&me_last, &me, sizeof(struct rusage));
}
+ static char created_charts = 0;
+ if(unlikely(!created_charts)) {
+ created_charts = 1;
+
+ fprintf(stdout
+ , "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
+ "DIMENSION user '' incremental 1 1000\n"
+ "DIMENSION system '' incremental 1 1000\n"
+ "CHART netdata.apps_sizes '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_sizes line 140001 %1$d\n"
+ "DIMENSION calls '' incremental 1 1\n"
+ "DIMENSION files '' incremental 1 1\n"
+ "DIMENSION pids '' absolute 1 1\n"
+ "DIMENSION fds '' absolute 1 1\n"
+ "DIMENSION targets '' absolute 1 1\n"
+ "DIMENSION new_pids 'new pids' incremental 1 1\n"
+ "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
+ "DIMENSION utime '' absolute 1 %2$llu\n"
+ "DIMENSION stime '' absolute 1 %2$llu\n"
+ "DIMENSION gtime '' absolute 1 %2$llu\n"
+ "DIMENSION minflt '' absolute 1 %2$llu\n"
+ "DIMENSION majflt '' absolute 1 %2$llu\n"
+ , update_every
+ , RATES_DETAIL
+ );
+
+ if(include_exited_childs)
+ fprintf(stdout
+ , "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
+ "DIMENSION cutime '' absolute 1 %2$llu\n"
+ "DIMENSION cstime '' absolute 1 %2$llu\n"
+ "DIMENSION cgtime '' absolute 1 %2$llu\n"
+ "DIMENSION cminflt '' absolute 1 %2$llu\n"
+ "DIMENSION cmajflt '' absolute 1 %2$llu\n"
+ , update_every
+ , RATES_DETAIL
+ );
+ }
+
fprintf(stdout,
"BEGIN netdata.apps_cpu %llu\n"
"SET user = %llu\n"
"SET system = %llu\n"
"END\n"
- "BEGIN netdata.apps_files %llu\n"
- "SET files = %llu\n"
- "SET pids = %ld\n"
+ "BEGIN netdata.apps_sizes %llu\n"
+ "SET calls = %zu\n"
+ "SET files = %zu\n"
+ "SET pids = %zu\n"
"SET fds = %d\n"
- "SET targets = %ld\n"
+ "SET targets = %zu\n"
+ "SET new_pids = %zu\n"
"END\n"
"BEGIN netdata.apps_fix %llu\n"
- "SET utime = %llu\n"
- "SET stime = %llu\n"
- "SET gtime = %llu\n"
- "SET minflt = %llu\n"
- "SET majflt = %llu\n"
+ "SET utime = %u\n"
+ "SET stime = %u\n"
+ "SET gtime = %u\n"
+ "SET minflt = %u\n"
+ "SET majflt = %u\n"
"END\n"
, usec
, cpuuser
, cpusyst
, usec
+ , calls_counter
, file_counter
, all_pids_count
, all_files_len
- , apps_groups_targets
+ , apps_groups_targets_count
+ , targets_assignment_counter
, usec
- , (unsigned long long)(utime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(stime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(gtime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(minflt_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(majflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(utime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(stime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(gtime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(minflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(majflt_fix_ratio * 100 * RATES_DETAIL)
);
if(include_exited_childs)
fprintf(stdout,
"BEGIN netdata.apps_children_fix %llu\n"
- "SET cutime = %llu\n"
- "SET cstime = %llu\n"
- "SET cgtime = %llu\n"
- "SET cminflt = %llu\n"
- "SET cmajflt = %llu\n"
+ "SET cutime = %u\n"
+ "SET cstime = %u\n"
+ "SET cgtime = %u\n"
+ "SET cminflt = %u\n"
+ "SET cmajflt = %u\n"
"END\n"
, usec
- , (unsigned long long)(cutime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cstime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cgtime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cminflt_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cutime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cstime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cgtime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cminflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
);
return usec;
}
-static void normalize_data(struct target *root) {
+static void normalize_utilization(struct target *root) {
struct target *w;
// childs processing introduces spikes
// here we try to eliminate them by disabling childs processing either for specific dimensions
// or entirely. Of course, either way, we disable it just a single iteration.
- unsigned long long max = processors * hz * RATES_DETAIL;
- unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
+ kernel_uint_t max_time = processors * hz * RATES_DETAIL;
+ kernel_uint_t utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
- if(global_utime > max) global_utime = max;
- if(global_stime > max) global_stime = max;
- if(global_gtime > max) global_gtime = max;
+ if(global_utime > max_time) global_utime = max_time;
+ if(global_stime > max_time) global_stime = max_time;
+ if(global_gtime > max_time) global_gtime = max_time;
for(w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
@@ -2397,11 +2862,11 @@ static void normalize_data(struct target *root) {
if(unlikely(debug)) {
fprintf(stderr,
- "SYSTEM: u=%llu s=%llu g=%llu "
- "COLLECTED: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
- "DELTA: u=%lld s=%lld g=%lld "
+ "SYSTEM: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " "
+ "COLLECTED: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " cu=" KERNEL_UINT_FORMAT " cs=" KERNEL_UINT_FORMAT " cg=" KERNEL_UINT_FORMAT " "
+ "DELTA: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " "
"FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
- "FINALLY: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
+ "FINALLY: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " cu=" KERNEL_UINT_FORMAT " cs=" KERNEL_UINT_FORMAT " cg=" KERNEL_UINT_FORMAT " "
"\n"
, global_utime
, global_stime
@@ -2412,21 +2877,21 @@ static void normalize_data(struct target *root) {
, cutime
, cstime
, cgtime
- , (long long)utime + (long long)cutime - (long long)global_utime
- , (long long)stime + (long long)cstime - (long long)global_stime
- , (long long)gtime + (long long)cgtime - (long long)global_gtime
+ , utime + cutime - global_utime
+ , stime + cstime - global_stime
+ , gtime + cgtime - global_gtime
, utime_fix_ratio
, stime_fix_ratio
, gtime_fix_ratio
, cutime_fix_ratio
, cstime_fix_ratio
, cgtime_fix_ratio
- , (unsigned long long)(utime * utime_fix_ratio)
- , (unsigned long long)(stime * stime_fix_ratio)
- , (unsigned long long)(gtime * gtime_fix_ratio)
- , (unsigned long long)(cutime * cutime_fix_ratio)
- , (unsigned long long)(cstime * cstime_fix_ratio)
- , (unsigned long long)(cgtime * cgtime_fix_ratio)
+ , (kernel_uint_t)(utime * utime_fix_ratio)
+ , (kernel_uint_t)(stime * stime_fix_ratio)
+ , (kernel_uint_t)(gtime * gtime_fix_ratio)
+ , (kernel_uint_t)(cutime * cutime_fix_ratio)
+ , (kernel_uint_t)(cstime * cstime_fix_ratio)
+ , (kernel_uint_t)(cgtime * cgtime_fix_ratio)
);
}
}
@@ -2437,21 +2902,21 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_BEGIN(type, "cpu", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (unsigned long long)(w->stime * stime_fix_ratio) + (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio) + (unsigned long long)(w->cstime * cstime_fix_ratio) + (unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->utime * utime_fix_ratio) + (kernel_uint_t)(w->stime * stime_fix_ratio) + (kernel_uint_t)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cutime * cutime_fix_ratio) + (kernel_uint_t)(w->cstime * cstime_fix_ratio) + (kernel_uint_t)(w->cgtime * cgtime_fix_ratio)):0ULL));
}
send_END();
send_BEGIN(type, "cpu_user", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->utime * utime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cutime * cutime_fix_ratio)):0ULL));
}
send_END();
send_BEGIN(type, "cpu_system", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->stime * stime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cstime * cstime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->stime * stime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cstime * cstime_fix_ratio)):0ULL));
}
send_END();
@@ -2459,7 +2924,7 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_BEGIN(type, "cpu_guest", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cgtime * cgtime_fix_ratio)):0ULL));
}
send_END();
}
@@ -2495,17 +2960,18 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_BEGIN(type, "minor_faults", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cminflt * cminflt_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cminflt * cminflt_fix_ratio)):0ULL));
}
send_END();
send_BEGIN(type, "major_faults", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
}
send_END();
+#ifndef __FreeBSD__
send_BEGIN(type, "lreads", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
@@ -2519,6 +2985,7 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_SET(w->name, w->io_logical_bytes_written);
}
send_END();
+#endif
send_BEGIN(type, "preads", usec);
for (w = root; w ; w = w->next) {
@@ -2644,29 +3111,43 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
+#ifdef __FreeBSD__
+ fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'blocks/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed))
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+ }
+
+ fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'blocks/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed))
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+ }
+#else
+ fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
+ fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
+ fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
+ fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
+#endif
if(enable_file_charts) {
fprintf(stdout, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type,
@@ -2696,6 +3177,22 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
// ----------------------------------------------------------------------------
// parse command line arguments
+int check_proc_1_io() {
+ int ret = 0;
+
+ procfile *ff = procfile_open("/proc/1/io", NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+ if(!ff) goto cleanup;
+
+ ff = procfile_readall(ff);
+ if(!ff) goto cleanup;
+
+ ret = 1;
+
+cleanup:
+ procfile_close(ff);
+ return ret;
+}
+
static void parse_args(int argc, char **argv)
{
int i, freq = 0;
@@ -2710,11 +3207,20 @@ static void parse_args(int argc, char **argv)
}
}
- if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0) {
+ if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
printf("apps.plugin %s\n", VERSION);
exit(0);
}
+ if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
+ if(!check_proc_1_io()) {
+ perror("Tried to read /proc/1/io and it failed");
+ exit(1);
+ }
+ printf("OK\n");
+ exit(0);
+ }
+
if(strcmp("debug", argv[i]) == 0) {
debug = 1;
// debug_flags = 0xffffffff;
@@ -2766,12 +3272,12 @@ static void parse_args(int argc, char **argv)
"\n"
" netdata apps.plugin %s\n"
" Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
- " Released under GNU Public License v3 or later.\n"
+ " Released under GNU General Public License v3 or later.\n"
" All rights reserved.\n"
"\n"
" This program is a data collector plugin for netdata.\n"
"\n"
- " Valid command line options:\n"
+ " Available command line options:\n"
"\n"
" SECONDS set the data collection frequency\n"
"\n"
@@ -2794,7 +3300,7 @@ static void parse_args(int argc, char **argv)
" apps_groups.conf\n"
" (default NAME=groups)\n"
"\n"
- " version print program version and exit\n"
+ " version or -v or -V print program version and exit\n"
"\n"
, VERSION
);
@@ -2819,15 +3325,74 @@ static void parse_args(int argc, char **argv)
}
}
-int main(int argc, char **argv)
-{
+static int am_i_running_as_root() {
+ uid_t uid = getuid(), euid = geteuid();
+
+ if(uid == 0 || euid == 0) {
+ if(debug) info("I am running with escalated privileges, uid = %u, euid = %u.", uid, euid);
+ return 1;
+ }
+
+ if(debug) info("I am not running with escalated privileges, uid = %u, euid = %u.", uid, euid);
+ return 0;
+}
+
+#ifdef HAVE_CAPABILITY
+static int check_capabilities() {
+ cap_t caps = cap_get_proc();
+ if(!caps) {
+ error("Cannot get current capabilities.");
+ return 0;
+ }
+ else if(debug)
+ info("Received my capabilities from the system.");
+
+ int ret = 1;
+
+ cap_flag_value_t cfv = CAP_CLEAR;
+ if(cap_get_flag(caps, CAP_DAC_READ_SEARCH, CAP_EFFECTIVE, &cfv) == -1) {
+ error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
+ ret = 0;
+ }
+ else {
+ if(cfv != CAP_SET) {
+ error("apps.plugin should run with CAP_DAC_READ_SEARCH.");
+ ret = 0;
+ }
+ else if(debug)
+ info("apps.plugin runs with CAP_DAC_READ_SEARCH.");
+ }
+
+ cfv = CAP_CLEAR;
+ if(cap_get_flag(caps, CAP_SYS_PTRACE, CAP_EFFECTIVE, &cfv) == -1) {
+ error("Cannot find if CAP_SYS_PTRACE is effective.");
+ ret = 0;
+ }
+ else {
+ if(cfv != CAP_SET) {
+ error("apps.plugin should run with CAP_SYS_PTRACE.");
+ ret = 0;
+ }
+ else if(debug)
+ info("apps.plugin runs with CAP_SYS_PTRACE.");
+ }
+
+ cap_free(caps);
+
+ return ret;
+}
+#else
+static int check_capabilities() {
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv) {
// debug_flags = D_PROCFILE;
// set the name for logging
program_name = "apps.plugin";
- info("started on pid %d", getpid());
-
// disable syslog for apps.plugin
error_log_syslog = 0;
@@ -2835,12 +3400,12 @@ int main(int argc, char **argv)
error_log_errors_per_period = 100;
error_log_throttle_period = 3600;
- global_host_prefix = getenv("NETDATA_HOST_PREFIX");
- if(global_host_prefix == NULL) {
+ netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
+ if(netdata_configured_host_prefix == NULL) {
// info("NETDATA_HOST_PREFIX is not passed from netdata");
- global_host_prefix = "";
+ netdata_configured_host_prefix = "";
}
- // else info("Found NETDATA_HOST_PREFIX='%s'", global_host_prefix);
+ // else info("Found NETDATA_HOST_PREFIX='%s'", netdata_configured_host_prefix);
config_dir = getenv("NETDATA_CONFIG_DIR");
if(config_dir == NULL) {
@@ -2854,58 +3419,53 @@ int main(int argc, char **argv)
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+#ifdef HAVE_SYS_PRCTL_H
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+#endif
}
#endif /* NETDATA_INTERNAL_CHECKS */
procfile_adaptive_initial_allocation = 1;
- time_t started_t = now_realtime_sec();
+ time_t started_t = now_monotonic_sec();
get_system_HZ();
get_system_pid_max();
get_system_cpus();
parse_args(argc, argv);
- all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
- all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
-
- fprintf(stdout,
- "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
- "DIMENSION user '' incremental 1 1000\n"
- "DIMENSION system '' incremental 1 1000\n"
- "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %1$d\n"
- "DIMENSION files '' incremental 1 1\n"
- "DIMENSION pids '' absolute 1 1\n"
- "DIMENSION fds '' absolute 1 1\n"
- "DIMENSION targets '' absolute 1 1\n"
- "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
- "DIMENSION utime '' absolute 1 %2$llu\n"
- "DIMENSION stime '' absolute 1 %2$llu\n"
- "DIMENSION gtime '' absolute 1 %2$llu\n"
- "DIMENSION minflt '' absolute 1 %2$llu\n"
- "DIMENSION majflt '' absolute 1 %2$llu\n"
- , update_every
- , RATES_DETAIL
+ if(!check_capabilities() && !am_i_running_as_root() && !check_proc_1_io()) {
+ uid_t uid = getuid(), euid = geteuid();
+#ifdef HAVE_CAPABILITY
+ error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
+ "Without these, apps.plugin cannot report disk I/O utilization of other processes. "
+ "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
+ "To enable setuid to root run: sudo chown root %s; sudo chmod 4755 %s; "
+ , uid, euid, argv[0], argv[0], argv[0]
);
+#else
+ error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
+ "Without these, apps.plugin cannot report disk I/O utilization of other processes. "
+ "Your system does not support capabilities. "
+ "To enable setuid to root run: sudo chown root %s; sudo chmod 4755 %s; "
+ , uid, euid, argv[0], argv[0]
+ );
+#endif
+ }
- if(include_exited_childs)
- fprintf(stdout,
- "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
- "DIMENSION cutime '' absolute 1 %2$llu\n"
- "DIMENSION cstime '' absolute 1 %2$llu\n"
- "DIMENSION cgtime '' absolute 1 %2$llu\n"
- "DIMENSION cminflt '' absolute 1 %2$llu\n"
- "DIMENSION cmajflt '' absolute 1 %2$llu\n"
- , update_every
- , RATES_DETAIL
- );
+ info("started on pid %d", getpid());
+
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
+ all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
+#endif
+
+ all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
usec_t step = update_every * USEC_PER_SEC;
global_iterations_counter = 1;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;1; global_iterations_counter++) {
- usec_t now = now_realtime_usec();
- usec_t next = now - (now % step) + step;
#ifdef NETDATA_PROFILING
#warning "compiling for profiling"
@@ -2913,20 +3473,17 @@ int main(int argc, char **argv)
profiling_count++;
if(unlikely(profiling_count > 1000)) exit(0);
#else
- while(now < next) {
- sleep_usec(next - now);
- now = now_realtime_usec();
- }
+ heartbeat_next(&hb, step);
#endif
- if(!collect_data_for_all_processes_from_proc()) {
+ if(!collect_data_for_all_processes()) {
error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
printf("DISABLE\n");
exit(1);
}
calculate_netdata_statistics();
- normalize_data(apps_groups_root_target);
+ normalize_utilization(apps_groups_root_target);
usec_t dt = send_resource_usage_to_netdata();
@@ -2952,11 +3509,9 @@ int main(int argc, char **argv)
show_guest_time_old = show_guest_time;
if(unlikely(debug))
- fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);
-
- time_t current_t = now_realtime_sec();
+ fprintf(stderr, "apps.plugin: done Loop No %zu\n", global_iterations_counter);
// restart check (14400 seconds)
- if(current_t - started_t > 14400) exit(0);
+ if(now_monotonic_sec() - started_t > 14400) exit(0);
}
}
diff --git a/src/avl.c b/src/avl.c
index 1ec1b8ad2..0ea119a7c 100644
--- a/src/avl.c
+++ b/src/avl.c
@@ -315,9 +315,9 @@ int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *da
void avl_read_lock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_lock(&t->mutex);
+ netdata_mutex_lock(&t->mutex);
#else
- pthread_rwlock_rdlock(&t->rwlock);
+ netdata_rwlock_rdlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
@@ -325,9 +325,9 @@ void avl_read_lock(avl_tree_lock *t) {
void avl_write_lock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_lock(&t->mutex);
+ netdata_mutex_lock(&t->mutex);
#else
- pthread_rwlock_wrlock(&t->rwlock);
+ netdata_rwlock_wrlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
@@ -335,9 +335,9 @@ void avl_write_lock(avl_tree_lock *t) {
void avl_unlock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_unlock(&t->mutex);
+ netdata_mutex_unlock(&t->mutex);
#else
- pthread_rwlock_unlock(&t->rwlock);
+ netdata_rwlock_unlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
@@ -352,9 +352,9 @@ void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) {
int lock;
#ifdef AVL_LOCK_WITH_MUTEX
- lock = pthread_mutex_init(&t->mutex, NULL);
+ lock = netdata_mutex_init(&t->mutex, NULL);
#else
- lock = pthread_rwlock_init(&t->rwlock, NULL);
+ lock = netdata_rwlock_init(&t->rwlock);
#endif
if(lock != 0)
diff --git a/src/avl.h b/src/avl.h
index d30be0dd8..19648cd1d 100644
--- a/src/avl.h
+++ b/src/avl.h
@@ -13,9 +13,9 @@
// #define AVL_LOCK_WITH_MUTEX 1
#ifdef AVL_LOCK_WITH_MUTEX
-#define AVL_LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define AVL_LOCK_INITIALIZER NETDATA_MUTEX_INITIALIZER
#else /* AVL_LOCK_WITH_MUTEX */
-#define AVL_LOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+#define AVL_LOCK_INITIALIZER NETDATA_RWLOCK_INITIALIZER
#endif /* AVL_LOCK_WITH_MUTEX */
#else /* AVL_WITHOUT_PTHREADS */
@@ -41,9 +41,9 @@ typedef struct avl_tree_lock {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_t mutex;
+ netdata_mutex_t mutex;
#else /* AVL_LOCK_WITH_MUTEX */
- pthread_rwlock_t rwlock;
+ netdata_rwlock_t rwlock;
#endif /* AVL_LOCK_WITH_MUTEX */
#endif /* AVL_WITHOUT_PTHREADS */
} avl_tree_lock;
diff --git a/src/backends.c b/src/backends.c
index 1272d0473..3e385cab5 100644
--- a/src/backends.c
+++ b/src/backends.c
@@ -1,16 +1,51 @@
#include "common.h"
+// ----------------------------------------------------------------------------
+// How backends work in netdata:
+//
+// 1. There is an independent thread that runs at the required interval
+// (for example, once every 10 seconds)
+//
+// 2. Every time it wakes, it calls the backend formatting functions to build
+// a buffer of data. This is a very fast, memory only operation.
+//
+// 3. If the buffer already includes data, the new data are appended.
+// If the buffer becomes too big, because the data cannot be sent, a
+// log is written and the buffer is discarded.
+//
+// 4. Then it tries to send all the data. It blocks until all the data are sent
+// or the socket returns an error.
+// If the time required for this is above the interval, it starts skipping
+// intervals, but the calculated values include the entire database, without
+// gaps (it remembers the timestamps and continues from where it stopped).
+//
+// 5. repeats the above forever.
+//
+
#define BACKEND_SOURCE_DATA_AS_COLLECTED 0x00000001
#define BACKEND_SOURCE_DATA_AVERAGE 0x00000002
#define BACKEND_SOURCE_DATA_SUM 0x00000004
-static inline calculated_number backend_calculate_value_from_stored_data(RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+
+// ----------------------------------------------------------------------------
+// helper functions for backends
+
+// calculate the SUM or AVERAGE of a dimension, for any timeframe
+// may return NAN if the database does not have any value in the give timeframe
+
+static inline calculated_number backend_calculate_value_from_stored_data(
+ RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
+ // find the edges of the rrd database for this chart
time_t first_t = rrdset_first_entry_t(st);
- time_t last_t = rrdset_last_entry_t(st);
+ time_t last_t = rrdset_last_entry_t(st);
- if(unlikely(before - after < st->update_every && after != after - after % st->update_every))
- // when st->update_every is bigger than the frequency we send data to backend
- // skip the iterations that are not aligned to the database
+ if(unlikely(before < first_t || after > last_t))
+ // the chart has not been updated in the wanted timeframe
return NAN;
// align the time-frame
@@ -22,7 +57,7 @@ static inline calculated_number backend_calculate_value_from_stored_data(RRDSET
after = first_t;
if(unlikely(after > before))
- // this can happen when the st->update_every > before - after
+ // this can happen when st->update_every > before - after
before = after;
if(unlikely(before > last_t))
@@ -36,14 +71,20 @@ static inline calculated_number backend_calculate_value_from_stored_data(RRDSET
slot, stop_now = 0;
for(slot = start_at_slot; !stop_now ; slot--) {
+
if(unlikely(slot < 0)) slot = st->entries - 1;
if(unlikely(slot == stop_at_slot)) stop_now = 1;
storage_number n = rd->values[slot];
- if(unlikely(!does_storage_number_exist(n))) continue;
+
+ if(unlikely(!does_storage_number_exist(n))) {
+ // not collected
+ continue;
+ }
calculated_number value = unpack_storage_number(n);
sum += value;
+
counter++;
}
@@ -56,84 +97,295 @@ static inline calculated_number backend_calculate_value_from_stored_data(RRDSET
return sum / (calculated_number)counter;
}
-static inline int format_dimension_collected_graphite_plaintext(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+
+// discard a response received by a backend
+// after logging a simple of it to error.log
+
+static inline int discard_response(BUFFER *b, const char *backend) {
+ char sample[1024];
+ const char *s = buffer_tostring(b);
+ char *d = sample, *e = &sample[sizeof(sample) - 1];
+
+ for(; *s && d < e ;s++) {
+ char c = *s;
+ if(unlikely(!isprint(c))) c = ' ';
+ *d++ = c;
+ }
+ *d = '\0';
+
+ info("Received %zu bytes from %s backend. Ignoring them. Sample: '%s'", buffer_strlen(b), backend, sample);
+ buffer_flush(b);
+ return 0;
+}
+
+
+// ----------------------------------------------------------------------------
+// graphite backend
+
+static inline int format_dimension_collected_graphite_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
(void)after;
(void)before;
(void)options;
- buffer_sprintf(b, "%s.%s.%s.%s " COLLECTED_NUMBER_FORMAT " %u\n", prefix, hostname, st->id, rd->id, rd->last_collected_value, (uint32_t)rd->last_collected_time.tv_sec);
+
+ buffer_sprintf(
+ b
+ , "%s.%s.%s.%s " COLLECTED_NUMBER_FORMAT " %u\n"
+ , prefix
+ , hostname
+ , st->id
+ , rd->id
+ , rd->last_collected_value
+ , (uint32_t)rd->last_collected_time.tv_sec
+ );
+
return 1;
}
-static inline int format_dimension_stored_graphite_plaintext(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+static inline int format_dimension_stored_graphite_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
+
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options);
+
if(!isnan(value)) {
- buffer_sprintf(b, "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n", prefix, hostname, st->id, rd->id, value, (uint32_t) before);
+
+ buffer_sprintf(
+ b
+ , "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n"
+ , prefix
+ , hostname
+ , st->id
+ , rd->id
+ , value
+ , (uint32_t) before
+ );
+
return 1;
}
return 0;
}
-static inline int format_dimension_collected_opentsdb_telnet(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+static inline int process_graphite_response(BUFFER *b) {
+ return discard_response(b, "graphite");
+}
+
+
+// ----------------------------------------------------------------------------
+// opentsdb backend
+
+static inline int format_dimension_collected_opentsdb_telnet(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
(void)after;
(void)before;
(void)options;
- buffer_sprintf(b, "put %s.%s.%s %u " COLLECTED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t)rd->last_collected_time.tv_sec, rd->last_collected_value, hostname);
+
+ buffer_sprintf(
+ b
+ , "put %s.%s.%s %u " COLLECTED_NUMBER_FORMAT " host=%s\n"
+ , prefix
+ , st->id
+ , rd->id
+ , (uint32_t)rd->last_collected_time.tv_sec
+ , rd->last_collected_value
+ , hostname
+ );
+
return 1;
}
-static inline int format_dimension_stored_opentsdb_telnet(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+static inline int format_dimension_stored_opentsdb_telnet(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
+
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options);
+
if(!isnan(value)) {
- buffer_sprintf(b, "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t) before, value, hostname);
+
+ buffer_sprintf(
+ b
+ , "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s\n"
+ , prefix
+ , st->id
+ , rd->id
+ , (uint32_t) before
+ , value
+ , hostname
+ );
+
return 1;
}
return 0;
}
-static inline int process_graphite_response(BUFFER *b) {
- char sample[1024];
- const char *s = buffer_tostring(b);
- char *d = sample, *e = &sample[sizeof(sample) - 1];
+static inline int process_opentsdb_response(BUFFER *b) {
+ return discard_response(b, "opentsdb");
+}
- for(; *s && d < e ;s++) {
- char c = *s;
- if(unlikely(!isprint(c))) c = ' ';
- *d++ = c;
- }
- *d = '\0';
- info("Received %zu bytes from graphite backend. Ignoring them. Sample: '%s'", buffer_strlen(b), sample);
- buffer_flush(b);
- return 0;
+// ----------------------------------------------------------------------------
+// json backend
+
+static inline int format_dimension_collected_json_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
+ (void)host;
+ (void)after;
+ (void)before;
+ (void)options;
+
+ buffer_sprintf(b, "{"
+ "\"prefix\":\"%s\","
+ "\"hostname\":\"%s\","
+
+ "\"chart_id\":\"%s\","
+ "\"chart_name\":\"%s\","
+ "\"chart_family\":\"%s\","
+ "\"chart_context\": \"%s\","
+ "\"chart_type\":\"%s\","
+ "\"units\": \"%s\","
+
+ "\"id\":\"%s\","
+ "\"name\":\"%s\","
+ "\"value\":" COLLECTED_NUMBER_FORMAT ","
+
+ "\"timestamp\": %u}\n",
+ prefix,
+ hostname,
+
+ st->id,
+ st->name,
+ st->family,
+ st->context,
+ st->type,
+ st->units,
+
+ rd->id,
+ rd->name,
+ rd->last_collected_value,
+
+ (uint32_t)rd->last_collected_time.tv_sec
+ );
+
+ return 1;
}
-static inline int process_opentsdb_response(BUFFER *b) {
- char sample[1024];
- const char *s = buffer_tostring(b);
- char *d = sample, *e = &sample[sizeof(sample) - 1];
+static inline int format_dimension_stored_json_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
+ (void)host;
- for(; *s && d < e ;s++) {
- char c = *s;
- if(unlikely(!isprint(c))) c = ' ';
- *d++ = c;
- }
- *d = '\0';
+ calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options);
- info("Received %zu bytes from opentsdb backend. Ignoring them. Sample: '%s'", buffer_strlen(b), sample);
- buffer_flush(b);
+ if(!isnan(value)) {
+ buffer_sprintf(b, "{"
+ "\"prefix\":\"%s\","
+ "\"hostname\":\"%s\","
+
+ "\"chart_id\":\"%s\","
+ "\"chart_name\":\"%s\","
+ "\"chart_family\":\"%s\","
+ "\"chart_context\": \"%s\","
+ "\"chart_type\":\"%s\","
+ "\"units\": \"%s\","
+
+ "\"id\":\"%s\","
+ "\"name\":\"%s\","
+ "\"value\":" CALCULATED_NUMBER_FORMAT ","
+
+ "\"timestamp\": %u}\n",
+ prefix,
+ hostname,
+
+ st->id,
+ st->name,
+ st->family,
+ st->context,
+ st->type,
+ st->units,
+
+ rd->id,
+ rd->name,
+ value,
+
+ (uint32_t)before
+ );
+
+ return 1;
+ }
return 0;
}
+static inline int process_json_response(BUFFER *b) {
+ return discard_response(b, "json");
+}
+
+
+// ----------------------------------------------------------------------------
+// the backend thread
+
void *backends_main(void *ptr) {
+ int default_port = 0;
+ int sock = -1;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
BUFFER *b = buffer_create(1), *response = buffer_create(1);
- int (*backend_request_formatter)(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) = NULL;
- int (*backend_response_checker)(BUFFER *b) = NULL;
+ int (*backend_request_formatter)(BUFFER *, const char *, RRDHOST *, const char *, RRDSET *, RRDDIM *, time_t, time_t, uint32_t) = NULL;
+ int (*backend_response_checker)(BUFFER *) = NULL;
info("BACKEND thread created with task id %d", gettid());
@@ -150,22 +402,21 @@ void *backends_main(void *ptr) {
.tv_sec = 0,
.tv_usec = 0
};
- int default_port = 0;
- int sock = -1;
uint32_t options;
- int enabled = config_get_boolean("backend", "enabled", 0);
- const char *source = config_get("backend", "data source", "average");
- const char *type = config_get("backend", "type", "graphite");
- const char *destination = config_get("backend", "destination", "localhost");
- const char *prefix = config_get("backend", "prefix", "netdata");
- const char *hostname = config_get("backend", "hostname", localhost.hostname);
- int frequency = (int)config_get_number("backend", "update every", 10);
- int buffer_on_failures = (int)config_get_number("backend", "buffer on failures", 10);
- long timeoutms = config_get_number("backend", "timeout ms", frequency * 2 * 1000);
+ int enabled = config_get_boolean(CONFIG_SECTION_BACKEND, "enabled", 0);
+ const char *source = config_get(CONFIG_SECTION_BACKEND, "data source", "average");
+ const char *type = config_get(CONFIG_SECTION_BACKEND, "type", "graphite");
+ const char *destination = config_get(CONFIG_SECTION_BACKEND, "destination", "localhost");
+ const char *prefix = config_get(CONFIG_SECTION_BACKEND, "prefix", "netdata");
+ const char *hostname = config_get(CONFIG_SECTION_BACKEND, "hostname", localhost->hostname);
+ int frequency = (int)config_get_number(CONFIG_SECTION_BACKEND, "update every", 10);
+ int buffer_on_failures = (int)config_get_number(CONFIG_SECTION_BACKEND, "buffer on failures", 10);
+ long timeoutms = config_get_number(CONFIG_SECTION_BACKEND, "timeout ms", frequency * 2 * 1000);
// ------------------------------------------------------------------------
// validate configuration options
// and prepare for sending data to our backend
+
if(!enabled || frequency < 1)
goto cleanup;
@@ -183,23 +434,49 @@ void *backends_main(void *ptr) {
goto cleanup;
}
+ if(timeoutms < 1) {
+ error("BACKED invalid timeout %ld ms given. Assuming %d ms.", timeoutms, frequency * 2 * 1000);
+ timeoutms = frequency * 2 * 1000;
+ }
+ timeout.tv_sec = (timeoutms * 1000) / 1000000;
+ timeout.tv_usec = (timeoutms * 1000) % 1000000;
+
+
+ // ------------------------------------------------------------------------
+ // select the backend type
+
if(!strcmp(type, "graphite") || !strcmp(type, "graphite:plaintext")) {
+
default_port = 2003;
+ backend_response_checker = process_graphite_response;
+
if(options == BACKEND_SOURCE_DATA_AS_COLLECTED)
backend_request_formatter = format_dimension_collected_graphite_plaintext;
else
backend_request_formatter = format_dimension_stored_graphite_plaintext;
- backend_response_checker = process_graphite_response;
}
else if(!strcmp(type, "opentsdb") || !strcmp(type, "opentsdb:telnet")) {
+
default_port = 4242;
+ backend_response_checker = process_opentsdb_response;
+
if(options == BACKEND_SOURCE_DATA_AS_COLLECTED)
backend_request_formatter = format_dimension_collected_opentsdb_telnet;
else
backend_request_formatter = format_dimension_stored_opentsdb_telnet;
- backend_response_checker = process_opentsdb_response;
+ }
+ else if (!strcmp(type, "json") || !strcmp(type, "json:plaintext")) {
+
+ default_port = 5448;
+ backend_response_checker = process_json_response;
+
+ if (options == BACKEND_SOURCE_DATA_AS_COLLECTED)
+ backend_request_formatter = format_dimension_collected_json_plaintext;
+ else
+ backend_request_formatter = format_dimension_stored_json_plaintext;
+
}
else {
error("Unknown backend type '%s'", type);
@@ -211,15 +488,9 @@ void *backends_main(void *ptr) {
goto cleanup;
}
- if(timeoutms < 1) {
- error("BACKED invalid timeout %ld ms given. Assuming %d ms.", timeoutms, frequency * 2 * 1000);
- timeoutms = frequency * 2 * 1000;
- }
- timeout.tv_sec = (timeoutms * 1000) / 1000000;
- timeout.tv_usec = (timeoutms * 1000) % 1000000;
// ------------------------------------------------------------------------
- // prepare the charts for monitoring the backend
+ // prepare the charts for monitoring the backend operation
struct rusage thread;
@@ -238,32 +509,23 @@ void *backends_main(void *ptr) {
chart_backend_reconnects = 0,
chart_backend_latency = 0;
- RRDSET *chart_metrics = rrdset_find("netdata.backend_metrics");
- if(!chart_metrics) {
- chart_metrics = rrdset_create("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", 130600, frequency, RRDSET_TYPE_LINE);
- rrddim_add(chart_metrics, "buffered", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_metrics, "lost", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_metrics, "sent", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_metrics = rrdset_create_localhost("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", 130600, frequency, RRDSET_TYPE_LINE);
+ rrddim_add(chart_metrics, "buffered", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_metrics, "lost", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_metrics, "sent", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- RRDSET *chart_bytes = rrdset_find("netdata.backend_bytes");
- if(!chart_bytes) {
- chart_bytes = rrdset_create("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", 130610, frequency, RRDSET_TYPE_AREA);
- rrddim_add(chart_bytes, "buffered", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(chart_bytes, "lost", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(chart_bytes, "sent", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(chart_bytes, "received", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_bytes = rrdset_create_localhost("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", 130610, frequency, RRDSET_TYPE_AREA);
+ rrddim_add(chart_bytes, "buffered", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_bytes, "lost", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_bytes, "sent", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_bytes, "received", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- RRDSET *chart_ops = rrdset_find("netdata.backend_ops");
- if(!chart_ops) {
- chart_ops = rrdset_create("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", 130630, frequency, RRDSET_TYPE_LINE);
- rrddim_add(chart_ops, "write", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "discard", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "reconnect", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "failure", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_ops = rrdset_create_localhost("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", 130630, frequency, RRDSET_TYPE_LINE);
+ rrddim_add(chart_ops, "write", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "discard", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "reconnect", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "failure", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
/*
* this is misleading - we can only measure the time we need to send data
@@ -272,19 +534,14 @@ void *backends_main(void *ptr) {
*
* issue #1432 and https://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html
*
- RRDSET *chart_latency = rrdset_find("netdata.backend_latency");
- if(!chart_latency) {
- chart_latency = rrdset_create("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", 130620, frequency, RRDSET_TYPE_AREA);
- rrddim_add(chart_latency, "latency", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_latency = rrdset_create_localhost("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", 130620, frequency, RRDSET_TYPE_AREA);
+ rrddim_add(chart_latency, "latency", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
*/
- RRDSET *chart_rusage = rrdset_find("netdata.backend_thread_cpu");
- if(!chart_rusage) {
- chart_rusage = rrdset_create("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", 130630, frequency, RRDSET_TYPE_STACKED);
- rrddim_add(chart_rusage, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(chart_rusage, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- }
+ RRDSET *chart_rusage = rrdset_create_localhost("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", 130630, frequency, RRDSET_TYPE_STACKED);
+ rrddim_add(chart_rusage, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(chart_rusage, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+
// ------------------------------------------------------------------------
// prepare the backend main loop
@@ -292,49 +549,49 @@ void *backends_main(void *ptr) {
info("BACKEND configured ('%s' on '%s' sending '%s' data, every %d seconds, as host '%s', with prefix '%s')", type, destination, source, frequency, hostname, prefix);
usec_t step_ut = frequency * USEC_PER_SEC;
- usec_t random_ut = now_realtime_usec() % (step_ut / 2);
- time_t before = (time_t)((now_realtime_usec() - step_ut) / USEC_PER_SEC);
- time_t after = before;
+ time_t after = now_realtime_sec();
int failures = 0;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;;) {
- // ------------------------------------------------------------------------
- // wait for the next iteration point
- usec_t now_ut = now_realtime_usec();
- usec_t next_ut = now_ut - (now_ut % step_ut) + step_ut;
- before = (time_t)(next_ut / USEC_PER_SEC);
-
- // add a little delay (1/4 of the step) plus some randomness
- next_ut += (step_ut / 4) + random_ut;
+ // ------------------------------------------------------------------------
+ // Wait for the next iteration point.
+ heartbeat_next(&hb, step_ut);
+ time_t before = now_realtime_sec();
- while(now_ut < next_ut) {
- sleep_usec(next_ut - now_ut);
- now_ut = now_realtime_usec();
- }
// ------------------------------------------------------------------------
// add to the buffer the data we need to send to the backend
- RRDSET *st;
int pthreadoldcancelstate;
if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
error("Cannot set pthread cancel state to DISABLE.");
- rrdhost_rdlock(&localhost);
- for(st = localhost.rrdset_root; st ;st = st->next) {
- pthread_rwlock_rdlock(&st->rwlock);
+ rrd_rdlock();
+ RRDHOST *host;
+ rrdhost_foreach_read(host) {
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE)
+ continue;
- RRDDIM *rd;
- for(rd = st->dimensions; rd ;rd = rd->next) {
- if(rd->last_collected_time.tv_sec >= after)
- chart_buffered_metrics += backend_request_formatter(b, prefix, &localhost, hostname, st, rd, after, before, options);
- }
+ rrdhost_rdlock(host);
- pthread_rwlock_unlock(&st->rwlock);
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ rrdset_rdlock(st);
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ if(rd->last_collected_time.tv_sec >= after)
+ chart_buffered_metrics += backend_request_formatter(b, prefix, host, (host == localhost)?hostname:host->hostname, st, rd, after, before, options);
+ }
+ rrdset_unlock(st);
+ }
+ rrdhost_unlock(host);
}
- rrdhost_unlock(&localhost);
+ rrd_unlock();
if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
@@ -360,6 +617,10 @@ void *backends_main(void *ptr) {
//fprintf(stderr, "\nBACKEND BEGIN:\n%s\nBACKEND END\n", buffer_tostring(b)); // FIXME
//fprintf(stderr, "after = %lu, before = %lu\n", after, before);
+ // prepare for the next iteration
+ // to add incrementally data to buffer
+ after = before;
+
// ------------------------------------------------------------------------
// if we are connected, receive a response, without blocking
@@ -399,28 +660,13 @@ void *backends_main(void *ptr) {
// if we are not connected, connect to a backend server
if(unlikely(sock == -1)) {
- usec_t start_ut = now_realtime_usec();
- const char *s = destination;
- while(*s) {
- const char *e = s;
-
- // skip separators, moving both s(tart) and e(nd)
- while(isspace(*e) || *e == ',') s = ++e;
-
- // move e(nd) to the first separator
- while(*e && !isspace(*e) && *e != ',') e++;
-
- // is there anything?
- if(!*s || s == e) break;
-
- char buf[e - s + 1];
- strncpyz(buf, s, e - s);
- chart_backend_reconnects++;
- sock = connect_to(buf, default_port, &timeout);
- if(sock != -1) break;
- s = e;
- }
- chart_backend_latency += now_realtime_usec() - start_ut;
+ usec_t start_ut = now_monotonic_usec();
+ size_t reconnects = 0;
+
+ sock = connect_to_one_of(destination, default_port, &timeout, &reconnects, NULL, 0);
+
+ chart_backend_reconnects += reconnects;
+ chart_backend_latency += now_monotonic_usec() - start_ut;
}
if(unlikely(netdata_exit)) break;
@@ -430,14 +676,14 @@ void *backends_main(void *ptr) {
if(likely(sock != -1)) {
size_t len = buffer_strlen(b);
- usec_t start_ut = now_realtime_usec();
+ usec_t start_ut = now_monotonic_usec();
int flags = 0;
#ifdef MSG_NOSIGNAL
flags += MSG_NOSIGNAL;
#endif
ssize_t written = send(sock, buffer_tostring(b), len, flags);
- chart_backend_latency += now_realtime_usec() - start_ut;
+ chart_backend_latency += now_monotonic_usec() - start_ut;
if(written != -1 && (size_t)written == len) {
// we sent the data successfully
chart_transmission_successes++;
@@ -465,12 +711,6 @@ void *backends_main(void *ptr) {
close(sock);
sock = -1;
}
-
- // either the buffer is empty
- // or is holding the data we couldn't send
- // so, make sure the next iteration will continue
- // from where we are now
- after = before;
}
else {
error("Failed to update database backend '%s'", destination);
@@ -495,7 +735,7 @@ void *backends_main(void *ptr) {
// ------------------------------------------------------------------------
// update the monitoring charts
- if(chart_ops->counter_done) rrdset_next(chart_ops);
+ if(likely(chart_ops->counter_done)) rrdset_next(chart_ops);
rrddim_set(chart_ops, "read", chart_receptions);
rrddim_set(chart_ops, "write", chart_transmission_successes);
rrddim_set(chart_ops, "discard", chart_data_lost_events);
@@ -503,13 +743,13 @@ void *backends_main(void *ptr) {
rrddim_set(chart_ops, "reconnect", chart_backend_reconnects);
rrdset_done(chart_ops);
- if(chart_metrics->counter_done) rrdset_next(chart_metrics);
+ if(likely(chart_metrics->counter_done)) rrdset_next(chart_metrics);
rrddim_set(chart_metrics, "buffered", chart_buffered_metrics);
rrddim_set(chart_metrics, "lost", chart_lost_metrics);
rrddim_set(chart_metrics, "sent", chart_sent_metrics);
rrdset_done(chart_metrics);
- if(chart_bytes->counter_done) rrdset_next(chart_bytes);
+ if(likely(chart_bytes->counter_done)) rrdset_next(chart_bytes);
rrddim_set(chart_bytes, "buffered", chart_buffered_bytes);
rrddim_set(chart_bytes, "lost", chart_lost_bytes);
rrddim_set(chart_bytes, "sent", chart_sent_bytes);
@@ -517,13 +757,13 @@ void *backends_main(void *ptr) {
rrdset_done(chart_bytes);
/*
- if(chart_latency->counter_done) rrdset_next(chart_latency);
+ if(likely(chart_latency->counter_done)) rrdset_next(chart_latency);
rrddim_set(chart_latency, "latency", chart_backend_latency);
rrdset_done(chart_latency);
*/
getrusage(RUSAGE_THREAD, &thread);
- if(chart_rusage->counter_done) rrdset_next(chart_rusage);
+ if(likely(chart_rusage->counter_done)) rrdset_next(chart_rusage);
rrddim_set(chart_rusage, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
rrddim_set(chart_rusage, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
rrdset_done(chart_rusage);
diff --git a/src/clocks.c b/src/clocks.c
index c90a07c2f..879ebf911 100644
--- a/src/clocks.c
+++ b/src/clocks.c
@@ -6,64 +6,89 @@ inline int clock_gettime(clockid_t clk_id, struct timespec *ts) {
if(unlikely(gettimeofday(&tv, NULL) == -1))
return -1;
ts->tv_sec = tv.tv_sec;
- ts->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+ ts->tv_nsec = (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC;
return 0;
}
#endif
-inline time_t now_realtime_sec(void) {
+static inline time_t now_sec(clockid_t clk_id) {
struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_REALTIME, &ts) == -1))
+ if(unlikely(clock_gettime(clk_id, &ts) == -1))
return 0;
return ts.tv_sec;
}
-inline int now_realtime_timeval(struct timeval *tv) {
+static inline usec_t now_usec(clockid_t clk_id) {
+ struct timespec ts;
+ if(unlikely(clock_gettime(clk_id, &ts) == -1))
+ return 0;
+ return (usec_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
+}
+
+static inline int now_timeval(clockid_t clk_id, struct timeval *tv) {
struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_REALTIME, &ts) == -1))
+
+ if(unlikely(clock_gettime(clk_id, &ts) == -1)) {
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
return -1;
+ }
+
tv->tv_sec = ts.tv_sec;
- tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ tv->tv_usec = (suseconds_t)((ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC);
return 0;
}
+inline time_t now_realtime_sec(void) {
+ return now_sec(CLOCK_REALTIME);
+}
+
inline usec_t now_realtime_usec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_REALTIME, &ts) == -1))
- return 0;
- return (usec_t)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
+ return now_usec(CLOCK_REALTIME);
+}
+
+inline int now_realtime_timeval(struct timeval *tv) {
+ return now_timeval(CLOCK_REALTIME, tv);
}
inline time_t now_monotonic_sec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_MONOTONIC, &ts) == -1))
- return 0;
- return ts.tv_sec;
+ return now_sec(CLOCK_MONOTONIC);
}
inline usec_t now_monotonic_usec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_MONOTONIC, &ts) == -1))
- return 0;
- return (usec_t)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
+ return now_usec(CLOCK_MONOTONIC);
+}
+
+inline int now_monotonic_timeval(struct timeval *tv) {
+ return now_timeval(CLOCK_MONOTONIC, tv);
}
inline time_t now_boottime_sec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_BOOTTIME, &ts) == -1))
- return 0;
- return ts.tv_sec;
+ return now_sec(CLOCK_BOOTTIME);
}
inline usec_t now_boottime_usec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_BOOTTIME, &ts) == -1))
- return 0;
- return (usec_t)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
+ return now_usec(CLOCK_BOOTTIME);
+}
+
+inline int now_boottime_timeval(struct timeval *tv) {
+ return now_timeval(CLOCK_BOOTTIME, tv);
}
inline usec_t timeval_usec(struct timeval *tv) {
- return (usec_t)tv->tv_sec * USEC_PER_SEC + tv->tv_usec;
+ return (usec_t)tv->tv_sec * USEC_PER_SEC + (tv->tv_usec % USEC_PER_SEC);
+}
+
+inline msec_t timeval_msec(struct timeval *tv) {
+ return (msec_t)tv->tv_sec * MSEC_PER_SEC + ((tv->tv_usec % USEC_PER_SEC) / MSEC_PER_SEC);
+}
+
+inline susec_t dt_usec_signed(struct timeval *now, struct timeval *old) {
+ usec_t ts1 = timeval_usec(now);
+ usec_t ts2 = timeval_usec(old);
+
+ if(likely(ts1 >= ts2)) return (susec_t)(ts1 - ts2);
+ return -((susec_t)(ts2 - ts1));
}
inline usec_t dt_usec(struct timeval *now, struct timeval *old) {
@@ -71,3 +96,38 @@ inline usec_t dt_usec(struct timeval *now, struct timeval *old) {
usec_t ts2 = timeval_usec(old);
return (ts1 > ts2) ? (ts1 - ts2) : (ts2 - ts1);
}
+
+inline void heartbeat_init(heartbeat_t *hb)
+{
+ *hb = 0ULL;
+}
+
+usec_t heartbeat_next(heartbeat_t *hb, usec_t tick)
+{
+ heartbeat_t now = now_monotonic_usec();
+ usec_t next = now - (now % tick) + tick;
+
+ while(now < next) {
+ sleep_usec(next - now);
+ now = now_monotonic_usec();
+ }
+
+ if(likely(*hb != 0ULL)) {
+ usec_t dt = now - *hb;
+ *hb = now;
+ if(unlikely(dt / tick > 1))
+ error("heartbeat missed between %llu usec and %llu usec", *hb, now);
+ return dt;
+ }
+ else {
+ *hb = now;
+ return 0ULL;
+ }
+}
+
+inline usec_t heartbeat_dt_usec(heartbeat_t *hb)
+{
+ if(!*hb)
+ return 0ULL;
+ return now_monotonic_usec() - *hb;
+}
diff --git a/src/clocks.h b/src/clocks.h
index c1b8e7017..197b5431f 100644
--- a/src/clocks.h
+++ b/src/clocks.h
@@ -12,9 +12,12 @@ struct timespec {
typedef int clockid_t;
#endif
-#ifndef HAVE_CLOCK_GETTIME
-int clock_gettime(clockid_t clk_id, struct timespec *ts);
-#endif
+typedef unsigned long long nsec_t;
+typedef unsigned long long msec_t;
+typedef unsigned long long usec_t;
+typedef long long susec_t;
+
+typedef usec_t heartbeat_t;
/* Linux value is as good as any other */
#ifndef CLOCK_REALTIME
@@ -27,20 +30,30 @@ int clock_gettime(clockid_t clk_id, struct timespec *ts);
#endif
#ifndef CLOCK_BOOTTIME
-/* fallback to CLOCK_MONOTONIC if not available */
+
+#ifdef CLOCK_UPTIME
+/* CLOCK_BOOTTIME falls back to CLOCK_UPTIME on FreeBSD */
+#define CLOCK_BOOTTIME CLOCK_UPTIME
+#else // CLOCK_UPTIME
+/* CLOCK_BOOTTIME falls back to CLOCK_MONOTONIC */
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
-#else
+#endif // CLOCK_UPTIME
+
+#else // CLOCK_BOOTTIME
+
#ifdef HAVE_CLOCK_GETTIME
#define CLOCK_BOOTTIME_IS_AVAILABLE 1 // required for /proc/uptime
-#endif
-#endif
+#endif // HAVE_CLOCK_GETTIME
-typedef unsigned long long usec_t;
+#endif // CLOCK_BOOTTIME
-#define NSEC_PER_SEC 1000000000ULL
#define NSEC_PER_MSEC 1000000ULL
+
+#define NSEC_PER_SEC 1000000000ULL
#define NSEC_PER_USEC 1000ULL
+
#define USEC_PER_SEC 1000000ULL
+#define MSEC_PER_SEC 1000ULL
#ifndef HAVE_CLOCK_GETTIME
/* Fallback function for POSIX.1-2001 clock_gettime() function.
@@ -52,41 +65,58 @@ typedef unsigned long long usec_t;
extern int clock_gettime(clockid_t clk_id, struct timespec *ts);
#endif
-/* Fills struct timeval with time since EPOCH from real-time clock (i.e. wall-clock).
- * - Hibernation/suspend time is included
- * - adjtime()/NTP adjustments affect this clock
- * Return 0 on succes, -1 else with errno set appropriately.
+/*
+ * Three clocks are available (cf. man 3 clock_gettime):
+ *
+ * REALTIME clock (i.e. wall-clock):
+ * This clock is affected by discontinuous jumps in the system time
+ * (e.g., if the system administrator manually changes the clock), and by the incremental adjustments performed by adjtime(3) and NTP.
+ *
+ * MONOTONIC clock
+ * Clock that cannot be set and represents monotonic time since some unspecified starting point.
+ * This clock is not affected by discontinuous jumps in the system time
+ * (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP.
+ * If not available on the system, this clock falls back to REALTIME clock.
+ *
+ * BOOTTIME clock
+ * Identical to CLOCK_MONOTONIC, except it also includes any time that the system is suspended.
+ * This allows applications to get a suspend-aware monotonic clock without having to deal with the complications of CLOCK_REALTIME,
+ * which may have discontinuities if the time is changed using settimeofday(2).
+ * If not available on the system, this clock falls back to MONOTONIC clock.
+ *
+ * All now_*_timeval() functions fill the `struct timeval` with the time from the appropriate clock.
+ * Those functions return 0 on success, -1 else with errno set appropriately.
+ *
+ * All now_*_sec() functions return the time in seconds from the approriate clock, or 0 on error.
+ * All now_*_usec() functions return the time in microseconds from the approriate clock, or 0 on error.
*/
extern int now_realtime_timeval(struct timeval *tv);
-
-/* Returns time since EPOCH from real-time clock (i.e. wall-clock).
- * - Hibernation/suspend time is included
- * - adjtime()/NTP adjustments affect this clock
- */
extern time_t now_realtime_sec(void);
extern usec_t now_realtime_usec(void);
-/* Returns time from monotonic clock if available, real-time clock else.
- * If monotonic clock is available:
- * - hibernation/suspend time is not included
- * - adjtime()/NTP adjusments affect this clock
- * If monotonic clock is not available, this fallbacks to now_realtime().
- */
+extern int now_monotonic_timeval(struct timeval *tv);
extern time_t now_monotonic_sec(void);
extern usec_t now_monotonic_usec(void);
-/* Returns time from boottime clock if available,
- * monotonic clock else if available, real-time clock else.
- * If boottime clock is available:
- * - hibernation/suspend time is included
- * - adjtime()/NTP adjusments affect this clock
- * If boottime clock is not available, this fallbacks to now_monotonic().
- * If monotonic clock is not available, this fallbacks to now_realtime().
- */
+extern int now_boottime_timeval(struct timeval *tv);
extern time_t now_boottime_sec(void);
extern usec_t now_boottime_usec(void);
+
extern usec_t timeval_usec(struct timeval *ts);
+extern msec_t timeval_msec(struct timeval *tv);
+
extern usec_t dt_usec(struct timeval *now, struct timeval *old);
+extern susec_t dt_usec_signed(struct timeval *now, struct timeval *old);
+
+extern void heartbeat_init(heartbeat_t *hb);
+
+/* Sleeps until next multiple of tick using monotonic clock.
+ * Returns elapsed time in microseconds since previous heartbeat
+ */
+extern usec_t heartbeat_next(heartbeat_t *hb, usec_t tick);
+
+/* Returns elapsed time in microseconds since last heartbeat */
+extern usec_t heartbeat_dt_usec(heartbeat_t *hb);
#endif /* NETDATA_CLOCKS_H */
diff --git a/src/common.c b/src/common.c
index 42f3d8d15..88fcf85bc 100644
--- a/src/common.c
+++ b/src/common.c
@@ -8,10 +8,21 @@
# define MADV_DONTFORK INHERIT_NONE
#endif /* __FreeBSD__ || __APPLE__*/
-char *global_host_prefix = "";
+char *netdata_configured_hostname = NULL;
+char *netdata_configured_config_dir = NULL;
+char *netdata_configured_log_dir = NULL;
+char *netdata_configured_plugins_dir = NULL;
+char *netdata_configured_web_dir = NULL;
+char *netdata_configured_cache_dir = NULL;
+char *netdata_configured_varlib_dir = NULL;
+char *netdata_configured_home_dir = NULL;
+char *netdata_configured_host_prefix = NULL;
+
int enable_ksm = 1;
volatile sig_atomic_t netdata_exit = 0;
+const char *os_type = NETDATA_OS_TYPE;
+const char *program_version = VERSION;
// ----------------------------------------------------------------------------
// memory allocation functions that handle failures
@@ -903,6 +914,9 @@ char *trim(char *s) {
}
void *mymmap(const char *filename, size_t size, int flags, int ksm) {
+#ifndef MADV_MERGEABLE
+ (void)ksm;
+#endif
static int log_madvise_1 = 1;
#ifdef MADV_MERGEABLE
static int log_madvise_2 = 1, log_madvise_3 = 1;
@@ -1060,17 +1074,6 @@ char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
return s;
}
-char *strncpyz(char *dst, const char *src, size_t n) {
- char *p = dst;
-
- while (*src && n--)
- *dst++ = *src++;
-
- *dst = '\0';
-
- return p;
-}
-
int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
int size = vsnprintf(dst, n, fmt, args);
@@ -1104,7 +1107,17 @@ long get_system_cpus(void) {
#ifdef __APPLE__
int32_t tmp_processors;
- if (unlikely(GETSYSCTL("hw.logicalcpu", tmp_processors))) {
+ if (unlikely(GETSYSCTL_BY_NAME("hw.logicalcpu", tmp_processors))) {
+ error("Assuming system has %d processors.", processors);
+ } else {
+ processors = tmp_processors;
+ }
+
+ return processors;
+ #elif __FreeBSD__
+ int32_t tmp_processors;
+
+ if (unlikely(GETSYSCTL_BY_NAME("hw.ncpu", tmp_processors))) {
error("Assuming system has %d processors.", processors);
} else {
processors = tmp_processors;
@@ -1114,7 +1127,7 @@ long get_system_cpus(void) {
#else
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix);
procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
if(!ff) {
@@ -1143,7 +1156,7 @@ long get_system_cpus(void) {
debug(D_SYSTEM, "System has %d processors.", processors);
return processors;
- #endif /* __APPLE__ */
+ #endif /* __APPLE__, __FreeBSD__ */
}
pid_t pid_max = 32768;
@@ -1153,35 +1166,41 @@ pid_t get_system_pid_max(void) {
// we use the number defined in bsd/sys/proc_internal.h in XNU sources
pid_max = 99999;
return pid_max;
+ #elif __FreeBSD__
+ int32_t tmp_pid_max;
+
+ if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
+ pid_max = 99999;
+ error("Assuming system's maximum pid is %d.", pid_max);
+ } else {
+ pid_max = tmp_pid_max;
+ }
+
+ return pid_max;
#else
+ static char read = 0;
+ if(unlikely(read)) return pid_max;
+ read = 1;
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", global_host_prefix);
- procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
- if(!ff) {
- error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
- return pid_max;
- }
+ snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix);
- ff = procfile_readall(ff);
- if(!ff) {
- error("Cannot read file '%s'. Assuming system supports %d pids.", filename, pid_max);
+ unsigned long long max = 0;
+ if(read_single_number_file(filename, &max) != 0) {
+ error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
return pid_max;
}
- pid_max = (pid_t)str2i(procfile_lineword(ff, 0, 0));
- if(!pid_max) {
- procfile_close(ff);
- pid_max = 32768;
+ if(!max) {
error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max);
return pid_max;
}
- procfile_close(ff);
- debug(D_SYSTEM, "System supports %d pids.", pid_max);
+ pid_max = (pid_t) max;
return pid_max;
- #endif /* __APPLE__ */
+ #endif /* __APPLE__, __FreeBSD__ */
}
unsigned int hz;
diff --git a/src/common.h b/src/common.h
index e38e95b48..b82c078fa 100644
--- a/src/common.h
+++ b/src/common.h
@@ -67,9 +67,9 @@
#include <syslog.h>
#include <sys/mman.h>
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
-#endif /* __FreeBSD__ || __APPLE__*/
+#endif
#include <sys/resource.h>
#include <sys/socket.h>
@@ -109,6 +109,10 @@
#include <zlib.h>
#endif
+#ifdef HAVE_CAPABILITY
+#include <sys/capability.h>
+#endif
+
// ----------------------------------------------------------------------------
// netdata common definitions
@@ -164,10 +168,11 @@
// ----------------------------------------------------------------------------
// netdata include files
-#include "simple_pattern.h"
-#include "avl.h"
#include "clocks.h"
#include "log.h"
+#include "locks.h"
+#include "simple_pattern.h"
+#include "avl.h"
#include "global_statistics.h"
#include "storage_number.h"
#include "web_buffer.h"
@@ -184,21 +189,26 @@
#include "plugin_nfacct.h"
#if defined(__FreeBSD__)
+#include <pthread_np.h>
#include "plugin_freebsd.h"
+#define NETDATA_OS_TYPE "freebsd"
#elif defined(__APPLE__)
#include "plugin_macos.h"
+#define NETDATA_OS_TYPE "macos"
#else
#include "plugin_proc.h"
#include "plugin_proc_diskspace.h"
+#define NETDATA_OS_TYPE "linux"
#endif /* __FreeBSD__, __APPLE__*/
-#include "plugin_tc.h"
-#include "plugins_d.h"
#include "socket.h"
#include "eval.h"
#include "health.h"
#include "rrd.h"
+#include "plugin_tc.h"
+#include "plugins_d.h"
#include "rrd2json.h"
+#include "rrd2json_api_old.h"
#include "web_client.h"
#include "web_server.h"
#include "registry.h"
@@ -209,6 +219,19 @@
#include "backends.h"
#include "inlined.h"
#include "adaptive_resortable_list.h"
+#include "rrdpush.h"
+#include "web_api_v1.h"
+#include "web_api_old.h"
+
+extern char *netdata_configured_hostname;
+extern char *netdata_configured_config_dir;
+extern char *netdata_configured_log_dir;
+extern char *netdata_configured_plugins_dir;
+extern char *netdata_configured_web_dir;
+extern char *netdata_configured_cache_dir;
+extern char *netdata_configured_varlib_dir;
+extern char *netdata_configured_home_dir;
+extern char *netdata_configured_host_prefix;
extern void netdata_fix_chart_id(char *s);
extern void netdata_fix_chart_name(char *s);
@@ -217,7 +240,6 @@ extern void strreverse(char* begin, char* end);
extern char *mystrsep(char **ptr, char *s);
extern char *trim(char *s);
-extern char *strncpyz(char *dst, const char *src, size_t n);
extern int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args);
extern int snprintfz(char *dst, size_t n, const char *fmt, ...) PRINTFLIKE(3, 4);
@@ -249,7 +271,6 @@ extern int savememory(const char *filename, void *mem, size_t size);
extern int fd_is_valid(int fd);
-extern char *global_host_prefix;
extern int enable_ksm;
extern pid_t gettid(void);
@@ -268,6 +289,10 @@ extern pid_t get_system_pid_max(void);
extern unsigned int hz;
extern void get_system_HZ(void);
+extern volatile sig_atomic_t netdata_exit;
+extern const char *os_type;
+
+extern const char *program_version;
/* fix for alpine linux */
#ifndef RUSAGE_THREAD
diff --git a/src/daemon.c b/src/daemon.c
index 4fd8ca5e5..42b04c401 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -27,7 +27,7 @@ void sig_handler_save(int signo)
if(signo) {
error_log_limit_unlimited();
info("Received signal %d to save the database...", signo);
- rrdset_save_all();
+ rrdhost_save_all();
error_log_limit_reset();
}
}
@@ -84,8 +84,8 @@ int become_user(const char *username, int pid_fd)
uid_t uid = pw->pw_uid;
gid_t gid = pw->pw_gid;
- create_needed_dir(CACHE_DIR, uid, gid);
- create_needed_dir(VARLIB_DIR, uid, gid);
+ create_needed_dir(netdata_configured_cache_dir, uid, gid);
+ create_needed_dir(netdata_configured_varlib_dir, uid, gid);
if(pidfile[0]) {
if(chown(pidfile, uid, gid) == -1)
@@ -155,13 +155,15 @@ int become_user(const char *username, int pid_fd)
return(0);
}
-void oom_score_adj(int score) {
+static void oom_score_adj(void) {
+ int score = (int)config_get_number(CONFIG_SECTION_GLOBAL, "OOM score", 1000);
+
int done = 0;
int fd = open("/proc/self/oom_score_adj", O_WRONLY);
if(fd != -1) {
char buf[10 + 1];
ssize_t len = snprintfz(buf, 10, "%d", score);
- if(write(fd, buf, len) == len) done = 1;
+ if(len > 0 && write(fd, buf, (size_t)len) == len) done = 1;
close(fd);
}
@@ -171,23 +173,130 @@ void oom_score_adj(int score) {
debug(D_SYSTEM, "Adjusted my Out-Of-Memory score to %d.", score);
}
-int sched_setscheduler_idle(void) {
+static void process_nice_level(void) {
+#ifdef HAVE_NICE
+ int nice_level = (int)config_get_number(CONFIG_SECTION_GLOBAL, "process nice level", 19);
+ if(nice(nice_level) == -1) error("Cannot set netdata CPU nice level to %d.", nice_level);
+ else debug(D_SYSTEM, "Set netdata nice level to %d.", nice_level);
+#endif // HAVE_NICE
+};
+
+#ifdef HAVE_SCHED_SETSCHEDULER
+
+#define SCHED_FLAG_NONE 0x00
+#define SCHED_FLAG_PRIORITY_CONFIGURABLE 0x01 // the priority is user configurable
+#define SCHED_FLAG_KEEP_AS_IS 0x04 // do not attempt to set policy, priority or nice()
+#define SCHED_FLAG_USE_NICE 0x08 // use nice() after setting this policy
+
+struct sched_def {
+ char *name;
+ int policy;
+ int priority;
+ uint8_t flags;
+} scheduler_defaults[] = {
+
+ // the order of array members is important!
+ // the first defined is the default used by netdata
+
+ // the available members are important too!
+ // these are all the possible scheduling policies supported by netdata
+
#ifdef SCHED_IDLE
- const struct sched_param param = {
- .sched_priority = 0
- };
+ { "idle", SCHED_IDLE, 0, SCHED_FLAG_NONE },
+#endif
- int i = sched_setscheduler(0, SCHED_IDLE, &param);
- if(i != 0)
- error("Cannot adjust my scheduling priority to IDLE.");
- else
- debug(D_SYSTEM, "Adjusted my scheduling priority to IDLE.");
+#ifdef SCHED_OTHER
+ { "nice", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE },
+ { "other", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE },
+#endif
- return i;
-#else
- return -1;
+#ifdef SCHED_RR
+ { "rr", SCHED_RR, 0, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_FIFO
+ { "fifo", SCHED_FIFO, 0, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_BATCH
+ { "batch", SCHED_BATCH, 0, SCHED_FLAG_USE_NICE },
+#endif
+
+ // do not change the scheduling priority
+ { "keep", 0, 0, SCHED_FLAG_KEEP_AS_IS },
+ { "none", 0, 0, SCHED_FLAG_KEEP_AS_IS },
+
+ // array termination
+ { NULL, 0, 0, 0 }
+};
+
+static void sched_setscheduler_set(void) {
+
+ if(scheduler_defaults[0].name) {
+ const char *name = scheduler_defaults[0].name;
+ int policy = scheduler_defaults[0].policy, priority = scheduler_defaults[0].priority;
+ uint8_t flags = scheduler_defaults[0].flags;
+ int found = 0;
+
+ // read the configuration
+ name = config_get(CONFIG_SECTION_GLOBAL, "process scheduling policy", name);
+ int i;
+ for(i = 0 ; scheduler_defaults[i].name ; i++) {
+ if(!strcmp(name, scheduler_defaults[i].name)) {
+ found = 1;
+ priority = scheduler_defaults[i].priority;
+ flags = scheduler_defaults[i].flags;
+
+ if(flags & SCHED_FLAG_KEEP_AS_IS)
+ return;
+
+ if(flags & SCHED_FLAG_PRIORITY_CONFIGURABLE)
+ priority = (int)config_get_number(CONFIG_SECTION_GLOBAL, "process scheduling priority", priority);
+
+#ifdef HAVE_SCHED_GET_PRIORITY_MIN
+ if(priority < sched_get_priority_min(policy)) {
+ error("scheduler %s priority %d is below the minimum %d. Using the minimum.", name, priority, sched_get_priority_min(policy));
+ priority = sched_get_priority_min(policy);
+ }
+#endif
+#ifdef HAVE_SCHED_GET_PRIORITY_MAX
+ if(priority > sched_get_priority_max(policy)) {
+ error("scheduler %s priority %d is above the maximum %d. Using the maximum.", name, priority, sched_get_priority_max(policy));
+ priority = sched_get_priority_max(policy);
+ }
#endif
+ break;
+ }
+ }
+
+ if(!found) {
+ error("Unknown scheduling policy %s - falling back to nice()", name);
+ goto fallback;
+ }
+
+ const struct sched_param param = {
+ .sched_priority = priority
+ };
+
+ i = sched_setscheduler(0, policy, &param);
+ if(i != 0) {
+ error("Cannot adjust netdata scheduling policy to %s (%d), with priority %d. Falling back to nice", name, policy, priority);
+ }
+ else {
+ debug(D_SYSTEM, "Adjusted netdata scheduling policy to %s (%d), with priority %d.", name, policy, priority);
+ if(!(flags & SCHED_FLAG_USE_NICE))
+ return;
+ }
+ }
+
+fallback:
+ process_nice_level();
}
+#else
+static void sched_setscheduler_set(void) {
+ process_nice_level();
+}
+#endif
int become_daemon(int dont_fork, const char *user)
{
@@ -239,13 +348,10 @@ int become_daemon(int dont_fork, const char *user)
umask(0007);
// adjust my Out-Of-Memory score
- oom_score_adj(1000);
+ oom_score_adj();
// never become a problem
- if(sched_setscheduler_idle() != 0) {
- if(nice(19) == -1) error("Cannot lower my CPU priority.");
- else debug(D_SYSTEM, "Set my nice value to 19.");
- }
+ sched_setscheduler_set();
if(user && *user) {
if(become_user(user, pidfd) != 0) {
@@ -254,8 +360,8 @@ int become_daemon(int dont_fork, const char *user)
else debug(D_SYSTEM, "Successfully became user '%s'.", user);
}
else {
- create_needed_dir(CACHE_DIR, getuid(), getgid());
- create_needed_dir(VARLIB_DIR, getuid(), getgid());
+ create_needed_dir(netdata_configured_cache_dir, getuid(), getgid());
+ create_needed_dir(netdata_configured_varlib_dir, getuid(), getgid());
}
if(pidfd != -1)
diff --git a/src/dictionary.c b/src/dictionary.c
index fb9efeedb..512b4bbe6 100644
--- a/src/dictionary.c
+++ b/src/dictionary.c
@@ -31,21 +31,21 @@ static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) {
static inline void dictionary_read_lock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary READ lock");
- pthread_rwlock_rdlock(dict->rwlock);
+ netdata_rwlock_rdlock(dict->rwlock);
}
}
static inline void dictionary_write_lock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary WRITE lock");
- pthread_rwlock_wrlock(dict->rwlock);
+ netdata_rwlock_wrlock(dict->rwlock);
}
}
static inline void dictionary_unlock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary UNLOCK lock");
- pthread_rwlock_unlock(dict->rwlock);
+ netdata_rwlock_unlock(dict->rwlock);
}
}
@@ -135,8 +135,8 @@ DICTIONARY *dictionary_create(uint8_t flags) {
dict->stats = callocz(1, sizeof(struct dictionary_stats));
if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
- dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
- pthread_rwlock_init(dict->rwlock, NULL);
+ dict->rwlock = callocz(1, sizeof(netdata_rwlock_t));
+ netdata_rwlock_init(dict->rwlock);
}
avl_init(&dict->values_index, name_value_compare);
@@ -158,8 +158,10 @@ void dictionary_destroy(DICTIONARY *dict) {
if(dict->stats)
freez(dict->stats);
- if(dict->rwlock)
+ if(dict->rwlock) {
+ netdata_rwlock_destroy(dict->rwlock);
freez(dict->rwlock);
+ }
freez(dict);
}
diff --git a/src/dictionary.h b/src/dictionary.h
index 6bebbfa85..f028dbb30 100644
--- a/src/dictionary.h
+++ b/src/dictionary.h
@@ -24,7 +24,7 @@ typedef struct dictionary {
uint8_t flags;
struct dictionary_stats *stats;
- pthread_rwlock_t *rwlock;
+ netdata_rwlock_t *rwlock;
} DICTIONARY;
#define DICTIONARY_FLAG_DEFAULT 0x00000000
diff --git a/src/freebsd_sysctl.c b/src/freebsd_sysctl.c
index 9400089db..965c1cbbf 100644
--- a/src/freebsd_sysctl.c
+++ b/src/freebsd_sysctl.c
@@ -1,1116 +1,1309 @@
#include "common.h"
-// NEEDED BY: struct vmtotal, struct vmmeter
#include <sys/vmmeter.h>
-// NEEDED BY: struct devstat
#include <sys/devicestat.h>
-// NEEDED BY: struct xswdev
+#include <sys/mount.h>
#include <vm/vm_param.h>
-// NEEDED BY: struct semid_kernel, struct shmid_kernel, struct msqid_kernel
+
#define _KERNEL
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#undef _KERNEL
-// NEEDED BY: struct sysctl_netisr_workstream, struct sysctl_netisr_work
+
#include <net/netisr.h>
-// NEEDED BY: struct ifaddrs, getifaddrs()
#include <net/if.h>
#include <ifaddrs.h>
-// NEEDED BY do_tcp...
-#include <netinet/tcp_var.h>
-#include <netinet/tcp_fsm.h>
-// NEEDED BY do_udp..., do_ip...
-#include <netinet/ip_var.h>
-// NEEDED BY do_udp...
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-// NEEDED BY do_icmp...
+
#include <netinet/ip.h>
+#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
-// NEEDED BY do_ip6...
#include <netinet6/ip6_var.h>
-// NEEDED BY do_icmp6...
#include <netinet/icmp6.h>
-// NEEDED BY do_space, do_inodes
-#include <sys/mount.h>
-// NEEDED BY do_uptime
-#include <time.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+// --------------------------------------------------------------------------------------------------------------------
+// common definitions and variables
#define KILO_FACTOR 1024
#define MEGA_FACTOR 1048576 // 1024 * 1024
#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024
-// NEEDED BY: do_disk_io
-#define RRD_TYPE_DISK "disk"
+#define MAX_INT_DIGITS 10 // maximum number of digits for int
-// FreeBSD calculates load averages once every 5 seconds
-#define MIN_LOADAVG_UPDATE_EVERY 5
+int system_pagesize = PAGE_SIZE;
+int number_of_cpus = 1;
-// NEEDED BY: do_bandwidth
-#define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+// --------------------------------------------------------------------------------------------------------------------
+// FreeBSD plugin initialization
-int do_freebsd_sysctl(int update_every, usec_t dt) {
- (void)dt;
-
- static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
- do_loadavg = -1, do_all_processes = -1, do_disk_io = -1, do_swap = -1, do_ram = -1, do_swapio = -1,
- do_pgfaults = -1, do_committed = -1, do_ipc_semaphores = -1, do_ipc_shared_mem = -1, do_ipc_msg_queues = -1,
- do_dev_intr = -1, do_soft_intr = -1, do_netisr = -1, do_netisr_per_core = -1, do_bandwidth = -1,
- do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
- do_ecn = -1, do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1,
- do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1,
- do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
- do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1,
- do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
- do_icmp6_neighbor = -1, do_icmp6_types = -1, do_space = -1, do_inodes = -1, do_uptime = -1;
-
- if (unlikely(do_cpu == -1)) {
- do_cpu = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
- do_cpu_cores = config_get_boolean("plugin:freebsd:sysctl", "per cpu core utilization", 1);
- do_interrupts = config_get_boolean("plugin:freebsd:sysctl", "cpu interrupts", 1);
- do_dev_intr = config_get_boolean("plugin:freebsd:sysctl", "device interrupts", 1);
- do_soft_intr = config_get_boolean("plugin:freebsd:sysctl", "software interrupts", 1);
- do_context = config_get_boolean("plugin:freebsd:sysctl", "context switches", 1);
- do_forks = config_get_boolean("plugin:freebsd:sysctl", "processes started", 1);
- do_processes = config_get_boolean("plugin:freebsd:sysctl", "processes running", 1);
- do_loadavg = config_get_boolean("plugin:freebsd:sysctl", "enable load average", 1);
- do_all_processes = config_get_boolean("plugin:freebsd:sysctl", "enable total processes", 1);
- do_disk_io = config_get_boolean("plugin:freebsd:sysctl", "stats for all disks", 1);
- do_swap = config_get_boolean("plugin:freebsd:sysctl", "system swap", 1);
- do_ram = config_get_boolean("plugin:freebsd:sysctl", "system ram", 1);
- do_swapio = config_get_boolean("plugin:freebsd:sysctl", "swap i/o", 1);
- do_pgfaults = config_get_boolean("plugin:freebsd:sysctl", "memory page faults", 1);
- do_committed = config_get_boolean("plugin:freebsd:sysctl", "committed memory", 1);
- do_ipc_semaphores = config_get_boolean("plugin:freebsd:sysctl", "ipc semaphores", 1);
- do_ipc_shared_mem = config_get_boolean("plugin:freebsd:sysctl", "ipc shared memory", 1);
- do_ipc_msg_queues = config_get_boolean("plugin:freebsd:sysctl", "ipc message queues", 1);
- do_netisr = config_get_boolean("plugin:freebsd:sysctl", "netisr", 1);
- do_netisr_per_core = config_get_boolean("plugin:freebsd:sysctl", "netisr per core", 1);
- do_bandwidth = config_get_boolean("plugin:freebsd:sysctl", "bandwidth", 1);
- do_tcp_sockets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP connections", 1);
- do_tcp_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP packets", 1);
- do_tcp_errors = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP errors", 1);
- do_tcp_handshake = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP handshake issues", 1);
- do_ecn = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
- do_udp_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP packets", 1);
- do_udp_errors = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP errors", 1);
- do_icmp_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP packets", 1);
- do_icmpmsg = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP messages", 1);
- do_ip_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 packets", 1);
- do_ip_fragsout = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments sent", 1);
- do_ip_fragsin = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments assembly", 1);
- do_ip_errors = config_get_boolean("plugin:freebsd:sysctl", "ipv4 errors", 1);
- do_ip6_packets = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsout = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsin = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_errors = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6 = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_redir = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_errors = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_echos = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_router = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_neighbor = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_types = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
- do_space = config_get_boolean("plugin:freebsd:sysctl", "space usage for all disks", 1);
- do_inodes = config_get_boolean("plugin:freebsd:sysctl", "inodes usage for all disks", 1);
- do_uptime = config_get_boolean("plugin:macos:sysctl", "system uptime", 1);
+int freebsd_plugin_init()
+{
+ system_pagesize = getpagesize();
+ if (system_pagesize <= 0) {
+ error("FREEBSD: can't get system page size");
+ return 1;
}
- RRDSET *st;
- RRDDIM *rd;
-
- int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
- int i, n;
- void *p;
- int common_error = 0;
- size_t size;
- char title[4096 + 1];
-
- // NEEDED BY: do_loadavg
- static usec_t last_loadavg_usec = 0;
- struct loadavg sysload;
-
- // NEEDED BY: do_cpu, do_cpu_cores
- long cp_time[CPUSTATES];
-
- // NEEDED BY: du_cpu_cores, do_netisr, do_netisr_per_core
- int ncpus;
-
- // NEEDED BY: do_cpu_cores
- static long *pcpu_cp_time = NULL;
- char cpuid[8]; // no more than 4 digits expected
-
- // NEEDED BY: do_all_processes, do_processes
- struct vmtotal vmtotal_data;
-
- // NEEDED BY: do_context, do_forks
- u_int u_int_data;
-
- // NEEDED BY: do_interrupts
- size_t intrcnt_size;
- unsigned long nintr = 0;
- static unsigned long *intrcnt = NULL;
- static char *intrnames = NULL;
- unsigned long long totalintr = 0;
-
- // NEEDED BY: do_disk_io
- #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
- int numdevs;
- static void *devstat_data = NULL;
- struct devstat *dstat;
- char disk[DEVSTAT_NAME_LEN + 10 + 1]; // 10 - maximum number of digits for int
- struct cur_dstat {
- collected_number duration_read_ms;
- collected_number duration_write_ms;
- collected_number busy_time_ms;
- } cur_dstat;
- struct prev_dstat {
- collected_number bytes_read;
- collected_number bytes_write;
- collected_number operations_read;
- collected_number operations_write;
- collected_number duration_read_ms;
- collected_number duration_write_ms;
- collected_number busy_time_ms;
- } prev_dstat;
-
- // NEEDED BY: do_swap
- size_t mibsize;
- int mib[3]; // CTL_MAXNAME = 24 maximum mib components (sysctl.h)
- struct xswdev xsw;
- struct total_xsw {
- collected_number bytes_used;
- collected_number bytes_total;
- } total_xsw = {0, 0};
-
- // NEEDED BY: do_swapio, do_ram
- struct vmmeter vmmeter_data;
-
- // NEEDED BY: do_ram
- int vfs_bufspace_count;
-
- // NEEDED BY: do_ipc_semaphores
- struct ipc_sem {
- int semmni;
- collected_number sets;
- collected_number semaphores;
- } ipc_sem = {0, 0, 0};
- static struct semid_kernel *ipc_sem_data = NULL;
-
- // NEEDED BY: do_ipc_shared_mem
- struct ipc_shm {
- u_long shmmni;
- collected_number segs;
- collected_number segsize;
- } ipc_shm = {0, 0, 0};
- static struct shmid_kernel *ipc_shm_data = NULL;
-
- // NEEDED BY: do_ipc_msg_queues
- struct ipc_msq {
- int msgmni;
- collected_number queues;
- collected_number messages;
- collected_number usedsize;
- collected_number allocsize;
- } ipc_msq = {0, 0, 0, 0, 0};
- static struct msqid_kernel *ipc_msq_data = NULL;
+ if (unlikely(GETSYSCTL_BY_NAME("kern.smp.cpus", number_of_cpus))) {
+ error("FREEBSD: can't get number of cpus");
+ return 1;
+ }
- // NEEDED BY: do_netisr, do_netisr_per_core
- size_t netisr_workstream_size;
- size_t netisr_work_size;
- unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
- static struct sysctl_netisr_workstream *netisr_workstream = NULL;
- static struct sysctl_netisr_work *netisr_work = NULL;
- static struct netisr_stats {
- collected_number dispatched;
- collected_number hybrid_dispatched;
- collected_number qdrops;
- collected_number queued;
- } *netisr_stats = NULL;
- char netstat_cpuid[21]; // no more than 4 digits expected
+ if (unlikely(!number_of_cpus)) {
+ error("FREEBSD: wrong number of cpus");
+ return 1;
+ }
- // NEEDED BY: do_bandwidth
- struct ifaddrs *ifa, *ifap;
- struct iftot {
- u_long ift_ibytes;
- u_long ift_obytes;
- } iftot = {0, 0};
+ return 0;
+}
- // NEEDED BY: do_tcp...
- struct tcpstat tcpstat;
- uint64_t tcps_states[TCP_NSTATES];
+// --------------------------------------------------------------------------------------------------------------------
+// vm.loadavg
- // NEEDED BY: do_udp...
- struct udpstat udpstat;
+// FreeBSD calculates load averages once every 5 seconds
+#define MIN_LOADAVG_UPDATE_EVERY 5
- // NEEDED BY: do_icmp...
- struct icmpstat icmpstat;
- struct icmp_total {
- u_long msgs_in;
- u_long msgs_out;
- } icmp_total = {0, 0};
+int do_vm_loadavg(int update_every, usec_t dt){
+ static usec_t next_loadavg_dt = 0;
- // NEEDED BY: do_ip...
- struct ipstat ipstat;
+ if (next_loadavg_dt <= dt) {
+ static int mib[2] = {0, 0};
+ struct loadavg sysload;
- // NEEDED BY: do_ip6...
- struct ip6stat ip6stat;
+ if (unlikely(GETSYSCTL_SIMPLE("vm.loadavg", mib, sysload))) {
+ error("DISABLED: system.load chart");
+ error("DISABLED: vm.loadavg module");
+ return 1;
+ } else {
- // NEEDED BY: do_icmp6...
- struct icmp6stat icmp6stat;
- struct icmp6_total {
- u_long msgs_in;
- u_long msgs_out;
- } icmp6_total = {0, 0};
+ // --------------------------------------------------------------------
- // NEEDED BY: do_space, do_inodes
- struct statfs *mntbuf;
- int mntsize;
- char mntonname[MNAMELEN + 1];
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_load1 = NULL, *rd_load2 = NULL, *rd_load3 = NULL;
- // NEEDED BY: do_uptime
- struct timespec boot_time, cur_time;
+ if (unlikely(!st)) {
+ st = 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(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rd_load2 = rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rd_load3 = rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_load1, (collected_number) ((double) sysload.ldavg[0] / sysload.fscale * 1000));
+ rrddim_set_by_pointer(st, rd_load2, (collected_number) ((double) sysload.ldavg[1] / sysload.fscale * 1000));
+ rrddim_set_by_pointer(st, rd_load3, (collected_number) ((double) sysload.ldavg[2] / sysload.fscale * 1000));
+ rrdset_done(st);
- // --------------------------------------------------------------------
+ next_loadavg_dt = st->update_every * USEC_PER_SEC;
+ }
+ }
+ else
+ next_loadavg_dt -= dt;
- if (last_loadavg_usec <= dt) {
- if (likely(do_loadavg)) {
- if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
- do_loadavg = 0;
- error("DISABLED: system.load");
- } else {
+ return 0;
+}
- st = rrdset_find_bytype("system", "load");
- if (unlikely(!st)) {
- st = rrdset_create("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(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.vmtotal
- rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
- rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
- rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
- rrdset_done(st);
- }
- }
+int do_vm_vmtotal(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_all_processes = -1, do_processes = -1, do_committed = -1;
- last_loadavg_usec = st->update_every * USEC_PER_SEC;
+ if (unlikely(do_all_processes == -1)) {
+ do_all_processes = config_get_boolean("plugin:freebsd:vm.vmtotal", "enable total processes", 1);
+ do_processes = config_get_boolean("plugin:freebsd:vm.vmtotal", "processes running", 1);
+ do_committed = config_get_boolean("plugin:freebsd:vm.vmtotal", "committed memory", 1);
}
- else last_loadavg_usec -= dt;
-
- // --------------------------------------------------------------------
if (likely(do_all_processes | do_processes | do_committed)) {
- if (unlikely(GETSYSCTL("vm.vmtotal", vmtotal_data))) {
+ static int mib[2] = {0, 0};
+ struct vmtotal vmtotal_data;
+
+ if (unlikely(GETSYSCTL_SIMPLE("vm.vmtotal", mib, vmtotal_data))) {
do_all_processes = 0;
- error("DISABLED: system.active_processes");
+ error("DISABLED: system.active_processes chart");
do_processes = 0;
- error("DISABLED: system.processes");
+ error("DISABLED: system.processes chart");
do_committed = 0;
- error("DISABLED: mem.committed");
+ error("DISABLED: mem.committed chart");
+ error("DISABLED: vm.vmtotal module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_all_processes)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- st = rrdset_find_bytype("system", "active_processes");
if (unlikely(!st)) {
- st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system",
+ "active_processes",
+ NULL,
+ "processes",
+ NULL,
+ "System Active Processes",
+ "processes",
+ 750,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+ rd = rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "active", (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
+ rrddim_set_by_pointer(st, rd, (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_processes)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_running = NULL, *rd_blocked = NULL;
- st = rrdset_find_bytype("system", "processes");
if (unlikely(!st)) {
- st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system",
+ "processes",
+ NULL,
+ "processes",
+ NULL,
+ "System Processes",
+ "processes",
+ 600,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_running = rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rd_blocked = rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "running", vmtotal_data.t_rq);
- rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
+ rrddim_set_by_pointer(st, rd_running, vmtotal_data.t_rq);
+ rrddim_set_by_pointer(st, rd_blocked, (vmtotal_data.t_dw + vmtotal_data.t_pw));
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_committed)) {
- st = rrdset_find("mem.committed");
- if (unlikely(!st)) {
- st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+ if (unlikely(!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);
+
+ rd = rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "Committed_AS", vmtotal_data.t_rm);
+ rrddim_set_by_pointer(st, rd, vmtotal_data.t_rm);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: vm.vmtotal module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.cp_time
+
+int do_kern_cp_time(int update_every, usec_t dt) {
+ (void)dt;
- if (likely(do_cpu)) {
- if (unlikely(CPUSTATES != 5)) {
- error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
- do_cpu = 0;
- error("DISABLED: system.cpu");
+ if (unlikely(CPUSTATES != 5)) {
+ error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+ error("DISABLED: system.cpu chart");
+ error("DISABLED: kern.cp_time module");
+ return 1;
+ } else {
+ static int mib[2] = {0, 0};
+ long cp_time[CPUSTATES];
+
+ if (unlikely(GETSYSCTL_SIMPLE("kern.cp_time", mib, cp_time))) {
+ error("DISABLED: system.cpu chart");
+ error("DISABLED: kern.cp_time module");
+ return 1;
} else {
- if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
- do_cpu = 0;
- error("DISABLED: system.cpu");
- } else {
- st = rrdset_find_bytype("system", "cpu");
- if (unlikely(!st)) {
- st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_hide(st, "idle");
- }
- else rrdset_next(st);
+ // --------------------------------------------------------------------
- rrddim_set(st, "user", cp_time[0]);
- rrddim_set(st, "nice", cp_time[1]);
- rrddim_set(st, "system", cp_time[2]);
- rrddim_set(st, "interrupt", cp_time[3]);
- rrddim_set(st, "idle", cp_time[4]);
- rrdset_done(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_nice = NULL, *rd_system = NULL, *rd_user = NULL, *rd_interrupt = NULL, *rd_idle = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "cpu",
+ NULL,
+ "cpu",
+ "system.cpu",
+ "Total CPU utilization",
+ "percentage",
+ 100, update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ rd_nice = rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_system = rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_user = rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_interrupt = rrddim_add(st, "interrupt", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_idle = rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_hide(st, "idle");
}
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_nice, cp_time[1]);
+ rrddim_set_by_pointer(st, rd_system, cp_time[2]);
+ rrddim_set_by_pointer(st, rd_user, cp_time[0]);
+ rrddim_set_by_pointer(st, rd_interrupt, cp_time[3]);
+ rrddim_set_by_pointer(st, rd_idle, cp_time[4]);
+ rrdset_done(st);
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.cp_times
+
+int do_kern_cp_times(int update_every, usec_t dt) {
+ (void)dt;
- if (likely(do_cpu_cores)) {
- if (unlikely(CPUSTATES != 5)) {
- error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
+ if (unlikely(CPUSTATES != 5)) {
+ error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+ error("DISABLED: cpu.cpuXX charts");
+ error("DISABLED: kern.cp_times module");
+ return 1;
+ } else {
+ static int mib[2] = {0, 0};
+ long cp_time[CPUSTATES];
+ static long *pcpu_cp_time = NULL;
+
+ pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * number_of_cpus);
+ if (unlikely(GETSYSCTL_WSIZE("kern.cp_times", mib, pcpu_cp_time, sizeof(cp_time) * number_of_cpus))) {
+ error("DISABLED: cpu.cpuXX charts");
+ error("DISABLED: kern.cp_times module");
+ return 1;
} else {
- if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
- } else {
- pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
- for (i = 0; i < ncpus; i++) {
- if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
- break;
- }
- if (unlikely(ncpus > 9999)) {
- error("FREEBSD: There are more than 4 digits in cpu cores number");
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
- break;
- }
- snprintfz(cpuid, 8, "cpu%d", i);
+ // --------------------------------------------------------------------
- st = rrdset_find_bytype("cpu", cpuid);
- if (unlikely(!st)) {
- st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_hide(st, "idle");
- }
- else rrdset_next(st);
+ int i;
+ static struct cpu_chart {
+ char cpuid[MAX_INT_DIGITS + 4];
+ RRDSET *st;
+ RRDDIM *rd_user;
+ RRDDIM *rd_nice;
+ RRDDIM *rd_system;
+ RRDDIM *rd_interrupt;
+ RRDDIM *rd_idle;
+ } *all_cpu_charts = NULL;
+ static int old_number_of_cpus = 0;
+
+ if(unlikely(number_of_cpus > old_number_of_cpus)) {
+ all_cpu_charts = reallocz(all_cpu_charts, sizeof(struct cpu_chart) * number_of_cpus);
+ memset(&all_cpu_charts[old_number_of_cpus], 0, sizeof(struct cpu_chart) * (number_of_cpus - old_number_of_cpus));
+ old_number_of_cpus = number_of_cpus;
+ }
- rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
- rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
- rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
- rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
- rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
- rrdset_done(st);
- }
+ for (i = 0; i < number_of_cpus; i++) {
+ if (unlikely(!all_cpu_charts[i].st)) {
+ snprintfz(all_cpu_charts[i].cpuid, MAX_INT_DIGITS, "cpu%d", i);
+ all_cpu_charts[i].st = rrdset_create_localhost("cpu",
+ all_cpu_charts[i].cpuid,
+ NULL,
+ "utilization",
+ "cpu.cpu",
+ "Core utilization",
+ "percentage",
+ 1000,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ all_cpu_charts[i].rd_nice = rrddim_add(all_cpu_charts[i].st, "nice", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_system = rrddim_add(all_cpu_charts[i].st, "system", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_user = rrddim_add(all_cpu_charts[i].st, "user", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_interrupt = rrddim_add(all_cpu_charts[i].st, "interrupt", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_idle = rrddim_add(all_cpu_charts[i].st, "idle", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_hide(all_cpu_charts[i].st, "idle");
+ } else rrdset_next(all_cpu_charts[i].st);
+
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_nice, pcpu_cp_time[i * 5 + 1]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_system, pcpu_cp_time[i * 5 + 2]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_user, pcpu_cp_time[i * 5 + 0]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_interrupt, pcpu_cp_time[i * 5 + 3]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_idle, pcpu_cp_time[i * 5 + 4]);
+ rrdset_done(all_cpu_charts[i].st);
}
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
- if (likely(do_interrupts)) {
- if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(hw.intrcnt...) failed: %s", strerror(errno));
- do_interrupts = 0;
- error("DISABLED: system.intr");
+// --------------------------------------------------------------------------------------------------------------------
+// hw.intrcnt
+
+int do_hw_intcnt(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_hw_intrcnt[2] = {0, 0};
+ size_t intrcnt_size = sizeof(mib_hw_intrcnt);
+ unsigned long i;
+
+ if (unlikely(GETSYSCTL_SIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt_size))) {
+ error("DISABLED: system.intr chart");
+ error("DISABLED: system.interrupts chart");
+ error("DISABLED: hw.intrcnt module");
+ return 1;
+ } else {
+ unsigned long nintr = 0;
+ static unsigned long *intrcnt = NULL;
+ unsigned long long totalintr = 0;
+
+ nintr = intrcnt_size / sizeof(u_long);
+ intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
+ if (unlikely(GETSYSCTL_WSIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt, nintr * sizeof(u_long)))) {
+ error("DISABLED: system.intr chart");
+ error("DISABLED: system.interrupts chart");
+ error("DISABLED: hw.intrcnt module");
+ return 1;
} else {
- nintr = intrcnt_size / sizeof(u_long);
- intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
- if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
- do_interrupts = 0;
- error("DISABLED: system.intr");
- } else {
- for (i = 0; i < nintr; i++)
- totalintr += intrcnt[i];
+ for (i = 0; i < nintr; i++)
+ totalintr += intrcnt[i];
- st = rrdset_find_bytype("system", "intr");
- if (unlikely(!st)) {
- st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Hardware Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ // --------------------------------------------------------------------
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ static RRDSET *st_intr = NULL;
+ static RRDDIM *rd_intr = NULL;
+
+ if (unlikely(!st_intr)) {
+ st_intr = rrdset_create_localhost("system",
+ "intr",
+ NULL,
+ "interrupts",
+ NULL,
+ "Total Hardware Interrupts",
+ "interrupts/s",
+ 900,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL);
+
+ rd_intr = rrddim_add(st_intr, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st_intr);
+
+ rrddim_set_by_pointer(st_intr, rd_intr, totalintr);
+ rrdset_done(st_intr);
- rrddim_set(st, "interrupts", totalintr);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ size_t size;
+ static int mib_hw_intrnames[2] = {0, 0};
+ static char *intrnames = NULL;
+
+ size = nintr * (MAXCOMLEN + 1);
+ intrnames = reallocz(intrnames, size);
+ if (unlikely(GETSYSCTL_WSIZE("hw.intrnames", mib_hw_intrnames, intrnames, size))) {
+ error("DISABLED: system.intr chart");
+ error("DISABLED: system.interrupts chart");
+ error("DISABLED: hw.intrcnt module");
+ return 1;
+ } else {
- size = nintr * (MAXCOMLEN +1);
- intrnames = reallocz(intrnames, size);
- if (unlikely(getsysctl("hw.intrnames", intrnames, size))) {
- do_interrupts = 0;
- error("DISABLED: system.intr");
- } else {
- st = rrdset_find_bytype("system", "interrupts");
- if (unlikely(!st))
- st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s",
- 1000, update_every, RRDSET_TYPE_STACKED);
- else
- rrdset_next(st);
+ // --------------------------------------------------------------------
- for (i = 0; i < nintr; i++) {
- p = intrnames + i * (MAXCOMLEN + 1);
- if (unlikely((intrcnt[i] != 0) && (*(char*)p != 0))) {
- rd = rrddim_find(st, p);
- if (unlikely(!rd))
- rd = rrddim_add(st, p, NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_set_by_pointer(st, rd, intrcnt[i]);
- }
+ static RRDSET *st_interrupts = NULL;
+ RRDDIM *rd_interrupts = NULL;
+ void *p;
+
+ if (unlikely(!st_interrupts))
+ st_interrupts = rrdset_create_localhost("system",
+ "interrupts",
+ NULL,
+ "interrupts",
+ NULL,
+ "System interrupts",
+ "interrupts/s",
+ 1000,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+ else
+ rrdset_next(st_interrupts);
+
+ for (i = 0; i < nintr; i++) {
+ p = intrnames + i * (MAXCOMLEN + 1);
+ if (unlikely((intrcnt[i] != 0) && (*(char *) p != 0))) {
+ rd_interrupts = rrddim_find(st_interrupts, p);
+ if (unlikely(!rd_interrupts))
+ rd_interrupts = rrddim_add(st_interrupts, p, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_set_by_pointer(st_interrupts, rd_interrupts, intrcnt[i]);
}
- rrdset_done(st);
}
+ rrdset_done(st_interrupts);
}
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
- if (likely(do_dev_intr)) {
- if (unlikely(GETSYSCTL("vm.stats.sys.v_intr", u_int_data))) {
- do_dev_intr = 0;
- error("DISABLED: system.dev_intr");
- } else {
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_intr
- st = rrdset_find_bytype("system", "dev_intr");
- if (unlikely(!st)) {
- st = rrdset_create("system", "dev_intr", NULL, "interrupts", NULL, "Device Interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_LINE);
+int do_vm_stats_sys_v_intr(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int int_number;
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_intr", mib, int_number))) {
+ error("DISABLED: system.dev_intr chart");
+ error("DISABLED: vm.stats.sys.v_intr module");
+ return 1;
+ } else {
- rrddim_set(st, "interrupts", u_int_data);
- rrdset_done(st);
- }
- }
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- if (likely(do_soft_intr)) {
- if (unlikely(GETSYSCTL("vm.stats.sys.v_soft", u_int_data))) {
- do_soft_intr = 0;
- error("DISABLED: system.dev_intr");
- } else {
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "dev_intr",
+ NULL,
+ "interrupts",
+ NULL,
+ "Device Interrupts",
+ "interrupts/s",
+ 1000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- st = rrdset_find_bytype("system", "soft_intr");
- if (unlikely(!st)) {
- st = rrdset_create("system", "soft_intr", NULL, "interrupts", NULL, "Software Interrupts", "interrupts/s", 1100, update_every, RRDSET_TYPE_LINE);
+ rrddim_set_by_pointer(st, rd, int_number);
+ rrdset_done(st);
+ }
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ return 0;
+}
- rrddim_set(st, "interrupts", u_int_data);
- rrdset_done(st);
- }
- }
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_soft
- // --------------------------------------------------------------------
+int do_vm_stats_sys_v_soft(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int soft_intr_number;
- if (likely(do_context)) {
- if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", u_int_data))) {
- do_context = 0;
- error("DISABLED: system.ctxt");
- } else {
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_soft", mib, soft_intr_number))) {
+ error("DISABLED: system.dev_intr chart");
+ error("DISABLED: vm.stats.sys.v_soft module");
+ return 1;
+ } else {
- st = rrdset_find_bytype("system", "ctxt");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+ // --------------------------------------------------------------------
- rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- rrddim_set(st, "switches", u_int_data);
- rrdset_done(st);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "soft_intr",
+ NULL,
+ "interrupts",
+ NULL,
+ "Software Interrupts",
+ "interrupts/s",
+ 1100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd, soft_intr_number);
+ rrdset_done(st);
}
- // --------------------------------------------------------------------
+ return 0;
+}
- if (likely(do_forks)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", u_int_data))) {
- do_forks = 0;
- error("DISABLED: system.forks");
- } else {
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_swtch
- st = rrdset_find_bytype("system", "forks");
- if (unlikely(!st)) {
- st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+int do_vm_stats_sys_v_swtch(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int ctxt_number;
- rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_swtch", mib, ctxt_number))) {
+ error("DISABLED: system.ctxt chart");
+ error("DISABLED: vm.stats.sys.v_swtch module");
+ return 1;
+ } else {
- rrddim_set(st, "started", u_int_data);
- rrdset_done(st);
- }
- }
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- if (likely(do_disk_io)) {
- if (unlikely(GETSYSCTL("kern.devstat.numdevs", numdevs))) {
- do_disk_io = 0;
- error("DISABLED: disk.io");
- } else {
- devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
- if (unlikely(getsysctl("kern.devstat.all", devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs))) {
- do_disk_io = 0;
- error("DISABLED: disk.io");
- } else {
- dstat = devstat_data + sizeof(long); // skip generation number
- collected_number total_disk_kbytes_read = 0;
- collected_number total_disk_kbytes_write = 0;
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ctxt",
+ NULL,
+ "processes",
+ NULL,
+ "CPU Context Switches",
+ "context switches/s",
+ 800,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- for (i = 0; i < numdevs; i++) {
- if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
- sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
+ rrddim_set_by_pointer(st, rd, ctxt_number);
+ rrdset_done(st);
+ }
- // --------------------------------------------------------------------
+ return 0;
+}
- st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
- if (unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_DISK, disk, NULL, disk, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_forks
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+int do_vm_stats_sys_v_forks(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int forks_number;
- total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ]/KILO_FACTOR;
- total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE]/KILO_FACTOR;
- prev_dstat.bytes_read = rrddim_set(st, "reads", dstat[i].bytes[DEVSTAT_READ]);
- prev_dstat.bytes_write = rrddim_set(st, "writes", dstat[i].bytes[DEVSTAT_WRITE]);
- rrdset_done(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_forks", mib, forks_number))) {
+ error("DISABLED: system.forks chart");
+ error("DISABLED: vm.stats.sys.v_swtch module");
+ return 1;
+ } else {
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_ops", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_ops", disk, NULL, disk, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ 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);
+
+ rd = rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- prev_dstat.operations_read = rrddim_set(st, "reads", dstat[i].operations[DEVSTAT_READ]);
- prev_dstat.operations_write = rrddim_set(st, "writes", dstat[i].operations[DEVSTAT_WRITE]);
- rrdset_done(st);
+ rrddim_set_by_pointer(st, rd, forks_number);
+ rrdset_done(st);
+ }
- // --------------------------------------------------------------------
+ return 0;
+}
- st = rrdset_find_bytype("disk_qops", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_qops", disk, NULL, disk, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+// --------------------------------------------------------------------------------------------------------------------
+// vm.swap_info
- rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+int do_vm_swap_info(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[3] = {0, 0, 0};
+
+ if (unlikely(getsysctl_mib("vm.swap_info", mib, 2))) {
+ error("DISABLED: system.swap chart");
+ error("DISABLED: vm.swap_info module");
+ return 1;
+ } else {
+ int i;
+ struct xswdev xsw;
+ struct total_xsw {
+ collected_number bytes_used;
+ collected_number bytes_total;
+ } total_xsw = {0, 0};
+
+ for (i = 0; ; i++) {
+ size_t size;
+
+ mib[2] = i;
+ size = sizeof(xsw);
+ if (unlikely(sysctl(mib, 3, &xsw, &size, NULL, 0) == -1 )) {
+ if (unlikely(errno != ENOENT)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
+ error("DISABLED: system.swap chart");
+ error("DISABLED: vm.swap_info module");
+ return 1;
+ } else {
+ if (unlikely(size != sizeof(xsw))) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
+ error("DISABLED: system.swap chart");
+ error("DISABLED: vm.swap_info module");
+ return 1;
+ } else break;
+ }
+ }
+ total_xsw.bytes_used += xsw.xsw_used;
+ total_xsw.bytes_total += xsw.xsw_nblks;
+ }
- rrddim_set(st, "operations", dstat[i].start_count - dstat[i].end_count);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_free = NULL, *rd_used = NULL;
- st = rrdset_find_bytype("disk_util", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_util", disk, NULL, disk, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ if (unlikely(!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);
+
+ rd_free = rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_used = rrddim_add(st, "used", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
- rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ rrddim_set_by_pointer(st, rd_free, total_xsw.bytes_total - total_xsw.bytes_used);
+ rrddim_set_by_pointer(st, rd_used, total_xsw.bytes_used);
+ rrdset_done(st);
+ }
- cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
- prev_dstat.busy_time_ms = rrddim_set(st, "utilization", cur_dstat.busy_time_ms);
- rrdset_done(st);
+ return 0;
+}
- // --------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
+// system.ram
- st = rrdset_find_bytype("disk_iotime", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_iotime", disk, NULL, disk, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+int do_system_ram(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_active_count[4] = {0, 0, 0, 0}, mib_inactive_count[4] = {0, 0, 0, 0}, mib_wire_count[4] = {0, 0, 0, 0},
+ mib_cache_count[4] = {0, 0, 0, 0}, mib_vfs_bufspace[2] = {0, 0}, mib_free_count[4] = {0, 0, 0, 0};
+ struct vmmeter vmmeter_data;
+ int vfs_bufspace_count;
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_active_count", mib_active_count, vmmeter_data.v_active_count) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_inactive_count", mib_inactive_count, vmmeter_data.v_inactive_count) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_wire_count", mib_wire_count, vmmeter_data.v_wire_count) ||
+#if __FreeBSD_version < 1200016
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_cache_count", mib_cache_count, vmmeter_data.v_cache_count) ||
+#endif
+ GETSYSCTL_SIMPLE("vfs.bufspace", mib_vfs_bufspace, vfs_bufspace_count) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_free_count", mib_free_count, vmmeter_data.v_free_count))) {
+ error("DISABLED: system.ram chart");
+ error("DISABLED: System.ram module");
+ return 1;
+ } else {
- cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
- cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
- prev_dstat.duration_read_ms = rrddim_set(st, "reads", cur_dstat.duration_read_ms);
- prev_dstat.duration_write_ms = rrddim_set(st, "writes", cur_dstat.duration_write_ms);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- // calculate differential charts
- // only if this is not the first time we run
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL,
+ *rd_wired = NULL, *rd_cache = NULL, *rd_buffers = NULL;
- if (likely(dt)) {
+ st = rrdset_find_localhost("system.ram");
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ram",
+ NULL,
+ "ram",
+ NULL,
+ "System RAM",
+ "MB",
+ 200,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ rd_free = rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_active = rrddim_add(st, "active", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_inactive = rrddim_add(st, "inactive", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_wired = rrddim_add(st, "wired", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+#if __FreeBSD_version < 1200016
+ rd_cache = rrddim_add(st, "cache", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+#endif
+ rd_buffers = rrddim_add(st, "buffers", NULL, 1, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st, rd_free, vmmeter_data.v_free_count);
+ rrddim_set_by_pointer(st, rd_active, vmmeter_data.v_active_count);
+ rrddim_set_by_pointer(st, rd_inactive, vmmeter_data.v_inactive_count);
+ rrddim_set_by_pointer(st, rd_wired, vmmeter_data.v_wire_count);
+#if __FreeBSD_version < 1200016
+ rrddim_set_by_pointer(st, rd_cache, vmmeter_data.v_cache_count);
+#endif
+ rrddim_set_by_pointer(st, rd_buffers, vfs_bufspace_count);
+ rrdset_done(st);
+ }
- st = rrdset_find_bytype("disk_await", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_await", disk, NULL, disk, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ return 0;
+}
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_swappgs
- rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
- (cur_dstat.duration_read_ms - prev_dstat.duration_read_ms) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
- rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
- (cur_dstat.duration_write_ms - prev_dstat.duration_write_ms) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
- rrdset_done(st);
+int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_swappgsin[4] = {0, 0, 0, 0}, mib_swappgsout[4] = {0, 0, 0, 0};
+ struct vmmeter vmmeter_data;
- // --------------------------------------------------------------------
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsin", mib_swappgsin, vmmeter_data.v_swappgsin) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsout", mib_swappgsout, vmmeter_data.v_swappgsout))) {
+ error("DISABLED: system.swapio chart");
+ error("DISABLED: vm.stats.vm.v_swappgs module");
+ return 1;
+ } else {
- st = rrdset_find_bytype("disk_avgsz", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_avgsz", disk, NULL, disk, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ // --------------------------------------------------------------------
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
- (dstat[i].bytes[DEVSTAT_READ] - prev_dstat.bytes_read) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
- rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
- (dstat[i].bytes[DEVSTAT_WRITE] - prev_dstat.bytes_write) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
- rrdset_done(st);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "swapio",
+ NULL,
+ "swap",
+ NULL,
+ "Swap I/O",
+ "kilobytes/s",
+ 250,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "in", NULL, system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "out", NULL, -system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st, rd_in, vmmeter_data.v_swappgsin);
+ rrddim_set_by_pointer(st, rd_out, vmmeter_data.v_swappgsout);
+ rrdset_done(st);
+ }
- st = rrdset_find_bytype("disk_svctm", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_svctm", disk, NULL, disk, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ return 0;
+}
- rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_pgfaults
- rrddim_set(st, "svctm", ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) ?
- (cur_dstat.busy_time_ms - prev_dstat.busy_time_ms) / ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) : 0);
- rrdset_done(st);
- }
- }
- }
+int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_vm_faults[4] = {0, 0, 0, 0}, mib_io_faults[4] = {0, 0, 0, 0}, mib_cow_faults[4] = {0, 0, 0, 0},
+ mib_cow_optim[4] = {0, 0, 0, 0}, mib_intrans[4] = {0, 0, 0, 0};
+ struct vmmeter vmmeter_data;
- // --------------------------------------------------------------------
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_vm_faults", mib_vm_faults, vmmeter_data.v_vm_faults) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_io_faults", mib_io_faults, vmmeter_data.v_io_faults) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_faults", mib_cow_faults, vmmeter_data.v_cow_faults) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_optim", mib_cow_optim, vmmeter_data.v_cow_optim) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_intrans", mib_intrans, vmmeter_data.v_intrans))) {
+ error("DISABLED: mem.pgfaults chart");
+ error("DISABLED: vm.stats.vm.v_pgfaults module");
+ return 1;
+ } else {
- st = rrdset_find_bytype("system", "io");
- if (unlikely(!st)) {
- st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "in", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ // --------------------------------------------------------------------
- rrddim_set(st, "in", total_disk_kbytes_read);
- rrddim_set(st, "out", total_disk_kbytes_write);
- rrdset_done(st);
- }
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_memory = NULL, *rd_io_requiring = NULL, *rd_cow = NULL,
+ *rd_cow_optimized = NULL, *rd_in_transit = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("mem",
+ "pgfaults",
+ NULL,
+ "system",
+ NULL,
+ "Memory Page Faults",
+ "page faults/s",
+ 500,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_memory = rrddim_add(st, "memory", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_io_requiring = rrddim_add(st, "io_requiring", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_cow = rrddim_add(st, "cow", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_cow_optimized = rrddim_add(st, "cow_optimized", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_transit = rrddim_add(st, "in_transit", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_memory, vmmeter_data.v_vm_faults);
+ rrddim_set_by_pointer(st, rd_io_requiring, vmmeter_data.v_io_faults);
+ rrddim_set_by_pointer(st, rd_cow, vmmeter_data.v_cow_faults);
+ rrddim_set_by_pointer(st, rd_cow_optimized, vmmeter_data.v_cow_optim);
+ rrddim_set_by_pointer(st, rd_in_transit, vmmeter_data.v_intrans);
+ rrdset_done(st);
}
- // --------------------------------------------------------------------
+ return 0;
+}
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.sem
- if (likely(do_swap)) {
- mibsize = sizeof mib / sizeof mib[0];
- if (unlikely(sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)) {
- error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
- do_swap = 0;
- error("DISABLED: system.swap");
- } else {
- for (i = 0; ; i++) {
- mib[mibsize] = i;
- size = sizeof(xsw);
- if (unlikely(sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1 )) {
- if (unlikely(errno != ENOENT)) {
- error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
- do_swap = 0;
- error("DISABLED: system.swap");
- } else {
- if (unlikely(size != sizeof(xsw))) {
- error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
- do_swap = 0;
- error("DISABLED: system.swap");
- } else break;
- }
- }
- total_xsw.bytes_used += xsw.xsw_used;
- total_xsw.bytes_total += xsw.xsw_nblks;
- }
+int do_kern_ipc_sem(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_semmni[3] = {0, 0, 0}, mib_sema[3] = {0, 0, 0};
+ struct ipc_sem {
+ int semmni;
+ collected_number sets;
+ collected_number semaphores;
+ } ipc_sem = {0, 0, 0};
- if (likely(do_swap)) {
- st = rrdset_find("system.swap");
- if (unlikely(!st)) {
- st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.semmni", mib_semmni, ipc_sem.semmni))) {
+ error("DISABLED: system.ipc_semaphores chart");
+ error("DISABLED: system.ipc_semaphore_arrays chart");
+ error("DISABLED: kern.ipc.sem module");
+ return 1;
+ } else {
+ static struct semid_kernel *ipc_sem_data = NULL;
+
+ ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
+ if (unlikely(GETSYSCTL_WSIZE("kern.ipc.sema", mib_sema, ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
+ error("DISABLED: system.ipc_semaphores chart");
+ error("DISABLED: system.ipc_semaphore_arrays chart");
+ error("DISABLED: kern.ipc.sem module");
+ return 1;
+ } else {
+ int i;
- rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+ for (i = 0; i < ipc_sem.semmni; i++) {
+ if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
+ ipc_sem.sets += 1;
+ ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
}
- else rrdset_next(st);
-
- rrddim_set(st, "used", total_xsw.bytes_used);
- rrddim_set(st, "free", total_xsw.bytes_total - total_xsw.bytes_used);
- rrdset_done(st);
}
- }
- }
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- if (likely(do_ram)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_active_count", vmmeter_data.v_active_count) ||
- GETSYSCTL("vm.stats.vm.v_inactive_count", vmmeter_data.v_inactive_count) ||
- GETSYSCTL("vm.stats.vm.v_wire_count", vmmeter_data.v_wire_count) ||
- GETSYSCTL("vm.stats.vm.v_cache_count", vmmeter_data.v_cache_count) ||
- GETSYSCTL("vfs.bufspace", vfs_bufspace_count) ||
- GETSYSCTL("vm.stats.vm.v_free_count", vmmeter_data.v_free_count))) {
- do_ram = 0;
- error("DISABLED: system.ram");
- } else {
- st = rrdset_find("system.ram");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "active", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "inactive", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "wired", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "cache", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "buffers", NULL, 1, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+ static RRDSET *st_semaphores = NULL, *st_semaphore_arrays = NULL;
+ static RRDDIM *rd_semaphores = NULL, *rd_semaphore_arrays = NULL;
+
+ if (unlikely(!st_semaphores)) {
+ st_semaphores = rrdset_create_localhost("system",
+ "ipc_semaphores",
+ NULL,
+ "ipc semaphores",
+ NULL,
+ "IPC Semaphores",
+ "semaphores",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
-
- rrddim_set(st, "active", vmmeter_data.v_active_count);
- rrddim_set(st, "inactive", vmmeter_data.v_inactive_count);
- rrddim_set(st, "wired", vmmeter_data.v_wire_count);
- rrddim_set(st, "cache", vmmeter_data.v_cache_count);
- rrddim_set(st, "buffers", vfs_bufspace_count);
- rrddim_set(st, "free", vmmeter_data.v_free_count);
- rrdset_done(st);
- }
- }
+ else rrdset_next(st_semaphores);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st_semaphores, rd_semaphores, ipc_sem.semaphores);
+ rrdset_done(st_semaphores);
- if (likely(do_swapio)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_swappgsin", vmmeter_data.v_swappgsin) || GETSYSCTL("vm.stats.vm.v_swappgsout", vmmeter_data.v_swappgsout))) {
- do_swapio = 0;
- error("DISABLED: system.swapio");
- } else {
- st = rrdset_find("system.swapio");
- if (unlikely(!st)) {
- st = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+ // --------------------------------------------------------------------
- rrddim_add(st, "in", NULL, system_pagesize, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRDDIM_INCREMENTAL);
+ if (unlikely(!st_semaphore_arrays)) {
+ st_semaphore_arrays = rrdset_create_localhost("system",
+ "ipc_semaphore_arrays",
+ NULL,
+ "ipc semaphores",
+ NULL,
+ "IPC Semaphore Arrays",
+ "arrays",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_semaphore_arrays = rrddim_add(st_semaphore_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_semaphore_arrays);
- rrddim_set(st, "in", vmmeter_data.v_swappgsin);
- rrddim_set(st, "out", vmmeter_data.v_swappgsout);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_semaphore_arrays, rd_semaphore_arrays, ipc_sem.sets);
+ rrdset_done(st_semaphore_arrays);
}
}
- // --------------------------------------------------------------------
-
- if (likely(do_pgfaults)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_vm_faults", vmmeter_data.v_vm_faults) ||
- GETSYSCTL("vm.stats.vm.v_io_faults", vmmeter_data.v_io_faults) ||
- GETSYSCTL("vm.stats.vm.v_cow_faults", vmmeter_data.v_cow_faults) ||
- GETSYSCTL("vm.stats.vm.v_cow_optim", vmmeter_data.v_cow_optim) ||
- GETSYSCTL("vm.stats.vm.v_intrans", vmmeter_data.v_intrans))) {
- do_pgfaults = 0;
- error("DISABLED: mem.pgfaults");
- } else {
- st = rrdset_find("mem.pgfaults");
- if (unlikely(!st)) {
- st = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "memory", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "io_requiring", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "cow", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "cow_optimized", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "in_transit", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ return 0;
+}
- rrddim_set(st, "memory", vmmeter_data.v_vm_faults);
- rrddim_set(st, "io_requiring", vmmeter_data.v_io_faults);
- rrddim_set(st, "cow", vmmeter_data.v_cow_faults);
- rrddim_set(st, "cow_optimized", vmmeter_data.v_cow_optim);
- rrddim_set(st, "in_transit", vmmeter_data.v_intrans);
- rrdset_done(st);
- }
- }
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.shm
- // --------------------------------------------------------------------
+int do_kern_ipc_shm(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_shmmni[3] = {0, 0, 0}, mib_shmsegs[3] = {0, 0, 0};
+ struct ipc_shm {
+ u_long shmmni;
+ collected_number segs;
+ collected_number segsize;
+ } ipc_shm = {0, 0, 0};
- if (likely(do_ipc_semaphores)) {
- if (unlikely(GETSYSCTL("kern.ipc.semmni", ipc_sem.semmni))) {
- do_ipc_semaphores = 0;
- error("DISABLED: system.ipc_semaphores");
- error("DISABLED: system.ipc_semaphore_arrays");
+ if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.shmmni", mib_shmmni, ipc_shm.shmmni))) {
+ error("DISABLED: system.ipc_shared_mem_segs chart");
+ error("DISABLED: system.ipc_shared_mem_size chart");
+ error("DISABLED: kern.ipc.shmmodule");
+ return 1;
+ } else {
+ static struct shmid_kernel *ipc_shm_data = NULL;
+
+ ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
+ if (unlikely(
+ GETSYSCTL_WSIZE("kern.ipc.shmsegs", mib_shmsegs, ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
+ error("DISABLED: system.ipc_shared_mem_segs chart");
+ error("DISABLED: system.ipc_shared_mem_size chart");
+ error("DISABLED: kern.ipc.shmmodule");
+ return 1;
} else {
- ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
- if (unlikely(getsysctl("kern.ipc.sema", ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
- do_ipc_semaphores = 0;
- error("DISABLED: system.ipc_semaphores");
- error("DISABLED: system.ipc_semaphore_arrays");
- } else {
- for (i = 0; i < ipc_sem.semmni; i++) {
- if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
- ipc_sem.sets += 1;
- ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
- }
- }
-
- // --------------------------------------------------------------------
+ unsigned long i;
- st = rrdset_find("system.ipc_semaphores");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ for (i = 0; i < ipc_shm.shmmni; i++) {
+ if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
+ ipc_shm.segs += 1;
+ ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
}
- else rrdset_next(st);
+ }
- rrddim_set(st, "semaphores", ipc_sem.semaphores);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st_segs = NULL, *st_size = NULL;
+ static RRDDIM *rd_segments = NULL, *rd_allocated = NULL;
+
+ if (unlikely(!st_segs)) {
+ st_segs = rrdset_create_localhost("system",
+ "ipc_shared_mem_segs",
+ NULL,
+ "ipc shared memory",
+ NULL,
+ "IPC Shared Memory Segments",
+ "segments",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_segments = rrddim_add(st_segs, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_segs);
- st = rrdset_find("system.ipc_semaphore_arrays");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ rrddim_set_by_pointer(st_segs, rd_segments, ipc_shm.segs);
+ rrdset_done(st_segs);
- rrddim_set(st, "arrays", ipc_sem.sets);
- rrdset_done(st);
+ // --------------------------------------------------------------------
+
+ if (unlikely(!st_size)) {
+ st_size = rrdset_create_localhost("system",
+ "ipc_shared_mem_size",
+ NULL,
+ "ipc shared memory",
+ NULL,
+ "IPC Shared Memory Segments Size",
+ "kilobytes",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, KILO_FACTOR, RRD_ALGORITHM_ABSOLUTE);
}
+ else rrdset_next(st_size);
+
+ rrddim_set_by_pointer(st_size, rd_allocated, ipc_shm.segsize);
+ rrdset_done(st_size);
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.msq
+
+int do_kern_ipc_msq(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_msgmni[3] = {0, 0, 0}, mib_msqids[3] = {0, 0, 0};
+ struct ipc_msq {
+ int msgmni;
+ collected_number queues;
+ collected_number messages;
+ collected_number usedsize;
+ collected_number allocsize;
+ } ipc_msq = {0, 0, 0, 0, 0};
- if (likely(do_ipc_shared_mem)) {
- if (unlikely(GETSYSCTL("kern.ipc.shmmni", ipc_shm.shmmni))) {
- do_ipc_shared_mem = 0;
- error("DISABLED: system.ipc_shared_mem_segs");
- error("DISABLED: system.ipc_shared_mem_size");
+ if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.msgmni", mib_msgmni, ipc_msq.msgmni))) {
+ error("DISABLED: system.ipc_msq_queues chart");
+ error("DISABLED: system.ipc_msq_messages chart");
+ error("DISABLED: system.ipc_msq_size chart");
+ error("DISABLED: kern.ipc.msg module");
+ return 1;
+ } else {
+ static struct msqid_kernel *ipc_msq_data = NULL;
+
+ ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
+ if (unlikely(
+ GETSYSCTL_WSIZE("kern.ipc.msqids", mib_msqids, ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
+ error("DISABLED: system.ipc_msq_queues chart");
+ error("DISABLED: system.ipc_msq_messages chart");
+ error("DISABLED: system.ipc_msq_size chart");
+ error("DISABLED: kern.ipc.msg module");
+ return 1;
} else {
- ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
- if (unlikely(getsysctl("kern.ipc.shmsegs", ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
- do_ipc_shared_mem = 0;
- error("DISABLED: system.ipc_shared_mem_segs");
- error("DISABLED: system.ipc_shared_mem_size");
- } else {
- for (i = 0; i < ipc_shm.shmmni; i++) {
- if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
- ipc_shm.segs += 1;
- ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
- }
+ int i;
+
+ for (i = 0; i < ipc_msq.msgmni; i++) {
+ if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
+ ipc_msq.queues += 1;
+ ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
+ ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
+ ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
}
+ }
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find("system.ipc_shared_mem_segs");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_shared_mem_segs", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments", "segments", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "segments", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ static RRDSET *st_queues = NULL, *st_messages = NULL, *st_size = NULL;
+ static RRDDIM *rd_queues = NULL, *rd_messages = NULL, *rd_allocated = NULL, *rd_used = NULL;
+
+ if (unlikely(!st_queues)) {
+ st_queues = rrdset_create_localhost("system",
+ "ipc_msq_queues",
+ NULL,
+ "ipc message queues",
+ NULL,
+ "Number of IPC Message Queues",
+ "queues",
+ 990,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_queues = rrddim_add(st_queues, "queues", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_queues);
- rrddim_set(st, "segments", ipc_shm.segs);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_queues, rd_queues, ipc_msq.queues);
+ rrdset_done(st_queues);
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find("system.ipc_shared_mem_size");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_shared_mem_size", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments Size", "kilobytes", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "allocated", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ if (unlikely(!st_messages)) {
+ st_messages = rrdset_create_localhost("system",
+ "ipc_msq_messages",
+ NULL,
+ "ipc message queues",
+ NULL,
+ "Number of Messages in IPC Message Queues",
+ "messages",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_messages = rrddim_add(st_messages, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_messages);
- rrddim_set(st, "allocated", ipc_shm.segsize);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_messages, rd_messages, ipc_msq.messages);
+ rrdset_done(st_messages);
+
+ // --------------------------------------------------------------------
+
+ if (unlikely(!st_size)) {
+ st_size = rrdset_create_localhost("system",
+ "ipc_msq_size",
+ NULL,
+ "ipc message queues",
+ NULL,
+ "Size of IPC Message Queues",
+ "bytes",
+ 1100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rd_used = rrddim_add(st_size, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
+ else rrdset_next(st_size);
+
+ rrddim_set_by_pointer(st_size, rd_allocated, ipc_msq.allocsize);
+ rrddim_set_by_pointer(st_size, rd_used, ipc_msq.usedsize);
+ rrdset_done(st_size);
}
}
- // --------------------------------------------------------------------
-
- if (likely(do_ipc_msg_queues)) {
- if (unlikely(GETSYSCTL("kern.ipc.msgmni", ipc_msq.msgmni))) {
- do_ipc_msg_queues = 0;
- error("DISABLED: system.ipc_msq_queues");
- error("DISABLED: system.ipc_msq_messages");
- error("DISABLED: system.ipc_msq_size");
- } else {
- ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
- if (unlikely(getsysctl("kern.ipc.msqids", ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
- do_ipc_msg_queues = 0;
- error("DISABLED: system.ipc_msq_queues");
- error("DISABLED: system.ipc_msq_messages");
- error("DISABLED: system.ipc_msq_size");
- } else {
- for (i = 0; i < ipc_msq.msgmni; i++) {
- if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
- ipc_msq.queues += 1;
- ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
- ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
- ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
- }
- }
+ return 0;
+}
- // --------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
+// uptime
- st = rrdset_find("system.ipc_msq_queues");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_msq_queues", NULL, "ipc message queues", NULL, "Number of IPC Message Queues", "queues", 990, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "queues", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+int do_uptime(int update_every, usec_t dt) {
+ (void)dt;
+ struct timespec up_time;
- rrddim_set(st, "queues", ipc_msq.queues);
- rrdset_done(st);
+ clock_gettime(CLOCK_UPTIME, &up_time);
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find("system.ipc_msq_messages");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_msq_messages", NULL, "ipc message queues", NULL, "Number of Messages in IPC Message Queues", "messages", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "messages", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ 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
+ );
+
+ rd = rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
- rrddim_set(st, "messages", ipc_msq.messages);
- rrdset_done(st);
+ rrddim_set_by_pointer(st, rd, up_time.tv_sec);
+ rrdset_done(st);
- // --------------------------------------------------------------------
+ return 0;
+}
- st = rrdset_find("system.ipc_msq_size");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_msq_size", NULL, "ipc message queues", NULL, "Size of IPC Message Queues", "bytes", 1100, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "allocated", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.isr
- rrddim_set(st, "allocated", ipc_msq.allocsize);
- rrddim_set(st, "used", ipc_msq.usedsize);
- rrdset_done(st);
+int do_net_isr(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_netisr = -1, do_netisr_per_core = -1;
- }
- }
+ if (unlikely(do_netisr == -1)) {
+ do_netisr = config_get_boolean("plugin:freebsd:net.isr", "netisr", 1);
+ do_netisr_per_core = config_get_boolean("plugin:freebsd:net.isr", "netisr per core", 1);
}
- // --------------------------------------------------------------------
+ static int mib_workstream[3] = {0, 0, 0}, mib_work[3] = {0, 0, 0};
+ int common_error = 0;
+ size_t netisr_workstream_size = sizeof(mib_workstream), netisr_work_size = sizeof(mib_work);
+ unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
+ static struct sysctl_netisr_workstream *netisr_workstream = NULL;
+ static struct sysctl_netisr_work *netisr_work = NULL;
+ static struct netisr_stats {
+ collected_number dispatched;
+ collected_number hybrid_dispatched;
+ collected_number qdrops;
+ collected_number queued;
+ } *netisr_stats = NULL;
if (likely(do_netisr || do_netisr_per_core)) {
- if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
- common_error = 1;
- } else if (unlikely(ncpus > 9999)) {
- error("FREEBSD: There are more than 4 digits in cpu cores number");
- common_error = 1;
- } else if (unlikely(sysctlbyname("net.isr.workstream", NULL, &netisr_workstream_size, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(net.isr.workstream...) failed: %s", strerror(errno));
+ if (unlikely(GETSYSCTL_SIZE("net.isr.workstream", mib_workstream, netisr_workstream_size))) {
common_error = 1;
- } else if (unlikely(sysctlbyname("net.isr.work", NULL, &netisr_work_size, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(net.isr.work...) failed: %s", strerror(errno));
+ } else if (unlikely(GETSYSCTL_SIZE("net.isr.work", mib_work, netisr_work_size))) {
common_error = 1;
} else {
num_netisr_workstreams = netisr_workstream_size / sizeof(struct sysctl_netisr_workstream);
netisr_workstream = reallocz(netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream));
- if (unlikely(getsysctl("net.isr.workstream", netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
+ if (unlikely(GETSYSCTL_WSIZE("net.isr.workstream", mib_workstream, netisr_workstream,
+ num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
common_error = 1;
} else {
num_netisr_works = netisr_work_size / sizeof(struct sysctl_netisr_work);
netisr_work = reallocz(netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work));
- if (unlikely(getsysctl("net.isr.work", netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work)))){
+ if (unlikely(GETSYSCTL_WSIZE("net.isr.work", mib_work, netisr_work,
+ num_netisr_works * sizeof(struct sysctl_netisr_work)))){
common_error = 1;
}
}
}
if (unlikely(common_error)) {
do_netisr = 0;
- error("DISABLED: system.softnet_stat");
+ error("DISABLED: system.softnet_stat chart");
do_netisr_per_core = 0;
- error("DISABLED: system.cpuX_softnet_stat");
+ error("DISABLED: system.cpuX_softnet_stat chart");
common_error = 0;
+ error("DISABLED: net.isr module");
+ return 1;
} else {
- netisr_stats = reallocz(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
- bzero(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
+ unsigned long i, n;
+ int j;
+
+ netisr_stats = reallocz(netisr_stats, (number_of_cpus + 1) * sizeof(struct netisr_stats));
+ memset(netisr_stats, 0, (number_of_cpus + 1) * sizeof(struct netisr_stats));
for (i = 0; i < num_netisr_workstreams; i++) {
for (n = 0; n < num_netisr_works; n++) {
if (netisr_workstream[i].snws_wsid == netisr_work[n].snw_wsid) {
@@ -1121,467 +1314,584 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
}
}
}
- for (i = 0; i < ncpus; i++) {
- netisr_stats[ncpus].dispatched += netisr_stats[i].dispatched;
- netisr_stats[ncpus].hybrid_dispatched += netisr_stats[i].hybrid_dispatched;
- netisr_stats[ncpus].qdrops += netisr_stats[i].qdrops;
- netisr_stats[ncpus].queued += netisr_stats[i].queued;
+ for (j = 0; j < number_of_cpus; j++) {
+ netisr_stats[number_of_cpus].dispatched += netisr_stats[j].dispatched;
+ netisr_stats[number_of_cpus].hybrid_dispatched += netisr_stats[j].hybrid_dispatched;
+ netisr_stats[number_of_cpus].qdrops += netisr_stats[j].qdrops;
+ netisr_stats[number_of_cpus].queued += netisr_stats[j].queued;
}
}
+ } else {
+ error("DISABLED: net.isr module");
+ return 1;
}
// --------------------------------------------------------------------
if (likely(do_netisr)) {
- st = rrdset_find_bytype("system", "softnet_stat");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_dispatched = NULL, *rd_hybrid_dispatched = NULL, *rd_qdrops = NULL, *rd_queued = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat", "events/s", 955, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "qdrops", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "queued", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("system",
+ "softnet_stat",
+ NULL,
+ "softnet_stat",
+ NULL,
+ "System softnet_stat",
+ "events/s",
+ 955,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_dispatched = rrddim_add(st, "dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_hybrid_dispatched = rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_qdrops = rrddim_add(st, "qdrops", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_queued = rrddim_add(st, "queued", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "dispatched", netisr_stats[ncpus].dispatched);
- rrddim_set(st, "hybrid_dispatched", netisr_stats[ncpus].hybrid_dispatched);
- rrddim_set(st, "qdrops", netisr_stats[ncpus].qdrops);
- rrddim_set(st, "queued", netisr_stats[ncpus].queued);
+ rrddim_set_by_pointer(st, rd_dispatched, netisr_stats[number_of_cpus].dispatched);
+ rrddim_set_by_pointer(st, rd_hybrid_dispatched, netisr_stats[number_of_cpus].hybrid_dispatched);
+ rrddim_set_by_pointer(st, rd_qdrops, netisr_stats[number_of_cpus].qdrops);
+ rrddim_set_by_pointer(st, rd_queued, netisr_stats[number_of_cpus].queued);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_netisr_per_core)) {
- for (i = 0; i < ncpus ;i++) {
- snprintfz(netstat_cpuid, 21, "cpu%d_softnet_stat", i);
+ static struct softnet_chart {
+ char netisr_cpuid[MAX_INT_DIGITS + 17];
+ RRDSET *st;
+ RRDDIM *rd_dispatched;
+ RRDDIM *rd_hybrid_dispatched;
+ RRDDIM *rd_qdrops;
+ RRDDIM *rd_queued;
+ } *all_softnet_charts = NULL;
+ static int old_number_of_cpus = 0;
+ int i;
+
+ if(unlikely(number_of_cpus > old_number_of_cpus)) {
+ all_softnet_charts = reallocz(all_softnet_charts, sizeof(struct softnet_chart) * number_of_cpus);
+ memset(&all_softnet_charts[old_number_of_cpus], 0, sizeof(struct softnet_chart) * (number_of_cpus - old_number_of_cpus));
+ old_number_of_cpus = number_of_cpus;
+ }
- st = rrdset_find_bytype("cpu", netstat_cpuid);
- if (unlikely(!st)) {
- st = rrdset_create("cpu", netstat_cpuid, NULL, "softnet_stat", NULL, "Per CPU netisr statistics", "events/s", 1101 + i, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "qdrops", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "queued", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ for (i = 0; i < number_of_cpus ;i++) {
+ snprintfz(all_softnet_charts[i].netisr_cpuid, MAX_INT_DIGITS + 17, "cpu%d_softnet_stat", i);
+
+ if (unlikely(!all_softnet_charts[i].st)) {
+ all_softnet_charts[i].st = rrdset_create_localhost("cpu",
+ all_softnet_charts[i].netisr_cpuid,
+ NULL,
+ "softnet_stat",
+ NULL,
+ "Per CPU netisr statistics",
+ "events/s",
+ 1101 + i,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ all_softnet_charts[i].rd_dispatched = rrddim_add(all_softnet_charts[i].st, "dispatched",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ all_softnet_charts[i].rd_hybrid_dispatched = rrddim_add(all_softnet_charts[i].st, "hybrid_dispatched",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ all_softnet_charts[i].rd_qdrops = rrddim_add(all_softnet_charts[i].st, "qdrops",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ all_softnet_charts[i].rd_queued = rrddim_add(all_softnet_charts[i].st, "queued",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
-
- rrddim_set(st, "dispatched", netisr_stats[i].dispatched);
- rrddim_set(st, "hybrid_dispatched", netisr_stats[i].hybrid_dispatched);
- rrddim_set(st, "qdrops", netisr_stats[i].qdrops);
- rrddim_set(st, "queued", netisr_stats[i].queued);
- rrdset_done(st);
+ else rrdset_next(all_softnet_charts[i].st);
+
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_dispatched,
+ netisr_stats[i].dispatched);
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_hybrid_dispatched,
+ netisr_stats[i].hybrid_dispatched);
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_qdrops,
+ netisr_stats[i].qdrops);
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_queued,
+ netisr_stats[i].queued);
+ rrdset_done(all_softnet_charts[i].st);
}
}
- // --------------------------------------------------------------------
-
- if (likely(do_bandwidth)) {
- if (unlikely(getifaddrs(&ifap))) {
- error("FREEBSD: getifaddrs()");
- do_bandwidth = 0;
- error("DISABLED: system.ipv4");
- } else {
- iftot.ift_ibytes = iftot.ift_obytes = 0;
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family != AF_INET)
- continue;
- iftot.ift_ibytes += IFA_DATA(ibytes);
- iftot.ift_obytes += IFA_DATA(obytes);
- }
-
- st = rrdset_find("system.ipv4");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "InOctets", iftot.ift_ibytes);
- rrddim_set(st, "OutOctets", iftot.ift_obytes);
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- iftot.ift_ibytes = iftot.ift_obytes = 0;
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- iftot.ift_ibytes += IFA_DATA(ibytes);
- iftot.ift_obytes += IFA_DATA(obytes);
- }
-
- st = rrdset_find("system.ipv6");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "sent", iftot.ift_obytes);
- rrddim_set(st, "received", iftot.ift_ibytes);
- rrdset_done(st);
-
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family != AF_LINK)
- continue;
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "received", IFA_DATA(ibytes));
- rrddim_set(st, "sent", IFA_DATA(obytes));
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net_packets", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "received", IFA_DATA(ipackets));
- rrddim_set(st, "sent", IFA_DATA(opackets));
- rrddim_set(st, "multicast_received", IFA_DATA(imcasts));
- rrddim_set(st, "multicast_sent", IFA_DATA(omcasts));
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net_errors", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "inbound", IFA_DATA(ierrors));
- rrddim_set(st, "outbound", IFA_DATA(oerrors));
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net_drops", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-#if __FreeBSD__ >= 11
- rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
-#endif
- }
- else rrdset_next(st);
+ return 0;
+}
- rrddim_set(st, "inbound", IFA_DATA(iqdrops));
-#if __FreeBSD__ >= 11
- rrddim_set(st, "outbound", IFA_DATA(oqdrops));
-#endif
- rrdset_done(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.tcp.states
- // --------------------------------------------------------------------
+int do_net_inet_tcp_states(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ uint64_t tcps_states[TCP_NSTATES];
- st = rrdset_find_bytype("net_events", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.states", mib, tcps_states))) {
+ error("DISABLED: ipv4.tcpsock chart");
+ error("DISABLED: net.inet.tcp.states module");
+ return 1;
+ } else {
- rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ // --------------------------------------------------------------------
- rrddim_set(st, "collisions", IFA_DATA(collisions));
- rrdset_done(st);
- }
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- freeifaddrs(ifap);
- }
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpsock",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Connections",
+ "active connections",
+ 2500,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd, tcps_states[TCPS_ESTABLISHED]);
+ rrdset_done(st);
}
- // --------------------------------------------------------------------
-
- // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
- if (likely(do_tcp_sockets)) {
- if (unlikely(GETSYSCTL("net.inet.tcp.states", tcps_states))) {
- do_tcp_sockets = 0;
- error("DISABLED: ipv4.tcpsock");
- } else {
- if (likely(do_tcp_sockets)) {
- st = rrdset_find("ipv4.tcpsock");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections",
- "active connections", 2500, update_every, RRDSET_TYPE_LINE);
+ return 0;
+}
- rrddim_add(st, "CurrEstab", "connections", 1, 1, RRDDIM_ABSOLUTE);
- } else
- rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.tcp.stats
- rrddim_set(st, "CurrEstab", tcps_states[TCPS_ESTABLISHED]);
- rrdset_done(st);
- }
- }
+int do_net_inet_tcp_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcpext_connaborts = -1, do_tcpext_ofo = -1, do_tcpext_syncookies = -1, do_ecn = -1;
+
+ if (unlikely(do_tcp_packets == -1)) {
+ do_tcp_packets = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP packets", 1);
+ do_tcp_errors = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP errors", 1);
+ do_tcp_handshake = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP handshake issues", 1);
+ do_tcpext_connaborts = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP connection aborts",
+ CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP out-of-order queue",
+ CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syncookies = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP SYN cookies",
+ CONFIG_BOOLEAN_AUTO);
+ do_ecn = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "ECN packets",
+ CONFIG_BOOLEAN_AUTO);
}
- // --------------------------------------------------------------------
-
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
- if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
- if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
+ if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syncookies || do_ecn)) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct tcpstat tcpstat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.stats", mib, tcpstat))) {
do_tcp_packets = 0;
- error("DISABLED: ipv4.tcppackets");
+ error("DISABLED: ipv4.tcppackets chart");
do_tcp_errors = 0;
- error("DISABLED: ipv4.tcperrors");
+ error("DISABLED: ipv4.tcperrors chart");
do_tcp_handshake = 0;
- error("DISABLED: ipv4.tcphandshake");
+ error("DISABLED: ipv4.tcphandshake chart");
do_tcpext_connaborts = 0;
- error("DISABLED: ipv4.tcpconnaborts");
+ error("DISABLED: ipv4.tcpconnaborts chart");
do_tcpext_ofo = 0;
- error("DISABLED: ipv4.tcpofo");
- do_tcpext_syscookies = 0;
- error("DISABLED: ipv4.tcpsyncookies");
+ error("DISABLED: ipv4.tcpofo chart");
+ do_tcpext_syncookies = 0;
+ error("DISABLED: ipv4.tcpsyncookies chart");
do_ecn = 0;
- error("DISABLED: ipv4.ecnpkts");
+ error("DISABLED: ipv4.ecnpkts chart");
+ error("DISABLED: net.inet.tcp.stats module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_tcp_packets)) {
- st = rrdset_find("ipv4.tcppackets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
- "packets/s",
- 2600, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_segs = NULL, *rd_out_segs = NULL;
- rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcppackets",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Packets",
+ "packets/s",
+ 2600,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_segs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_segs = rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InSegs", tcpstat.tcps_rcvtotal);
- rrddim_set(st, "OutSegs", tcpstat.tcps_sndtotal);
+ rrddim_set_by_pointer(st, rd_in_segs, tcpstat.tcps_rcvtotal);
+ rrddim_set_by_pointer(st, rd_out_segs, tcpstat.tcps_sndtotal);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_tcp_errors)) {
- st = rrdset_find("ipv4.tcperrors");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_errs = NULL, *rd_in_csum_errs = NULL, *rd_retrans_segs = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
- "packets/s",
- 2700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "tcperrors",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Errors",
+ "packets/s",
+ 2700,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_errs = rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum_errs = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_retrans_segs = rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
#if __FreeBSD__ >= 11
- rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull + tcpstat.tcps_rcvshort);
+ rrddim_set_by_pointer(st, rd_in_errs, tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull +
+ tcpstat.tcps_rcvshort);
#else
- rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
+ rrddim_set_by_pointer(st, rd_in_errs, tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
#endif
- rrddim_set(st, "InCsumErrors", tcpstat.tcps_rcvbadsum);
- rrddim_set(st, "RetransSegs", tcpstat.tcps_sndrexmitpack);
+ rrddim_set_by_pointer(st, rd_in_csum_errs, tcpstat.tcps_rcvbadsum);
+ rrddim_set_by_pointer(st, rd_retrans_segs, tcpstat.tcps_sndrexmitpack);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_tcp_handshake)) {
- st = rrdset_find("ipv4.tcphandshake");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_estab_resets = NULL, *rd_active_opens = NULL, *rd_passive_opens = NULL,
+ *rd_attempt_fails = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
- "IPv4 TCP Handshake Issues",
- "events/s", 2900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "tcphandshake",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Handshake Issues",
+ "events/s",
+ 2900,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_estab_resets = rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_active_opens = rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_passive_opens = rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_attempt_fails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "EstabResets", tcpstat.tcps_drops);
- rrddim_set(st, "ActiveOpens", tcpstat.tcps_connattempt);
- rrddim_set(st, "PassiveOpens", tcpstat.tcps_accepts);
- rrddim_set(st, "AttemptFails", tcpstat.tcps_conndrops);
+ rrddim_set_by_pointer(st, rd_estab_resets, tcpstat.tcps_drops);
+ rrddim_set_by_pointer(st, rd_active_opens, tcpstat.tcps_connattempt);
+ rrddim_set_by_pointer(st, rd_passive_opens, tcpstat.tcps_accepts);
+ rrddim_set_by_pointer(st, rd_attempt_fails, tcpstat.tcps_conndrops);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
- do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpconnaborts");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
+ if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
+ do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_on_data = NULL, *rd_on_close = NULL, *rd_on_memory = NULL,
+ *rd_on_timeout = NULL, *rd_on_linger = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpconnaborts",
+ NULL,
+ "tcp",
+ NULL,
+ "TCP Connection Aborts",
+ "connections/s",
+ 3010,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_on_data = rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_close = rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_memory = rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_timeout = rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_linger = rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "TCPAbortOnData", tcpstat.tcps_rcvpackafterwin);
- rrddim_set(st, "TCPAbortOnClose", tcpstat.tcps_rcvafterclose);
- rrddim_set(st, "TCPAbortOnMemory", tcpstat.tcps_rcvmemdrop);
- rrddim_set(st, "TCPAbortOnTimeout", tcpstat.tcps_persistdrop);
- rrddim_set(st, "TCPAbortOnLinger", tcpstat.tcps_finwait2_drops);
+ rrddim_set_by_pointer(st, rd_on_data, tcpstat.tcps_rcvpackafterwin);
+ rrddim_set_by_pointer(st, rd_on_close, tcpstat.tcps_rcvafterclose);
+ rrddim_set_by_pointer(st, rd_on_memory, tcpstat.tcps_rcvmemdrop);
+ rrddim_set_by_pointer(st, rd_on_timeout, tcpstat.tcps_persistdrop);
+ rrddim_set_by_pointer(st, rd_on_linger, tcpstat.tcps_finwait2_drops);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
- do_tcpext_ofo = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpofo");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+ if (do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
+ do_tcpext_ofo = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ofo_queue = NULL;
- rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRDDIM_INCREMENTAL);
+ 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
+ );
+
+ rd_ofo_queue = rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "TCPOFOQueue", tcpstat.tcps_rcvoopack);
+ rrddim_set_by_pointer(st, rd_ofo_queue, tcpstat.tcps_rcvoopack);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
- do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
+ if (do_tcpext_syncookies == CONFIG_BOOLEAN_YES || (do_tcpext_syncookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
+ do_tcpext_syncookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find("ipv4.tcpsyncookies");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_recv = NULL, *rd_send = NULL, *rd_failed = NULL;
- rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpsyncookies",
+ NULL,
+ "tcp",
+ NULL,
+ "TCP SYN Cookies",
+ "packets/s",
+ 3100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_recv = rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_send = rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "SyncookiesRecv", tcpstat.tcps_sc_recvcookie);
- rrddim_set(st, "SyncookiesSent", tcpstat.tcps_sc_sendcookie);
- rrddim_set(st, "SyncookiesFailed", tcpstat.tcps_sc_zonefail);
+ rrddim_set_by_pointer(st, rd_recv, tcpstat.tcps_sc_recvcookie);
+ rrddim_set_by_pointer(st, rd_send, tcpstat.tcps_sc_sendcookie);
+ rrddim_set_by_pointer(st, rd_failed, tcpstat.tcps_sc_zonefail);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_ce || tcpstat.tcps_ecn_ect0 || tcpstat.tcps_ecn_ect1))) {
- do_ecn = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.ecnpkts");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_ce || tcpstat.tcps_ecn_ect0 || tcpstat.tcps_ecn_ect1))) {
+ do_ecn = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ce = NULL, *rd_no_ect = NULL, *rd_ect0 = NULL, *rd_ect1 = NULL;
- rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRDDIM_INCREMENTAL);
+ 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);
+
+ rd_ce = rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_no_ect = rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ect0 = rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ect1 = rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_ce);
- rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 + tcpstat.tcps_ecn_ect1));
- rrddim_set(st, "InECT0Pkts", tcpstat.tcps_ecn_ect0);
- rrddim_set(st, "InECT1Pkts", tcpstat.tcps_ecn_ect1);
+ rrddim_set_by_pointer(st, rd_ce, tcpstat.tcps_ecn_ce);
+ rrddim_set_by_pointer(st, rd_no_ect, tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 +
+ tcpstat.tcps_ecn_ect1));
+ rrddim_set_by_pointer(st, rd_ect0, tcpstat.tcps_ecn_ect0);
+ rrddim_set_by_pointer(st, rd_ect1, tcpstat.tcps_ecn_ect1);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.tcp.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.udp.stats
+
+int do_net_inet_udp_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_udp_packets = -1, do_udp_errors = -1;
+
+ if (unlikely(do_udp_packets == -1)) {
+ do_udp_packets = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP packets", 1);
+ do_udp_errors = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP errors", 1);
+ }
// see http://net-snmp.sourceforge.net/docs/mibs/udp.html
if (likely(do_udp_packets || do_udp_errors)) {
- if (unlikely(GETSYSCTL("net.inet.udp.stats", udpstat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct udpstat udpstat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.udp.stats", mib, udpstat))) {
do_udp_packets = 0;
- error("DISABLED: ipv4.udppackets");
+ error("DISABLED: ipv4.udppackets chart");
do_udp_errors = 0;
- error("DISABLED: ipv4.udperrors");
+ error("DISABLED: ipv4.udperrors chart");
+ error("DISABLED: net.inet.udp.stats module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_udp_packets)) {
- st = rrdset_find("ipv4.udppackets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
- "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "udppackets",
+ NULL,
+ "udp",
+ NULL,
+ "IPv4 UDP Packets",
+ "packets/s",
+ 2601,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InDatagrams", udpstat.udps_ipackets);
- rrddim_set(st, "OutDatagrams", udpstat.udps_opackets);
+ rrddim_set_by_pointer(st, rd_in, udpstat.udps_ipackets);
+ rrddim_set_by_pointer(st, rd_out, udpstat.udps_opackets);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_udp_errors)) {
- st = rrdset_find("ipv4.udperrors");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_errors = NULL, *rd_no_ports = NULL, *rd_recv_buf_errors = NULL,
+ *rd_in_csum_errors = NULL, *rd_ignored_multi = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
- 2701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "udperrors",
+ NULL,
+ "udp",
+ NULL,
+ "IPv4 UDP Errors",
+ "events/s",
+ 2701,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_errors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_no_ports = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_recv_buf_errors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum_errors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ignored_multi = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InErrors", udpstat.udps_hdrops + udpstat.udps_badlen);
- rrddim_set(st, "NoPorts", udpstat.udps_noport);
- rrddim_set(st, "RcvbufErrors", udpstat.udps_fullsock);
- rrddim_set(st, "InCsumErrors", udpstat.udps_badsum + udpstat.udps_nosum);
- rrddim_set(st, "IgnoredMulti", udpstat.udps_filtermcast);
+ rrddim_set_by_pointer(st, rd_in_errors, udpstat.udps_hdrops + udpstat.udps_badlen);
+ rrddim_set_by_pointer(st, rd_no_ports, udpstat.udps_noport);
+ rrddim_set_by_pointer(st, rd_recv_buf_errors, udpstat.udps_fullsock);
+ rrddim_set_by_pointer(st, rd_in_csum_errors, udpstat.udps_badsum + udpstat.udps_nosum);
+ rrddim_set_by_pointer(st, rd_ignored_multi, udpstat.udps_filtermcast);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.udp.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.icmp.stats
+
+int do_net_inet_icmp_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_icmp_packets = -1, do_icmp_errors = -1, do_icmpmsg = -1;
+
+ if (unlikely(do_icmp_packets == -1)) {
+ do_icmp_packets = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP packets", 1);
+ do_icmp_errors = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP errors", 1);
+ do_icmpmsg = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP messages", 1);
+ }
- if (likely(do_icmp_packets || do_icmpmsg)) {
- if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+ if (likely(do_icmp_packets || do_icmp_errors || do_icmpmsg)) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct icmpstat icmpstat;
+ int i;
+ struct icmp_total {
+ u_long msgs_in;
+ u_long msgs_out;
+ } icmp_total = {0, 0};
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.icmp.stats", mib, icmpstat))) {
do_icmp_packets = 0;
- error("DISABLED: ipv4.icmp");
- error("DISABLED: ipv4.icmp_errors");
+ error("DISABLED: ipv4.icmp chart");
+ do_icmp_errors = 0;
+ error("DISABLED: ipv4.icmp_errors chart");
do_icmpmsg = 0;
- error("DISABLED: ipv4.icmpmsg");
+ error("DISABLED: ipv4.icmpmsg chart");
+ error("DISABLED: net.inet.icmp.stats module");
+ return 1;
} else {
for (i = 0; i <= ICMP_MAXTYPE; i++) {
icmp_total.msgs_in += icmpstat.icps_inhist[i];
@@ -1592,39 +1902,54 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp_packets)) {
- st = rrdset_find("ipv4.icmp");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
- 2602,
- update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "icmp",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv4 ICMP Packets",
+ "packets/s",
+ 2602,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InMsgs", icmp_total.msgs_in);
- rrddim_set(st, "OutMsgs", icmp_total.msgs_out);
+ rrddim_set_by_pointer(st, rd_in, icmp_total.msgs_in);
+ rrddim_set_by_pointer(st, rd_out, icmp_total.msgs_out);
rrdset_done(st);
+ }
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
+
+ if (likely(do_icmp_errors)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_csum = NULL;
- st = rrdset_find("ipv4.icmp_errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
- "packets/s",
- 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
+ "packets/s",
+ 2603, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rd_in = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InErrors", icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort);
- rrddim_set(st, "OutErrors", icmpstat.icps_error);
- rrddim_set(st, "InCsumErrors", icmpstat.icps_checksum);
+ rrddim_set_by_pointer(st, rd_in, icmpstat.icps_badcode + icmpstat.icps_badlen +
+ icmpstat.icps_checksum + icmpstat.icps_tooshort);
+ rrddim_set_by_pointer(st, rd_out, icmpstat.icps_error);
+ rrddim_set_by_pointer(st, rd_in_csum, icmpstat.icps_checksum);
rrdset_done(st);
}
@@ -1632,226 +1957,370 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmpmsg)) {
- st = rrdset_find("ipv4.icmpmsg");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_reps = NULL, *rd_out_reps = NULL, *rd_in = NULL, *rd_out = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
- "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
+ "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchoReps", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rd_in_reps = rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_reps = rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InEchoReps", icmpstat.icps_inhist[ICMP_ECHOREPLY]);
- rrddim_set(st, "OutEchoReps", icmpstat.icps_outhist[ICMP_ECHOREPLY]);
- rrddim_set(st, "InEchos", icmpstat.icps_inhist[ICMP_ECHO]);
- rrddim_set(st, "OutEchos", icmpstat.icps_outhist[ICMP_ECHO]);
+ rrddim_set_by_pointer(st, rd_in_reps, icmpstat.icps_inhist[ICMP_ECHOREPLY]);
+ rrddim_set_by_pointer(st, rd_out_reps, icmpstat.icps_outhist[ICMP_ECHOREPLY]);
+ rrddim_set_by_pointer(st, rd_in, icmpstat.icps_inhist[ICMP_ECHO]);
+ rrddim_set_by_pointer(st, rd_out, icmpstat.icps_outhist[ICMP_ECHO]);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.icmp.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.ip.stats
+
+int do_net_inet_ip_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1;
+
+ if (unlikely(do_ip_packets == -1)) {
+ do_ip_packets = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 packets", 1);
+ do_ip_fragsout = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments sent", 1);
+ do_ip_fragsin = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments assembly", 1);
+ do_ip_errors = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 errors", 1);
+ }
// see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
if (likely(do_ip_packets || do_ip_fragsout || do_ip_fragsin || do_ip_errors)) {
- if (unlikely(GETSYSCTL("net.inet.ip.stats", ipstat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct ipstat ipstat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.ip.stats", mib, ipstat))) {
do_ip_packets = 0;
- error("DISABLED: ipv4.packets");
+ error("DISABLED: ipv4.packets chart");
do_ip_fragsout = 0;
- error("DISABLED: ipv4.fragsout");
+ error("DISABLED: ipv4.fragsout chart");
do_ip_fragsin = 0;
- error("DISABLED: ipv4.fragsin");
+ error("DISABLED: ipv4.fragsin chart");
do_ip_errors = 0;
- error("DISABLED: ipv4.errors");
+ error("DISABLED: ipv4.errors chart");
+ error("DISABLED: net.inet.ip.stats module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_ip_packets)) {
- st = rrdset_find("ipv4.packets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s",
- 3000, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_receives = NULL, *rd_out_requests = NULL, *rd_forward_datagrams = NULL,
+ *rd_in_delivers = NULL;
- rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "packets",
+ NULL,
+ "packets",
+ NULL,
+ "IPv4 Packets",
+ "packets/s",
+ 3000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_receives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_requests = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_forward_datagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_delivers = rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "OutRequests", ipstat.ips_localout);
- rrddim_set(st, "InReceives", ipstat.ips_total);
- rrddim_set(st, "ForwDatagrams", ipstat.ips_forward);
- rrddim_set(st, "InDelivers", ipstat.ips_delivered);
+ rrddim_set_by_pointer(st, rd_in_receives, ipstat.ips_total);
+ rrddim_set_by_pointer(st, rd_out_requests, ipstat.ips_localout);
+ rrddim_set_by_pointer(st, rd_forward_datagrams, ipstat.ips_forward);
+ rrddim_set_by_pointer(st, rd_in_delivers, ipstat.ips_delivered);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_ip_fragsout)) {
- st = rrdset_find("ipv4.fragsout");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_fails = NULL, *rd_created = NULL;
- rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "fragsout",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv4 Fragments Sent",
+ "packets/s",
+ 3010,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_fails = rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_created = rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "FragOKs", ipstat.ips_fragmented);
- rrddim_set(st, "FragFails", ipstat.ips_cantfrag);
- rrddim_set(st, "FragCreates", ipstat.ips_ofragments);
+ rrddim_set_by_pointer(st, rd_ok, ipstat.ips_fragmented);
+ rrddim_set_by_pointer(st, rd_fails, ipstat.ips_cantfrag);
+ rrddim_set_by_pointer(st, rd_created, ipstat.ips_ofragments);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_ip_fragsin)) {
- st = rrdset_find("ipv4.fragsin");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsin", NULL, "fragments", NULL,
- "IPv4 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "fragsin",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv4 Fragments Reassembly",
+ "packets/s",
+ 3011,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_all = rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "ReasmOKs", ipstat.ips_fragments);
- rrddim_set(st, "ReasmFails", ipstat.ips_fragdropped);
- rrddim_set(st, "ReasmReqds", ipstat.ips_reassembled);
+ rrddim_set_by_pointer(st, rd_ok, ipstat.ips_fragments);
+ rrddim_set_by_pointer(st, rd_failed, ipstat.ips_fragdropped);
+ rrddim_set_by_pointer(st, rd_all, ipstat.ips_reassembled);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_ip_errors)) {
- st = rrdset_find("ipv4.errors");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s",
- 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
+ *rd_in_hdr_errors = NULL, *rd_out_no_routes = NULL,
+ *rd_in_addr_errors = NULL, *rd_in_unknown_protos = NULL;
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "errors",
+ NULL,
+ "errors",
+ NULL,
+ "IPv4 Errors",
+ "packets/s",
+ 3002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_discards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_discards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_hdr_errors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_no_routes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_addr_errors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_unknown_protos = rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InDiscards", ipstat.ips_badsum + ipstat.ips_tooshort + ipstat.ips_toosmall + ipstat.ips_toolong);
- rrddim_set(st, "OutDiscards", ipstat.ips_odropped);
- rrddim_set(st, "InHdrErrors", ipstat.ips_badhlen + ipstat.ips_badlen + ipstat.ips_badoptions + ipstat.ips_badvers);
- rrddim_set(st, "InAddrErrors", ipstat.ips_badaddr);
- rrddim_set(st, "InUnknownProtos", ipstat.ips_noproto);
- rrddim_set(st, "OutNoRoutes", ipstat.ips_noroute);
+ rrddim_set_by_pointer(st, rd_in_discards, ipstat.ips_badsum + ipstat.ips_tooshort +
+ ipstat.ips_toosmall + ipstat.ips_toolong);
+ rrddim_set_by_pointer(st, rd_out_discards, ipstat.ips_odropped);
+ rrddim_set_by_pointer(st, rd_in_hdr_errors, ipstat.ips_badhlen + ipstat.ips_badlen +
+ ipstat.ips_badoptions + ipstat.ips_badvers);
+ rrddim_set_by_pointer(st, rd_out_no_routes, ipstat.ips_noroute);
+ rrddim_set_by_pointer(st, rd_in_addr_errors, ipstat.ips_badaddr);
+ rrddim_set_by_pointer(st, rd_in_unknown_protos, ipstat.ips_noproto);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.ip.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet6.ip6.stats
+
+int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1;
+
+ if (unlikely(do_ip6_packets == -1)) {
+ do_ip6_packets = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 packets",
+ CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsout = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments sent",
+ CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsin = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments assembly",
+ CONFIG_BOOLEAN_AUTO);
+ do_ip6_errors = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 errors",
+ CONFIG_BOOLEAN_AUTO);
+ }
if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
- if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct ip6stat ip6stat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet6.ip6.stats", mib, ip6stat))) {
do_ip6_packets = 0;
- error("DISABLED: ipv6.packets");
+ error("DISABLED: ipv6.packets chart");
do_ip6_fragsout = 0;
- error("DISABLED: ipv6.fragsout");
+ error("DISABLED: ipv6.fragsout chart");
do_ip6_fragsin = 0;
- error("DISABLED: ipv6.fragsin");
+ error("DISABLED: ipv6.fragsin chart");
do_ip6_errors = 0;
- error("DISABLED: ipv6.errors");
+ error("DISABLED: ipv6.errors chart");
+ error("DISABLED: net.inet6.ip6.stats module");
+ return 1;
} else {
- if (do_ip6_packets == CONFIG_ONDEMAND_YES || (do_ip6_packets == CONFIG_ONDEMAND_ONDEMAND &&
- (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
- ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
- do_ip6_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.packets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000,
- update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ // --------------------------------------------------------------------
+
+ if (do_ip6_packets == CONFIG_BOOLEAN_YES || (do_ip6_packets == CONFIG_BOOLEAN_AUTO &&
+ (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
+ ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
+ do_ip6_packets = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_forwarded = NULL, *rd_delivers = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "packets",
+ NULL,
+ "packets",
+ NULL,
+ "IPv6 Packets",
+ "packets/s",
+ 3000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_forwarded = rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_delivers = rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "sent", ip6stat.ip6s_localout);
- rrddim_set(st, "received", ip6stat.ip6s_total);
- rrddim_set(st, "forwarded", ip6stat.ip6s_forward);
- rrddim_set(st, "delivers", ip6stat.ip6s_delivered);
+ rrddim_set_by_pointer(st, rd_sent, ip6stat.ip6s_localout);
+ rrddim_set_by_pointer(st, rd_received, ip6stat.ip6s_total);
+ rrddim_set_by_pointer(st, rd_forwarded, ip6stat.ip6s_forward);
+ rrddim_set_by_pointer(st, rd_delivers, ip6stat.ip6s_delivered);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ip6_fragsout == CONFIG_ONDEMAND_YES || (do_ip6_fragsout == CONFIG_ONDEMAND_ONDEMAND &&
- (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
- ip6stat.ip6s_ofragments))) {
- do_ip6_fragsout = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsout");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ if (do_ip6_fragsout == CONFIG_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO &&
+ (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
+ ip6stat.ip6s_ofragments))) {
+ do_ip6_fragsout = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "fragsout",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv6 Fragments Sent",
+ "packets/s",
+ 3010,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_all = rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "ok", ip6stat.ip6s_fragmented);
- rrddim_set(st, "failed", ip6stat.ip6s_cantfrag);
- rrddim_set(st, "all", ip6stat.ip6s_ofragments);
+ rrddim_set_by_pointer(st, rd_ok, ip6stat.ip6s_fragmented);
+ rrddim_set_by_pointer(st, rd_failed, ip6stat.ip6s_cantfrag);
+ rrddim_set_by_pointer(st, rd_all, ip6stat.ip6s_ofragments);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ip6_fragsin == CONFIG_ONDEMAND_YES || (do_ip6_fragsin == CONFIG_ONDEMAND_ONDEMAND &&
- (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
- ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
- do_ip6_fragsin = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsin");
+ if (do_ip6_fragsin == CONFIG_BOOLEAN_YES || (do_ip6_fragsin == CONFIG_BOOLEAN_AUTO &&
+ (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
+ ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
+ do_ip6_fragsin = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_timeout = NULL, *rd_all = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6",
+ "fragsin",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv6 Fragments Reassembly",
+ "packets/s",
+ 3011,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_timeout = rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_all = rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "ok", ip6stat.ip6s_reassembled);
- rrddim_set(st, "failed", ip6stat.ip6s_fragdropped);
- rrddim_set(st, "timeout", ip6stat.ip6s_fragtimeout);
- rrddim_set(st, "all", ip6stat.ip6s_fragments);
+ rrddim_set_by_pointer(st, rd_ok, ip6stat.ip6s_reassembled);
+ rrddim_set_by_pointer(st, rd_failed, ip6stat.ip6s_fragdropped);
+ rrddim_set_by_pointer(st, rd_timeout, ip6stat.ip6s_fragtimeout);
+ rrddim_set_by_pointer(st, rd_all, ip6stat.ip6s_fragments);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ip6_errors == CONFIG_ONDEMAND_YES || (do_ip6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_ip6_errors == CONFIG_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && (
ip6stat.ip6s_toosmall ||
ip6stat.ip6s_odropped ||
ip6stat.ip6s_badoptions ||
@@ -1861,346 +2330,1634 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
ip6stat.ip6s_tooshort ||
ip6stat.ip6s_cantforward ||
ip6stat.ip6s_noroute))) {
- do_ip6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.errors");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ do_ip6_errors = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
+ *rd_in_hdr_errors = NULL, *rd_in_addr_errors = NULL, *rd_in_truncated_pkts = NULL,
+ *rd_in_no_routes = NULL, *rd_out_no_routes = NULL;
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "errors",
+ NULL,
+ "errors",
+ NULL,
+ "IPv6 Errors",
+ "packets/s",
+ 3002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_discards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_discards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_hdr_errors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_addr_errors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_truncated_pkts = rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_no_routes = rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_no_routes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InDiscards", ip6stat.ip6s_toosmall);
- rrddim_set(st, "OutDiscards", ip6stat.ip6s_odropped);
-
- rrddim_set(st, "InHdrErrors",
- ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers + ip6stat.ip6s_exthdrtoolong);
- rrddim_set(st, "InAddrErrors", ip6stat.ip6s_sources_none);
- rrddim_set(st, "InTruncatedPkts", ip6stat.ip6s_tooshort);
- rrddim_set(st, "InNoRoutes", ip6stat.ip6s_cantforward);
-
- rrddim_set(st, "OutNoRoutes", ip6stat.ip6s_noroute);
+ rrddim_set_by_pointer(st, rd_in_discards, ip6stat.ip6s_toosmall);
+ rrddim_set_by_pointer(st, rd_out_discards, ip6stat.ip6s_odropped);
+ rrddim_set_by_pointer(st, rd_in_hdr_errors, ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers +
+ ip6stat.ip6s_exthdrtoolong);
+ rrddim_set_by_pointer(st, rd_in_addr_errors, ip6stat.ip6s_sources_none);
+ rrddim_set_by_pointer(st, rd_in_truncated_pkts, ip6stat.ip6s_tooshort);
+ rrddim_set_by_pointer(st, rd_in_no_routes, ip6stat.ip6s_cantforward);
+ rrddim_set_by_pointer(st, rd_out_no_routes, ip6stat.ip6s_noroute);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet6.ip6.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet6.icmp6.stats
+
+int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
+ do_icmp6_neighbor = -1, do_icmp6_types = -1;
+
+ if (unlikely(do_icmp6 == -1)) {
+ do_icmp6 = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_redir = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp redirects",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_errors = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp errors",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_echos = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp echos",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_router = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp router",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_neighbor = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp neighbor",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_types = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp types",
+ CONFIG_BOOLEAN_AUTO);
+ }
if (likely(do_icmp6 || do_icmp6_redir || do_icmp6_errors || do_icmp6_echos || do_icmp6_router || do_icmp6_neighbor || do_icmp6_types)) {
- if (unlikely(GETSYSCTL("net.inet6.icmp6.stats", icmp6stat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct icmp6stat icmp6stat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet6.icmp6.stats", mib, icmp6stat))) {
do_icmp6 = 0;
- error("DISABLED: ipv6.icmp");
+ error("DISABLED: ipv6.icmp chart");
+ do_icmp6_redir = 0;
+ error("DISABLED: ipv6.icmpredir chart");
+ do_icmp6_errors = 0;
+ error("DISABLED: ipv6.icmperrors chart");
+ do_icmp6_echos = 0;
+ error("DISABLED: ipv6.icmpechos chart");
+ do_icmp6_router = 0;
+ error("DISABLED: ipv6.icmprouter chart");
+ do_icmp6_neighbor = 0;
+ error("DISABLED: ipv6.icmpneighbor chart");
+ do_icmp6_types = 0;
+ error("DISABLED: ipv6.icmptypes chart");
+ error("DISABLED: net.inet6.icmp6.stats module");
+ return 1;
} else {
+ int i;
+ struct icmp6_total {
+ u_long msgs_in;
+ u_long msgs_out;
+ } icmp6_total = {0, 0};
+
for (i = 0; i <= ICMP6_MAXTYPE; i++) {
icmp6_total.msgs_in += icmp6stat.icp6s_inhist[i];
icmp6_total.msgs_out += icmp6stat.icp6s_outhist[i];
}
icmp6_total.msgs_in += icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort;
- if (do_icmp6 == CONFIG_ONDEMAND_YES || (do_icmp6 == CONFIG_ONDEMAND_ONDEMAND && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
- do_icmp6 = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmp");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages",
- "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ // --------------------------------------------------------------------
+
+ if (do_icmp6 == CONFIG_BOOLEAN_YES || (do_icmp6 == CONFIG_BOOLEAN_AUTO && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
+ do_icmp6 = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmp",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Messages",
+ "messages/s",
+ 10000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "sent", icmp6_total.msgs_in);
- rrddim_set(st, "received", icmp6_total.msgs_out);
+ rrddim_set_by_pointer(st, rd_received, icmp6_total.msgs_out);
+ rrddim_set_by_pointer(st, rd_sent, icmp6_total.msgs_in);
+
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_redir == CONFIG_ONDEMAND_YES || (do_icmp6_redir == CONFIG_ONDEMAND_ONDEMAND && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
- do_icmp6_redir = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpredir");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects",
- "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_redir == CONFIG_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
+ do_icmp6_redir = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmpredir",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Redirects",
+ "redirects/s",
+ 10050,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "sent", icmp6stat.icp6s_inhist[ND_REDIRECT]);
- rrddim_set(st, "received", icmp6stat.icp6s_outhist[ND_REDIRECT]);
+ rrddim_set_by_pointer(st, rd_received, icmp6stat.icp6s_outhist[ND_REDIRECT]);
+ rrddim_set_by_pointer(st, rd_sent, icmp6stat.icp6s_inhist[ND_REDIRECT]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_errors == CONFIG_ONDEMAND_YES || (do_icmp6_errors == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_badcode ||
- icmp6stat.icp6s_badlen ||
- icmp6stat.icp6s_checksum ||
- icmp6stat.icp6s_tooshort ||
- icmp6stat.icp6s_error ||
- icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH] ||
- icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED] ||
- icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB] ||
- icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
- icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
- icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
- do_icmp6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmperrors");
+ if (do_icmp6_errors == CONFIG_BOOLEAN_YES || (do_icmp6_errors == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_badcode ||
+ icmp6stat.icp6s_badlen ||
+ icmp6stat.icp6s_checksum ||
+ icmp6stat.icp6s_tooshort ||
+ icmp6stat.icp6s_error ||
+ icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH] ||
+ icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED] ||
+ icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB] ||
+ icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
+ icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
+ icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
+ do_icmp6_errors = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_errors = NULL, *rd_out_errors = NULL, *rd_in_csum_errors = NULL,
+ *rd_in_dest_unreachs = NULL, *rd_in_pkt_too_bigs = NULL, *rd_in_time_excds = NULL,
+ *rd_in_parm_problems = NULL, *rd_out_dest_unreachs = NULL, *rd_out_time_excds = NULL,
+ *rd_out_parm_problems = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6",
+ "icmperrors",
+ NULL, "icmp",
+ NULL,
+ "IPv6 ICMP Errors",
+ "errors/s",
+ 10100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_errors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_errors = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum_errors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_dest_unreachs = rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_pkt_too_bigs = rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_time_excds = rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_parm_problems = rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_dest_unreachs = rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_time_excds = rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_parm_problems = rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InErrors", icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
- rrddim_set(st, "OutErrors", icmp6stat.icp6s_error);
- rrddim_set(st, "InCsumErrors", icmp6stat.icp6s_checksum);
- rrddim_set(st, "InDestUnreachs", icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
- rrddim_set(st, "InPktTooBigs", icmp6stat.icp6s_badlen);
- rrddim_set(st, "InTimeExcds", icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
- rrddim_set(st, "InParmProblems", icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
- rrddim_set(st, "OutDestUnreachs", icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
- rrddim_set(st, "OutTimeExcds", icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
- rrddim_set(st, "OutParmProblems", icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
+ rrddim_set_by_pointer(st, rd_in_errors, icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen +
+ icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
+ rrddim_set_by_pointer(st, rd_out_errors, icmp6stat.icp6s_error);
+ rrddim_set_by_pointer(st, rd_in_csum_errors, icmp6stat.icp6s_checksum);
+ rrddim_set_by_pointer(st, rd_in_dest_unreachs, icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
+ rrddim_set_by_pointer(st, rd_in_pkt_too_bigs, icmp6stat.icp6s_badlen);
+ rrddim_set_by_pointer(st, rd_in_time_excds, icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
+ rrddim_set_by_pointer(st, rd_in_parm_problems, icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
+ rrddim_set_by_pointer(st, rd_out_dest_unreachs, icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
+ rrddim_set_by_pointer(st, rd_out_time_excds, icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
+ rrddim_set_by_pointer(st, rd_out_parm_problems, icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_echos == CONFIG_ONDEMAND_YES || (do_icmp6_echos == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
- icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
- icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
- icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
- do_icmp6_echos = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpechos");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_echos == CONFIG_BOOLEAN_YES || (do_icmp6_echos == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
+ icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
+ icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
+ icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
+ do_icmp6_echos = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_replies = NULL, *rd_out_replies = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmpechos",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Echo",
+ "messages/s",
+ 10200,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_replies = rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_replies = rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InEchos", icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
- rrddim_set(st, "OutEchos", icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
- rrddim_set(st, "InEchoReplies", icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
- rrddim_set(st, "OutEchoReplies", icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
+ rrddim_set_by_pointer(st, rd_in, icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
+ rrddim_set_by_pointer(st, rd_out, icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
+ rrddim_set_by_pointer(st, rd_in_replies, icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
+ rrddim_set_by_pointer(st, rd_out_replies, icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_router == CONFIG_ONDEMAND_YES || (do_icmp6_router == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
- icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
- icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
- icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
- do_icmp6_router = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmprouter");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_router == CONFIG_BOOLEAN_YES || (do_icmp6_router == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
+ icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
+ icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
+ icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
+ do_icmp6_router = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
+ *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmprouter",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 Router Messages",
+ "messages/s",
+ 10400,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_solicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_solicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_advertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InSolicits", icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
- rrddim_set(st, "OutSolicits", icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
- rrddim_set(st, "InAdvertisements", icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
- rrddim_set(st, "OutAdvertisements", icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
+ rrddim_set_by_pointer(st, rd_in_solicits, icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_out_solicits, icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_in_advertisements, icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
+ rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_neighbor == CONFIG_ONDEMAND_YES || (do_icmp6_neighbor == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
- icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
- icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
- icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
- do_icmp6_neighbor = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpneighbor");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_neighbor == CONFIG_BOOLEAN_YES || (do_icmp6_neighbor == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
+ icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
+ icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
+ icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
+ do_icmp6_neighbor = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
+ *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmpneighbor",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 Neighbor Messages",
+ "messages/s",
+ 10500,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_solicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_solicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_advertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InSolicits", icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
- rrddim_set(st, "OutSolicits", icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
- rrddim_set(st, "InAdvertisements", icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
- rrddim_set(st, "OutAdvertisements", icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
+ rrddim_set_by_pointer(st, rd_in_solicits, icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_out_solicits, icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_in_advertisements, icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
+ rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_types == CONFIG_ONDEMAND_YES || (do_icmp6_types == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[1] ||
- icmp6stat.icp6s_inhist[128] ||
- icmp6stat.icp6s_inhist[129] ||
- icmp6stat.icp6s_inhist[136] ||
- icmp6stat.icp6s_outhist[1] ||
- icmp6stat.icp6s_outhist[128] ||
- icmp6stat.icp6s_outhist[129] ||
- icmp6stat.icp6s_outhist[133] ||
- icmp6stat.icp6s_outhist[135] ||
- icmp6stat.icp6s_outhist[136]))) {
- do_icmp6_types = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmptypes");
+ if (do_icmp6_types == CONFIG_BOOLEAN_YES || (do_icmp6_types == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[1] ||
+ icmp6stat.icp6s_inhist[128] ||
+ icmp6stat.icp6s_inhist[129] ||
+ icmp6stat.icp6s_inhist[136] ||
+ icmp6stat.icp6s_outhist[1] ||
+ icmp6stat.icp6s_outhist[128] ||
+ icmp6stat.icp6s_outhist[129] ||
+ icmp6stat.icp6s_outhist[133] ||
+ icmp6stat.icp6s_outhist[135] ||
+ icmp6stat.icp6s_outhist[136]))) {
+ do_icmp6_types = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_1 = NULL, *rd_in_128 = NULL, *rd_in_129 = NULL, *rd_in_136 = NULL,
+ *rd_out_1 = NULL, *rd_out_128 = NULL, *rd_out_129 = NULL, *rd_out_133 = NULL,
+ *rd_out_135 = NULL, *rd_out_143 = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types",
- "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6",
+ "icmptypes",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Types",
+ "messages/s",
+ 10700,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_1 = rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_128 = rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_129 = rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_136 = rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_1 = rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_128 = rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_129 = rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_133 = rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_135 = rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_143 = rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InType1", icmp6stat.icp6s_inhist[1]);
- rrddim_set(st, "InType128", icmp6stat.icp6s_inhist[128]);
- rrddim_set(st, "InType129", icmp6stat.icp6s_inhist[129]);
- rrddim_set(st, "InType136", icmp6stat.icp6s_inhist[136]);
- rrddim_set(st, "OutType1", icmp6stat.icp6s_outhist[1]);
- rrddim_set(st, "OutType128", icmp6stat.icp6s_outhist[128]);
- rrddim_set(st, "OutType129", icmp6stat.icp6s_outhist[129]);
- rrddim_set(st, "OutType133", icmp6stat.icp6s_outhist[133]);
- rrddim_set(st, "OutType135", icmp6stat.icp6s_outhist[135]);
- rrddim_set(st, "OutType143", icmp6stat.icp6s_outhist[143]);
+ rrddim_set_by_pointer(st, rd_in_1, icmp6stat.icp6s_inhist[1]);
+ rrddim_set_by_pointer(st, rd_in_128, icmp6stat.icp6s_inhist[128]);
+ rrddim_set_by_pointer(st, rd_in_129, icmp6stat.icp6s_inhist[129]);
+ rrddim_set_by_pointer(st, rd_in_136, icmp6stat.icp6s_inhist[136]);
+ rrddim_set_by_pointer(st, rd_out_1, icmp6stat.icp6s_outhist[1]);
+ rrddim_set_by_pointer(st, rd_out_128, icmp6stat.icp6s_outhist[128]);
+ rrddim_set_by_pointer(st, rd_out_129, icmp6stat.icp6s_outhist[129]);
+ rrddim_set_by_pointer(st, rd_out_133, icmp6stat.icp6s_outhist[133]);
+ rrddim_set_by_pointer(st, rd_out_135, icmp6stat.icp6s_outhist[135]);
+ rrddim_set_by_pointer(st, rd_out_143, icmp6stat.icp6s_outhist[143]);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet6.icmp6.stats module");
+ return 1;
}
- // --------------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// getmntinfo
+
+int do_getmntinfo(int update_every, usec_t dt) {
+ (void)dt;
+
+#define DELAULT_EXLUDED_PATHS "/proc/*"
+// taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
+#define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
+#define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
+
+ static int do_space = -1, do_inodes = -1;
+
+ if (unlikely(do_space == -1)) {
+ do_space = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
+ do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
+ }
if (likely(do_space || do_inodes)) {
+ struct statfs *mntbuf;
+ int mntsize;
+
// there is no mount info in sysctl MIBs
if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
error("FREEBSD: getmntinfo() failed");
do_space = 0;
- error("DISABLED: disk_space.X");
+ error("DISABLED: disk_space.* charts");
do_inodes = 0;
- error("DISABLED: disk_inodes.X");
+ error("DISABLED: disk_inodes.* charts");
+ error("DISABLED: getmntinfo module");
+ return 1;
} else {
+ // Data to be stored in DICTIONARY mount_points.
+ // This DICTIONARY is used to lookup the settings of the mount point on each iteration.
+ struct mount_point_metadata {
+ int do_space;
+ int do_inodes;
+
+ size_t collected; // the number of times this has been collected
+
+ // charts and dimensions
+
+ RRDSET *st_space;
+ RRDDIM *rd_space_used;
+ RRDDIM *rd_space_avail;
+ RRDDIM *rd_space_reserved;
+
+ RRDSET *st_inodes;
+ RRDDIM *rd_inodes_used;
+ RRDDIM *rd_inodes_avail;
+ };
+ static DICTIONARY *mount_points = NULL;
+ static SIMPLE_PATTERN *excluded_mountpoints = NULL;
+ static SIMPLE_PATTERN *excluded_filesystems = NULL;
+ int i;
+
+ if(unlikely(!mount_points)) {
+
+ excluded_mountpoints = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
+ DELAULT_EXLUDED_PATHS),
+ SIMPLE_PATTERN_EXACT
+ );
+
+ excluded_filesystems = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
+ DEFAULT_EXCLUDED_FILESYSTEMS),
+ SIMPLE_PATTERN_EXACT
+ );
+
+ mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+ }
+
for (i = 0; i < mntsize; i++) {
- if (mntbuf[i].f_flags == MNT_RDONLY ||
- mntbuf[i].f_blocks == 0 ||
- // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
- strcmp(mntbuf[i].f_fstypename, "autofs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "procfs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "subfs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "devfs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "none") == 0)
+
+ char title[4096 + 1];
+ int def_space, def_inodes, iter_space, iter_inodes;
+
+ struct mount_point_metadata *m = dictionary_get(mount_points, mntbuf[i].f_mntonname);
+ if(unlikely(!m)) {
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname);
+
+ def_space = do_space;
+ def_inodes = do_space;
+
+ if(unlikely(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname))) {
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
+ }
+
+ if(unlikely(simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename))) {
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
+ }
+
+ iter_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
+ iter_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
+
+ struct mount_point_metadata mp = {
+ .do_space = iter_space,
+ .do_inodes = iter_inodes,
+
+ .collected = 0,
+
+ .st_space = NULL,
+ .rd_space_avail = NULL,
+ .rd_space_used = NULL,
+ .rd_space_reserved = NULL,
+
+ .st_inodes = NULL,
+ .rd_inodes_avail = NULL,
+ .rd_inodes_used = NULL,
+ };
+
+ m = dictionary_set(mount_points, mntbuf[i].f_mntonname, &mp, sizeof(struct mount_point_metadata));
+ }
+
+ if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
+ continue;
+
+ if(unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected))
continue;
// --------------------------------------------------------------------------
- if (likely(do_space)) {
- st = rrdset_find_bytype("disk_space", mntbuf[i].f_mntonname);
- if (unlikely(!st)) {
- snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023,
- update_every,
- RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
- RRDDIM_ABSOLUTE);
+ int rendered = 0;
+
+ if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_blocks > 2))) {
+ if (unlikely(!m->st_space)) {
+ snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
+ mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+ m->st_space = rrdset_create_localhost("disk_space",
+ mntbuf[i].f_mntonname,
+ NULL,
+ mntbuf[i].f_mntonname,
+ "disk.space",
+ title,
+ "GB",
+ 2023,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL,
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_used = rrddim_add(m->st_space, "used", NULL,
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
} else
- rrdset_next(st);
+ rrdset_next(m->st_space);
- rrddim_set(st, "avail", (collected_number) mntbuf[i].f_bavail);
- rrddim_set(st, "used", (collected_number) (mntbuf[i].f_blocks - mntbuf[i].f_bfree));
- rrddim_set(st, "reserved_for_root", (collected_number) (mntbuf[i].f_bfree - mntbuf[i].f_bavail));
- rrdset_done(st);
+ rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number) mntbuf[i].f_bavail);
+ rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number) (mntbuf[i].f_blocks -
+ mntbuf[i].f_bfree));
+ rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
+ mntbuf[i].f_bavail));
+ rrdset_done(m->st_space);
+
+ rendered++;
}
// --------------------------------------------------------------------------
- if (likely(do_inodes)) {
- st = rrdset_find_bytype("disk_inodes", mntbuf[i].f_mntonname);
- if (unlikely(!st)) {
- snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024,
- update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+ if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_files > 1))) {
+ if (unlikely(!m->st_inodes)) {
+ snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
+ mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+ m->st_inodes = rrdset_create_localhost("disk_inodes",
+ mntbuf[i].f_mntonname,
+ NULL,
+ mntbuf[i].f_mntonname,
+ "disk.inodes",
+ title,
+ "Inodes",
+ 2024,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
} else
- rrdset_next(st);
+ rrdset_next(m->st_inodes);
- rrddim_set(st, "avail", (collected_number) mntbuf[i].f_ffree);
- rrddim_set(st, "used", (collected_number) (mntbuf[i].f_files - mntbuf[i].f_ffree));
- rrdset_done(st);
+ rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
+ rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number) (mntbuf[i].f_files -
+ mntbuf[i].f_ffree));
+ rrdset_done(m->st_inodes);
+
+ rendered++;
}
+
+ if(likely(rendered))
+ m->collected++;
}
}
+ } else {
+ error("DISABLED: getmntinfo module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// getifaddrs
- if (likely(do_uptime)) {
- if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
- do_uptime = 0;
- error("DISABLED: system.uptime");
+int do_getifaddrs(int update_every, usec_t dt) {
+ (void)dt;
+
+#define DELAULT_EXLUDED_INTERFACES "lo*"
+#define CONFIG_SECTION_GETIFADDRS "plugin:freebsd:getifaddrs"
+
+ static int do_bandwidth_ipv4 = -1, do_bandwidth_ipv6 = -1, do_bandwidth = -1, do_packets = -1,
+ do_errors = -1, do_drops = -1, do_events = -1;
+
+ if (unlikely(do_bandwidth_ipv4 == -1)) {
+ do_bandwidth_ipv4 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv4 interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_bandwidth_ipv6 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv6 interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_bandwidth = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "bandwidth for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_packets = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "packets for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_errors = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "errors for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_drops = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "drops for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_events = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "collisions for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ }
+
+ if (likely(do_bandwidth_ipv4 || do_bandwidth_ipv6 || do_bandwidth || do_packets || do_errors ||
+ do_drops || do_events)) {
+ struct ifaddrs *ifap;
+
+ if (unlikely(getifaddrs(&ifap))) {
+ error("FREEBSD: getifaddrs() failed");
+ do_bandwidth_ipv4 = 0;
+ error("DISABLED: system.ipv4 chart");
+ do_bandwidth_ipv6 = 0;
+ error("DISABLED: system.ipv6 chart");
+ do_bandwidth = 0;
+ error("DISABLED: net.* charts");
+ do_packets = 0;
+ error("DISABLED: net_packets.* charts");
+ do_errors = 0;
+ error("DISABLED: net_errors.* charts");
+ do_drops = 0;
+ error("DISABLED: net_drops.* charts");
+ do_events = 0;
+ error("DISABLED: net_events.* charts");
+ error("DISABLED: getifaddrs module");
+ return 1;
} else {
- clock_gettime(CLOCK_REALTIME, &cur_time);
- st = rrdset_find("system.uptime");
+ #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+ struct ifaddrs *ifa;
+ struct iftot {
+ u_long ift_ibytes;
+ u_long ift_obytes;
+ } iftot = {0, 0};
- if(unlikely(!st)) {
- st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ // --------------------------------------------------------------------
+
+ if (likely(do_bandwidth_ipv4)) {
+ iftot.ift_ibytes = iftot.ift_obytes = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ iftot.ift_ibytes += IFA_DATA(ibytes);
+ iftot.ift_obytes += IFA_DATA(obytes);
+ }
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ipv4",
+ NULL,
+ "network",
+ NULL,
+ "IPv4 Bandwidth",
+ "kilobits/s",
+ 500,
+ update_every,
+ 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);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes);
+ rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+ rrdset_done(st);
}
- else rrdset_next(st);
- rrddim_set(st, "uptime", cur_time.tv_sec - boot_time.tv_sec);
- rrdset_done(st);
+ // --------------------------------------------------------------------
+
+ if (likely(do_bandwidth_ipv6)) {
+ iftot.ift_ibytes = iftot.ift_obytes = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ iftot.ift_ibytes += IFA_DATA(ibytes);
+ iftot.ift_obytes += IFA_DATA(obytes);
+ }
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ipv6",
+ NULL,
+ "network",
+ NULL,
+ "IPv6 Bandwidth",
+ "kilobits/s",
+ 500,
+ update_every,
+ 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);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes);
+ rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ // Data to be stored in DICTIONARY interfaces.
+ // This DICTIONARY is used to lookup the settings of the interfaces on each iteration.
+ struct interfaces_metadata {
+ int do_bandwidth;
+ int do_packets;
+ int do_errors;
+ int do_drops;
+ int do_events;
+
+ // charts and dimensions
+
+ RRDSET *st_bandwidth;
+ RRDDIM *rd_bandwidth_in;
+ RRDDIM *rd_bandwidth_out;
+
+ RRDSET *st_packets;
+ RRDDIM *rd_packets_in;
+ RRDDIM *rd_packets_out;
+ RRDDIM *rd_packets_m_in;
+ RRDDIM *rd_packets_m_out;
+
+ RRDSET *st_errors;
+ RRDDIM *rd_errors_in;
+ RRDDIM *rd_errors_out;
+
+ RRDSET *st_drops;
+ RRDDIM *rd_drops_in;
+ RRDDIM *rd_drops_out;
+
+ RRDSET *st_events;
+ RRDDIM *rd_events_coll;
+ };
+ static DICTIONARY *interfaces = NULL;
+ static SIMPLE_PATTERN *excluded_interfaces = NULL;
+
+ if(unlikely(!interfaces)) {
+
+ excluded_interfaces = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching",
+ DELAULT_EXLUDED_INTERFACES)
+ , SIMPLE_PATTERN_EXACT
+ );
+
+ interfaces = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ int def_bandwidth, def_packets, def_errors, def_drops, def_events,
+ iter_bandwidth, iter_packets, iter_errors, iter_drops, iter_events;
+
+ struct interfaces_metadata *ifm = dictionary_get(interfaces, ifa->ifa_name);
+ if(unlikely(!ifm)) {
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETIFADDRS, ifa->ifa_name);
+
+ def_bandwidth = do_bandwidth;
+ def_packets = do_packets;
+ def_errors = do_errors;
+ def_drops = do_drops;
+ def_events = do_events;
+
+ if(unlikely(simple_pattern_matches(excluded_interfaces, ifa->ifa_name))) {
+ def_bandwidth = CONFIG_BOOLEAN_NO;
+ def_packets = CONFIG_BOOLEAN_NO;
+ def_errors = CONFIG_BOOLEAN_NO;
+ def_drops = CONFIG_BOOLEAN_NO;
+ def_events = CONFIG_BOOLEAN_NO;
+ }
+
+ iter_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", def_bandwidth);
+ iter_packets = config_get_boolean_ondemand(var_name, "packets", def_packets);
+ iter_errors = config_get_boolean_ondemand(var_name, "errors", def_errors);
+ iter_drops = config_get_boolean_ondemand(var_name, "drops", def_drops);
+ iter_events = config_get_boolean_ondemand(var_name, "events", def_events);
+
+ struct interfaces_metadata ifmp = {
+ .do_bandwidth = iter_bandwidth,
+ .do_packets = iter_packets,
+ .do_errors = iter_errors,
+ .do_drops = iter_drops,
+ .do_events = iter_events,
+
+ .st_bandwidth = NULL,
+ .rd_bandwidth_in = NULL,
+ .rd_bandwidth_out = NULL,
+
+ .st_packets = NULL,
+ .rd_packets_in = NULL,
+ .rd_packets_out = NULL,
+ .rd_packets_m_in = NULL,
+ .rd_packets_m_out = NULL,
+
+ .st_errors = NULL,
+ .rd_errors_in = NULL,
+ .rd_errors_out = NULL,
+
+ .st_drops = NULL,
+ .rd_drops_in = NULL,
+ .rd_drops_out = NULL,
+
+ .st_events = NULL,
+ .rd_events_coll = NULL,
+ };
+
+ ifm = dictionary_set(interfaces, ifa->ifa_name, &ifmp, sizeof(struct interfaces_metadata));
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_bandwidth == CONFIG_BOOLEAN_YES || (ifm->do_bandwidth == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(ibytes) || IFA_DATA(obytes)))) {
+ if (unlikely(!ifm->st_bandwidth)) {
+ ifm->st_bandwidth = rrdset_create_localhost("net",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.net",
+ "Bandwidth",
+ "kilobits/s",
+ 7000,
+ update_every,
+ 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);
+ } else
+ rrdset_next(ifm->st_bandwidth);
+
+ rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_in, IFA_DATA(ibytes));
+ rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_out, IFA_DATA(obytes));
+ rrdset_done(ifm->st_bandwidth);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_packets == CONFIG_BOOLEAN_YES || (ifm->do_packets == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(ipackets) || IFA_DATA(opackets) || IFA_DATA(imcasts) || IFA_DATA(omcasts)))) {
+ if (unlikely(!ifm->st_packets)) {
+ ifm->st_packets = rrdset_create_localhost("net_packets",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.packets",
+ "Packets",
+ "packets/s",
+ 7001,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_packets, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_packets_in = rrddim_add(ifm->st_packets, "received", NULL, 1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_packets_out = rrddim_add(ifm->st_packets, "sent", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_packets_m_in = rrddim_add(ifm->st_packets, "multicast_received", NULL, 1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_packets_m_out = rrddim_add(ifm->st_packets, "multicast_sent", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_packets);
+
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_in, IFA_DATA(ipackets));
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_out, IFA_DATA(opackets));
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_in, IFA_DATA(imcasts));
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_out, IFA_DATA(omcasts));
+ rrdset_done(ifm->st_packets);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_errors == CONFIG_BOOLEAN_YES || (ifm->do_errors == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(ierrors) || IFA_DATA(oerrors)))) {
+ if (unlikely(!ifm->st_errors)) {
+ ifm->st_errors = rrdset_create_localhost("net_errors",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.errors",
+ "Interface Errors",
+ "errors/s",
+ 7002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_errors, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_errors_in = rrddim_add(ifm->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_errors_out = rrddim_add(ifm->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_errors);
+
+ rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_in, IFA_DATA(ierrors));
+ rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_out, IFA_DATA(oerrors));
+ rrdset_done(ifm->st_errors);
+ }
+ // --------------------------------------------------------------------
+
+ if (ifm->do_drops == CONFIG_BOOLEAN_YES || (ifm->do_drops == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(iqdrops) || IFA_DATA(oqdrops)))) {
+ if (unlikely(!ifm->st_drops)) {
+ ifm->st_drops = rrdset_create_localhost("net_drops",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.drops",
+ "Interface Drops",
+ "drops/s",
+ 7003,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_drops, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_drops_in = rrddim_add(ifm->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+#if __FreeBSD__ >= 11
+ ifm->rd_drops_out = rrddim_add(ifm->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+#endif
+ } else
+ rrdset_next(ifm->st_drops);
+
+ rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_in, IFA_DATA(iqdrops));
+#if __FreeBSD__ >= 11
+ rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_out, IFA_DATA(oqdrops));
+#endif
+ rrdset_done(ifm->st_drops);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_events == CONFIG_BOOLEAN_YES || (ifm->do_events == CONFIG_BOOLEAN_AUTO &&
+ IFA_DATA(collisions))) {
+ if (unlikely(!ifm->st_events)) {
+ ifm->st_events = rrdset_create_localhost("net_events",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.events",
+ "Network Interface Events",
+ "events/s",
+ 7006,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_events, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_events_coll = rrddim_add(ifm->st_events, "collisions", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_events);
+
+ rrddim_set_by_pointer(ifm->st_events, ifm->rd_events_coll, IFA_DATA(collisions));
+ rrdset_done(ifm->st_events);
+ }
+ }
+
+ freeifaddrs(ifap);
+ }
+ } else {
+ error("DISABLED: getifaddrs module");
+ return 1;
+ }
+
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.devstat
+
+int do_kern_devstat(int update_every, usec_t dt) {
+
+#define DELAULT_EXLUDED_DISKS ""
+#define CONFIG_SECTION_KERN_DEVSTAT "plugin:freebsd:kern.devstat"
+#define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
+
+ static int enable_pass_devices = -1, do_system_io = -1, do_io = -1, do_ops = -1, do_qops = -1, do_util = -1,
+ do_iotime = -1, do_await = -1, do_avagsz = -1, do_svctm = -1;
+
+ if (unlikely(enable_pass_devices == -1)) {
+ enable_pass_devices = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT,
+ "performance metrics for pass devices", CONFIG_BOOLEAN_AUTO);
+
+ do_system_io = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "total bandwidth for all disks",
+ CONFIG_BOOLEAN_YES);
+
+ do_io = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "bandwidth for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_ops = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "operations for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_qops = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "queued operations for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_util = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "utilization percentage for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "i/o time for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_await = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o time for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_avagsz = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o bandwidth for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_svctm = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average service time for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ }
+
+ if (likely(do_system_io || do_io || do_ops || do_qops || do_util || do_iotime || do_await || do_avagsz || do_svctm)) {
+ static int mib_numdevs[3] = {0, 0, 0};
+ int numdevs;
+ int common_error = 0;
+
+ if (unlikely(GETSYSCTL_SIMPLE("kern.devstat.numdevs", mib_numdevs, numdevs))) {
+ common_error = 1;
+ } else {
+ static int mib_devstat[3] = {0, 0, 0};
+ static void *devstat_data = NULL;
+
+ devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
+ if (unlikely(GETSYSCTL_WSIZE("kern.devstat.all", mib_devstat, devstat_data,
+ sizeof(long) + sizeof(struct devstat) * numdevs))) {
+ common_error = 1;
+ } else {
+ struct devstat *dstat;
+ int i;
+ collected_number total_disk_kbytes_read = 0;
+ collected_number total_disk_kbytes_write = 0;
+
+ // Data to be stored in DICTIONARY disks.
+ // This DICTIONARY is used to lookup the settings of the disks on each iteration.
+ struct disks_metadata {
+ int do_io;
+ int do_ops;
+ int do_qops;
+ int do_util;
+ int do_iotime;
+ int do_await;
+ int do_avagsz;
+ int do_svctm;
+
+
+ // data for differential charts
+
+ struct prev_dstat {
+ collected_number bytes_read;
+ collected_number bytes_write;
+ collected_number operations_read;
+ collected_number operations_write;
+ collected_number duration_read_ms;
+ collected_number duration_write_ms;
+ collected_number busy_time_ms;
+ } prev_dstat;
+
+ // charts and dimensions
+
+ RRDSET *st_io;
+ RRDDIM *rd_io_in;
+ RRDDIM *rd_io_out;
+
+ RRDSET *st_ops;
+ RRDDIM *rd_ops_in;
+ RRDDIM *rd_ops_out;
+
+ RRDSET *st_qops;
+ RRDDIM *rd_qops;
+
+ RRDSET *st_util;
+ RRDDIM *rd_util;
+
+ RRDSET *st_iotime;
+ RRDDIM *rd_iotime_in;
+ RRDDIM *rd_iotime_out;
+
+ RRDSET *st_await;
+ RRDDIM *rd_await_in;
+ RRDDIM *rd_await_out;
+
+ RRDSET *st_avagsz;
+ RRDDIM *rd_avagsz_in;
+ RRDDIM *rd_avagsz_out;
+
+ RRDSET *st_svctm;
+ RRDDIM *rd_svctm;
+
+ };
+ static DICTIONARY *disks = NULL;
+ static SIMPLE_PATTERN *excluded_disks = NULL;
+
+ if(unlikely(!disks)) {
+
+ excluded_disks = simple_pattern_create(
+ config_get(CONFIG_SECTION_KERN_DEVSTAT, "disable by default disks matching",
+ DELAULT_EXLUDED_DISKS)
+ , SIMPLE_PATTERN_EXACT
+ );
+
+ disks = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+ }
+
+ dstat = devstat_data + sizeof(long); // skip generation number
+
+ for (i = 0; i < numdevs; i++) {
+ if (likely(do_system_io)) {
+ if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+ total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ] / KILO_FACTOR;
+ total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE] / KILO_FACTOR;
+ }
+ }
+
+ if (unlikely(!enable_pass_devices))
+ if ((dstat[i].device_type & DEVSTAT_TYPE_PASS) == DEVSTAT_TYPE_PASS)
+ continue;
+
+ if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+ char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
+ int def_io, def_ops, def_qops, def_util, def_iotime, def_await, def_avagsz, def_svctm,
+ iter_io, iter_ops, iter_qops, iter_util, iter_iotime, iter_await, iter_avagsz, iter_svctm;
+ struct cur_dstat {
+ collected_number duration_read_ms;
+ collected_number duration_write_ms;
+ collected_number busy_time_ms;
+ } cur_dstat;
+
+ sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
+
+ struct disks_metadata *dm = dictionary_get(disks, disk);
+ if(unlikely(!dm)) {
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_KERN_DEVSTAT, disk);
+
+ def_io = do_io;
+ def_ops = do_ops;
+ def_qops = do_qops;
+ def_util = do_util;
+ def_iotime = do_iotime;
+ def_await = do_await;
+ def_avagsz = do_avagsz;
+ def_svctm = do_svctm;
+
+ if(unlikely(simple_pattern_matches(excluded_disks, disk))) {
+ def_io = CONFIG_BOOLEAN_NO;
+ def_ops = CONFIG_BOOLEAN_NO;
+ def_qops = CONFIG_BOOLEAN_NO;
+ def_util = CONFIG_BOOLEAN_NO;
+ def_iotime = CONFIG_BOOLEAN_NO;
+ def_await = CONFIG_BOOLEAN_NO;
+ def_avagsz = CONFIG_BOOLEAN_NO;
+ def_svctm = CONFIG_BOOLEAN_NO;
+ }
+
+ iter_io = config_get_boolean_ondemand(var_name, "bandwidth", def_io);
+ iter_ops = config_get_boolean_ondemand(var_name, "operations", def_ops);
+ iter_qops = config_get_boolean_ondemand(var_name, "queued operations", def_qops);
+ iter_util = config_get_boolean_ondemand(var_name, "utilization percentage", def_util);
+ iter_iotime = config_get_boolean_ondemand(var_name, "i/o time", def_iotime);
+ iter_await = config_get_boolean_ondemand(var_name, "average completed i/o time", def_await);
+ iter_avagsz = config_get_boolean_ondemand(var_name, "average completed i/o bandwidth",
+ def_avagsz);
+ iter_svctm = config_get_boolean_ondemand(var_name, "average service time", def_svctm);
+
+ struct disks_metadata dmp = {
+ .do_io = iter_io,
+ .do_ops = iter_ops,
+ .do_qops = iter_qops,
+ .do_util = iter_util,
+ .do_iotime = iter_iotime,
+ .do_await = iter_await,
+ .do_avagsz = iter_avagsz,
+ .do_svctm = iter_svctm,
+
+ .st_io = NULL,
+ .rd_io_in = NULL,
+ .rd_io_out = NULL,
+
+ .st_ops = NULL,
+ .rd_ops_in = NULL,
+ .rd_ops_out = NULL,
+
+ .st_qops = NULL,
+ .rd_qops = NULL,
+
+ .st_util = NULL,
+ .rd_util = NULL,
+
+ .st_iotime = NULL,
+ .rd_iotime_in = NULL,
+ .rd_iotime_out = NULL,
+
+ .st_await = NULL,
+ .rd_await_in = NULL,
+ .rd_await_out = NULL,
+
+ .st_avagsz = NULL,
+ .rd_avagsz_in = NULL,
+ .rd_avagsz_out = NULL,
+
+ .st_svctm = NULL,
+ .rd_svctm = NULL,
+ };
+
+ // initialise data for differential charts
+
+ dmp.prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
+ dmp.prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
+ dmp.prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
+ dmp.prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
+ dmp.prev_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ dmp.prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ dmp.prev_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000
+ + dstat[i].busy_time.frac * BINTIME_SCALE;
+
+ dm = dictionary_set(disks, disk, &dmp, sizeof(struct disks_metadata));
+ }
+
+ cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_io == CONFIG_BOOLEAN_YES || (dm->do_io == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].bytes[DEVSTAT_READ] || dstat[i].bytes[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_io)) {
+ dm->st_io = rrdset_create_localhost("disk",
+ disk,
+ NULL,
+ disk,
+ "disk.io",
+ "Disk I/O Bandwidth",
+ "kilobytes/s",
+ 2000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ dm->rd_io_in = rrddim_add(dm->st_io, "reads", NULL, 1, KILO_FACTOR,
+ RRD_ALGORITHM_INCREMENTAL);
+ dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_io);
+
+ rrddim_set_by_pointer(dm->st_io, dm->rd_io_in, dstat[i].bytes[DEVSTAT_READ]);
+ rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]);
+ rrdset_done(dm->st_io);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_ops == CONFIG_BOOLEAN_YES || (dm->do_ops == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_ops)) {
+ dm->st_ops = rrdset_create_localhost("disk_ops",
+ disk,
+ NULL,
+ disk,
+ "disk.ops",
+ "Disk Completed I/O Operations",
+ "operations/s",
+ 2001,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_ops, RRDSET_FLAG_DETAIL);
+
+ dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_ops);
+
+ rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]);
+ rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]);
+ rrdset_done(dm->st_ops);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_qops == CONFIG_BOOLEAN_YES || (dm->do_qops == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].start_count || dstat[i].end_count))) {
+ if (unlikely(!dm->st_qops)) {
+ dm->st_qops = rrdset_create_localhost("disk_qops",
+ disk,
+ NULL,
+ disk,
+ "disk.qops",
+ "Disk Current I/O Operations",
+ "operations",
+ 2002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_qops, RRDSET_FLAG_DETAIL);
+
+ dm->rd_qops = rrddim_add(dm->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_qops);
+
+ rrddim_set_by_pointer(dm->st_qops, dm->rd_qops, dstat[i].start_count - dstat[i].end_count);
+ rrdset_done(dm->st_qops);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_util == CONFIG_BOOLEAN_YES || (dm->do_util == CONFIG_BOOLEAN_AUTO &&
+ cur_dstat.busy_time_ms)) {
+ if (unlikely(!dm->st_util)) {
+ dm->st_util = rrdset_create_localhost("disk_util",
+ disk,
+ NULL,
+ disk,
+ "disk.util",
+ "Disk Utilization Time",
+ "% of time working",
+ 2004,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(dm->st_util, RRDSET_FLAG_DETAIL);
+
+ dm->rd_util = rrddim_add(dm->st_util, "utilization", NULL, 1, 10,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_util);
+
+ rrddim_set_by_pointer(dm->st_util, dm->rd_util, cur_dstat.busy_time_ms);
+ rrdset_done(dm->st_util);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_iotime == CONFIG_BOOLEAN_YES || (dm->do_iotime == CONFIG_BOOLEAN_AUTO &&
+ (cur_dstat.duration_read_ms || cur_dstat.duration_write_ms))) {
+ if (unlikely(!dm->st_iotime)) {
+ dm->st_iotime = rrdset_create_localhost("disk_iotime",
+ disk,
+ NULL,
+ disk,
+ "disk.iotime",
+ "Disk Total I/O Time",
+ "milliseconds/s",
+ 2022,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_iotime, RRDSET_FLAG_DETAIL);
+
+ dm->rd_iotime_in = rrddim_add(dm->st_iotime, "reads", NULL, 1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_iotime);
+
+ rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in, cur_dstat.duration_read_ms);
+ rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms);
+ rrdset_done(dm->st_iotime);
+ }
+
+ // --------------------------------------------------------------------
+ // calculate differential charts
+ // only if this is not the first time we run
+
+ if (likely(dt)) {
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_await == CONFIG_BOOLEAN_YES || (dm->do_await == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_await)) {
+ dm->st_await = rrdset_create_localhost("disk_await",
+ disk,
+ NULL,
+ disk,
+ "disk.await",
+ "Average Completed I/O Operation Time",
+ "ms per operation",
+ 2005,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_await, RRDSET_FLAG_DETAIL);
+
+ dm->rd_await_in = rrddim_add(dm->st_await, "reads", NULL, 1, 1,
+ RRD_ALGORITHM_ABSOLUTE);
+ dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1,
+ RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_await);
+
+ rrddim_set_by_pointer(dm->st_await, dm->rd_await_in,
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) ?
+ (cur_dstat.duration_read_ms - dm->prev_dstat.duration_read_ms) /
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) :
+ 0);
+ rrddim_set_by_pointer(dm->st_await, dm->rd_await_out,
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) ?
+ (cur_dstat.duration_write_ms - dm->prev_dstat.duration_write_ms) /
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) :
+ 0);
+ rrdset_done(dm->st_await);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_avagsz == CONFIG_BOOLEAN_YES || (dm->do_avagsz == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_avagsz)) {
+ dm->st_avagsz = rrdset_create_localhost("disk_avgsz",
+ disk,
+ NULL,
+ disk,
+ "disk.avgsz",
+ "Average Completed I/O Operation Bandwidth",
+ "kilobytes per operation",
+ 2006,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(dm->st_avagsz, RRDSET_FLAG_DETAIL);
+
+ dm->rd_avagsz_in = rrddim_add(dm->st_avagsz, "reads", NULL, 1, KILO_FACTOR,
+ RRD_ALGORITHM_ABSOLUTE);
+ dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR,
+ RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_avagsz);
+
+ rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_in,
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) ?
+ (dstat[i].bytes[DEVSTAT_READ] - dm->prev_dstat.bytes_read) /
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) :
+ 0);
+ rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_out,
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) ?
+ (dstat[i].bytes[DEVSTAT_WRITE] - dm->prev_dstat.bytes_write) /
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) :
+ 0);
+ rrdset_done(dm->st_avagsz);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_svctm == CONFIG_BOOLEAN_YES || (dm->do_svctm == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_svctm)) {
+ dm->st_svctm = rrdset_create_localhost("disk_svctm",
+ disk,
+ NULL,
+ disk,
+ "disk.svctm",
+ "Average Service Time",
+ "ms per operation",
+ 2007,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_svctm, RRDSET_FLAG_DETAIL);
+
+ dm->rd_svctm = rrddim_add(dm->st_svctm, "svctm", NULL, 1, 1,
+ RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_svctm);
+
+ rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm,
+ ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
+ (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) ?
+ (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) /
+ ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
+ (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) :
+ 0);
+ rrdset_done(dm->st_svctm);
+ }
+
+ // --------------------------------------------------------------------
+
+ dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
+ dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
+ dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
+ dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
+ dm->prev_dstat.duration_read_ms = cur_dstat.duration_read_ms;
+ dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms;
+ dm->prev_dstat.busy_time_ms = cur_dstat.busy_time_ms;
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ if (likely(do_system_io)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "io",
+ NULL,
+ "disk",
+ NULL,
+ "Disk I/O",
+ "kilobytes/s",
+ 150,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, total_disk_kbytes_read);
+ rrddim_set_by_pointer(st, rd_out, total_disk_kbytes_write);
+ rrdset_done(st);
+ }
+ }
+ }
+ if (unlikely(common_error)) {
+ do_system_io = 0;
+ error("DISABLED: system.io chart");
+ do_io = 0;
+ error("DISABLED: disk.* charts");
+ do_ops = 0;
+ error("DISABLED: disk_ops.* charts");
+ do_qops = 0;
+ error("DISABLED: disk_qops.* charts");
+ do_util = 0;
+ error("DISABLED: disk_util.* charts");
+ do_iotime = 0;
+ error("DISABLED: disk_iotime.* charts");
+ do_await = 0;
+ error("DISABLED: disk_await.* charts");
+ do_avagsz = 0;
+ error("DISABLED: disk_avgsz.* charts");
+ do_svctm = 0;
+ error("DISABLED: disk_svctm.* charts");
+ error("DISABLED: kern.devstat module");
+ return 1;
}
+ } else {
+ error("DISABLED: kern.devstat module");
+ return 1;
}
return 0;
diff --git a/src/freeipmi_plugin.c b/src/freeipmi_plugin.c
new file mode 100644
index 000000000..4459de7ca
--- /dev/null
+++ b/src/freeipmi_plugin.c
@@ -0,0 +1,1621 @@
+/*
+ * netdata freeipmi.plugin
+ * Copyright (C) 2017 Costa Tsaousis
+ * GPL v3+
+ *
+ * Based on:
+ * ipmimonitoring-sensors.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
+ * ipmimonitoring-sel.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
+ *
+ * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
+ * Copyright (C) 2006-2007 The Regents of the University of California.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * Written by Albert Chu <chu11@llnl.gov>
+ * UCRL-CODE-222073
+ */
+
+#include "common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef HAVE_FREEIPMI
+
+#include <ipmi_monitoring.h>
+#include <ipmi_monitoring_bitmasks.h>
+
+/* Communication Configuration - Initialize accordingly */
+
+/* Hostname, NULL for In-band communication, non-null for a hostname */
+char *hostname = NULL;
+
+/* In-band Communication Configuration */
+int driver_type = -1; // IPMI_MONITORING_DRIVER_TYPE_KCS; /* or -1 for default */
+int disable_auto_probe = 0; /* probe for in-band device */
+unsigned int driver_address = 0; /* not used if probing */
+unsigned int register_spacing = 0; /* not used if probing */
+char *driver_device = NULL; /* not used if probing */
+
+/* Out-of-band Communication Configuration */
+int protocol_version = -1; //IPMI_MONITORING_PROTOCOL_VERSION_1_5; /* or -1 for default */
+char *username = "foousername";
+char *password = "foopassword";
+unsigned char *k_g = NULL;
+unsigned int k_g_len = 0;
+int privilege_level = -1; // IPMI_MONITORING_PRIVILEGE_LEVEL_USER; /* or -1 for default */
+int authentication_type = -1; // IPMI_MONITORING_AUTHENTICATION_TYPE_MD5; /* or -1 for default */
+int cipher_suite_id = 0; /* or -1 for default */
+int session_timeout = 0; /* 0 for default */
+int retransmission_timeout = 0; /* 0 for default */
+
+/* Workarounds - specify workaround flags if necessary */
+unsigned int workaround_flags = 0;
+
+/* Initialize w/ record id numbers to only monitor specific record ids */
+unsigned int record_ids[] = {0};
+unsigned int record_ids_length = 0;
+
+/* Initialize w/ sensor types to only monitor specific sensor types
+ * see ipmi_monitoring.h sensor types list.
+ */
+unsigned int sensor_types[] = {0};
+unsigned int sensor_types_length = 0;
+
+/* Set to an appropriate alternate if desired */
+char *sdr_cache_directory = "/tmp";
+char *sensor_config_file = NULL;
+
+/* Set to 1 or 0 to enable these sensor reading flags
+ * - See ipmi_monitoring.h for descriptions of these flags.
+ */
+int reread_sdr_cache = 0;
+int ignore_non_interpretable_sensors = 1;
+int bridge_sensors = 0;
+int interpret_oem_data = 0;
+int shared_sensors = 0;
+int discrete_reading = 0;
+int ignore_scanning_disabled = 0;
+int assume_bmc_owner = 0;
+int entity_sensor_names = 0;
+
+/* Initialization flags
+ *
+ * Most commonly bitwise OR IPMI_MONITORING_FLAGS_DEBUG and/or
+ * IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS for extra debugging
+ * information.
+ */
+unsigned int ipmimonitoring_init_flags = 0;
+
+int errnum;
+
+// ----------------------------------------------------------------------------
+// SEL only variables
+
+/* Initialize w/ date range to only monitoring specific date range */
+char *date_begin = NULL; /* use MM/DD/YYYY format */
+char *date_end = NULL; /* use MM/DD/YYYY format */
+
+int assume_system_event_record = 0;
+
+char *sel_config_file = NULL;
+
+
+// ----------------------------------------------------------------------------
+// functions common to sensors and SEL
+
+static void
+_init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
+{
+ assert (ipmi_config);
+
+ ipmi_config->driver_type = driver_type;
+ ipmi_config->disable_auto_probe = disable_auto_probe;
+ ipmi_config->driver_address = driver_address;
+ ipmi_config->register_spacing = register_spacing;
+ ipmi_config->driver_device = driver_device;
+
+ ipmi_config->protocol_version = protocol_version;
+ ipmi_config->username = username;
+ ipmi_config->password = password;
+ ipmi_config->k_g = k_g;
+ ipmi_config->k_g_len = k_g_len;
+ ipmi_config->privilege_level = privilege_level;
+ ipmi_config->authentication_type = authentication_type;
+ ipmi_config->cipher_suite_id = cipher_suite_id;
+ ipmi_config->session_timeout_len = session_timeout;
+ ipmi_config->retransmission_timeout_len = retransmission_timeout;
+
+ ipmi_config->workaround_flags = workaround_flags;
+}
+
+#ifdef NETDATA_COMMENTED
+static const char *
+_get_sensor_type_string (int sensor_type)
+{
+ switch (sensor_type)
+ {
+ case IPMI_MONITORING_SENSOR_TYPE_RESERVED:
+ return ("Reserved");
+ case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
+ return ("Temperature");
+ case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
+ return ("Voltage");
+ case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
+ return ("Current");
+ case IPMI_MONITORING_SENSOR_TYPE_FAN:
+ return ("Fan");
+ case IPMI_MONITORING_SENSOR_TYPE_PHYSICAL_SECURITY:
+ return ("Physical Security");
+ case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_SECURITY_VIOLATION_ATTEMPT:
+ return ("Platform Security Violation Attempt");
+ case IPMI_MONITORING_SENSOR_TYPE_PROCESSOR:
+ return ("Processor");
+ case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
+ return ("Power Supply");
+ case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
+ return ("Power Unit");
+ case IPMI_MONITORING_SENSOR_TYPE_COOLING_DEVICE:
+ return ("Cooling Device");
+ case IPMI_MONITORING_SENSOR_TYPE_OTHER_UNITS_BASED_SENSOR:
+ return ("Other Units Based Sensor");
+ case IPMI_MONITORING_SENSOR_TYPE_MEMORY:
+ return ("Memory");
+ case IPMI_MONITORING_SENSOR_TYPE_DRIVE_SLOT:
+ return ("Drive Slot");
+ case IPMI_MONITORING_SENSOR_TYPE_POST_MEMORY_RESIZE:
+ return ("POST Memory Resize");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS:
+ return ("System Firmware Progress");
+ case IPMI_MONITORING_SENSOR_TYPE_EVENT_LOGGING_DISABLED:
+ return ("Event Logging Disabled");
+ case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG1:
+ return ("Watchdog 1");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_EVENT:
+ return ("System Event");
+ case IPMI_MONITORING_SENSOR_TYPE_CRITICAL_INTERRUPT:
+ return ("Critical Interrupt");
+ case IPMI_MONITORING_SENSOR_TYPE_BUTTON_SWITCH:
+ return ("Button/Switch");
+ case IPMI_MONITORING_SENSOR_TYPE_MODULE_BOARD:
+ return ("Module/Board");
+ case IPMI_MONITORING_SENSOR_TYPE_MICROCONTROLLER_COPROCESSOR:
+ return ("Microcontroller/Coprocessor");
+ case IPMI_MONITORING_SENSOR_TYPE_ADD_IN_CARD:
+ return ("Add In Card");
+ case IPMI_MONITORING_SENSOR_TYPE_CHASSIS:
+ return ("Chassis");
+ case IPMI_MONITORING_SENSOR_TYPE_CHIP_SET:
+ return ("Chip Set");
+ case IPMI_MONITORING_SENSOR_TYPE_OTHER_FRU:
+ return ("Other Fru");
+ case IPMI_MONITORING_SENSOR_TYPE_CABLE_INTERCONNECT:
+ return ("Cable/Interconnect");
+ case IPMI_MONITORING_SENSOR_TYPE_TERMINATOR:
+ return ("Terminator");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_BOOT_INITIATED:
+ return ("System Boot Initiated");
+ case IPMI_MONITORING_SENSOR_TYPE_BOOT_ERROR:
+ return ("Boot Error");
+ case IPMI_MONITORING_SENSOR_TYPE_OS_BOOT:
+ return ("OS Boot");
+ case IPMI_MONITORING_SENSOR_TYPE_OS_CRITICAL_STOP:
+ return ("OS Critical Stop");
+ case IPMI_MONITORING_SENSOR_TYPE_SLOT_CONNECTOR:
+ return ("Slot/Connector");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
+ return ("System ACPI Power State");
+ case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG2:
+ return ("Watchdog 2");
+ case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_ALERT:
+ return ("Platform Alert");
+ case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
+ return ("Entity Presence");
+ case IPMI_MONITORING_SENSOR_TYPE_MONITOR_ASIC_IC:
+ return ("Monitor ASIC/IC");
+ case IPMI_MONITORING_SENSOR_TYPE_LAN:
+ return ("LAN");
+ case IPMI_MONITORING_SENSOR_TYPE_MANAGEMENT_SUBSYSTEM_HEALTH:
+ return ("Management Subsystem Health");
+ case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
+ return ("Battery");
+ case IPMI_MONITORING_SENSOR_TYPE_SESSION_AUDIT:
+ return ("Session Audit");
+ case IPMI_MONITORING_SENSOR_TYPE_VERSION_CHANGE:
+ return ("Version Change");
+ case IPMI_MONITORING_SENSOR_TYPE_FRU_STATE:
+ return ("FRU State");
+ }
+
+ return ("Unrecognized");
+}
+#endif // NETDATA_COMMENTED
+
+
+// ----------------------------------------------------------------------------
+// BEGIN NETDATA CODE
+
+static int debug = 0;
+
+static int netdata_update_every = 5;
+static int netdata_priority = 90000;
+static int netdata_do_sel = 1;
+
+static size_t netdata_sensors_updated = 0;
+static size_t netdata_sensors_collected = 0;
+static size_t netdata_sel_events = 0;
+static size_t netdata_sensors_states_nominal = 0;
+static size_t netdata_sensors_states_warning = 0;
+static size_t netdata_sensors_states_critical = 0;
+
+struct sensor {
+ int record_id;
+ int sensor_number;
+ int sensor_type;
+ int sensor_state;
+ int sensor_units;
+ char *sensor_name;
+
+ int sensor_reading_type;
+ union {
+ uint8_t bool_value;
+ uint32_t uint32_value;
+ double double_value;
+ } sensor_reading;
+
+ int sent;
+ int ignore;
+ int exposed;
+ int updated;
+ struct sensor *next;
+} *sensors_root = NULL;
+
+static void netdata_mark_as_not_updated() {
+ struct sensor *sn;
+ for(sn = sensors_root; sn ;sn = sn->next)
+ sn->updated = sn->sent = 0;
+
+ netdata_sensors_updated = 0;
+ netdata_sensors_collected = 0;
+ netdata_sel_events = 0;
+
+ netdata_sensors_states_nominal = 0;
+ netdata_sensors_states_warning = 0;
+ netdata_sensors_states_critical = 0;
+}
+
+static void send_chart_to_netdata_for_units(int units) {
+ struct sensor *sn;
+
+ switch(units) {
+ case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
+ printf("CHART ipmi.temperatures_c '' 'System Celcius Temperatures read by IPMI' 'Celcius' 'temperatures' 'ipmi.temperatures_c' 'line' %d %d\n"
+ , netdata_priority + 10
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
+ printf("CHART ipmi.temperatures_f '' 'System Fahrenheit Temperatures read by IPMI' 'Fahrenheit' 'temperatures' 'ipmi.temperatures_f' 'line' %d %d\n"
+ , netdata_priority + 11
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
+ printf("CHART ipmi.volts '' 'System Voltages read by IPMI' 'Volts' 'voltages' 'ipmi.voltages' 'line' %d %d\n"
+ , netdata_priority + 12
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_AMPS:
+ printf("CHART ipmi.amps '' 'System Current read by IPMI' 'Amps' 'current' 'ipmi.amps' 'line' %d %d\n"
+ , netdata_priority + 13
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_RPM:
+ printf("CHART ipmi.rpm '' 'System Fans read by IPMI' 'RPM' 'fans' 'ipmi.rpm' 'line' %d %d\n"
+ , netdata_priority + 14
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_WATTS:
+ printf("CHART ipmi.watts '' 'System Power read by IPMI' 'Watts' 'power' 'ipmi.watts' 'line' %d %d\n"
+ , netdata_priority + 5
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
+ printf("CHART ipmi.percent '' 'System Metrics read by IPMI' '%%' 'other' 'ipmi.percent' 'line' %d %d\n"
+ , netdata_priority + 15
+ , netdata_update_every
+ );
+ break;
+
+ default:
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->sensor_units == units)
+ sn->ignore = 1;
+ return;
+ }
+
+ for(sn = sensors_root; sn; sn = sn->next) {
+ if(sn->sensor_units == units && sn->updated && !sn->ignore) {
+ sn->exposed = 1;
+
+ switch(sn->sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 1\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_name
+ , sn->sensor_number
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 1000\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_name
+ , sn->sensor_number
+ );
+ break;
+
+ default:
+ sn->ignore = 1;
+ break;
+ }
+ }
+ }
+}
+
+static void send_metrics_to_netdata_for_units(int units) {
+ struct sensor *sn;
+
+ switch(units) {
+ case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
+ printf("BEGIN ipmi.temperatures_c\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
+ printf("BEGIN ipmi.temperatures_f\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
+ printf("BEGIN ipmi.volts\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_AMPS:
+ printf("BEGIN ipmi.amps\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_RPM:
+ printf("BEGIN ipmi.rpm\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_WATTS:
+ printf("BEGIN ipmi.watts\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
+ printf("BEGIN ipmi.percent\n");
+ break;
+
+ default:
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->sensor_units == units)
+ sn->ignore = 1;
+ return;
+ }
+
+ for(sn = sensors_root; sn; sn = sn->next) {
+ if(sn->sensor_units == units && sn->updated && !sn->sent && !sn->ignore) {
+ netdata_sensors_updated++;
+
+ sn->sent = 1;
+
+ switch(sn->sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ printf("SET i%d_n%d_r%d = %u\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_reading.bool_value
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ printf("SET i%d_n%d_r%d = %u\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_reading.uint32_value
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ printf("SET i%d_n%d_r%d = %lld\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , (long long int)(sn->sensor_reading.double_value * 1000)
+ );
+ break;
+
+ default:
+ sn->ignore = 1;
+ break;
+ }
+ }
+ }
+
+ printf("END\n");
+}
+
+static void send_metrics_to_netdata() {
+ static int sel_chart_generated = 0, sensors_states_chart_generated = 0;
+ struct sensor *sn;
+
+ if(netdata_do_sel && !sel_chart_generated) {
+ sel_chart_generated = 1;
+ printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' ipmi.sel area %d %d\n"
+ , netdata_priority + 2
+ , netdata_update_every
+ );
+ printf("DIMENSION events '' absolute 1 1\n");
+ }
+
+ if(!sensors_states_chart_generated) {
+ sensors_states_chart_generated = 1;
+ printf("CHART ipmi.sensors_states '' 'IPMI Sensors State' 'sensors' 'states' ipmi.sensors_states line %d %d\n"
+ , netdata_priority + 1
+ , netdata_update_every
+ );
+ printf("DIMENSION nominal '' absolute 1 1\n");
+ printf("DIMENSION critical '' absolute 1 1\n");
+ printf("DIMENSION warning '' absolute 1 1\n");
+ }
+
+ // generate the CHART/DIMENSION lines, if we have to
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->updated && !sn->exposed && !sn->ignore)
+ send_chart_to_netdata_for_units(sn->sensor_units);
+
+ if(netdata_do_sel) {
+ printf(
+ "BEGIN ipmi.events\n"
+ "SET events = %zu\n"
+ "END\n"
+ , netdata_sel_events
+ );
+ }
+
+ printf(
+ "BEGIN ipmi.sensors_states\n"
+ "SET nominal = %zu\n"
+ "SET warning = %zu\n"
+ "SET critical = %zu\n"
+ "END\n"
+ , netdata_sensors_states_nominal
+ , netdata_sensors_states_warning
+ , netdata_sensors_states_critical
+ );
+
+ // send metrics to netdata
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->updated && sn->exposed && !sn->sent && !sn->ignore)
+ send_metrics_to_netdata_for_units(sn->sensor_units);
+
+}
+
+static void netdata_get_sensor(
+ int record_id
+ , int sensor_number
+ , int sensor_type
+ , int sensor_state
+ , int sensor_units
+ , int sensor_reading_type
+ , char *sensor_name
+ , void *sensor_reading
+) {
+ // find the sensor record
+ struct sensor *sn;
+ for(sn = sensors_root; sn ;sn = sn->next)
+ if( sn->record_id == record_id &&
+ sn->sensor_number == sensor_number &&
+ sn->sensor_reading_type == sensor_reading_type &&
+ sn->sensor_units == sensor_units &&
+ !strcmp(sn->sensor_name, sensor_name)
+ )
+ break;
+
+ if(!sn) {
+ // not found, create it
+
+ sn = calloc(1, sizeof(struct sensor));
+ if(!sn) {
+ fatal("cannot allocate %zu bytes of memory.", sizeof(struct sensor));
+ }
+
+ sn->record_id = record_id;
+ sn->sensor_number = sensor_number;
+ sn->sensor_type = sensor_type;
+ sn->sensor_state = sensor_state;
+ sn->sensor_units = sensor_units;
+ sn->sensor_reading_type = sensor_reading_type;
+ sn->sensor_name = strdup(sensor_name);
+ if(!sn->sensor_name) {
+ fatal("cannot allocate %zu bytes of memory.", strlen(sensor_name));
+ }
+
+ sn->next = sensors_root;
+ sensors_root = sn;
+ }
+
+ switch(sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ sn->sensor_reading.bool_value = *((uint8_t *)sensor_reading);
+ sn->updated = 1;
+ netdata_sensors_collected++;
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ sn->sensor_reading.uint32_value = *((uint32_t *)sensor_reading);
+ sn->updated = 1;
+ netdata_sensors_collected++;
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ sn->sensor_reading.double_value = *((double *)sensor_reading);
+ sn->updated = 1;
+ netdata_sensors_collected++;
+ break;
+
+ default:
+ sn->ignore = 1;
+ break;
+ }
+
+ switch(sensor_state) {
+ case IPMI_MONITORING_STATE_NOMINAL:
+ netdata_sensors_states_nominal++;
+ break;
+
+ case IPMI_MONITORING_STATE_WARNING:
+ netdata_sensors_states_warning++;
+ break;
+
+ case IPMI_MONITORING_STATE_CRITICAL:
+ netdata_sensors_states_critical++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void netdata_get_sel(
+ int record_id
+ , int record_type_class
+ , int sel_state
+) {
+ (void)record_id;
+ (void)record_type_class;
+ (void)sel_state;
+
+ netdata_sel_events++;
+}
+
+
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+// END NETDATA CODE
+// ----------------------------------------------------------------------------
+
+
+static int
+_ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
+{
+ ipmi_monitoring_ctx_t ctx = NULL;
+ unsigned int sensor_reading_flags = 0;
+ int i;
+ int sensor_count;
+ int rv = -1;
+
+ if (!(ctx = ipmi_monitoring_ctx_create ())) {
+ error("ipmi_monitoring_ctx_create()");
+ goto cleanup;
+ }
+
+ if (sdr_cache_directory)
+ {
+ if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
+ sdr_cache_directory) < 0)
+ {
+ error("ipmi_monitoring_ctx_sdr_cache_directory(): %s\n",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ /* Must call otherwise only default interpretations ever used */
+ if (sensor_config_file)
+ {
+ if (ipmi_monitoring_ctx_sensor_config_file (ctx,
+ sensor_config_file) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if (ipmi_monitoring_ctx_sensor_config_file (ctx, NULL) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ if (reread_sdr_cache)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
+
+ if (ignore_non_interpretable_sensors)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
+
+ if (bridge_sensors)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_BRIDGE_SENSORS;
+
+ if (interpret_oem_data)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_INTERPRET_OEM_DATA;
+
+ if (shared_sensors)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_SHARED_SENSORS;
+
+ if (discrete_reading)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING;
+
+ if (ignore_scanning_disabled)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_SCANNING_DISABLED;
+
+ if (assume_bmc_owner)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ASSUME_BMC_OWNER;
+
+#ifdef IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
+ if (entity_sensor_names)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES;
+#endif // IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
+
+ if (!record_ids_length && !sensor_types_length)
+ {
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sensor_reading_flags,
+ NULL,
+ 0,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else if (record_ids_length)
+ {
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sensor_reading_flags,
+ record_ids,
+ record_ids_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_sensor_type (ctx,
+ hostname,
+ ipmi_config,
+ sensor_reading_flags,
+ sensor_types,
+ sensor_types_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_readings_by_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+#ifdef NETDATA_COMMENTED
+ printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
+ "Record ID",
+ "Sensor Name",
+ "Sensor Number",
+ "Sensor Type",
+ "Sensor State",
+ "Sensor Reading",
+ "Sensor Units",
+ "Sensor Event/Reading Type Code",
+ "Sensor Event Bitmask",
+ "Sensor Event String");
+#endif // NETDATA_COMMENTED
+
+ for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (ctx))
+ {
+ int record_id, sensor_number, sensor_type, sensor_state, sensor_units,
+ sensor_reading_type;
+
+#ifdef NETDATA_COMMENTED
+ int sensor_bitmask_type, sensor_bitmask, event_reading_type_code;
+ char **sensor_bitmask_strings = NULL;
+ const char *sensor_type_str;
+ const char *sensor_state_str;
+#endif // NETDATA_COMMENTED
+
+ char *sensor_name = NULL;
+ void *sensor_reading;
+
+ if ((record_id = ipmi_monitoring_sensor_read_record_id (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_number = ipmi_monitoring_sensor_read_sensor_number (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_number(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!(sensor_name = ipmi_monitoring_sensor_read_sensor_name (ctx)))
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_name(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_state(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_units = ipmi_monitoring_sensor_read_sensor_units (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_units(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+#ifdef NETDATA_COMMENTED
+ if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_bitmask_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ if ((sensor_bitmask = ipmi_monitoring_sensor_read_sensor_bitmask (ctx)) < 0)
+ {
+ error(
+ "ipmi_monitoring_sensor_read_sensor_bitmask(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!(sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (ctx)))
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_bitmask_strings(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+#endif // NETDATA_COMMENTED
+
+ if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_reading_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (ctx);
+
+#ifdef NETDATA_COMMENTED
+ if ((event_reading_type_code = ipmi_monitoring_sensor_read_event_reading_type_code (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_event_reading_type_code(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+#endif // NETDATA_COMMENTED
+
+ netdata_get_sensor(
+ record_id
+ , sensor_number
+ , sensor_type
+ , sensor_state
+ , sensor_units
+ , sensor_reading_type
+ , sensor_name
+ , sensor_reading
+ );
+
+#ifdef NETDATA_COMMENTED
+ if (!strlen (sensor_name))
+ sensor_name = "N/A";
+
+ sensor_type_str = _get_sensor_type_string (sensor_type);
+
+ printf ("%d, %s, %d, %s",
+ record_id,
+ sensor_name,
+ sensor_number,
+ sensor_type_str);
+
+ if (sensor_state == IPMI_MONITORING_STATE_NOMINAL)
+ sensor_state_str = "Nominal";
+ else if (sensor_state == IPMI_MONITORING_STATE_WARNING)
+ sensor_state_str = "Warning";
+ else if (sensor_state == IPMI_MONITORING_STATE_CRITICAL)
+ sensor_state_str = "Critical";
+ else
+ sensor_state_str = "N/A";
+
+ printf (", %s", sensor_state_str);
+
+ if (sensor_reading)
+ {
+ const char *sensor_units_str;
+
+ if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL)
+ printf (", %s",
+ (*((uint8_t *)sensor_reading) ? "true" : "false"));
+ else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32)
+ printf (", %u",
+ *((uint32_t *)sensor_reading));
+ else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE)
+ printf (", %.2f",
+ *((double *)sensor_reading));
+ else
+ printf (", N/A");
+
+ if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_CELSIUS)
+ sensor_units_str = "C";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT)
+ sensor_units_str = "F";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_VOLTS)
+ sensor_units_str = "V";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_AMPS)
+ sensor_units_str = "A";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_RPM)
+ sensor_units_str = "RPM";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_WATTS)
+ sensor_units_str = "W";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_PERCENT)
+ sensor_units_str = "%";
+ else
+ sensor_units_str = "N/A";
+
+ printf (", %s", sensor_units_str);
+ }
+ else
+ printf (", N/A, N/A");
+
+ printf (", %Xh", event_reading_type_code);
+
+ /* It is possible you may want to monitor specific event
+ * conditions that may occur. If that is the case, you may want
+ * to check out what specific bitmask type and bitmask events
+ * occurred. See ipmi_monitoring_bitmasks.h for a list of
+ * bitmasks and types.
+ */
+
+ if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
+ printf (", %Xh", sensor_bitmask);
+ else
+ printf (", N/A");
+
+ if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
+ {
+ unsigned int i = 0;
+
+ printf (",");
+
+ while (sensor_bitmask_strings[i])
+ {
+ printf (" ");
+
+ printf ("'%s'",
+ sensor_bitmask_strings[i]);
+
+ i++;
+ }
+ }
+ else
+ printf (", N/A");
+
+ printf ("\n");
+#endif // NETDATA_COMMENTED
+ }
+
+ rv = 0;
+ cleanup:
+ if (ctx)
+ ipmi_monitoring_ctx_destroy (ctx);
+ return (rv);
+}
+
+
+static int
+_ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
+{
+ ipmi_monitoring_ctx_t ctx = NULL;
+ unsigned int sel_flags = 0;
+ int i;
+ int sel_count;
+ int rv = -1;
+
+ if (!(ctx = ipmi_monitoring_ctx_create ()))
+ {
+ error("ipmi_monitoring_ctx_create()");
+ goto cleanup;
+ }
+
+ if (sdr_cache_directory)
+ {
+ if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
+ sdr_cache_directory) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sdr_cache_directory(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ /* Must call otherwise only default interpretations ever used */
+ if (sel_config_file)
+ {
+ if (ipmi_monitoring_ctx_sel_config_file (ctx,
+ sel_config_file) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sel_config_file(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if (ipmi_monitoring_ctx_sel_config_file (ctx, NULL) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sel_config_file(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ if (reread_sdr_cache)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
+
+ if (interpret_oem_data)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_INTERPRET_OEM_DATA;
+
+ if (assume_system_event_record)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_ASSUME_SYSTEM_EVENT_RECORD;
+
+#ifdef IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
+ if (entity_sensor_names)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES;
+#endif // IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
+
+ if (record_ids_length)
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ record_ids,
+ record_ids_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else if (sensor_types_length)
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_sensor_type (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ sensor_types,
+ sensor_types_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else if (date_begin
+ || date_end)
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_date_range (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ date_begin,
+ date_end,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ NULL,
+ 0,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+#ifdef NETDATA_COMMENTED
+ printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
+ "Record ID",
+ "Record Type",
+ "SEL State",
+ "Timestamp",
+ "Sensor Name",
+ "Sensor Type",
+ "Event Direction",
+ "Event Type Code",
+ "Event Data",
+ "Event Offset",
+ "Event Offset String");
+#endif // NETDATA_COMMENTED
+
+ for (i = 0; i < sel_count; i++, ipmi_monitoring_sel_iterator_next (ctx))
+ {
+ int record_id, record_type, sel_state, record_type_class;
+#ifdef NETDATA_COMMENTED
+ int sensor_type, sensor_number, event_direction,
+ event_offset_type, event_offset, event_type_code, manufacturer_id;
+ unsigned int timestamp, event_data1, event_data2, event_data3;
+ char *event_offset_string = NULL;
+ const char *sensor_type_str;
+ const char *event_direction_str;
+ const char *sel_state_str;
+ char *sensor_name = NULL;
+ unsigned char oem_data[64];
+ int oem_data_len;
+ unsigned int j;
+#endif // NETDATA_COMMENTED
+
+ if ((record_id = ipmi_monitoring_sel_read_record_id (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((record_type = ipmi_monitoring_sel_read_record_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_record_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((record_type_class = ipmi_monitoring_sel_read_record_type_class (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_record_type_class(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sel_state = ipmi_monitoring_sel_read_sel_state (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_sel_state(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ netdata_get_sel(
+ record_id
+ , record_type_class
+ , sel_state
+ );
+
+#ifdef NETDATA_COMMENTED
+ if (sel_state == IPMI_MONITORING_STATE_NOMINAL)
+ sel_state_str = "Nominal";
+ else if (sel_state == IPMI_MONITORING_STATE_WARNING)
+ sel_state_str = "Warning";
+ else if (sel_state == IPMI_MONITORING_STATE_CRITICAL)
+ sel_state_str = "Critical";
+ else
+ sel_state_str = "N/A";
+
+ printf ("%d, %d, %s",
+ record_id,
+ record_type,
+ sel_state_str);
+
+ if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD
+ || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
+ {
+
+ if (ipmi_monitoring_sel_read_timestamp (ctx, &timestamp) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_timestamp(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ /* XXX: This should be converted to a nice date output using
+ * your favorite timestamp -> string conversion functions.
+ */
+ printf (", %u", timestamp);
+ }
+ else
+ printf (", N/A");
+
+ if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD)
+ {
+ /* If you are integrating ipmimonitoring SEL into a monitoring application,
+ * you may wish to count the number of times a specific error occurred
+ * and report that to the monitoring application.
+ *
+ * In this particular case, you'll probably want to check out
+ * what sensor type each SEL event is reporting, the
+ * event offset type, and the specific event offset that occurred.
+ *
+ * See ipmi_monitoring_offsets.h for a list of event offsets
+ * and types.
+ */
+
+ if (!(sensor_name = ipmi_monitoring_sel_read_sensor_name (ctx)))
+ {
+ error( "ipmi_monitoring_sel_read_sensor_name(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_type = ipmi_monitoring_sel_read_sensor_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_number = ipmi_monitoring_sel_read_sensor_number (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_sensor_number(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_direction = ipmi_monitoring_sel_read_event_direction (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_direction(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_type_code = ipmi_monitoring_sel_read_event_type_code (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_type_code(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (ipmi_monitoring_sel_read_event_data (ctx,
+ &event_data1,
+ &event_data2,
+ &event_data3) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_data(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_offset_type = ipmi_monitoring_sel_read_event_offset_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_offset_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_offset = ipmi_monitoring_sel_read_event_offset (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_offset(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!(event_offset_string = ipmi_monitoring_sel_read_event_offset_string (ctx)))
+ {
+ error( "ipmi_monitoring_sel_read_event_offset_string(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!strlen (sensor_name))
+ sensor_name = "N/A";
+
+ sensor_type_str = _get_sensor_type_string (sensor_type);
+
+ if (event_direction == IPMI_MONITORING_SEL_EVENT_DIRECTION_ASSERTION)
+ event_direction_str = "Assertion";
+ else
+ event_direction_str = "Deassertion";
+
+ printf (", %s, %s, %d, %s, %Xh, %Xh-%Xh-%Xh",
+ sensor_name,
+ sensor_type_str,
+ sensor_number,
+ event_direction_str,
+ event_type_code,
+ event_data1,
+ event_data2,
+ event_data3);
+
+ if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
+ printf (", %Xh", event_offset);
+ else
+ printf (", N/A");
+
+ if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
+ printf (", %s", event_offset_string);
+ else
+ printf (", N/A");
+ }
+ else if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD
+ || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_NON_TIMESTAMPED_OEM_RECORD)
+ {
+ if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
+ {
+ if ((manufacturer_id = ipmi_monitoring_sel_read_manufacturer_id (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_manufacturer_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ printf (", Manufacturer ID = %Xh", manufacturer_id);
+ }
+
+ if ((oem_data_len = ipmi_monitoring_sel_read_oem_data (ctx, oem_data, 1024)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_oem_data(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ printf (", OEM Data = ");
+
+ for (j = 0; j < oem_data_len; j++)
+ printf ("%02Xh ", oem_data[j]);
+ }
+ else
+ printf (", N/A, N/A, N/A, N/A, N/A, N/A, N/A");
+
+ printf ("\n");
+#endif // NETDATA_COMMENTED
+ }
+
+ rv = 0;
+ cleanup:
+ if (ctx)
+ ipmi_monitoring_ctx_destroy (ctx);
+ return (rv);
+}
+
+// ----------------------------------------------------------------------------
+// MAIN PROGRAM FOR NETDATA PLUGIN
+
+int ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config) {
+ errno = 0;
+
+ if (_ipmimonitoring_sensors(ipmi_config) < 0) return -1;
+
+ if(netdata_do_sel) {
+ if(_ipmimonitoring_sel(ipmi_config) < 0) return -2;
+ }
+
+ return 0;
+}
+
+int ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config) {
+ int i, checks = 10;
+ unsigned long long total = 0;
+
+ for(i = 0 ; i < checks ; i++) {
+ if(debug) fprintf(stderr, "freeipmi.plugin: checking data collection speed iteration %d of %d\n", i+1, checks);
+
+ // measure the time a data collection needs
+ unsigned long long start = now_realtime_usec();
+ if(ipmi_collect_data(ipmi_config) < 0)
+ fatal("freeipmi.plugin: data collection failed.");
+
+ unsigned long long end = now_realtime_usec();
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: data collection speed was %llu usec\n", end - start);
+
+ // add it to our total
+ total += end - start;
+
+ // wait the same time
+ // to avoid flooding the IPMI processor with requests
+ sleep_usec(end - start);
+ }
+
+ // so, we assume it needed 2x the time
+ // we find the average in microseconds
+ // and we round-up to the closest second
+
+ return (( total * 2 / checks / 1000000 ) + 1);
+}
+
+int main (int argc, char **argv) {
+
+ // ------------------------------------------------------------------------
+ // initialization of netdata plugin
+
+ program_name = "freeipmi.plugin";
+
+ // disable syslog
+ error_log_syslog = 0;
+
+ // set errors flood protection to 100 logs per hour
+ error_log_errors_per_period = 100;
+ error_log_throttle_period = 3600;
+
+
+ // ------------------------------------------------------------------------
+ // parse command line parameters
+
+ int i, freq = 0;
+ for(i = 1; i < argc ; i++) {
+ if(!freq) {
+ int n = atoi(argv[i]);
+ if(n > 0) {
+ freq = n;
+ continue;
+ }
+ }
+
+ if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
+ printf("freeipmi.plugin %s\n", VERSION);
+ exit(0);
+ }
+ else if(strcmp("debug", argv[i]) == 0) {
+ debug = 1;
+ continue;
+ }
+ else if(strcmp("sel", argv[i]) == 0) {
+ netdata_do_sel = 1;
+ continue;
+ }
+ else if(strcmp("no-sel", argv[i]) == 0) {
+ netdata_do_sel = 0;
+ continue;
+ }
+ else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
+ fprintf(stderr,
+ "\n"
+ " netdata freeipmi.plugin %s\n"
+ " Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
+ " Released under GNU General Public License v3 or later.\n"
+ " All rights reserved.\n"
+ "\n"
+ " This program is a data collector plugin for netdata.\n"
+ "\n"
+ " Available command line options:\n"
+ "\n"
+ " SECONDS data collection frequency\n"
+ " minimum: %d\n"
+ "\n"
+ " debug enable verbose output\n"
+ " default: disabled\n"
+ "\n"
+ " sel\n"
+ " no-sel enable/disable SEL collection\n"
+ " default: %s\n"
+ "\n"
+ " hostname HOST\n"
+ " username USER\n"
+ " password PASS connect to remote IPMI host\n"
+ " default: local IPMI processor\n"
+ "\n"
+ " sdr-cache-dir PATH directory for SDR cache files\n"
+ " default: %s\n"
+ "\n"
+ " sensor-config-file FILE filename to read sensor configuration\n"
+ " default: %s\n"
+ "\n"
+ " -v\n"
+ " -V\n"
+ " version print version and exit\n"
+ "\n"
+ " Linux kernel module for IPMI is CPU hungry.\n"
+ " On Linux run this to lower kipmiN CPU utilization:\n"
+ " # echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us\n"
+ "\n"
+ " or create: /etc/modprobe.d/ipmi.conf with these contents:\n"
+ " options ipmi_si kipmid_max_busy_us=10\n"
+ "\n"
+ " For more information:\n"
+ " https://github.com/firehol/netdata/wiki/monitoring-IPMI\n"
+ "\n"
+ , VERSION
+ , netdata_update_every
+ , netdata_do_sel?"enabled":"disabled"
+ , sdr_cache_directory?sdr_cache_directory:"system default"
+ , sensor_config_file?sensor_config_file:"system default"
+ );
+ exit(1);
+ }
+ else if(i < argc && strcmp("hostname", argv[i]) == 0) {
+ hostname = strdupz(argv[++i]);
+ char *s = argv[i];
+ // mask it be hidden from the process tree
+ while(*s) *s++ = 'x';
+ if(debug) fprintf(stderr, "freeipmi.plugin: hostname set to '%s'\n", hostname);
+ continue;
+ }
+ else if(i < argc && strcmp("username", argv[i]) == 0) {
+ username = strdupz(argv[++i]);
+ char *s = argv[i];
+ // mask it be hidden from the process tree
+ while(*s) *s++ = 'x';
+ if(debug) fprintf(stderr, "freeipmi.plugin: username set to '%s'\n", username);
+ continue;
+ }
+ else if(i < argc && strcmp("password", argv[i]) == 0) {
+ password = strdupz(argv[++i]);
+ char *s = argv[i];
+ // mask it be hidden from the process tree
+ while(*s) *s++ = 'x';
+ if(debug) fprintf(stderr, "freeipmi.plugin: password set to '%s'\n", password);
+ continue;
+ }
+ else if(i < argc && strcmp("sdr-cache-dir", argv[i]) == 0) {
+ sdr_cache_directory = argv[++i];
+ if(debug) fprintf(stderr, "freeipmi.plugin: SDR cache directory set to '%s'\n", sdr_cache_directory);
+ continue;
+ }
+ else if(i < argc && strcmp("sensor-config-file", argv[i]) == 0) {
+ sensor_config_file = argv[++i];
+ if(debug) fprintf(stderr, "freeipmi.plugin: sensor config file set to '%s'\n", sensor_config_file);
+ continue;
+ }
+
+ error("freeipmi.plugin: ignoring parameter '%s'", argv[i]);
+ }
+
+ if(freq > netdata_update_every)
+ netdata_update_every = freq;
+
+ else if(freq)
+ error("update frequency %d seconds is too small for IPMI. Using %d.", freq, netdata_update_every);
+
+
+ // ------------------------------------------------------------------------
+ // initialize IPMI
+
+ struct ipmi_monitoring_ipmi_config ipmi_config;
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling _init_ipmi_config()\n");
+
+ _init_ipmi_config(&ipmi_config);
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_monitoring_init()\n");
+
+ if(ipmi_monitoring_init(ipmimonitoring_init_flags, &errnum) < 0)
+ fatal("ipmi_monitoring_init: %s", ipmi_monitoring_ctx_strerror(errnum));
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: detecting IPMI minimum update frequency...\n");
+ freq = ipmi_detect_speed_secs(&ipmi_config);
+ if(debug) fprintf(stderr, "freeipmi.plugin: IPMI minimum update frequency was calculated to %d seconds.\n", freq);
+
+ if(netdata_update_every < freq) {
+ info("enforcing minimum data collection frequency, calculated to %d seconds.", freq);
+ netdata_update_every = freq;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // the main loop
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: starting data collection\n");
+
+ time_t started_t = now_monotonic_sec();
+
+ size_t iteration = 0;
+ usec_t step = netdata_update_every * USEC_PER_SEC;
+
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+ for(iteration = 0; 1 ; iteration++) {
+ usec_t dt = heartbeat_next(&hb, step);
+
+ if(debug && iteration)
+ fprintf(stderr, "freeipmi.plugin: iteration %zu, dt %llu usec, sensors collected %zu, sensors sent to netdata %zu \n"
+ , iteration
+ , dt
+ , netdata_sensors_collected
+ , netdata_sensors_updated
+ );
+
+ netdata_mark_as_not_updated();
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_collect_data()\n");
+ if(ipmi_collect_data(&ipmi_config) < 0)
+ fatal("data collection failed.");
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling send_metrics_to_netdata()\n");
+ send_metrics_to_netdata();
+ fflush(stdout);
+
+ // restart check (14400 seconds)
+ if(now_monotonic_sec() - started_t > 14400) exit(0);
+ }
+}
+
+#else // !HAVE_FREEIPMI
+
+int main(int argc, char **argv) {
+ fatal("freeipmi.plugin is not compiled.");
+}
+
+#endif // !HAVE_FREEIPMI
diff --git a/src/global_statistics.c b/src/global_statistics.c
index a698615f4..8575061ac 100644
--- a/src/global_statistics.c
+++ b/src/global_statistics.c
@@ -10,14 +10,14 @@ volatile struct global_statistics global_statistics = {
.compressed_content_size = 0
};
-pthread_mutex_t global_statistics_mutex = PTHREAD_MUTEX_INITIALIZER;
+netdata_mutex_t global_statistics_mutex = NETDATA_MUTEX_INITIALIZER;
inline void global_statistics_lock(void) {
- pthread_mutex_lock(&global_statistics_mutex);
+ netdata_mutex_lock(&global_statistics_mutex);
}
inline void global_statistics_unlock(void) {
- pthread_mutex_unlock(&global_statistics_mutex);
+ netdata_mutex_unlock(&global_statistics_mutex);
}
void finished_web_request_statistics(uint64_t dt,
@@ -129,14 +129,22 @@ void global_statistics_charts(void) {
getrusage(RUSAGE_THREAD, &thread);
getrusage(RUSAGE_SELF, &me);
- if (!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_proc_cpu");
+#ifdef __FreeBSD__
+ if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_freebsd_cpu");
if (!stcpu_thread) {
- stcpu_thread = rrdset_create("netdata", "plugin_proc_cpu", NULL, "proc", NULL,
- "NetData Proc Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every,
- RRDSET_TYPE_STACKED);
+ stcpu_thread = rrdset_create_localhost("netdata", "plugin_freebsd_cpu", NULL, "freebsd", NULL
+ , "NetData FreeBSD Plugin CPU usage", "milliseconds/s", 132000
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+#else
+ if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_proc_cpu");
+ if (!stcpu_thread) {
+ stcpu_thread = rrdset_create_localhost("netdata", "plugin_proc_cpu", NULL, "proc", NULL
+ , "NetData Proc Plugin CPU usage", "milliseconds/s", 132000
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+#endif
- rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stcpu_thread);
rrddim_set(stcpu_thread, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
@@ -145,13 +153,13 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stcpu) stcpu = rrdset_find("netdata.server_cpu");
+ if (!stcpu) stcpu = rrdset_find_localhost("netdata.server_cpu");
if (!stcpu) {
- stcpu = rrdset_create("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage", "milliseconds/s",
- 130000, rrd_update_every, RRDSET_TYPE_STACKED);
+ stcpu = rrdset_create_localhost("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage"
+ , "milliseconds/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
- rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stcpu);
rrddim_set(stcpu, "user", me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec);
@@ -160,12 +168,12 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stclients) stclients = rrdset_find("netdata.clients");
+ if (!stclients) stclients = rrdset_find_localhost("netdata.clients");
if (!stclients) {
- stclients = rrdset_create("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients",
- "connected clients", 130200, rrd_update_every, RRDSET_TYPE_LINE);
+ stclients = rrdset_create_localhost("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients"
+ , "connected clients", 130200, localhost->rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(stclients, "clients", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(stclients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
} else rrdset_next(stclients);
rrddim_set(stclients, "clients", gs.connected_clients);
@@ -173,12 +181,12 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!streqs) streqs = rrdset_find("netdata.requests");
+ if (!streqs) streqs = rrdset_find_localhost("netdata.requests");
if (!streqs) {
- streqs = rrdset_create("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests", "requests/s",
- 130300, rrd_update_every, RRDSET_TYPE_LINE);
+ streqs = rrdset_create_localhost("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests"
+ , "requests/s", 130300, localhost->rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(streqs, "requests", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(streqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(streqs);
rrddim_set(streqs, "requests", (collected_number) gs.web_requests);
@@ -186,13 +194,13 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stbytes) stbytes = rrdset_find("netdata.net");
+ if (!stbytes) stbytes = rrdset_find_localhost("netdata.net");
if (!stbytes) {
- stbytes = rrdset_create("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic", "kilobits/s",
- 130000, rrd_update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(stbytes, "out", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(stbytes, "in", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stbytes, "out", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stbytes);
rrddim_set(stbytes, "in", (collected_number) gs.bytes_received);
@@ -201,13 +209,14 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stduration) stduration = rrdset_find("netdata.response_time");
+ if (!stduration) stduration = rrdset_find_localhost("netdata.response_time");
if (!stduration) {
- stduration = rrdset_create("netdata", "response_time", NULL, "netdata", NULL, "NetData API Response Time",
- "ms/request", 130400, rrd_update_every, RRDSET_TYPE_LINE);
+ stduration = rrdset_create_localhost("netdata", "response_time", NULL, "netdata", NULL
+ , "NetData API Response Time", "ms/request", 130400, localhost->rrd_update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(stduration, "average", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(stduration, "max", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ rrddim_add(stduration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stduration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
} else rrdset_next(stduration);
uint64_t gweb_usec = gs.web_usec;
@@ -232,13 +241,13 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stcompression) stcompression = rrdset_find("netdata.compression_ratio");
+ if (!stcompression) stcompression = rrdset_find_localhost("netdata.compression_ratio");
if (!stcompression) {
- stcompression = rrdset_create("netdata", "compression_ratio", NULL, "netdata", NULL,
- "NetData API Responses Compression Savings Ratio", "percentage", 130500,
- rrd_update_every, RRDSET_TYPE_LINE);
+ stcompression = rrdset_create_localhost("netdata", "compression_ratio", NULL, "netdata", NULL
+ , "NetData API Responses Compression Savings Ratio", "percentage"
+ , 130500, localhost->rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(stcompression, "savings", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ rrddim_add(stcompression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
} else rrdset_next(stcompression);
// since we don't lock here to read the global statistics
diff --git a/src/health.c b/src/health.c
index 193312eec..46b27db6f 100755..100644
--- a/src/health.c
+++ b/src/health.c
@@ -1,2588 +1,84 @@
+#define NETDATA_HEALTH_INTERNALS
#include "common.h"
-#define RRDVAR_MAX_LENGTH 1024
-
-struct health_options {
- const char *health_default_exec;
- const char *health_default_recipient;
- const char *log_filename;
- size_t log_entries_written;
- FILE *log_fp;
-};
-
-static struct health_options health = {
- .health_default_exec = PLUGINS_DIR "/alarm-notify.sh",
- .health_default_recipient = "root",
- .log_filename = VARLIB_DIR "/health/alarm_log.db",
- .log_entries_written = 0,
- .log_fp = NULL
-};
-
-int health_enabled = 1;
-
-// ----------------------------------------------------------------------------
-// health alarm log load/save
-// no need for locking - only one thread is reading / writing the alarms log
-
-static inline int health_alarm_log_open(void) {
- if(health.log_fp)
- fclose(health.log_fp);
-
- health.log_fp = fopen(health.log_filename, "a");
-
- if(health.log_fp) {
- if (setvbuf(health.log_fp, NULL, _IOLBF, 0) != 0)
- error("Health: cannot set line buffering on health log file.");
- return 0;
- }
-
- error("Health: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", health.log_filename);
- return -1;
-}
-
-static inline void health_alarm_log_close(void) {
- if(health.log_fp) {
- fclose(health.log_fp);
- health.log_fp = NULL;
- }
-}
-
-static inline void health_log_rotate(void) {
- static size_t rotate_every = 0;
-
- if(unlikely(rotate_every == 0)) {
- rotate_every = (size_t)config_get_number("health", "rotate log every lines", 2000);
- if(rotate_every < 100) rotate_every = 100;
- }
-
- if(unlikely(health.log_entries_written > rotate_every)) {
- health_alarm_log_close();
-
- char old_filename[FILENAME_MAX + 1];
- snprintfz(old_filename, FILENAME_MAX, "%s.old", health.log_filename);
-
- if(unlink(old_filename) == -1 && errno != ENOENT)
- error("Health: cannot remove old alarms log file '%s'", old_filename);
-
- if(link(health.log_filename, old_filename) == -1 && errno != ENOENT)
- error("Health: cannot move file '%s' to '%s'.", health.log_filename, old_filename);
-
- if(unlink(health.log_filename) == -1 && errno != ENOENT)
- error("Health: cannot remove old alarms log file '%s'", health.log_filename);
-
- // open it with truncate
- health.log_fp = fopen(health.log_filename, "w");
-
- if(health.log_fp)
- fclose(health.log_fp);
- else
- error("Health: cannot truncate health log '%s'", health.log_filename);
-
- health.log_fp = NULL;
-
- health.log_entries_written = 0;
- health_alarm_log_open();
- }
-}
-
-static inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
- health_log_rotate();
-
- if(likely(health.log_fp)) {
- if(unlikely(fprintf(health.log_fp
- , "%c\t%s"
- "\t%08x\t%08x\t%08x\t%08x\t%08x"
- "\t%08x\t%08x\t%08x"
- "\t%08x\t%08x\t%08x"
- "\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s"
- "\t%d\t%d\t%d\t%d"
- "\t%Lf\t%Lf"
- "\n"
- , (ae->flags & HEALTH_ENTRY_FLAG_SAVED)?'U':'A'
- , host->hostname
-
- , ae->unique_id
- , ae->alarm_id
- , ae->alarm_event_id
- , ae->updated_by_id
- , ae->updates_id
-
- , (uint32_t)ae->when
- , (uint32_t)ae->duration
- , (uint32_t)ae->non_clear_duration
- , (uint32_t)ae->flags
- , (uint32_t)ae->exec_run_timestamp
- , (uint32_t)ae->delay_up_to_timestamp
-
- , (ae->name)?ae->name:""
- , (ae->chart)?ae->chart:""
- , (ae->family)?ae->family:""
- , (ae->exec)?ae->exec:""
- , (ae->recipient)?ae->recipient:""
- , (ae->source)?ae->source:""
- , (ae->units)?ae->units:""
- , (ae->info)?ae->info:""
-
- , ae->exec_code
- , ae->new_status
- , ae->old_status
- , ae->delay
-
- , (long double)ae->new_value
- , (long double)ae->old_value
- ) < 0))
- error("Health: failed to save alarm log entry. Health data may be lost in case of abnormal restart.");
- else {
- ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
- health.log_entries_written++;
- }
- }
-}
-
-static 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);
- size_t line = 0, len = 0;
- ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
-
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
-
- while((s = fgets_trim_len(buf, 65536, fp, &len))) {
- health.log_entries_written++;
- line++;
-
- int max_entries = 30, entries = 0;
- char *pointers[max_entries];
-
- pointers[entries++] = s++;
- while(*s) {
- if(unlikely(*s == '\t')) {
- *s = '\0';
- pointers[entries++] = ++s;
- if(entries >= max_entries) {
- error("Health: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", line, filename, max_entries);
- break;
- }
- }
- else s++;
- }
-
- if(likely(*pointers[0] == 'U' || *pointers[0] == 'A')) {
- ALARM_ENTRY *ae = NULL;
-
- if(entries < 26) {
- error("Health: line %zu of file '%s' should have at least 26 entries, but it has %d. Ignoring it.", line, filename, entries);
- errored++;
- continue;
- }
-
- // check that we have valid ids
- uint32_t unique_id = (uint32_t)strtoul(pointers[2], NULL, 16);
- if(!unique_id) {
- error("Health: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", line, filename, unique_id, pointers[2]);
- errored++;
- continue;
- }
-
- uint32_t alarm_id = (uint32_t)strtoul(pointers[3], NULL, 16);
- if(!alarm_id) {
- error("Health: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", line, filename, alarm_id, pointers[3]);
- errored++;
- continue;
- }
-
- if(unlikely(*pointers[0] == 'A')) {
- // make sure it is properly numbered
- if(unlikely(host->health_log.alarms && unique_id < host->health_log.alarms->unique_id)) {
- error("Health: line %zu of file '%s' has alarm log entry with %u in wrong order. Ignoring it.", line, filename, unique_id);
- errored++;
- continue;
- }
-
- ae = callocz(1, sizeof(ALARM_ENTRY));
- }
- else if(unlikely(*pointers[0] == 'U')) {
- // find the original
- for(ae = host->health_log.alarms; ae; ae = ae->next) {
- if(unlikely(unique_id == ae->unique_id)) {
- if(unlikely(*pointers[0] == 'A')) {
- error("Health: line %zu of file '%s' adds duplicate alarm log entry with unique id %u. Using the later."
- , line, filename, unique_id);
- *pointers[0] = 'U';
- duplicate++;
- }
- break;
- }
- else if(unlikely(unique_id > ae->unique_id)) {
- // no need to continue
- // the linked list is sorted
- ae = NULL;
- break;
- }
- }
-
- // if not found, skip this line
- if(!ae) {
- // error("Health: line %zu of file '%s' updates alarm log entry with unique id %u, but it is not found.", line, filename, unique_id);
- continue;
- }
- }
-
- // check for a possible host missmatch
- //if(strcmp(pointers[1], host->hostname))
- // error("Health: line %zu of file '%s' provides an alarm for host '%s' but this is named '%s'.", line, filename, pointers[1], host->hostname);
-
- ae->unique_id = unique_id;
- ae->alarm_id = alarm_id;
- ae->alarm_event_id = (uint32_t)strtoul(pointers[4], NULL, 16);
- ae->updated_by_id = (uint32_t)strtoul(pointers[5], NULL, 16);
- ae->updates_id = (uint32_t)strtoul(pointers[6], NULL, 16);
-
- ae->when = (uint32_t)strtoul(pointers[7], NULL, 16);
- ae->duration = (uint32_t)strtoul(pointers[8], NULL, 16);
- ae->non_clear_duration = (uint32_t)strtoul(pointers[9], NULL, 16);
-
- ae->flags = (uint32_t)strtoul(pointers[10], NULL, 16);
- ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
-
- ae->exec_run_timestamp = (uint32_t)strtoul(pointers[11], NULL, 16);
- ae->delay_up_to_timestamp = (uint32_t)strtoul(pointers[12], NULL, 16);
-
- if(unlikely(ae->name)) freez(ae->name);
- ae->name = strdupz(pointers[13]);
- ae->hash_name = simple_hash(ae->name);
-
- if(unlikely(ae->chart)) freez(ae->chart);
- ae->chart = strdupz(pointers[14]);
- ae->hash_chart = simple_hash(ae->chart);
-
- if(unlikely(ae->family)) freez(ae->family);
- ae->family = strdupz(pointers[15]);
-
- if(unlikely(ae->exec)) freez(ae->exec);
- ae->exec = strdupz(pointers[16]);
- if(!*ae->exec) { freez(ae->exec); ae->exec = NULL; }
-
- if(unlikely(ae->recipient)) freez(ae->recipient);
- ae->recipient = strdupz(pointers[17]);
- if(!*ae->recipient) { freez(ae->recipient); ae->recipient = NULL; }
-
- if(unlikely(ae->source)) freez(ae->source);
- ae->source = strdupz(pointers[18]);
- if(!*ae->source) { freez(ae->source); ae->source = NULL; }
-
- if(unlikely(ae->units)) freez(ae->units);
- ae->units = strdupz(pointers[19]);
- if(!*ae->units) { freez(ae->units); ae->units = NULL; }
-
- if(unlikely(ae->info)) freez(ae->info);
- ae->info = strdupz(pointers[20]);
- if(!*ae->info) { freez(ae->info); ae->info = NULL; }
-
- ae->exec_code = str2i(pointers[21]);
- ae->new_status = str2i(pointers[22]);
- ae->old_status = str2i(pointers[23]);
- ae->delay = str2i(pointers[24]);
-
- ae->new_value = str2l(pointers[25]);
- ae->old_value = str2l(pointers[26]);
-
- // add it to host if not already there
- if(unlikely(*pointers[0] == 'A')) {
- ae->next = host->health_log.alarms;
- host->health_log.alarms = ae;
- loaded++;
- }
- else updated++;
-
- if(unlikely(ae->unique_id > max_unique_id))
- max_unique_id = ae->unique_id;
-
- if(unlikely(ae->alarm_id >= max_alarm_id))
- max_alarm_id = ae->alarm_id;
- }
- else {
- error("Health: line %zu of file '%s' is invalid (unrecognized entry type '%s').", line, filename, pointers[0]);
- errored++;
- }
- }
-
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-
- 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();
-
- host->health_log.next_log_id = max_unique_id + 1;
- host->health_log.next_alarm_id = max_alarm_id + 1;
-
- debug(D_HEALTH, "Health: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", filename, loaded, updated, errored, duplicate);
- return loaded;
-}
-
-static inline void health_alarm_log_load(RRDHOST *host) {
- health_alarm_log_close();
-
- char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s.old", health.log_filename);
- FILE *fp = fopen(filename, "r");
- if(!fp)
- error("Health: cannot open health file: %s", filename);
- else {
- health_alarm_log_read(host, fp, filename);
- fclose(fp);
- }
-
- health.log_entries_written = 0;
- fp = fopen(health.log_filename, "r");
- if(!fp)
- error("Health: cannot open health file: %s", health.log_filename);
- else {
- health_alarm_log_read(host, fp, health.log_filename);
- fclose(fp);
- }
-
- health_alarm_log_open();
-}
-
-
-// ----------------------------------------------------------------------------
-// health alarm log management
-
-static inline void health_alarm_log(RRDHOST *host,
- uint32_t alarm_id, uint32_t alarm_event_id,
- time_t when,
- const char *name, const char *chart, const char *family,
- const char *exec, const char *recipient, time_t duration,
- calculated_number old_value, calculated_number new_value,
- int old_status, int new_status,
- const char *source,
- const char *units,
- const char *info,
- int delay
-) {
- debug(D_HEALTH, "Health adding alarm log entry with id: %u", host->health_log.next_log_id);
-
- ALARM_ENTRY *ae = callocz(1, sizeof(ALARM_ENTRY));
- ae->name = strdupz(name);
- ae->hash_name = simple_hash(ae->name);
-
- if(chart) {
- ae->chart = strdupz(chart);
- ae->hash_chart = simple_hash(ae->chart);
- }
-
- if(family)
- ae->family = strdupz(family);
-
- if(exec) ae->exec = strdupz(exec);
- if(recipient) ae->recipient = strdupz(recipient);
- if(source) ae->source = strdupz(source);
- if(units) ae->units = strdupz(units);
- if(info) ae->info = strdupz(info);
-
- ae->unique_id = host->health_log.next_log_id++;
- ae->alarm_id = alarm_id;
- ae->alarm_event_id = alarm_event_id;
- ae->when = when;
- ae->old_value = old_value;
- ae->new_value = new_value;
- ae->old_status = old_status;
- ae->new_status = new_status;
- ae->duration = duration;
- ae->delay = delay;
- ae->delay_up_to_timestamp = when + delay;
-
- if(ae->old_status == RRDCALC_STATUS_WARNING || ae->old_status == RRDCALC_STATUS_CRITICAL)
- ae->non_clear_duration += ae->duration;
-
- // link it
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
- ae->next = host->health_log.alarms;
- host->health_log.alarms = ae;
- host->health_log.count++;
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-
- // match previous alarms
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
- ALARM_ENTRY *t;
- for(t = host->health_log.alarms ; t ; t = t->next) {
- if(t != ae && t->alarm_id == ae->alarm_id) {
- if(!(t->flags & HEALTH_ENTRY_FLAG_UPDATED) && !t->updated_by_id) {
- t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
- t->updated_by_id = ae->unique_id;
- ae->updates_id = t->unique_id;
-
- if((t->new_status == RRDCALC_STATUS_WARNING || t->new_status == RRDCALC_STATUS_CRITICAL) &&
- (t->old_status == RRDCALC_STATUS_WARNING || t->old_status == RRDCALC_STATUS_CRITICAL))
- ae->non_clear_duration += t->non_clear_duration;
-
- health_alarm_log_save(host, t);
- }
-
- // no need to continue
- break;
- }
- }
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-
- health_alarm_log_save(host, ae);
-}
-
-// ----------------------------------------------------------------------------
-// RRDVAR management
-
-static inline int rrdvar_fix_name(char *variable) {
- int fixed = 0;
- while(*variable) {
- if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
- *variable++ = '_';
- fixed++;
- }
- else
- variable++;
- }
-
- return fixed;
-}
-
-int rrdvar_compare(void* a, void* b) {
- if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
- else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
- else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
-}
-
-static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
- RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
- if(ret != rv)
- debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
-
- return ret;
-}
-
-static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
- RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
- if(!ret)
- error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
-
- return ret;
-}
-
-static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
- RRDVAR tmp;
- tmp.name = (char *)name;
- tmp.hash = (hash)?hash:simple_hash(tmp.name);
-
- return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
-}
-
-static inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
- (void)host;
-
- if(!rv) return;
-
- if(tree) {
- debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
- if(unlikely(!rrdvar_index_del(tree, rv)))
- error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
- }
-
- freez(rv->name);
- freez(rv);
-}
-
-static inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) {
- char *variable = strdupz(name);
- rrdvar_fix_name(variable);
- uint32_t hash = simple_hash(variable);
-
- RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
- if(unlikely(!rv)) {
- debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
-
- rv = callocz(1, sizeof(RRDVAR));
- rv->name = variable;
- rv->hash = hash;
- rv->type = type;
- rv->value = value;
-
- RRDVAR *ret = rrdvar_index_add(tree, rv);
- if(unlikely(ret != rv)) {
- debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
- rrdvar_free(NULL, NULL, rv);
- rv = NULL;
- }
- else
- debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
- }
- else {
- debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
-
- // already exists
- freez(variable);
-
- // this is important
- // it must return NULL - not the existing variable - or double-free will happen
- rv = NULL;
- }
-
- return rv;
-}
-
-// ----------------------------------------------------------------------------
-// CUSTOM VARIABLES
-
-RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
- calculated_number *v = callocz(1, sizeof(calculated_number));
- *v = NAN;
- RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v);
- if(unlikely(!rv)) {
- free(v);
- error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name);
-
- char *variable = strdupz(name);
- rrdvar_fix_name(variable);
- uint32_t hash = simple_hash(variable);
-
- rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
- }
-
- return rv;
-}
-
-void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) {
- char *variable = strdupz(name);
- rrdvar_fix_name(variable);
- uint32_t hash = simple_hash(variable);
-
- RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
- freez(variable);
-
- if(!rv) {
- error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname);
- return;
- }
-
- if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) {
- error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname);
- return;
- }
-
- if(!rrdvar_index_del(&host->variables_root_index, rv)) {
- error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname);
- return;
- }
-
- freez(rv->name);
- freez(rv->value);
- freez(rv);
-}
-
-void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) {
- if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED)
- error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value);
- else {
- calculated_number *v = rv->value;
- *v = value;
- }
-}
-
-// ----------------------------------------------------------------------------
-// RRDVAR lookup
-
-static calculated_number rrdvar2number(RRDVAR *rv) {
- switch(rv->type) {
- case RRDVAR_TYPE_CALCULATED_ALLOCATED:
- case RRDVAR_TYPE_CALCULATED: {
- calculated_number *n = (calculated_number *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_TIME_T: {
- time_t *n = (time_t *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_COLLECTED: {
- collected_number *n = (collected_number *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_TOTAL: {
- total_number *n = (total_number *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_INT: {
- int *n = (int *)rv->value;
- return *n;
- }
-
- default:
- error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type);
- return NAN;
- }
-}
-
-int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
- RRDSET *st = rc->rrdset;
- RRDVAR *rv;
-
- if(!st) return 0;
-
- rv = rrdvar_index_find(&st->variables_root_index, variable, hash);
- if(rv) {
- *result = rrdvar2number(rv);
- return 1;
- }
-
- rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash);
- if(rv) {
- *result = rrdvar2number(rv);
- return 1;
- }
-
- rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash);
- if(rv) {
- *result = rrdvar2number(rv);
- return 1;
- }
-
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-// RRDVAR to JSON
-
-struct variable2json_helper {
- BUFFER *buf;
- size_t counter;
-};
-
-static int single_variable2json(void *entry, void *data) {
- struct variable2json_helper *helper = (struct variable2json_helper *)data;
- RRDVAR *rv = (RRDVAR *)entry;
- calculated_number value = rrdvar2number(rv);
-
- if(unlikely(isnan(value) || isinf(value)))
- buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
- else
- buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
-
- helper->counter++;
-
- return 0;
-}
-
-void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
- struct variable2json_helper helper = {
- .buf = buf,
- .counter = 0
- };
-
- buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", st->id, st->name, st->context);
- avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
- buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
- helper.counter = 0;
- avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
- buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
- helper.counter = 0;
- avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
- buffer_strcat(buf, "\n\t}\n}\n");
-}
-
-
-// ----------------------------------------------------------------------------
-// RRDDIMVAR management
-// DIMENSION VARIABLES
-
-#define RRDDIMVAR_ID_MAX 1024
-
-static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
- RRDDIM *rd = rs->rrddim;
- RRDSET *st = rd->rrdset;
-
- // CHART VARIABLES FOR THIS DIMENSION
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id);
- rs->var_local_id = NULL;
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name);
- rs->var_local_name = NULL;
-
- // FAMILY VARIABLES FOR THIS DIMENSION
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id);
- rs->var_family_id = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
- rs->var_family_name = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid);
- rs->var_family_contextid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname);
- rs->var_family_contextname = NULL;
-
- // HOST VARIABLES FOR THIS DIMENSION
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid);
- rs->var_host_chartidid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname);
- rs->var_host_chartidname = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid);
- rs->var_host_chartnameid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename);
- rs->var_host_chartnamename = NULL;
-
- // KEYS
-
- freez(rs->key_id);
- rs->key_id = NULL;
-
- freez(rs->key_name);
- rs->key_name = NULL;
-
- freez(rs->key_fullidid);
- rs->key_fullidid = NULL;
-
- freez(rs->key_fullidname);
- rs->key_fullidname = NULL;
-
- freez(rs->key_contextid);
- rs->key_contextid = NULL;
-
- freez(rs->key_contextname);
- rs->key_contextname = NULL;
-
- freez(rs->key_fullnameid);
- rs->key_fullnameid = NULL;
-
- freez(rs->key_fullnamename);
- rs->key_fullnamename = NULL;
-}
-
-static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
- rrddimvar_free_variables(rs);
-
- RRDDIM *rd = rs->rrddim;
- RRDSET *st = rd->rrdset;
-
- char buffer[RRDDIMVAR_ID_MAX + 1];
-
- // KEYS
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
- rs->key_id = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
- rs->key_name = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
- rs->key_fullidid = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
- rs->key_fullidname = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
- rs->key_contextid = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
- rs->key_contextname = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
- rs->key_fullnameid = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
- rs->key_fullnamename = strdupz(buffer);
-
- // CHART VARIABLES FOR THIS DIMENSION
- // -----------------------------------
- //
- // dimensions are available as:
- // - $id
- // - $name
-
- rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value);
- rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value);
-
- // FAMILY VARIABLES FOR THIS DIMENSION
- // -----------------------------------
- //
- // dimensions are available as:
- // - $id (only the first, when multiple overlap)
- // - $name (only the first, when multiple overlap)
- // - $chart-context.id
- // - $chart-context.name
-
- rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value);
- rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value);
- rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value);
- rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value);
-
- // HOST VARIABLES FOR THIS DIMENSION
- // -----------------------------------
- //
- // dimensions are available as:
- // - $chart-id.id
- // - $chart-id.name
- // - $chart-name.id
- // - $chart-name.name
-
- rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value);
- rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value);
- rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value);
- rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value);
-}
-
-RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
- RRDSET *st = rd->rrdset;
-
- debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", st->id, st->name, rd->id, (prefix)?prefix:"", rd->name, (suffix)?suffix:"");
-
- if(!prefix) prefix = "";
- if(!suffix) suffix = "";
-
- RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
-
- rs->prefix = strdupz(prefix);
- rs->suffix = strdupz(suffix);
-
- rs->type = type;
- rs->value = value;
- rs->options = options;
- rs->rrddim = rd;
-
- rs->next = rd->variables;
- rd->variables = rs;
-
- rrddimvar_create_variables(rs);
-
- return rs;
-}
-
-void rrddimvar_rename_all(RRDDIM *rd) {
- RRDSET *st = rd->rrdset;
- debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
-
- RRDDIMVAR *rs, *next = rd->variables;
- while((rs = next)) {
- next = rs->next;
- rrddimvar_create_variables(rs);
- }
-}
-
-void rrddimvar_free(RRDDIMVAR *rs) {
- RRDDIM *rd = rs->rrddim;
- RRDSET *st = rd->rrdset;
- debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", st->id, st->name, rd->id, rd->name, rs->prefix, rs->suffix);
-
- rrddimvar_free_variables(rs);
-
- if(rd->variables == rs) {
- debug(D_VARIABLES, "RRDDIMSET removing first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
- rd->variables = rs->next;
- }
- else {
- debug(D_VARIABLES, "RRDDIMSET removing non-first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
- RRDDIMVAR *t;
- for (t = rd->variables; t && t->next != rs; t = t->next) ;
- if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
- else t->next = rs->next;
- }
-
- freez(rs->prefix);
- freez(rs->suffix);
- freez(rs);
-}
-
-// ----------------------------------------------------------------------------
-// RRDSETVAR management
-// CHART VARIABLES
-
-static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
- RRDSET *st = rs->rrdset;
-
- // CHART
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local);
- rs->var_local = NULL;
-
- // FAMILY
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family);
- rs->var_family = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host);
- rs->var_host = NULL;
-
- // HOST
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
- rs->var_family_name = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name);
- rs->var_host_name = NULL;
-
- // KEYS
-
- freez(rs->key_fullid);
- rs->key_fullid = NULL;
-
- freez(rs->key_fullname);
- rs->key_fullname = NULL;
-}
-
-static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
- rrdsetvar_free_variables(rs);
-
- RRDSET *st = rs->rrdset;
-
- // KEYS
-
- char buffer[RRDVAR_MAX_LENGTH + 1];
- snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
- rs->key_fullid = strdupz(buffer);
-
- snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
- rs->key_fullname = strdupz(buffer);
-
- // CHART
-
- rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
-
- // FAMILY
-
- rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value);
- rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value);
-
- // HOST
-
- rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value);
- rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value);
-
-}
-
-RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
- debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
- RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
-
- rs->variable = strdupz(variable);
- rs->type = type;
- rs->value = value;
- rs->options = options;
- rs->rrdset = st;
-
- rs->next = st->variables;
- st->variables = rs;
-
- rrdsetvar_create_variables(rs);
-
- return rs;
-}
-
-void rrdsetvar_rename_all(RRDSET *st) {
- debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
-
- RRDSETVAR *rs, *next = st->variables;
- while((rs = next)) {
- next = rs->next;
- rrdsetvar_create_variables(rs);
- }
-
- rrdsetcalc_link_matching(st);
-}
-
-void rrdsetvar_free(RRDSETVAR *rs) {
- RRDSET *st = rs->rrdset;
- debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
-
- if(st->variables == rs) {
- st->variables = rs->next;
- }
- else {
- RRDSETVAR *t;
- for (t = st->variables; t && t->next != rs; t = t->next);
- if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
- else t->next = rs->next;
- }
-
- rrdsetvar_free_variables(rs);
-
- freez(rs->variable);
- freez(rs);
-}
-
-// ----------------------------------------------------------------------------
-// RRDCALC management
-
-inline const char *rrdcalc_status2string(int status) {
- switch(status) {
- case RRDCALC_STATUS_REMOVED:
- return "REMOVED";
-
- case RRDCALC_STATUS_UNDEFINED:
- return "UNDEFINED";
-
- case RRDCALC_STATUS_UNINITIALIZED:
- return "UNINITIALIZED";
-
- case RRDCALC_STATUS_CLEAR:
- return "CLEAR";
-
- case RRDCALC_STATUS_RAISED:
- return "RAISED";
-
- case RRDCALC_STATUS_WARNING:
- return "WARNING";
-
- case RRDCALC_STATUS_CRITICAL:
- return "CRITICAL";
-
- default:
- error("Unknown alarm status %d", status);
- return "UNKNOWN";
- }
-}
-
-static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
- debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
-
- rc->last_status_change = now_realtime_sec();
- rc->rrdset = st;
-
- rc->rrdset_next = st->alarms;
- rc->rrdset_prev = NULL;
-
- if(rc->rrdset_next)
- rc->rrdset_next->rrdset_prev = rc;
-
- st->alarms = rc;
-
- if(rc->update_every < rc->rrdset->update_every) {
- error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
- rc->update_every = rc->rrdset->update_every;
- }
-
- if(!isnan(rc->green) && isnan(st->green)) {
- debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
- st->green = rc->green;
- }
-
- if(!isnan(rc->red) && isnan(st->red)) {
- debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
- st->red = rc->red;
- }
-
- rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
- rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
-
- char fullname[RRDVAR_MAX_LENGTH + 1];
- snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
- rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
-
- snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
- rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
-
- if(!rc->units) rc->units = strdupz(st->units);
-
- {
- time_t now = now_realtime_sec();
- health_alarm_log(st->rrdhost, rc->id, rc->next_event_id++, now, rc->name, rc->rrdset->id, rc->rrdset->family, rc->exec, rc->recipient, now - rc->last_status_change, rc->old_value, rc->value, rc->status, RRDCALC_STATUS_UNINITIALIZED, rc->source, rc->units, rc->info, 0);
- }
-}
-
-static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
- if( (rc->hash_chart == st->hash && !strcmp(rc->chart, st->id)) ||
- (rc->hash_chart == st->hash_name && !strcmp(rc->chart, st->name)))
- return 1;
-
- return 0;
-}
-
-// this has to be called while the RRDHOST is locked
-inline void rrdsetcalc_link_matching(RRDSET *st) {
- // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
-
- RRDCALC *rc;
- for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
- if(unlikely(rc->rrdset))
- continue;
-
- if(unlikely(rrdcalc_is_matching_this_rrdset(rc, st)))
- rrdsetcalc_link(st, rc);
- }
-}
-
-// this has to be called while the RRDHOST is locked
-inline void rrdsetcalc_unlink(RRDCALC *rc) {
- RRDSET *st = rc->rrdset;
-
- if(!st) {
- debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
- error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
- return;
- }
-
- {
- time_t now = now_realtime_sec();
- health_alarm_log(st->rrdhost, rc->id, rc->next_event_id++, now, rc->name, rc->rrdset->id, rc->rrdset->family, rc->exec, rc->recipient, now - rc->last_status_change, rc->old_value, rc->value, rc->status, RRDCALC_STATUS_REMOVED, rc->source, rc->units, rc->info, 0);
- }
-
- RRDHOST *host = st->rrdhost;
-
- debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
-
- // unlink it
- if(rc->rrdset_prev)
- rc->rrdset_prev->rrdset_next = rc->rrdset_next;
-
- if(rc->rrdset_next)
- rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
-
- if(st->alarms == rc)
- st->alarms = rc->rrdset_next;
-
- rc->rrdset_prev = rc->rrdset_next = NULL;
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
- rc->local = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family);
- rc->family = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
- rc->hostid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
- rc->hostname = NULL;
-
- rc->rrdset = NULL;
-
- // RRDCALC will remain in RRDHOST
- // so that if the matching chart is found in the future
- // it will be applied automatically
-}
-
-RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
- RRDCALC *rc;
- uint32_t hash = simple_hash(name);
-
- for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
- if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
- return rc;
- }
-
- return NULL;
-}
-
-static inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
- RRDCALC *rc;
-
- if(unlikely(!chart)) {
- error("attempt to find RRDCALC '%s' without giving a chart name", name);
- return 1;
- }
-
- if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
- if(unlikely(!hash_name)) hash_name = simple_hash(name);
-
- // make sure it does not already exist
- for(rc = host->alarms; rc ; rc = rc->next) {
- if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
- debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
- error("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
- return 1;
- }
- }
-
- return 0;
-}
-
-static inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
- if(chart && name) {
- uint32_t hash_chart = simple_hash(chart);
- uint32_t hash_name = simple_hash(name);
-
- // re-use old IDs, by looking them up in the alarm log
- ALARM_ENTRY *ae;
- for(ae = host->health_log.alarms; ae ;ae = ae->next) {
- if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
- if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
- return ae->alarm_id;
- }
- }
- }
-
- return host->health_log.next_alarm_id++;
-}
-
-static inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
- rrdhost_check_rdlock(host);
-
- if(rc->calculation) {
- rc->calculation->status = &rc->status;
- rc->calculation->this = &rc->value;
- rc->calculation->after = &rc->db_after;
- rc->calculation->before = &rc->db_before;
- rc->calculation->rrdcalc = rc;
- }
-
- if(rc->warning) {
- rc->warning->status = &rc->status;
- rc->warning->this = &rc->value;
- rc->warning->after = &rc->db_after;
- rc->warning->before = &rc->db_before;
- rc->warning->rrdcalc = rc;
- }
-
- if(rc->critical) {
- rc->critical->status = &rc->status;
- rc->critical->this = &rc->value;
- rc->critical->after = &rc->db_after;
- rc->critical->before = &rc->db_before;
- rc->critical->rrdcalc = rc;
- }
-
- // link it to the host
- if(likely(host->alarms)) {
- // append it
- RRDCALC *t;
- for(t = host->alarms; t && t->next ; t = t->next) ;
- t->next = rc;
- }
- else {
- host->alarms = rc;
- }
-
- // link it to its chart
- RRDSET *st;
- for(st = host->rrdset_root; st ; st = st->next) {
- if(rrdcalc_is_matching_this_rrdset(rc, st)) {
- rrdsetcalc_link(st, rc);
- break;
- }
- }
-}
-
-static inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
-
- debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
-
- if(rrdcalc_exists(host, chart, rt->name, 0, 0))
- return NULL;
-
- RRDCALC *rc = callocz(1, sizeof(RRDCALC));
- rc->next_event_id = 1;
- rc->id = rrdcalc_get_unique_id(host, chart, rt->name, &rc->next_event_id);
- rc->name = strdupz(rt->name);
- rc->hash = simple_hash(rc->name);
- rc->chart = strdupz(chart);
- rc->hash_chart = simple_hash(rc->chart);
-
- if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
-
- rc->green = rt->green;
- rc->red = rt->red;
- rc->value = NAN;
- rc->old_value = NAN;
-
- rc->delay_up_duration = rt->delay_up_duration;
- rc->delay_down_duration = rt->delay_down_duration;
- rc->delay_max_duration = rt->delay_max_duration;
- rc->delay_multiplier = rt->delay_multiplier;
-
- rc->group = rt->group;
- rc->after = rt->after;
- rc->before = rt->before;
- rc->update_every = rt->update_every;
- rc->options = rt->options;
-
- if(rt->exec) rc->exec = strdupz(rt->exec);
- if(rt->recipient) rc->recipient = strdupz(rt->recipient);
- if(rt->source) rc->source = strdupz(rt->source);
- if(rt->units) rc->units = strdupz(rt->units);
- if(rt->info) rc->info = strdupz(rt->info);
-
- if(rt->calculation) {
- rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
- if(!rc->calculation)
- error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
- }
- if(rt->warning) {
- rc->warning = expression_parse(rt->warning->source, NULL, NULL);
- if(!rc->warning)
- error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
- }
- if(rt->critical) {
- rc->critical = expression_parse(rt->critical->source, NULL, NULL);
- if(!rc->critical)
- error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
- }
-
- debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
- (rc->chart)?rc->chart:"NOCHART",
- rc->name,
- (rc->exec)?rc->exec:"DEFAULT",
- (rc->recipient)?rc->recipient:"DEFAULT",
- rc->green,
- rc->red,
- rc->group,
- rc->after,
- rc->before,
- rc->options,
- (rc->dimensions)?rc->dimensions:"NONE",
- rc->update_every,
- (rc->calculation)?rc->calculation->parsed_as:"NONE",
- (rc->warning)?rc->warning->parsed_as:"NONE",
- (rc->critical)?rc->critical->parsed_as:"NONE",
- rc->source,
- rc->delay_up_duration,
- rc->delay_down_duration,
- rc->delay_max_duration,
- rc->delay_multiplier
- );
-
- rrdcalc_create_part2(host, rc);
- return rc;
-}
-
-void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
- if(!rc) return;
-
- debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
-
- // unlink it from RRDSET
- if(rc->rrdset) rrdsetcalc_unlink(rc);
-
- // unlink it from RRDHOST
- if(unlikely(rc == host->alarms))
- host->alarms = rc->next;
-
- else if(likely(host->alarms)) {
- RRDCALC *t, *last = host->alarms;
- for(t = last->next; t && t != rc; last = t, t = t->next) ;
- if(last->next == rc)
- last->next = rc->next;
- else
- error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
- }
- else
- error("Cannot unlink unlink '%s.%s' from host '%s': This host does not have any calculations", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
-
- expression_free(rc->calculation);
- expression_free(rc->warning);
- expression_free(rc->critical);
-
- freez(rc->name);
- freez(rc->chart);
- freez(rc->family);
- freez(rc->dimensions);
- freez(rc->exec);
- freez(rc->recipient);
- freez(rc->source);
- freez(rc->units);
- freez(rc->info);
- freez(rc);
-}
+int default_health_enabled = 1;
// ----------------------------------------------------------------------------
-// RRDCALCTEMPLATE management
-
-void rrdcalctemplate_link_matching(RRDSET *st) {
- RRDCALCTEMPLATE *rt;
-
- for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
- if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)
- && (!rt->family_pattern || simple_pattern_matches(rt->family_pattern, st->family))) {
- RRDCALC *rc = rrdcalc_create(st->rrdhost, rt, st->id);
- if(unlikely(!rc))
- error("Health tried to create alarm from template '%s', but it failed", rt->name);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- else if(rc->rrdset != st)
- error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
-#endif
- }
- }
-}
-
-static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
- debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
-
- if(host->templates) {
- if(host->templates == rt) {
- host->templates = rt->next;
- }
- else {
- RRDCALCTEMPLATE *t, *last = host->templates;
- for (t = last->next; t && t != rt; last = t, t = t->next ) ;
- if(last && last->next == rt) {
- last->next = rt->next;
- rt->next = NULL;
- }
- else
- error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
- }
- }
-
- expression_free(rt->calculation);
- expression_free(rt->warning);
- expression_free(rt->critical);
-
- freez(rt->family_match);
- simple_pattern_free(rt->family_pattern);
-
- freez(rt->name);
- freez(rt->exec);
- freez(rt->recipient);
- freez(rt->context);
- freez(rt->source);
- freez(rt->units);
- freez(rt->info);
- freez(rt->dimensions);
- freez(rt);
-}
-
-// ----------------------------------------------------------------------------
-// load health configuration
-
-#define HEALTH_CONF_MAX_LINE 4096
-
-#define HEALTH_ALARM_KEY "alarm"
-#define HEALTH_TEMPLATE_KEY "template"
-#define HEALTH_ON_KEY "on"
-#define HEALTH_FAMILIES_KEY "families"
-#define HEALTH_LOOKUP_KEY "lookup"
-#define HEALTH_CALC_KEY "calc"
-#define HEALTH_EVERY_KEY "every"
-#define HEALTH_GREEN_KEY "green"
-#define HEALTH_RED_KEY "red"
-#define HEALTH_WARN_KEY "warn"
-#define HEALTH_CRIT_KEY "crit"
-#define HEALTH_EXEC_KEY "exec"
-#define HEALTH_RECIPIENT_KEY "to"
-#define HEALTH_UNITS_KEY "units"
-#define HEALTH_INFO_KEY "info"
-#define HEALTH_DELAY_KEY "delay"
-
-static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
- if(!rc->chart) {
- error("Health configuration for alarm '%s' does not have a chart", rc->name);
- return 0;
- }
+// health initialization
- if(!rc->update_every) {
- error("Health configuration for alarm '%s.%s' has no frequency (parameter 'every'). Ignoring it.", rc->chart?rc->chart:"NOCHART", rc->name);
- return 0;
- }
-
- if(!RRDCALC_HAS_DB_LOOKUP(rc) && !rc->warning && !rc->critical) {
- error("Health configuration for alarm '%s.%s' is useless (no calculation, no warning and no critical evaluation)", rc->chart?rc->chart:"NOCHART", rc->name);
- return 0;
- }
-
- if (rrdcalc_exists(host, rc->chart, rc->name, rc->hash_chart, rc->hash))
- return 0;
-
- rc->id = rrdcalc_get_unique_id(&localhost, rc->chart, rc->name, &rc->next_event_id);
-
- debug(D_HEALTH, "Health configuration adding alarm '%s.%s' (%u): exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
- rc->chart?rc->chart:"NOCHART",
- rc->name,
- rc->id,
- (rc->exec)?rc->exec:"DEFAULT",
- (rc->recipient)?rc->recipient:"DEFAULT",
- rc->green,
- rc->red,
- rc->group,
- rc->after,
- rc->before,
- rc->options,
- (rc->dimensions)?rc->dimensions:"NONE",
- rc->update_every,
- (rc->calculation)?rc->calculation->parsed_as:"NONE",
- (rc->warning)?rc->warning->parsed_as:"NONE",
- (rc->critical)?rc->critical->parsed_as:"NONE",
- rc->source,
- rc->delay_up_duration,
- rc->delay_down_duration,
- rc->delay_max_duration,
- rc->delay_multiplier
- );
-
- rrdcalc_create_part2(host, rc);
- return 1;
-}
-
-static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCALCTEMPLATE *rt) {
- if(unlikely(!rt->context)) {
- error("Health configuration for template '%s' does not have a context", rt->name);
- return 0;
- }
-
- if(unlikely(!rt->update_every)) {
- error("Health configuration for template '%s' has no frequency (parameter 'every'). Ignoring it.", rt->name);
- return 0;
- }
-
- if(unlikely(!RRDCALCTEMPLATE_HAS_CALCULATION(rt) && !rt->warning && !rt->critical)) {
- error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
- return 0;
- }
-
- 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))) {
- error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
- return 0;
- }
- }
-
- debug(D_HEALTH, "Health configuration adding template '%s': context '%s', exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
- rt->name,
- (rt->context)?rt->context:"NONE",
- (rt->exec)?rt->exec:"DEFAULT",
- (rt->recipient)?rt->recipient:"DEFAULT",
- rt->green,
- rt->red,
- rt->group,
- rt->after,
- rt->before,
- rt->options,
- (rt->dimensions)?rt->dimensions:"NONE",
- rt->update_every,
- (rt->calculation)?rt->calculation->parsed_as:"NONE",
- (rt->warning)?rt->warning->parsed_as:"NONE",
- (rt->critical)?rt->critical->parsed_as:"NONE",
- rt->source,
- rt->delay_up_duration,
- rt->delay_down_duration,
- rt->delay_max_duration,
- rt->delay_multiplier
- );
-
- if(likely(last)) {
- last->next = rt;
- }
- else {
- rt->next = host->templates;
- host->templates = rt;
- }
-
- return 1;
-}
-
-static inline int health_parse_duration(char *string, int *result) {
- // make sure it is a number
- if(!*string || !(isdigit(*string) || *string == '+' || *string == '-')) {
- *result = 0;
- return 0;
- }
-
- char *e = NULL;
- calculated_number n = strtold(string, &e);
- if(e && *e) {
- switch (*e) {
- case 'Y':
- *result = (int) (n * 86400 * 365);
- break;
- case 'M':
- *result = (int) (n * 86400 * 30);
- break;
- case 'w':
- *result = (int) (n * 86400 * 7);
- break;
- case 'd':
- *result = (int) (n * 86400);
- break;
- case 'h':
- *result = (int) (n * 3600);
- break;
- case 'm':
- *result = (int) (n * 60);
- break;
-
- default:
- case 's':
- *result = (int) (n);
- break;
- }
- }
- else
- *result = (int)(n);
-
- return 1;
-}
-
-static inline int health_parse_delay(
- size_t line, const char *path, const char *file, char *string,
- int *delay_up_duration,
- int *delay_down_duration,
- int *delay_max_duration,
- float *delay_multiplier) {
-
- char given_up = 0;
- char given_down = 0;
- char given_max = 0;
- char given_multiplier = 0;
-
- char *s = string;
- while(*s) {
- char *key = s;
-
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if(!*key) break;
-
- char *value = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if(!strcasecmp(key, "up")) {
- if (!health_parse_duration(value, delay_up_duration)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_up = 1;
- }
- else if(!strcasecmp(key, "down")) {
- if (!health_parse_duration(value, delay_down_duration)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_down = 1;
- }
- else if(!strcasecmp(key, "multiplier")) {
- *delay_multiplier = strtof(value, NULL);
- if(isnan(*delay_multiplier) || isinf(*delay_multiplier) || islessequal(*delay_multiplier, 0)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_multiplier = 1;
- }
- else if(!strcasecmp(key, "max")) {
- if (!health_parse_duration(value, delay_max_duration)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_max = 1;
- }
- else {
- error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
- line, path, file, key);
- }
- }
-
- if(!given_up)
- *delay_up_duration = 0;
-
- if(!given_down)
- *delay_down_duration = 0;
-
- if(!given_multiplier)
- *delay_multiplier = 1.0;
-
- if(!given_max) {
- if((*delay_max_duration) < (*delay_up_duration) * (*delay_multiplier))
- *delay_max_duration = (*delay_up_duration) * (*delay_multiplier);
-
- if((*delay_max_duration) < (*delay_down_duration) * (*delay_multiplier))
- *delay_max_duration = (*delay_down_duration) * (*delay_multiplier);
- }
-
- return 1;
-}
-
-static inline int health_parse_db_lookup(
- size_t line, const char *path, const char *file, char *string,
- int *group_method, int *after, int *before, int *every,
- uint32_t *options, char **dimensions
-) {
- debug(D_HEALTH, "Health configuration parsing database lookup %zu@%s/%s: %s", line, path, file, string);
-
- if(*dimensions) freez(*dimensions);
- *dimensions = NULL;
- *after = 0;
- *before = 0;
- *every = 0;
- *options = 0;
-
- char *s = string, *key;
-
- // first is the group method
- key = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
- if(!*s) {
- error("Health configuration invalid chart calculation at line %zu of file '%s/%s': expected group method followed by the 'after' time, but got '%s'",
- line, path, file, key);
- return 0;
- }
-
- if((*group_method = web_client_api_request_v1_data_group(key, -1)) == -1) {
- error("Health configuration at line %zu of file '%s/%s': invalid group method '%s'",
- line, path, file, key);
- return 0;
- }
-
- // then is the 'after' time
- key = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if(!health_parse_duration(key, after)) {
- error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' after group method",
- line, path, file, key);
- return 0;
- }
-
- // sane defaults
- *every = abs(*after);
-
- // now we may have optional parameters
- while(*s) {
- key = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
- if(!*key) break;
-
- if(!strcasecmp(key, "at")) {
- char *value = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if (!health_parse_duration(value, before)) {
- error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- }
- else if(!strcasecmp(key, HEALTH_EVERY_KEY)) {
- char *value = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if (!health_parse_duration(value, every)) {
- error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- }
- else if(!strcasecmp(key, "absolute") || !strcasecmp(key, "abs") || !strcasecmp(key, "absolute_sum")) {
- *options |= RRDR_OPTION_ABSOLUTE;
- }
- else if(!strcasecmp(key, "min2max")) {
- *options |= RRDR_OPTION_MIN2MAX;
- }
- else if(!strcasecmp(key, "null2zero")) {
- *options |= RRDR_OPTION_NULL2ZERO;
- }
- else if(!strcasecmp(key, "percentage")) {
- *options |= RRDR_OPTION_PERCENTAGE;
- }
- else if(!strcasecmp(key, "unaligned")) {
- *options |= RRDR_OPTION_NOT_ALIGNED;
- }
- else if(!strcasecmp(key, "of")) {
- if(*s && strcasecmp(s, "all"))
- *dimensions = strdupz(s);
- break;
- }
- else {
- error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
- line, path, file, key);
- }
- }
-
- return 1;
-}
-
-static inline char *tabs2spaces(char *s) {
- char *t = s;
- while(*t) {
- if(unlikely(*t == '\t')) *t = ' ';
- t++;
- }
-
- return s;
-}
-
-static inline char *health_source_file(size_t line, const char *path, const char *filename) {
+inline char *health_config_dir(void) {
char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%zu@%s/%s", line, path, filename);
- return strdupz(buffer);
-}
-
-static inline void strip_quotes(char *s) {
- while(*s) {
- if(*s == '\'' || *s == '"') *s = ' ';
- s++;
- }
-}
-
-int health_readfile(const char *path, const char *filename) {
- debug(D_HEALTH, "Health configuration reading file '%s/%s'", path, filename);
-
- static uint32_t hash_alarm = 0, hash_template = 0, hash_on = 0, hash_families = 0, hash_calc = 0, hash_green = 0, hash_red = 0, hash_warn = 0, hash_crit = 0, hash_exec = 0, hash_every = 0, hash_lookup = 0, hash_units = 0, hash_info = 0, hash_recipient = 0, hash_delay = 0;
- char buffer[HEALTH_CONF_MAX_LINE + 1];
-
- if(unlikely(!hash_alarm)) {
- hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
- hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
- hash_on = simple_uhash(HEALTH_ON_KEY);
- hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
- hash_calc = simple_uhash(HEALTH_CALC_KEY);
- hash_lookup = simple_uhash(HEALTH_LOOKUP_KEY);
- hash_green = simple_uhash(HEALTH_GREEN_KEY);
- hash_red = simple_uhash(HEALTH_RED_KEY);
- hash_warn = simple_uhash(HEALTH_WARN_KEY);
- hash_crit = simple_uhash(HEALTH_CRIT_KEY);
- hash_exec = simple_uhash(HEALTH_EXEC_KEY);
- hash_every = simple_uhash(HEALTH_EVERY_KEY);
- hash_units = simple_hash(HEALTH_UNITS_KEY);
- hash_info = simple_hash(HEALTH_INFO_KEY);
- hash_recipient = simple_hash(HEALTH_RECIPIENT_KEY);
- hash_delay = simple_uhash(HEALTH_DELAY_KEY);
- }
-
- snprintfz(buffer, HEALTH_CONF_MAX_LINE, "%s/%s", path, filename);
- FILE *fp = fopen(buffer, "r");
- if(!fp) {
- error("Health configuration cannot read file '%s'.", buffer);
- return 0;
- }
-
- RRDCALC *rc = NULL;
- RRDCALCTEMPLATE *rt = NULL;
-
- size_t line = 0, append = 0;
- char *s;
- while((s = fgets(&buffer[append], (int)(HEALTH_CONF_MAX_LINE - append), fp)) || append) {
- int stop_appending = !s;
- line++;
- s = trim(buffer);
- if(!s) continue;
-
- append = strlen(s);
- if(!stop_appending && s[append - 1] == '\\') {
- s[append - 1] = ' ';
- append = &s[append] - buffer;
- if(append < HEALTH_CONF_MAX_LINE)
- continue;
- else {
- error("Health configuration has too long muli-line at line %zu of file '%s/%s'.", line, path, filename);
- }
- }
- append = 0;
-
- char *key = s;
- while(*s && *s != ':') s++;
- if(!*s) {
- error("Health configuration has invalid line %zu of file '%s/%s'. It does not contain a ':'. Ignoring it.", line, path, filename);
- continue;
- }
- *s = '\0';
- s++;
-
- char *value = s;
- key = trim(key);
- value = trim(value);
-
- if(!key) {
- error("Health configuration has invalid line %zu of file '%s/%s'. Keyword is empty. Ignoring it.", line, path, filename);
- continue;
- }
-
- if(!value) {
- error("Health configuration has invalid line %zu of file '%s/%s'. value is empty. Ignoring it.", line, path, filename);
- continue;
- }
-
- uint32_t hash = simple_uhash(key);
-
- if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
- if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
- rrdcalc_free(&localhost, rc);
-
- if(rt) {
- if (!rrdcalctemplate_add_template_from_config(&localhost, rt))
- rrdcalctemplate_free(&localhost, rt);
- rt = NULL;
- }
-
- rc = callocz(1, sizeof(RRDCALC));
- rc->next_event_id = 1;
- rc->name = tabs2spaces(strdupz(value));
- rc->hash = simple_hash(rc->name);
- rc->source = health_source_file(line, path, filename);
- rc->green = NAN;
- rc->red = NAN;
- rc->value = NAN;
- rc->old_value = NAN;
- rc->delay_multiplier = 1.0;
-
- if(rrdvar_fix_name(rc->name))
- error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
- }
- else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
- if(rc) {
- if(!rrdcalc_add_alarm_from_config(&localhost, rc))
- rrdcalc_free(&localhost, rc);
- rc = NULL;
- }
-
- if(rt && !rrdcalctemplate_add_template_from_config(&localhost, rt))
- rrdcalctemplate_free(&localhost, rt);
-
- rt = callocz(1, sizeof(RRDCALCTEMPLATE));
- rt->name = tabs2spaces(strdupz(value));
- rt->hash_name = simple_hash(rt->name);
- rt->source = health_source_file(line, path, filename);
- rt->green = NAN;
- rt->red = NAN;
- rt->delay_multiplier = 1.0;
-
- if(rrdvar_fix_name(rt->name))
- error("Health configuration renamed template '%s' to '%s'", value, rt->name);
- }
- else if(rc) {
- if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
- if(rc->chart) {
- if(strcmp(rc->chart, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->chart, value, value);
-
- freez(rc->chart);
- }
- rc->chart = tabs2spaces(strdupz(value));
- rc->hash_chart = simple_hash(rc->chart);
- }
- else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
- health_parse_db_lookup(line, path, filename, value, &rc->group, &rc->after, &rc->before,
- &rc->update_every,
- &rc->options, &rc->dimensions);
- }
- else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
- if(!health_parse_duration(value, &rc->update_every))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' cannot parse duration: '%s'.",
- line, path, filename, rc->name, key, value);
- }
- else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
- char *e;
- rc->green = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rc->name, key, e);
- }
- }
- else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
- char *e;
- rc->red = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rc->name, key, e);
- }
- }
- else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rc->calculation = expression_parse(value, &failed_at, &error);
- if(!rc->calculation) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rc->warning = expression_parse(value, &failed_at, &error);
- if(!rc->warning) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rc->critical = expression_parse(value, &failed_at, &error);
- if(!rc->critical) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
- if(rc->exec) {
- if(strcmp(rc->exec, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->exec, value, value);
-
- freez(rc->exec);
- }
- rc->exec = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
- if(rc->recipient) {
- if(strcmp(rc->recipient, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->recipient, value, value);
-
- freez(rc->recipient);
- }
- rc->recipient = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
- if(rc->units) {
- if(strcmp(rc->units, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->units, value, value);
-
- freez(rc->units);
- }
- rc->units = tabs2spaces(strdupz(value));
- strip_quotes(rc->units);
- }
- else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
- if(rc->info) {
- if(strcmp(rc->info, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->info, value, value);
-
- freez(rc->info);
- }
- rc->info = tabs2spaces(strdupz(value));
- strip_quotes(rc->info);
- }
- else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
- health_parse_delay(line, path, filename, value, &rc->delay_up_duration, &rc->delay_down_duration, &rc->delay_max_duration, &rc->delay_multiplier);
- }
- else {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has unknown key '%s'.",
- line, path, filename, rc->name, key);
- }
- }
- else if(rt) {
- if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
- if(rt->context) {
- if(strcmp(rt->context, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->context, value, value);
-
- freez(rt->context);
- }
- rt->context = tabs2spaces(strdupz(value));
- rt->hash_context = simple_hash(rt->context);
- }
- else if(hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
- freez(rt->family_match);
- simple_pattern_free(rt->family_pattern);
-
- rt->family_match = tabs2spaces(strdupz(value));
- rt->family_pattern = simple_pattern_create(rt->family_match, SIMPLE_PATTERN_EXACT);
- }
- else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
- health_parse_db_lookup(line, path, filename, value, &rt->group, &rt->after, &rt->before,
- &rt->update_every, &rt->options, &rt->dimensions);
- }
- else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
- if(!health_parse_duration(value, &rt->update_every))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' cannot parse duration: '%s'.",
- line, path, filename, rt->name, key, value);
- }
- else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
- char *e;
- rt->green = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rt->name, key, e);
- }
- }
- else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
- char *e;
- rt->red = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rt->name, key, e);
- }
- }
- else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rt->calculation = expression_parse(value, &failed_at, &error);
- if(!rt->calculation) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rt->warning = expression_parse(value, &failed_at, &error);
- if(!rt->warning) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rt->critical = expression_parse(value, &failed_at, &error);
- if(!rt->critical) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
- if(rt->exec) {
- if(strcmp(rt->exec, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->exec, value, value);
-
- freez(rt->exec);
- }
- rt->exec = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
- if(rt->recipient) {
- if(strcmp(rt->recipient, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->recipient, value, value);
-
- freez(rt->recipient);
- }
- rt->recipient = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
- if(rt->units) {
- if(strcmp(rt->units, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->units, value, value);
-
- freez(rt->units);
- }
- rt->units = tabs2spaces(strdupz(value));
- strip_quotes(rt->units);
- }
- else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
- if(rt->info) {
- if(strcmp(rt->info, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->info, value, value);
-
- freez(rt->info);
- }
- rt->info = tabs2spaces(strdupz(value));
- strip_quotes(rt->info);
- }
- else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
- health_parse_delay(line, path, filename, value, &rt->delay_up_duration, &rt->delay_down_duration, &rt->delay_max_duration, &rt->delay_multiplier);
- }
- else {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has unknown key '%s'.",
- line, path, filename, rt->name, key);
- }
- }
- else {
- error("Health configuration at line %zu of file '%s/%s' has unknown key '%s'. Expected either '" HEALTH_ALARM_KEY "' or '" HEALTH_TEMPLATE_KEY "'.",
- line, path, filename, key);
- }
- }
-
- if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
- rrdcalc_free(&localhost, rc);
-
- if(rt && !rrdcalctemplate_add_template_from_config(&localhost, rt))
- rrdcalctemplate_free(&localhost, rt);
-
- fclose(fp);
- return 1;
-}
-
-void health_readdir(const char *path) {
- size_t pathlen = strlen(path);
-
- debug(D_HEALTH, "Health configuration reading directory '%s'", path);
-
- DIR *dir = opendir(path);
- if (!dir) {
- error("Health configuration cannot open directory '%s'.", path);
- return;
- }
-
- struct dirent *de = NULL;
- while ((de = readdir(dir))) {
- size_t len = strlen(de->d_name);
-
- if(de->d_type == DT_DIR
- && (
- (de->d_name[0] == '.' && de->d_name[1] == '\0')
- || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
- )) {
- debug(D_HEALTH, "Ignoring directory '%s'", de->d_name);
- continue;
- }
-
- else if(de->d_type == DT_DIR) {
- char *s = mallocz(pathlen + strlen(de->d_name) + 2);
- strcpy(s, path);
- strcat(s, "/");
- strcat(s, de->d_name);
- health_readdir(s);
- freez(s);
- continue;
- }
-
- else if((de->d_type == DT_LNK || de->d_type == DT_REG || de->d_type == DT_UNKNOWN) &&
- len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
- health_readfile(path, de->d_name);
- }
-
- else debug(D_HEALTH, "Ignoring file '%s'", de->d_name);
- }
-
- closedir(dir);
-}
-
-static inline char *health_config_dir(void) {
- char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%s/health.d", config_get("global", "config directory", CONFIG_DIR));
- return config_get("health", "health configuration directory", buffer);
+ snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_config_dir);
+ return config_get(CONFIG_SECTION_HEALTH, "health configuration directory", buffer);
}
void health_init(void) {
debug(D_HEALTH, "Health configuration initializing");
- if(!(health_enabled = config_get_boolean("health", "enabled", 1))) {
+ if(!(default_health_enabled = config_get_boolean(CONFIG_SECTION_HEALTH, "enabled", 1))) {
debug(D_HEALTH, "Health is disabled.");
return;
}
-
- char *pathname = config_get("health", "health db directory", VARLIB_DIR "/health");
- if(mkdir(pathname, 0770) == -1 && errno != EEXIST)
- fatal("Cannot create directory '%s'.", pathname);
-
- char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/health-log.db", pathname);
- health.log_filename = config_get("health", "health db file", filename);
-
- health_alarm_log_load(&localhost);
- health_alarm_log_open();
-
- char *path = health_config_dir();
-
- {
- char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%s/alarm-notify.sh", config_get("global", "plugins directory", PLUGINS_DIR));
- health.health_default_exec = config_get("health", "script to execute on alarm", buffer);
- }
-
- long n = config_get_number("health", "in memory max health log entries", (long)localhost.health_log.max);
- if(n < 10) {
- error("Health configuration has invalid max log entries %ld. Using default %u", n, localhost.health_log.max);
- config_set_number("health", "in memory max health log entries", (long)localhost.health_log.max);
- }
- else localhost.health_log.max = (unsigned int)n;
-
- rrdhost_rwlock(&localhost);
- health_readdir(path);
- rrdhost_unlock(&localhost);
}
// ----------------------------------------------------------------------------
-// JSON generation
-
-static inline void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix) {
- if(value && *value)
- buffer_sprintf(wb, "%s\"%s\":\"%s\"%s", prefix, label, value, suffix);
- else
- buffer_sprintf(wb, "%s\"%s\":null%s", prefix, label, suffix);
-}
-
-static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host) {
- buffer_sprintf(wb, "\n\t{\n"
- "\t\t\"hostname\": \"%s\",\n"
- "\t\t\"unique_id\": %u,\n"
- "\t\t\"alarm_id\": %u,\n"
- "\t\t\"alarm_event_id\": %u,\n"
- "\t\t\"name\": \"%s\",\n"
- "\t\t\"chart\": \"%s\",\n"
- "\t\t\"family\": \"%s\",\n"
- "\t\t\"processed\": %s,\n"
- "\t\t\"updated\": %s,\n"
- "\t\t\"exec_run\": %lu,\n"
- "\t\t\"exec_failed\": %s,\n"
- "\t\t\"exec\": \"%s\",\n"
- "\t\t\"recipient\": \"%s\",\n"
- "\t\t\"exec_code\": %d,\n"
- "\t\t\"source\": \"%s\",\n"
- "\t\t\"units\": \"%s\",\n"
- "\t\t\"info\": \"%s\",\n"
- "\t\t\"when\": %lu,\n"
- "\t\t\"duration\": %lu,\n"
- "\t\t\"non_clear_duration\": %lu,\n"
- "\t\t\"status\": \"%s\",\n"
- "\t\t\"old_status\": \"%s\",\n"
- "\t\t\"delay\": %d,\n"
- "\t\t\"delay_up_to_timestamp\": %lu,\n"
- "\t\t\"updated_by_id\": %u,\n"
- "\t\t\"updates_id\": %u,\n",
- host->hostname,
- ae->unique_id,
- ae->alarm_id,
- ae->alarm_event_id,
- ae->name,
- ae->chart,
- ae->family,
- (ae->flags & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false",
- (ae->flags & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false",
- (unsigned long)ae->exec_run_timestamp,
- (ae->flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false",
- ae->exec?ae->exec:health.health_default_exec,
- ae->recipient?ae->recipient:health.health_default_recipient,
- ae->exec_code,
- ae->source,
- ae->units?ae->units:"",
- ae->info?ae->info:"",
- (unsigned long)ae->when,
- (unsigned long)ae->duration,
- (unsigned long)ae->non_clear_duration,
- rrdcalc_status2string(ae->new_status),
- rrdcalc_status2string(ae->old_status),
- ae->delay,
- (unsigned long)ae->delay_up_to_timestamp,
- ae->updated_by_id,
- ae->updates_id
- );
-
- buffer_strcat(wb, "\t\t\"value\":");
- buffer_rrd_value(wb, ae->new_value);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\t\"old_value\":");
- buffer_rrd_value(wb, ae->old_value);
- buffer_strcat(wb, "\n");
-
- buffer_strcat(wb, "\t}");
-}
-
-void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after) {
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
-
- buffer_strcat(wb, "[");
-
- unsigned int max = host->health_log.max;
- unsigned int count = 0;
- ALARM_ENTRY *ae;
- for(ae = host->health_log.alarms; ae && count < max ; count++, ae = ae->next) {
- if(ae->unique_id > after) {
- if(likely(count)) buffer_strcat(wb, ",");
- health_alarm_entry2json_nolock(wb, ae, host);
- }
- }
-
- buffer_strcat(wb, "\n]\n");
-
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-}
-
-static inline void health_rrdcalc2json_nolock(BUFFER *wb, RRDCALC *rc) {
- buffer_sprintf(wb,
- "\t\t\"%s.%s\": {\n"
- "\t\t\t\"id\": %lu,\n"
- "\t\t\t\"name\": \"%s\",\n"
- "\t\t\t\"chart\": \"%s\",\n"
- "\t\t\t\"family\": \"%s\",\n"
- "\t\t\t\"active\": %s,\n"
- "\t\t\t\"exec\": \"%s\",\n"
- "\t\t\t\"recipient\": \"%s\",\n"
- "\t\t\t\"source\": \"%s\",\n"
- "\t\t\t\"units\": \"%s\",\n"
- "\t\t\t\"info\": \"%s\",\n"
- "\t\t\t\"status\": \"%s\",\n"
- "\t\t\t\"last_status_change\": %lu,\n"
- "\t\t\t\"last_updated\": %lu,\n"
- "\t\t\t\"next_update\": %lu,\n"
- "\t\t\t\"update_every\": %d,\n"
- "\t\t\t\"delay_up_duration\": %d,\n"
- "\t\t\t\"delay_down_duration\": %d,\n"
- "\t\t\t\"delay_max_duration\": %d,\n"
- "\t\t\t\"delay_multiplier\": %f,\n"
- "\t\t\t\"delay\": %d,\n"
- "\t\t\t\"delay_up_to_timestamp\": %lu,\n"
- , rc->chart, rc->name
- , (unsigned long)rc->id
- , rc->name
- , rc->chart
- , (rc->rrdset && rc->rrdset->family)?rc->rrdset->family:""
- , (rc->rrdset)?"true":"false"
- , rc->exec?rc->exec:health.health_default_exec
- , rc->recipient?rc->recipient:health.health_default_recipient
- , rc->source
- , rc->units?rc->units:""
- , rc->info?rc->info:""
- , rrdcalc_status2string(rc->status)
- , (unsigned long)rc->last_status_change
- , (unsigned long)rc->last_updated
- , (unsigned long)rc->next_update
- , rc->update_every
- , rc->delay_up_duration
- , rc->delay_down_duration
- , rc->delay_max_duration
- , rc->delay_multiplier
- , rc->delay_last
- , (unsigned long)rc->delay_up_to_timestamp
- );
-
- if(RRDCALC_HAS_DB_LOOKUP(rc)) {
- if(rc->dimensions && *rc->dimensions)
- health_string2json(wb, "\t\t\t", "lookup_dimensions", rc->dimensions, ",\n");
-
- buffer_sprintf(wb,
- "\t\t\t\"db_after\": %lu,\n"
- "\t\t\t\"db_before\": %lu,\n"
- "\t\t\t\"lookup_method\": \"%s\",\n"
- "\t\t\t\"lookup_after\": %d,\n"
- "\t\t\t\"lookup_before\": %d,\n"
- "\t\t\t\"lookup_options\": \"",
- (unsigned long) rc->db_after,
- (unsigned long) rc->db_before,
- group_method2string(rc->group),
- rc->after,
- rc->before
- );
- buffer_data_options2string(wb, rc->options);
- buffer_strcat(wb, "\",\n");
- }
-
- if(rc->calculation) {
- health_string2json(wb, "\t\t\t", "calc", rc->calculation->source, ",\n");
- health_string2json(wb, "\t\t\t", "calc_parsed", rc->calculation->parsed_as, ",\n");
- }
-
- if(rc->warning) {
- health_string2json(wb, "\t\t\t", "warn", rc->warning->source, ",\n");
- health_string2json(wb, "\t\t\t", "warn_parsed", rc->warning->parsed_as, ",\n");
- }
-
- if(rc->critical) {
- health_string2json(wb, "\t\t\t", "crit", rc->critical->source, ",\n");
- health_string2json(wb, "\t\t\t", "crit_parsed", rc->critical->parsed_as, ",\n");
- }
-
- buffer_strcat(wb, "\t\t\t\"green\":");
- buffer_rrd_value(wb, rc->green);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\t\t\"red\":");
- buffer_rrd_value(wb, rc->red);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\t\t\"value\":");
- buffer_rrd_value(wb, rc->value);
- buffer_strcat(wb, "\n");
-
- buffer_strcat(wb, "\t\t}");
-}
-
-//void health_rrdcalctemplate2json_nolock(BUFFER *wb, RRDCALCTEMPLATE *rt) {
-//
-//}
-
-void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
- int i;
-
- rrdhost_rdlock(&localhost);
- buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
- "\n\t\"latest_alarm_log_unique_id\": %u,"
- "\n\t\"status\": %s,"
- "\n\t\"now\": %lu,"
- "\n\t\"alarms\": {\n",
- host->hostname,
- (host->health_log.next_log_id > 0)?(host->health_log.next_log_id - 1):0,
- health_enabled?"true":"false",
- (unsigned long)now_realtime_sec());
-
- RRDCALC *rc;
- for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
- if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
- continue;
-
- if(likely(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL)))
- continue;
-
- if(likely(i)) buffer_strcat(wb, ",\n");
- health_rrdcalc2json_nolock(wb, rc);
- i++;
- }
-
-// buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
-// RRDCALCTEMPLATE *rt;
-// for(rt = host->templates; rt ; rt = rt->next)
-// health_rrdcalctemplate2json_nolock(wb, rt);
+// re-load health configuration
- buffer_strcat(wb, "\n\t}\n}\n");
- rrdhost_unlock(&localhost);
-}
+void health_reload_host(RRDHOST *host) {
+ if(unlikely(!host->health_enabled))
+ return;
+ char *path = health_config_dir();
-// ----------------------------------------------------------------------------
-// re-load health configuration
+ // free all running alarms
+ rrdhost_wrlock(host);
-static inline void health_free_all_nolock(RRDHOST *host) {
while(host->templates)
rrdcalctemplate_free(host, host->templates);
while(host->alarms)
rrdcalc_free(host, host->alarms);
-}
-
-void health_reload(void) {
- if(!health_enabled) {
- error("Health reload is requested, but health is not enabled.");
- return;
- }
-
- char *path = health_config_dir();
- // free all running alarms
- rrdhost_rwlock(&localhost);
- health_free_all_nolock(&localhost);
- rrdhost_unlock(&localhost);
+ rrdhost_unlock(host);
// invalidate all previous entries in the alarm log
ALARM_ENTRY *t;
- for(t = localhost.health_log.alarms ; t ; t = t->next) {
+ for(t = host->health_log.alarms ; t ; t = t->next) {
if(t->new_status != RRDCALC_STATUS_REMOVED)
t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
}
+ rrdhost_rdlock(host);
// reset all thresholds to all charts
RRDSET *st;
- for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdset_foreach_read(st, host) {
st->green = NAN;
st->red = NAN;
}
+ rrdhost_unlock(host);
// load the new alarms
- rrdhost_rwlock(&localhost);
- health_readdir(path);
- rrdhost_unlock(&localhost);
+ rrdhost_wrlock(host);
+ health_readdir(host, path);
// link the loaded alarms to their charts
- for(st = localhost.rrdset_root; st ; st = st->next) {
- rrdhost_rwlock(&localhost);
-
+ rrdset_foreach_write(st, host) {
rrdsetcalc_link_matching(st);
rrdcalctemplate_link_matching(st);
-
- rrdhost_unlock(&localhost);
}
+
+ rrdhost_unlock(host);
+}
+
+void health_reload(void) {
+
+ rrd_rdlock();
+
+ RRDHOST *host;
+ rrdhost_foreach_read(host)
+ health_reload_host(host);
+
+ rrd_unlock();
}
// ----------------------------------------------------------------------------
@@ -2601,12 +97,21 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
if(unlikely(ae->new_status < RRDCALC_STATUS_CLEAR)) {
// do not send notifications for internal statuses
+ debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (internal statuses)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
+ goto done;
+ }
+
+ if(unlikely(ae->new_status <= RRDCALC_STATUS_CLEAR && (ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
+ // do not send notifications for disabled statuses
+ debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (it has no-clear-notification enabled)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
+ // mark it as run, so that we will send the same alarm if it happens again
goto done;
}
// find the previous notification for the same alarm
// which we have run the exec script
- {
+ // exception: alarms with HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION set
+ if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
uint32_t id = ae->alarm_id;
ALARM_ENTRY *t;
for(t = ae->next; t ; t = t->next) {
@@ -2637,13 +142,10 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
static char command_to_run[ALARM_EXEC_COMMAND_LENGTH + 1];
pid_t command_pid;
- const char *exec = ae->exec;
- if(!exec) exec = health.health_default_exec;
+ const char *exec = (ae->exec) ? ae->exec : host->health_default_exec;
+ const char *recipient = (ae->recipient) ? ae->recipient : host->health_default_recipient;
- const char *recipient = ae->recipient;
- if(!recipient) recipient = health.health_default_recipient;
-
- snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '%0.0Lf' '%0.0Lf' '%s' '%u' '%u' '%s' '%s'",
+ snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '%0.0Lf' '%0.0Lf' '%s' '%u' '%u' '%s' '%s' '%s' '%s'",
exec,
recipient,
host->hostname,
@@ -2662,7 +164,9 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
(uint32_t)ae->duration,
(uint32_t)ae->non_clear_duration,
ae->units?ae->units:"",
- ae->info?ae->info:""
+ ae->info?ae->info:"",
+ ae->new_value_string,
+ ae->old_value_string
);
ae->flags |= HEALTH_ENTRY_FLAG_EXEC_RUN;
@@ -2704,7 +208,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
uint32_t first_waiting = (host->health_log.alarms)?host->health_log.alarms->unique_id:0;
time_t now = now_realtime_sec();
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ 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) {
@@ -2724,13 +228,13 @@ static inline void health_alarm_log_process(RRDHOST *host) {
// remember this for the next iteration
stop_at_id = first_waiting;
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
if(host->health_log.count <= host->health_log.max)
return;
// cleanup excess entries in the log
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *last = NULL;
unsigned int count = host->health_log.max * 2 / 3;
@@ -2746,21 +250,13 @@ static inline void health_alarm_log_process(RRDHOST *host) {
ALARM_ENTRY *t = ae->next;
- freez(ae->name);
- freez(ae->chart);
- freez(ae->family);
- freez(ae->exec);
- freez(ae->recipient);
- freez(ae->source);
- freez(ae->units);
- freez(ae->info);
- freez(ae);
+ health_alarm_log_free_one_nochecks_nounlink(ae);
ae = t;
host->health_log.count--;
}
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
}
static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
@@ -2785,6 +281,16 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
return 0;
}
+ if(unlikely(rrdset_flag_check(rc->rrdset, RRDSET_FLAG_OBSOLETE))) {
+ debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as obsolete", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
+ if(unlikely(!rrdset_flag_check(rc->rrdset, RRDSET_FLAG_ENABLED))) {
+ debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart is not enabled", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
if(unlikely(!rc->rrdset->last_collected_time.tv_sec || rc->rrdset->counter_done < 2)) {
debug(D_HEALTH, "Health not running alarm '%s.%s'. Chart is not fully collected yet.", rc->chart?rc->chart:"NOCHART", rc->name);
return 0;
@@ -2828,299 +334,396 @@ void *health_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- int min_run_every = (int)config_get_number("health", "run at least every seconds", 10);
+ int min_run_every = (int)config_get_number(CONFIG_SECTION_HEALTH, "run at least every seconds", 10);
if(min_run_every < 1) min_run_every = 1;
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);
+
unsigned int loop = 0;
- while(health_enabled && !netdata_exit) {
+ while(!netdata_exit) {
loop++;
debug(D_HEALTH, "Health monitoring iteration no %u started", loop);
- int oldstate, runnable = 0;
- time_t now = now_realtime_sec();
+ int oldstate, runnable = 0, apply_hibernation_delay = 0;
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)))
+ apply_hibernation_delay = 1;
+
+ 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.");
- rrdhost_rdlock(&localhost);
+ rrd_rdlock();
- // the first loop is to lookup values from the db
- for(rc = localhost.alarms; rc; rc = rc->next) {
- if(unlikely(!rrdcalc_isrunnable(rc, now, &next_run))) {
- if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_RUNNABLE;
+ RRDHOST *host;
+ rrdhost_foreach_read(host) {
+ if(unlikely(!host->health_enabled))
continue;
- }
-
- runnable++;
- rc->old_value = rc->value;
- rc->rrdcalc_flags |= RRDCALC_FLAG_RUNNABLE;
- // 1. if there is database lookup, do it
- // 2. if there is calculation expression, run it
+ if(unlikely(apply_hibernation_delay)) {
- if (unlikely(RRDCALC_HAS_DB_LOOKUP(rc))) {
- /* time_t old_db_timestamp = rc->db_before; */
- int value_is_null = 0;
+ info("Postponing alarm checks for %ld seconds, on host '%s', due to boottime discrepancy (realtime dt: %ld, boottime dt: %ld)."
+ , hibernation_delay
+ , host->hostname
+ , (long)(now - last_now)
+ , (long)(now_boottime - last_now_boottime)
+ );
- int ret = rrd2value(rc->rrdset, wb, &rc->value,
- rc->dimensions, 1, rc->after, rc->before, rc->group,
- rc->options, &rc->db_after, &rc->db_before, &value_is_null);
+ host->health_delay_up_to = now + hibernation_delay;
+ }
- if (unlikely(ret != 200)) {
- // database lookup failed
- rc->value = NAN;
+ if(unlikely(!host->health_enabled || now < host->health_delay_up_to))
+ continue;
- debug(D_HEALTH, "Health alarm '%s.%s': database lookup returned error %d", rc->chart?rc->chart:"NOCHART", rc->name, ret);
+ rrdhost_rdlock(host);
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_ERROR))) {
- rc->rrdcalc_flags |= RRDCALC_FLAG_DB_ERROR;
- error("Health alarm '%s.%s': database lookup returned error %d", rc->chart?rc->chart:"NOCHART", rc->name, ret);
- }
+ // the first loop is to lookup values from the db
+ for(rc = host->alarms; rc; rc = rc->next) {
+ if(unlikely(!rrdcalc_isrunnable(rc, now, &next_run))) {
+ if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE))
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_RUNNABLE;
+ continue;
}
- else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_ERROR))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_ERROR;
- /* - RRDCALC_FLAG_DB_STALE not currently used
- if (unlikely(old_db_timestamp == rc->db_before)) {
- // database is stale
+ runnable++;
+ rc->old_value = rc->value;
+ rc->rrdcalc_flags |= RRDCALC_FLAG_RUNNABLE;
+
+ // ------------------------------------------------------------
+ // if there is database lookup, do it
+
+ if(unlikely(RRDCALC_HAS_DB_LOOKUP(rc))) {
+ /* time_t old_db_timestamp = rc->db_before; */
+ int value_is_null = 0;
+
+ int ret = rrdset2value_api_v1(rc->rrdset
+ , wb
+ , &rc->value
+ , rc->dimensions
+ , 1
+ , rc->after
+ , rc->before
+ , rc->group
+ , rc->options
+ , &rc->db_after
+ , &rc->db_before
+ , &value_is_null
+ );
- debug(D_HEALTH, "Health alarm '%s.%s': database is stale", rc->chart?rc->chart:"NOCHART", rc->name);
+ if(unlikely(ret != 200)) {
+ // database lookup failed
+ rc->value = NAN;
+ rc->rrdcalc_flags |= RRDCALC_FLAG_DB_ERROR;
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))) {
- rc->rrdcalc_flags |= RRDCALC_FLAG_DB_STALE;
- error("Health alarm '%s.%s': database is stale", rc->chart?rc->chart:"NOCHART", rc->name);
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': database lookup returned error %d"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , ret
+ );
}
- }
- else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_STALE;
- */
+ else
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_ERROR;
- if (unlikely(value_is_null)) {
- // collected value is null
+ /* - RRDCALC_FLAG_DB_STALE not currently used
+ if (unlikely(old_db_timestamp == rc->db_before)) {
+ // database is stale
- rc->value = NAN;
+ debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database is stale", host->hostname, rc->chart?rc->chart:"NOCHART", rc->name);
- debug(D_HEALTH, "Health alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
- rc->chart?rc->chart:"NOCHART", rc->name);
+ if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))) {
+ rc->rrdcalc_flags |= RRDCALC_FLAG_DB_STALE;
+ error("Health on host '%s', alarm '%s.%s': database is stale", host->hostname, rc->chart?rc->chart:"NOCHART", rc->name);
+ }
+ }
+ else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_STALE;
+ */
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_NAN))) {
+ if(unlikely(value_is_null)) {
+ // collected value is null
+ rc->value = NAN;
rc->rrdcalc_flags |= RRDCALC_FLAG_DB_NAN;
- error("Health alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
- rc->chart?rc->chart:"NOCHART", rc->name);
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ );
}
+ else
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_NAN;
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': database lookup gave value " CALCULATED_NUMBER_FORMAT
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->value
+ );
}
- else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_NAN))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_NAN;
-
- debug(D_HEALTH, "Health alarm '%s.%s': database lookup gave value "
- CALCULATED_NUMBER_FORMAT, rc->chart?rc->chart:"NOCHART", rc->name, rc->value);
- }
- if(unlikely(rc->calculation)) {
- if (unlikely(!expression_evaluate(rc->calculation))) {
- // calculation failed
+ // ------------------------------------------------------------
+ // if there is calculation expression, run it
- rc->value = NAN;
-
- debug(D_HEALTH, "Health alarm '%s.%s': expression '%s' failed: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, rc->calculation->parsed_as, buffer_tostring(rc->calculation->error_msg));
-
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_CALC_ERROR))) {
+ if(unlikely(rc->calculation)) {
+ if(unlikely(!expression_evaluate(rc->calculation))) {
+ // calculation failed
+ rc->value = NAN;
rc->rrdcalc_flags |= RRDCALC_FLAG_CALC_ERROR;
- error("Health alarm '%s.%s': expression '%s' failed: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, rc->calculation->parsed_as, buffer_tostring(rc->calculation->error_msg));
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': expression '%s' failed: %s"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->calculation->parsed_as
+ , buffer_tostring(rc->calculation->error_msg)
+ );
}
- }
- else {
- if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_CALC_ERROR))
+ else {
rc->rrdcalc_flags &= ~RRDCALC_FLAG_CALC_ERROR;
- debug(D_HEALTH, "Health alarm '%s.%s': expression '%s' gave value "
- CALCULATED_NUMBER_FORMAT
- ": %s (source: %s)",
- rc->chart?rc->chart:"NOCHART", rc->name,
- rc->calculation->parsed_as,
- rc->calculation->result,
- buffer_tostring(rc->calculation->error_msg),
- rc->source
- );
+ debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': expression '%s' gave value " CALCULATED_NUMBER_FORMAT ": %s (source: %s)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->calculation->parsed_as
+ , rc->calculation->result
+ , buffer_tostring(rc->calculation->error_msg)
+ , rc->source
+ );
- rc->value = rc->calculation->result;
+ rc->value = rc->calculation->result;
+ }
}
}
- }
- rrdhost_unlock(&localhost);
+ rrdhost_unlock(host);
- if(unlikely(runnable && !netdata_exit)) {
- rrdhost_rdlock(&localhost);
+ if(unlikely(runnable && !netdata_exit)) {
+ rrdhost_rdlock(host);
- for(rc = localhost.alarms; rc; rc = rc->next) {
- if(unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE)))
- continue;
+ for(rc = host->alarms; rc; rc = rc->next) {
+ if(unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE)))
+ continue;
- int warning_status = RRDCALC_STATUS_UNDEFINED;
- int critical_status = RRDCALC_STATUS_UNDEFINED;
+ int warning_status = RRDCALC_STATUS_UNDEFINED;
+ int critical_status = RRDCALC_STATUS_UNDEFINED;
- if(likely(rc->warning)) {
- if(unlikely(!expression_evaluate(rc->warning))) {
- // calculation failed
+ // --------------------------------------------------------
+ // check the warning expression
- debug(D_HEALTH, "Health alarm '%s.%s': warning expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->warning->error_msg));
-
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_WARN_ERROR))) {
+ if(likely(rc->warning)) {
+ if(unlikely(!expression_evaluate(rc->warning))) {
+ // calculation failed
rc->rrdcalc_flags |= RRDCALC_FLAG_WARN_ERROR;
- error("Health alarm '%s.%s': warning expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->warning->error_msg));
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': warning expression failed with error: %s"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , buffer_tostring(rc->warning->error_msg)
+ );
}
- }
- else {
- if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_WARN_ERROR))
+ else {
rc->rrdcalc_flags &= ~RRDCALC_FLAG_WARN_ERROR;
-
- debug(D_HEALTH, "Health alarm '%s.%s': warning expression gave value "
- CALCULATED_NUMBER_FORMAT
- ": %s (source: %s)",
- rc->chart?rc->chart:"NOCHART", rc->name,
- rc->warning->result,
- buffer_tostring(rc->warning->error_msg),
- rc->source
- );
-
- warning_status = rrdcalc_value2status(rc->warning->result);
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': warning expression gave value " CALCULATED_NUMBER_FORMAT ": %s (source: %s)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->warning->result
+ , buffer_tostring(rc->warning->error_msg)
+ , rc->source
+ );
+ warning_status = rrdcalc_value2status(rc->warning->result);
+ }
}
- }
- if(likely(rc->critical)) {
- if(unlikely(!expression_evaluate(rc->critical))) {
- // calculation failed
+ // --------------------------------------------------------
+ // check the critical expression
- debug(D_HEALTH, "Health alarm '%s.%s': critical expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->critical->error_msg));
-
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_CRIT_ERROR))) {
+ if(likely(rc->critical)) {
+ if(unlikely(!expression_evaluate(rc->critical))) {
+ // calculation failed
rc->rrdcalc_flags |= RRDCALC_FLAG_CRIT_ERROR;
- error("Health alarm '%s.%s': critical expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->critical->error_msg));
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': critical expression failed with error: %s"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , buffer_tostring(rc->critical->error_msg)
+ );
}
- }
- else {
- if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_CRIT_ERROR))
+ else {
rc->rrdcalc_flags &= ~RRDCALC_FLAG_CRIT_ERROR;
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': critical expression gave value " CALCULATED_NUMBER_FORMAT ": %s (source: %s)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->critical->result
+ , buffer_tostring(rc->critical->error_msg)
+ , rc->source
+ );
+ critical_status = rrdcalc_value2status(rc->critical->result);
+ }
+ }
- debug(D_HEALTH, "Health alarm '%s.%s': critical expression gave value "
- CALCULATED_NUMBER_FORMAT
- ": %s (source: %s)",
- rc->chart?rc->chart:"NOCHART", rc->name,
- rc->critical->result,
- buffer_tostring(rc->critical->error_msg),
- rc->source
- );
+ // --------------------------------------------------------
+ // decide the final alarm status
- critical_status = rrdcalc_value2status(rc->critical->result);
+ int status = RRDCALC_STATUS_UNDEFINED;
+
+ switch(warning_status) {
+ case RRDCALC_STATUS_CLEAR:
+ status = RRDCALC_STATUS_CLEAR;
+ break;
+
+ case RRDCALC_STATUS_RAISED:
+ status = RRDCALC_STATUS_WARNING;
+ break;
+
+ default:
+ break;
}
- }
- int status = RRDCALC_STATUS_UNDEFINED;
+ switch(critical_status) {
+ case RRDCALC_STATUS_CLEAR:
+ if(status == RRDCALC_STATUS_UNDEFINED)
+ status = RRDCALC_STATUS_CLEAR;
+ break;
- switch(warning_status) {
- case RRDCALC_STATUS_CLEAR:
- status = RRDCALC_STATUS_CLEAR;
- break;
+ case RRDCALC_STATUS_RAISED:
+ status = RRDCALC_STATUS_CRITICAL;
+ break;
- case RRDCALC_STATUS_RAISED:
- status = RRDCALC_STATUS_WARNING;
- break;
+ default:
+ break;
+ }
- default:
- break;
- }
+ // --------------------------------------------------------
+ // check if the new status and the old differ
- switch(critical_status) {
- case RRDCALC_STATUS_CLEAR:
- if(status == RRDCALC_STATUS_UNDEFINED)
- status = RRDCALC_STATUS_CLEAR;
- break;
+ if(status != rc->status) {
+ int delay = 0;
- case RRDCALC_STATUS_RAISED:
- status = RRDCALC_STATUS_CRITICAL;
- break;
+ // apply trigger hysteresis
- default:
- break;
- }
+ if(now > rc->delay_up_to_timestamp) {
+ rc->delay_up_current = rc->delay_up_duration;
+ rc->delay_down_current = rc->delay_down_duration;
+ rc->delay_last = 0;
+ rc->delay_up_to_timestamp = 0;
+ }
+ else {
+ rc->delay_up_current = (int) (rc->delay_up_current * rc->delay_multiplier);
+ if(rc->delay_up_current > rc->delay_max_duration)
+ rc->delay_up_current = rc->delay_max_duration;
+
+ rc->delay_down_current = (int) (rc->delay_down_current * rc->delay_multiplier);
+ if(rc->delay_down_current > rc->delay_max_duration)
+ rc->delay_down_current = rc->delay_max_duration;
+ }
- if(status != rc->status) {
- int delay = 0;
+ if(status > rc->status)
+ delay = rc->delay_up_current;
+ else
+ delay = rc->delay_down_current;
+
+ // COMMENTED: because we do need to send raising alarms
+ // if(now + delay < rc->delay_up_to_timestamp)
+ // delay = (int)(rc->delay_up_to_timestamp - now);
+
+ rc->delay_last = delay;
+ rc->delay_up_to_timestamp = now + delay;
+
+ // add the alarm into the log
+
+ health_alarm_log(
+ host
+ , rc->id
+ , rc->next_event_id++
+ , now
+ , rc->name
+ , rc->rrdset->id
+ , rc->rrdset->family
+ , rc->exec
+ , rc->recipient
+ , now - rc->last_status_change
+ , rc->old_value
+ , rc->value
+ , rc->status
+ , status
+ , rc->source
+ , rc->units
+ , rc->info
+ , rc->delay_last
+ , (rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION) ? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0
+ );
- if(now > rc->delay_up_to_timestamp) {
- rc->delay_up_current = rc->delay_up_duration;
- rc->delay_down_current = rc->delay_down_duration;
- rc->delay_last = 0;
- rc->delay_up_to_timestamp = 0;
+ rc->last_status_change = now;
+ rc->status = status;
}
- else {
- rc->delay_up_current = (int)(rc->delay_up_current * rc->delay_multiplier);
- if(rc->delay_up_current > rc->delay_max_duration) rc->delay_up_current = rc->delay_max_duration;
- rc->delay_down_current = (int)(rc->delay_down_current * rc->delay_multiplier);
- if(rc->delay_down_current > rc->delay_max_duration) rc->delay_down_current = rc->delay_max_duration;
- }
+ rc->last_updated = now;
+ rc->next_update = now + rc->update_every;
- if(status > rc->status)
- delay = rc->delay_up_current;
- else
- delay = rc->delay_down_current;
+ if(next_run > rc->next_update)
+ next_run = rc->next_update;
+ }
- // COMMENTED: because we do need to send raising alarms
- // if(now + delay < rc->delay_up_to_timestamp)
- // delay = (int)(rc->delay_up_to_timestamp - now);
+ rrdhost_unlock(host);
+ }
- rc->delay_last = delay;
- rc->delay_up_to_timestamp = now + delay;
- health_alarm_log(&localhost, rc->id, rc->next_event_id++, now, rc->name, rc->rrdset->id, rc->rrdset->family, rc->exec, rc->recipient, now - rc->last_status_change, rc->old_value, rc->value, rc->status, status, rc->source, rc->units, rc->info, rc->delay_last);
- rc->last_status_change = now;
- rc->status = status;
- }
+ if(unlikely(netdata_exit))
+ break;
- rc->last_updated = now;
- rc->next_update = now + rc->update_every;
+ // execute notifications
+ // and cleanup
+ health_alarm_log_process(host);
- if (next_run > rc->next_update)
- next_run = rc->next_update;
- }
+ if(unlikely(netdata_exit))
+ break;
- rrdhost_unlock(&localhost);
- }
+ } /* rrdhost_foreach */
+
+ rrd_unlock();
- if (unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
+ if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);
if(unlikely(netdata_exit))
break;
- // execute notifications
- // and cleanup
- health_alarm_log_process(&localhost);
-
- if(unlikely(netdata_exit))
- break;
-
now = now_realtime_sec();
if(now < next_run) {
- debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration in %d secs",
- loop, (int) (next_run - now));
+ debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration in %d secs", loop, (int) (next_run - now));
sleep_usec(USEC_PER_SEC * (usec_t) (next_run - now));
+ now = now_realtime_sec();
}
- else {
+ 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.h b/src/health.h
index 79831d4fc..7028a914b 100644
--- a/src/health.h
+++ b/src/health.h
@@ -1,7 +1,7 @@
#ifndef NETDATA_HEALTH_H
#define NETDATA_HEALTH_H
-extern int health_enabled;
+extern int default_health_enabled;
extern int rrdvar_compare(void *a, void *b);
@@ -119,13 +119,14 @@ typedef struct rrddimvar {
#define RRDCALC_STATUS_WARNING 3
#define RRDCALC_STATUS_CRITICAL 4
-#define RRDCALC_FLAG_DB_ERROR 0x00000001
-#define RRDCALC_FLAG_DB_NAN 0x00000002
-/* #define RRDCALC_FLAG_DB_STALE 0x00000004 */
-#define RRDCALC_FLAG_CALC_ERROR 0x00000008
-#define RRDCALC_FLAG_WARN_ERROR 0x00000010
-#define RRDCALC_FLAG_CRIT_ERROR 0x00000020
-#define RRDCALC_FLAG_RUNNABLE 0x00000040
+#define RRDCALC_FLAG_DB_ERROR 0x00000001
+#define RRDCALC_FLAG_DB_NAN 0x00000002
+/* #define RRDCALC_FLAG_DB_STALE 0x00000004 */
+#define RRDCALC_FLAG_CALC_ERROR 0x00000008
+#define RRDCALC_FLAG_WARN_ERROR 0x00000010
+#define RRDCALC_FLAG_CRIT_ERROR 0x00000020
+#define RRDCALC_FLAG_RUNNABLE 0x00000040
+#define RRDCALC_FLAG_NO_CLEAR_NOTIFICATION 0x80000000
typedef struct rrdcalc {
uint32_t id; // the unique id of this alarm
@@ -274,11 +275,12 @@ typedef struct rrdcalctemplate {
#define RRDCALCTEMPLATE_HAS_CALCULATION(rt) ((rt)->after)
-#define HEALTH_ENTRY_FLAG_PROCESSED 0x00000001
-#define HEALTH_ENTRY_FLAG_UPDATED 0x00000002
-#define HEALTH_ENTRY_FLAG_EXEC_RUN 0x00000004
-#define HEALTH_ENTRY_FLAG_EXEC_FAILED 0x00000008
-#define HEALTH_ENTRY_FLAG_SAVED 0x10000000
+#define HEALTH_ENTRY_FLAG_PROCESSED 0x00000001
+#define HEALTH_ENTRY_FLAG_UPDATED 0x00000002
+#define HEALTH_ENTRY_FLAG_EXEC_RUN 0x00000004
+#define HEALTH_ENTRY_FLAG_EXEC_FAILED 0x00000008
+#define HEALTH_ENTRY_FLAG_SAVED 0x10000000
+#define HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION 0x80000000
typedef struct alarm_entry {
uint32_t unique_id;
@@ -308,6 +310,10 @@ typedef struct alarm_entry {
calculated_number old_value;
calculated_number new_value;
+
+ char *old_value_string;
+ char *new_value_string;
+
int old_status;
int new_status;
@@ -328,7 +334,7 @@ typedef struct alarm_log {
unsigned int count;
unsigned int max;
ALARM_ENTRY *alarms;
- pthread_rwlock_t alarm_log_rwlock;
+ netdata_rwlock_t alarm_log_rwlock;
} ALARM_LOG;
#include "rrd.h"
@@ -363,4 +369,58 @@ extern void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value)
extern const char *rrdcalc_status2string(int status);
+
+extern int health_alarm_log_open(RRDHOST *host);
+extern void health_alarm_log_close(RRDHOST *host);
+extern void health_log_rotate(RRDHOST *host);
+extern void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae);
+extern ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename);
+extern void health_alarm_log_load(RRDHOST *host);
+extern void health_alarm_log(
+ RRDHOST *host,
+ uint32_t alarm_id,
+ uint32_t alarm_event_id,
+ time_t when,
+ const char *name,
+ const char *chart,
+ const char *family,
+ const char *exec,
+ const char *recipient,
+ time_t duration,
+ calculated_number old_value,
+ calculated_number new_value,
+ int old_status,
+ int new_status,
+ const char *source,
+ const char *units,
+ const char *info,
+ int delay,
+ uint32_t flags
+);
+
+extern void health_readdir(RRDHOST *host, const char *path);
+extern char *health_config_dir(void);
+extern void health_reload_host(RRDHOST *host);
+extern void health_alarm_log_free(RRDHOST *host);
+
+extern void rrdcalc_free(RRDHOST *host, RRDCALC *rc);
+extern void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt);
+
+#ifdef NETDATA_HEALTH_INTERNALS
+#define RRDVAR_MAX_LENGTH 1024
+
+extern int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name);
+extern uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id);
+extern int rrdvar_fix_name(char *variable);
+
+extern RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart);
+extern void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc);
+
+extern RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value);
+extern void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv);
+
+extern void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae);
+
+#endif // NETDATA_HEALTH_INTERNALS
+
#endif //NETDATA_HEALTH_H
diff --git a/src/health_config.c b/src/health_config.c
new file mode 100644
index 000000000..ad954cbe1
--- /dev/null
+++ b/src/health_config.c
@@ -0,0 +1,877 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+#define HEALTH_CONF_MAX_LINE 4096
+
+#define HEALTH_ALARM_KEY "alarm"
+#define HEALTH_TEMPLATE_KEY "template"
+#define HEALTH_ON_KEY "on"
+#define HEALTH_FAMILIES_KEY "families"
+#define HEALTH_LOOKUP_KEY "lookup"
+#define HEALTH_CALC_KEY "calc"
+#define HEALTH_EVERY_KEY "every"
+#define HEALTH_GREEN_KEY "green"
+#define HEALTH_RED_KEY "red"
+#define HEALTH_WARN_KEY "warn"
+#define HEALTH_CRIT_KEY "crit"
+#define HEALTH_EXEC_KEY "exec"
+#define HEALTH_RECIPIENT_KEY "to"
+#define HEALTH_UNITS_KEY "units"
+#define HEALTH_INFO_KEY "info"
+#define HEALTH_DELAY_KEY "delay"
+#define HEALTH_OPTIONS_KEY "options"
+
+static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
+ if(!rc->chart) {
+ error("Health configuration for alarm '%s' does not have a chart", rc->name);
+ return 0;
+ }
+
+ if(!rc->update_every) {
+ error("Health configuration for alarm '%s.%s' has no frequency (parameter 'every'). Ignoring it.", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
+ if(!RRDCALC_HAS_DB_LOOKUP(rc) && !rc->warning && !rc->critical) {
+ error("Health configuration for alarm '%s.%s' is useless (no calculation, no warning and no critical evaluation)", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
+ if (rrdcalc_exists(host, rc->chart, rc->name, rc->hash_chart, rc->hash))
+ return 0;
+
+ rc->id = rrdcalc_get_unique_id(host, rc->chart, rc->name, &rc->next_event_id);
+
+ debug(D_HEALTH, "Health configuration adding alarm '%s.%s' (%u): exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
+ rc->chart?rc->chart:"NOCHART",
+ rc->name,
+ rc->id,
+ (rc->exec)?rc->exec:"DEFAULT",
+ (rc->recipient)?rc->recipient:"DEFAULT",
+ rc->green,
+ rc->red,
+ rc->group,
+ rc->after,
+ rc->before,
+ rc->options,
+ (rc->dimensions)?rc->dimensions:"NONE",
+ rc->update_every,
+ (rc->calculation)?rc->calculation->parsed_as:"NONE",
+ (rc->warning)?rc->warning->parsed_as:"NONE",
+ (rc->critical)?rc->critical->parsed_as:"NONE",
+ rc->source,
+ rc->delay_up_duration,
+ rc->delay_down_duration,
+ rc->delay_max_duration,
+ rc->delay_multiplier
+ );
+
+ rrdcalc_create_part2(host, rc);
+ return 1;
+}
+
+static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCALCTEMPLATE *rt) {
+ if(unlikely(!rt->context)) {
+ error("Health configuration for template '%s' does not have a context", rt->name);
+ return 0;
+ }
+
+ if(unlikely(!rt->update_every)) {
+ error("Health configuration for template '%s' has no frequency (parameter 'every'). Ignoring it.", rt->name);
+ return 0;
+ }
+
+ if(unlikely(!RRDCALCTEMPLATE_HAS_CALCULATION(rt) && !rt->warning && !rt->critical)) {
+ error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
+ return 0;
+ }
+
+ 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))) {
+ error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
+ return 0;
+ }
+ }
+
+ debug(D_HEALTH, "Health configuration adding template '%s': context '%s', exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
+ rt->name,
+ (rt->context)?rt->context:"NONE",
+ (rt->exec)?rt->exec:"DEFAULT",
+ (rt->recipient)?rt->recipient:"DEFAULT",
+ rt->green,
+ rt->red,
+ rt->group,
+ rt->after,
+ rt->before,
+ rt->options,
+ (rt->dimensions)?rt->dimensions:"NONE",
+ rt->update_every,
+ (rt->calculation)?rt->calculation->parsed_as:"NONE",
+ (rt->warning)?rt->warning->parsed_as:"NONE",
+ (rt->critical)?rt->critical->parsed_as:"NONE",
+ rt->source,
+ rt->delay_up_duration,
+ rt->delay_down_duration,
+ rt->delay_max_duration,
+ rt->delay_multiplier
+ );
+
+ if(likely(last)) {
+ last->next = rt;
+ }
+ else {
+ rt->next = host->templates;
+ host->templates = rt;
+ }
+
+ return 1;
+}
+
+static inline int health_parse_duration(char *string, int *result) {
+ // make sure it is a number
+ if(!*string || !(isdigit(*string) || *string == '+' || *string == '-')) {
+ *result = 0;
+ return 0;
+ }
+
+ char *e = NULL;
+ calculated_number n = strtold(string, &e);
+ if(e && *e) {
+ switch (*e) {
+ case 'Y':
+ *result = (int) (n * 86400 * 365);
+ break;
+ case 'M':
+ *result = (int) (n * 86400 * 30);
+ break;
+ case 'w':
+ *result = (int) (n * 86400 * 7);
+ break;
+ case 'd':
+ *result = (int) (n * 86400);
+ break;
+ case 'h':
+ *result = (int) (n * 3600);
+ break;
+ case 'm':
+ *result = (int) (n * 60);
+ break;
+
+ default:
+ case 's':
+ *result = (int) (n);
+ break;
+ }
+ }
+ else
+ *result = (int)(n);
+
+ return 1;
+}
+
+static inline int health_parse_delay(
+ size_t line, const char *path, const char *file, char *string,
+ int *delay_up_duration,
+ int *delay_down_duration,
+ int *delay_max_duration,
+ float *delay_multiplier) {
+
+ char given_up = 0;
+ char given_down = 0;
+ char given_max = 0;
+ char given_multiplier = 0;
+
+ char *s = string;
+ while(*s) {
+ char *key = s;
+
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if(!*key) break;
+
+ char *value = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if(!strcasecmp(key, "up")) {
+ if (!health_parse_duration(value, delay_up_duration)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_up = 1;
+ }
+ else if(!strcasecmp(key, "down")) {
+ if (!health_parse_duration(value, delay_down_duration)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_down = 1;
+ }
+ else if(!strcasecmp(key, "multiplier")) {
+ *delay_multiplier = strtof(value, NULL);
+ if(isnan(*delay_multiplier) || isinf(*delay_multiplier) || islessequal(*delay_multiplier, 0)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_multiplier = 1;
+ }
+ else if(!strcasecmp(key, "max")) {
+ if (!health_parse_duration(value, delay_max_duration)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_max = 1;
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
+ line, path, file, key);
+ }
+ }
+
+ if(!given_up)
+ *delay_up_duration = 0;
+
+ if(!given_down)
+ *delay_down_duration = 0;
+
+ if(!given_multiplier)
+ *delay_multiplier = 1.0;
+
+ if(!given_max) {
+ if((*delay_max_duration) < (*delay_up_duration) * (*delay_multiplier))
+ *delay_max_duration = (*delay_up_duration) * (*delay_multiplier);
+
+ if((*delay_max_duration) < (*delay_down_duration) * (*delay_multiplier))
+ *delay_max_duration = (*delay_down_duration) * (*delay_multiplier);
+ }
+
+ return 1;
+}
+
+static inline uint32_t health_parse_options(const char *s) {
+ uint32_t options = 0;
+ char buf[100+1] = "";
+
+ while(*s) {
+ buf[0] = '\0';
+
+ // skip spaces
+ while(*s && isspace(*s))
+ s++;
+
+ // find the next space
+ size_t count = 0;
+ while(*s && count < 100 && !isspace(*s))
+ buf[count++] = *s++;
+
+ if(buf[0]) {
+ buf[count] = '\0';
+
+ if(!strcasecmp(buf, "no-clear-notification") || !strcasecmp(buf, "no-clear"))
+ options |= RRDCALC_FLAG_NO_CLEAR_NOTIFICATION;
+ else
+ error("Ignoring unknown alarm option '%s'", buf);
+ }
+ }
+
+ return options;
+}
+
+static inline int health_parse_db_lookup(
+ size_t line, const char *path, const char *file, char *string,
+ int *group_method, int *after, int *before, int *every,
+ uint32_t *options, char **dimensions
+) {
+ debug(D_HEALTH, "Health configuration parsing database lookup %zu@%s/%s: %s", line, path, file, string);
+
+ if(*dimensions) freez(*dimensions);
+ *dimensions = NULL;
+ *after = 0;
+ *before = 0;
+ *every = 0;
+ *options = 0;
+
+ char *s = string, *key;
+
+ // first is the group method
+ key = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+ if(!*s) {
+ error("Health configuration invalid chart calculation at line %zu of file '%s/%s': expected group method followed by the 'after' time, but got '%s'",
+ line, path, file, key);
+ return 0;
+ }
+
+ if((*group_method = web_client_api_request_v1_data_group(key, -1)) == -1) {
+ error("Health configuration at line %zu of file '%s/%s': invalid group method '%s'",
+ line, path, file, key);
+ return 0;
+ }
+
+ // then is the 'after' time
+ key = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if(!health_parse_duration(key, after)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' after group method",
+ line, path, file, key);
+ return 0;
+ }
+
+ // sane defaults
+ *every = abs(*after);
+
+ // now we may have optional parameters
+ while(*s) {
+ key = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+ if(!*key) break;
+
+ if(!strcasecmp(key, "at")) {
+ char *value = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if (!health_parse_duration(value, before)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ }
+ else if(!strcasecmp(key, HEALTH_EVERY_KEY)) {
+ char *value = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if (!health_parse_duration(value, every)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ }
+ else if(!strcasecmp(key, "absolute") || !strcasecmp(key, "abs") || !strcasecmp(key, "absolute_sum")) {
+ *options |= RRDR_OPTION_ABSOLUTE;
+ }
+ else if(!strcasecmp(key, "min2max")) {
+ *options |= RRDR_OPTION_MIN2MAX;
+ }
+ else if(!strcasecmp(key, "null2zero")) {
+ *options |= RRDR_OPTION_NULL2ZERO;
+ }
+ else if(!strcasecmp(key, "percentage")) {
+ *options |= RRDR_OPTION_PERCENTAGE;
+ }
+ else if(!strcasecmp(key, "unaligned")) {
+ *options |= RRDR_OPTION_NOT_ALIGNED;
+ }
+ else if(!strcasecmp(key, "of")) {
+ if(*s && strcasecmp(s, "all"))
+ *dimensions = strdupz(s);
+ break;
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
+ line, path, file, key);
+ }
+ }
+
+ return 1;
+}
+
+static inline char *trim_all_spaces(char *buffer) {
+ char *d = buffer, *s = buffer;
+
+ // skip spaces
+ while(isspace(*s)) s++;
+
+ while(*s) {
+ // copy the non-space part
+ while(*s && !isspace(*s)) *d++ = *s++;
+
+ // add a space if we have to
+ if(*s && isspace(*s)) {
+ *d++ = ' ';
+ s++;
+ }
+
+ // skip spaces
+ while(isspace(*s)) s++;
+ }
+
+ *d = '\0';
+
+ if(d > buffer) {
+ d--;
+ if(isspace(*d)) *d = '\0';
+ }
+
+ if(!buffer[0]) return NULL;
+ return buffer;
+}
+
+static inline char *health_source_file(size_t line, const char *path, const char *filename) {
+ char buffer[FILENAME_MAX + 1];
+ snprintfz(buffer, FILENAME_MAX, "%zu@%s/%s", line, path, filename);
+ return strdupz(buffer);
+}
+
+static inline void strip_quotes(char *s) {
+ while(*s) {
+ if(*s == '\'' || *s == '"') *s = ' ';
+ s++;
+ }
+}
+
+int health_readfile(RRDHOST *host, const char *path, const char *filename) {
+ debug(D_HEALTH, "Health configuration reading file '%s/%s'", path, filename);
+
+ static uint32_t
+ hash_alarm = 0,
+ hash_template = 0,
+ hash_on = 0,
+ hash_families = 0,
+ hash_calc = 0,
+ hash_green = 0,
+ hash_red = 0,
+ hash_warn = 0,
+ hash_crit = 0,
+ hash_exec = 0,
+ hash_every = 0,
+ hash_lookup = 0,
+ hash_units = 0,
+ hash_info = 0,
+ hash_recipient = 0,
+ hash_delay = 0,
+ hash_options = 0;
+
+ char buffer[HEALTH_CONF_MAX_LINE + 1];
+
+ if(unlikely(!hash_alarm)) {
+ hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
+ hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
+ hash_on = simple_uhash(HEALTH_ON_KEY);
+ hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
+ hash_calc = simple_uhash(HEALTH_CALC_KEY);
+ hash_lookup = simple_uhash(HEALTH_LOOKUP_KEY);
+ hash_green = simple_uhash(HEALTH_GREEN_KEY);
+ hash_red = simple_uhash(HEALTH_RED_KEY);
+ hash_warn = simple_uhash(HEALTH_WARN_KEY);
+ hash_crit = simple_uhash(HEALTH_CRIT_KEY);
+ hash_exec = simple_uhash(HEALTH_EXEC_KEY);
+ hash_every = simple_uhash(HEALTH_EVERY_KEY);
+ hash_units = simple_hash(HEALTH_UNITS_KEY);
+ hash_info = simple_hash(HEALTH_INFO_KEY);
+ hash_recipient = simple_hash(HEALTH_RECIPIENT_KEY);
+ hash_delay = simple_uhash(HEALTH_DELAY_KEY);
+ hash_options = simple_uhash(HEALTH_OPTIONS_KEY);
+ }
+
+ snprintfz(buffer, HEALTH_CONF_MAX_LINE, "%s/%s", path, filename);
+ FILE *fp = fopen(buffer, "r");
+ if(!fp) {
+ error("Health configuration cannot read file '%s'.", buffer);
+ return 0;
+ }
+
+ RRDCALC *rc = NULL;
+ RRDCALCTEMPLATE *rt = NULL;
+
+ size_t line = 0, append = 0;
+ char *s;
+ while((s = fgets(&buffer[append], (int)(HEALTH_CONF_MAX_LINE - append), fp)) || append) {
+ int stop_appending = !s;
+ line++;
+ s = trim(buffer);
+ if(!s) continue;
+
+ append = strlen(s);
+ if(!stop_appending && s[append - 1] == '\\') {
+ s[append - 1] = ' ';
+ append = &s[append] - buffer;
+ if(append < HEALTH_CONF_MAX_LINE)
+ continue;
+ else {
+ error("Health configuration has too long muli-line at line %zu of file '%s/%s'.", line, path, filename);
+ }
+ }
+ append = 0;
+
+ char *key = s;
+ while(*s && *s != ':') s++;
+ if(!*s) {
+ error("Health configuration has invalid line %zu of file '%s/%s'. It does not contain a ':'. Ignoring it.", line, path, filename);
+ continue;
+ }
+ *s = '\0';
+ s++;
+
+ char *value = s;
+ key = trim_all_spaces(key);
+ value = trim_all_spaces(value);
+
+ if(!key) {
+ error("Health configuration has invalid line %zu of file '%s/%s'. Keyword is empty. Ignoring it.", line, path, filename);
+ continue;
+ }
+
+ if(!value) {
+ error("Health configuration has invalid line %zu of file '%s/%s'. value is empty. Ignoring it.", line, path, filename);
+ continue;
+ }
+
+ uint32_t hash = simple_uhash(key);
+
+ if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
+ if(rc && !rrdcalc_add_alarm_from_config(host, rc))
+ rrdcalc_free(host, rc);
+
+ if(rt) {
+ if (!rrdcalctemplate_add_template_from_config(host, rt))
+ rrdcalctemplate_free(host, rt);
+ rt = NULL;
+ }
+
+ rc = callocz(1, sizeof(RRDCALC));
+ rc->next_event_id = 1;
+ rc->name = strdupz(value);
+ rc->hash = simple_hash(rc->name);
+ rc->source = health_source_file(line, path, filename);
+ rc->green = NAN;
+ rc->red = NAN;
+ rc->value = NAN;
+ rc->old_value = NAN;
+ rc->delay_multiplier = 1.0;
+
+ if(rrdvar_fix_name(rc->name))
+ error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
+ }
+ else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
+ if(rc) {
+ if(!rrdcalc_add_alarm_from_config(host, rc))
+ rrdcalc_free(host, rc);
+ rc = NULL;
+ }
+
+ if(rt && !rrdcalctemplate_add_template_from_config(host, rt))
+ rrdcalctemplate_free(host, rt);
+
+ rt = callocz(1, sizeof(RRDCALCTEMPLATE));
+ rt->name = strdupz(value);
+ rt->hash_name = simple_hash(rt->name);
+ rt->source = health_source_file(line, path, filename);
+ rt->green = NAN;
+ rt->red = NAN;
+ rt->delay_multiplier = 1.0;
+
+ if(rrdvar_fix_name(rt->name))
+ error("Health configuration renamed template '%s' to '%s'", value, rt->name);
+ }
+ else if(rc) {
+ if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
+ if(rc->chart) {
+ if(strcmp(rc->chart, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->chart, value, value);
+
+ freez(rc->chart);
+ }
+ rc->chart = strdupz(value);
+ rc->hash_chart = simple_hash(rc->chart);
+ }
+ else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
+ health_parse_db_lookup(line, path, filename, value, &rc->group, &rc->after, &rc->before,
+ &rc->update_every,
+ &rc->options, &rc->dimensions);
+ }
+ else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
+ if(!health_parse_duration(value, &rc->update_every))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' cannot parse duration: '%s'.",
+ line, path, filename, rc->name, key, value);
+ }
+ else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
+ char *e;
+ rc->green = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rc->name, key, e);
+ }
+ }
+ else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
+ char *e;
+ rc->red = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rc->name, key, e);
+ }
+ }
+ else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rc->calculation = expression_parse(value, &failed_at, &error);
+ if(!rc->calculation) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rc->warning = expression_parse(value, &failed_at, &error);
+ if(!rc->warning) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rc->critical = expression_parse(value, &failed_at, &error);
+ if(!rc->critical) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
+ if(rc->exec) {
+ if(strcmp(rc->exec, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->exec, value, value);
+
+ freez(rc->exec);
+ }
+ rc->exec = strdupz(value);
+ }
+ else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
+ if(rc->recipient) {
+ if(strcmp(rc->recipient, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->recipient, value, value);
+
+ freez(rc->recipient);
+ }
+ rc->recipient = strdupz(value);
+ }
+ else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
+ if(rc->units) {
+ if(strcmp(rc->units, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->units, value, value);
+
+ freez(rc->units);
+ }
+ rc->units = strdupz(value);
+ strip_quotes(rc->units);
+ }
+ else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
+ if(rc->info) {
+ if(strcmp(rc->info, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->info, value, value);
+
+ freez(rc->info);
+ }
+ rc->info = strdupz(value);
+ strip_quotes(rc->info);
+ }
+ else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
+ health_parse_delay(line, path, filename, value, &rc->delay_up_duration, &rc->delay_down_duration, &rc->delay_max_duration, &rc->delay_multiplier);
+ }
+ else if(hash == hash_options && !strcasecmp(key, HEALTH_OPTIONS_KEY)) {
+ rc->options |= health_parse_options(value);
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has unknown key '%s'.",
+ line, path, filename, rc->name, key);
+ }
+ }
+ else if(rt) {
+ if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
+ if(rt->context) {
+ if(strcmp(rt->context, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->context, value, value);
+
+ freez(rt->context);
+ }
+ rt->context = strdupz(value);
+ rt->hash_context = simple_hash(rt->context);
+ }
+ else if(hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
+ freez(rt->family_match);
+ simple_pattern_free(rt->family_pattern);
+
+ rt->family_match = strdupz(value);
+ rt->family_pattern = simple_pattern_create(rt->family_match, SIMPLE_PATTERN_EXACT);
+ }
+ else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
+ health_parse_db_lookup(line, path, filename, value, &rt->group, &rt->after, &rt->before,
+ &rt->update_every, &rt->options, &rt->dimensions);
+ }
+ else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
+ if(!health_parse_duration(value, &rt->update_every))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' cannot parse duration: '%s'.",
+ line, path, filename, rt->name, key, value);
+ }
+ else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
+ char *e;
+ rt->green = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rt->name, key, e);
+ }
+ }
+ else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
+ char *e;
+ rt->red = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rt->name, key, e);
+ }
+ }
+ else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rt->calculation = expression_parse(value, &failed_at, &error);
+ if(!rt->calculation) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rt->warning = expression_parse(value, &failed_at, &error);
+ if(!rt->warning) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rt->critical = expression_parse(value, &failed_at, &error);
+ if(!rt->critical) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
+ if(rt->exec) {
+ if(strcmp(rt->exec, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->exec, value, value);
+
+ freez(rt->exec);
+ }
+ rt->exec = strdupz(value);
+ }
+ else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
+ if(rt->recipient) {
+ if(strcmp(rt->recipient, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->recipient, value, value);
+
+ freez(rt->recipient);
+ }
+ rt->recipient = strdupz(value);
+ }
+ else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
+ if(rt->units) {
+ if(strcmp(rt->units, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->units, value, value);
+
+ freez(rt->units);
+ }
+ rt->units = strdupz(value);
+ strip_quotes(rt->units);
+ }
+ else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
+ if(rt->info) {
+ if(strcmp(rt->info, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->info, value, value);
+
+ freez(rt->info);
+ }
+ rt->info = strdupz(value);
+ strip_quotes(rt->info);
+ }
+ else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
+ health_parse_delay(line, path, filename, value, &rt->delay_up_duration, &rt->delay_down_duration, &rt->delay_max_duration, &rt->delay_multiplier);
+ }
+ else if(hash == hash_options && !strcasecmp(key, HEALTH_OPTIONS_KEY)) {
+ rt->options |= health_parse_options(value);
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has unknown key '%s'.",
+ line, path, filename, rt->name, key);
+ }
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s' has unknown key '%s'. Expected either '" HEALTH_ALARM_KEY "' or '" HEALTH_TEMPLATE_KEY "'.",
+ line, path, filename, key);
+ }
+ }
+
+ if(rc && !rrdcalc_add_alarm_from_config(host, rc))
+ rrdcalc_free(host, rc);
+
+ if(rt && !rrdcalctemplate_add_template_from_config(host, rt))
+ rrdcalctemplate_free(host, rt);
+
+ fclose(fp);
+ return 1;
+}
+
+void health_readdir(RRDHOST *host, const char *path) {
+ if(!host->health_enabled) return;
+
+ size_t pathlen = strlen(path);
+
+ debug(D_HEALTH, "Health configuration reading directory '%s'", path);
+
+ DIR *dir = opendir(path);
+ if (!dir) {
+ error("Health configuration cannot open directory '%s'.", path);
+ return;
+ }
+
+ struct dirent *de = NULL;
+ while ((de = readdir(dir))) {
+ size_t len = strlen(de->d_name);
+
+ if(de->d_type == DT_DIR
+ && (
+ (de->d_name[0] == '.' && de->d_name[1] == '\0')
+ || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
+ )) {
+ debug(D_HEALTH, "Ignoring directory '%s'", de->d_name);
+ continue;
+ }
+
+ else if(de->d_type == DT_DIR) {
+ char *s = mallocz(pathlen + strlen(de->d_name) + 2);
+ strcpy(s, path);
+ strcat(s, "/");
+ strcat(s, de->d_name);
+ health_readdir(host, s);
+ freez(s);
+ continue;
+ }
+
+ else if((de->d_type == DT_LNK || de->d_type == DT_REG || de->d_type == DT_UNKNOWN) &&
+ len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
+ health_readfile(host, path, de->d_name);
+ }
+
+ else debug(D_HEALTH, "Ignoring file '%s'", de->d_name);
+ }
+
+ closedir(dir);
+}
+
+
diff --git a/src/health_json.c b/src/health_json.c
new file mode 100644
index 000000000..a9697aaa7
--- /dev/null
+++ b/src/health_json.c
@@ -0,0 +1,256 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+static inline void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix) {
+ if(value && *value)
+ buffer_sprintf(wb, "%s\"%s\":\"%s\"%s", prefix, label, value, suffix);
+ else
+ buffer_sprintf(wb, "%s\"%s\":null%s", prefix, label, suffix);
+}
+
+static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host) {
+ buffer_sprintf(wb,
+ "\n\t{\n"
+ "\t\t\"hostname\": \"%s\",\n"
+ "\t\t\"unique_id\": %u,\n"
+ "\t\t\"alarm_id\": %u,\n"
+ "\t\t\"alarm_event_id\": %u,\n"
+ "\t\t\"name\": \"%s\",\n"
+ "\t\t\"chart\": \"%s\",\n"
+ "\t\t\"family\": \"%s\",\n"
+ "\t\t\"processed\": %s,\n"
+ "\t\t\"updated\": %s,\n"
+ "\t\t\"exec_run\": %lu,\n"
+ "\t\t\"exec_failed\": %s,\n"
+ "\t\t\"exec\": \"%s\",\n"
+ "\t\t\"recipient\": \"%s\",\n"
+ "\t\t\"exec_code\": %d,\n"
+ "\t\t\"source\": \"%s\",\n"
+ "\t\t\"units\": \"%s\",\n"
+ "\t\t\"info\": \"%s\",\n"
+ "\t\t\"when\": %lu,\n"
+ "\t\t\"duration\": %lu,\n"
+ "\t\t\"non_clear_duration\": %lu,\n"
+ "\t\t\"status\": \"%s\",\n"
+ "\t\t\"old_status\": \"%s\",\n"
+ "\t\t\"delay\": %d,\n"
+ "\t\t\"delay_up_to_timestamp\": %lu,\n"
+ "\t\t\"updated_by_id\": %u,\n"
+ "\t\t\"updates_id\": %u,\n"
+ "\t\t\"value_string\": \"%s\",\n"
+ "\t\t\"old_value_string\": \"%s\",\n"
+ , host->hostname
+ , ae->unique_id
+ , ae->alarm_id
+ , ae->alarm_event_id
+ , ae->name
+ , ae->chart
+ , ae->family
+ , (ae->flags & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false"
+ , (ae->flags & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false"
+ , (unsigned long)ae->exec_run_timestamp
+ , (ae->flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false"
+ , ae->exec?ae->exec:host->health_default_exec
+ , ae->recipient?ae->recipient:host->health_default_recipient
+ , ae->exec_code
+ , ae->source
+ , ae->units?ae->units:""
+ , ae->info?ae->info:""
+ , (unsigned long)ae->when
+ , (unsigned long)ae->duration
+ , (unsigned long)ae->non_clear_duration
+ , rrdcalc_status2string(ae->new_status)
+ , rrdcalc_status2string(ae->old_status)
+ , ae->delay
+ , (unsigned long)ae->delay_up_to_timestamp
+ , ae->updated_by_id
+ , ae->updates_id
+ , ae->new_value_string
+ , ae->old_value_string
+ );
+
+ if(unlikely(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
+ buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
+ }
+
+ buffer_strcat(wb, "\t\t\"value\":");
+ buffer_rrd_value(wb, ae->new_value);
+ buffer_strcat(wb, ",\n");
+
+ buffer_strcat(wb, "\t\t\"old_value\":");
+ buffer_rrd_value(wb, ae->old_value);
+ buffer_strcat(wb, "\n");
+
+ buffer_strcat(wb, "\t}");
+}
+
+void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after) {
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+
+ buffer_strcat(wb, "[");
+
+ unsigned int max = host->health_log.max;
+ unsigned int count = 0;
+ ALARM_ENTRY *ae;
+ for(ae = host->health_log.alarms; ae && count < max ; count++, ae = ae->next) {
+ if(ae->unique_id > after) {
+ if(likely(count)) buffer_strcat(wb, ",");
+ health_alarm_entry2json_nolock(wb, ae, host);
+ }
+ }
+
+ buffer_strcat(wb, "\n]\n");
+
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+}
+
+static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
+ char value_string[100 + 1];
+ format_value_and_unit(value_string, 100, rc->value, rc->units, -1);
+
+ buffer_sprintf(wb,
+ "\t\t\"%s.%s\": {\n"
+ "\t\t\t\"id\": %lu,\n"
+ "\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\"chart\": \"%s\",\n"
+ "\t\t\t\"family\": \"%s\",\n"
+ "\t\t\t\"active\": %s,\n"
+ "\t\t\t\"exec\": \"%s\",\n"
+ "\t\t\t\"recipient\": \"%s\",\n"
+ "\t\t\t\"source\": \"%s\",\n"
+ "\t\t\t\"units\": \"%s\",\n"
+ "\t\t\t\"info\": \"%s\",\n"
+ "\t\t\t\"status\": \"%s\",\n"
+ "\t\t\t\"last_status_change\": %lu,\n"
+ "\t\t\t\"last_updated\": %lu,\n"
+ "\t\t\t\"next_update\": %lu,\n"
+ "\t\t\t\"update_every\": %d,\n"
+ "\t\t\t\"delay_up_duration\": %d,\n"
+ "\t\t\t\"delay_down_duration\": %d,\n"
+ "\t\t\t\"delay_max_duration\": %d,\n"
+ "\t\t\t\"delay_multiplier\": %f,\n"
+ "\t\t\t\"delay\": %d,\n"
+ "\t\t\t\"delay_up_to_timestamp\": %lu,\n"
+ "\t\t\t\"value_string\": \"%s\",\n"
+ , rc->chart, rc->name
+ , (unsigned long)rc->id
+ , rc->name
+ , rc->chart
+ , (rc->rrdset && rc->rrdset->family)?rc->rrdset->family:""
+ , (rc->rrdset)?"true":"false"
+ , rc->exec?rc->exec:host->health_default_exec
+ , rc->recipient?rc->recipient:host->health_default_recipient
+ , rc->source
+ , rc->units?rc->units:""
+ , rc->info?rc->info:""
+ , rrdcalc_status2string(rc->status)
+ , (unsigned long)rc->last_status_change
+ , (unsigned long)rc->last_updated
+ , (unsigned long)rc->next_update
+ , rc->update_every
+ , rc->delay_up_duration
+ , rc->delay_down_duration
+ , rc->delay_max_duration
+ , rc->delay_multiplier
+ , rc->delay_last
+ , (unsigned long)rc->delay_up_to_timestamp
+ , value_string
+ );
+
+ if(unlikely(rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION)) {
+ buffer_strcat(wb, "\t\t\t\"no_clear_notification\": true,\n");
+ }
+
+ if(RRDCALC_HAS_DB_LOOKUP(rc)) {
+ if(rc->dimensions && *rc->dimensions)
+ health_string2json(wb, "\t\t\t", "lookup_dimensions", rc->dimensions, ",\n");
+
+ buffer_sprintf(wb,
+ "\t\t\t\"db_after\": %lu,\n"
+ "\t\t\t\"db_before\": %lu,\n"
+ "\t\t\t\"lookup_method\": \"%s\",\n"
+ "\t\t\t\"lookup_after\": %d,\n"
+ "\t\t\t\"lookup_before\": %d,\n"
+ "\t\t\t\"lookup_options\": \"",
+ (unsigned long) rc->db_after,
+ (unsigned long) rc->db_before,
+ group_method2string(rc->group),
+ rc->after,
+ rc->before
+ );
+ buffer_data_options2string(wb, rc->options);
+ buffer_strcat(wb, "\",\n");
+ }
+
+ if(rc->calculation) {
+ health_string2json(wb, "\t\t\t", "calc", rc->calculation->source, ",\n");
+ health_string2json(wb, "\t\t\t", "calc_parsed", rc->calculation->parsed_as, ",\n");
+ }
+
+ if(rc->warning) {
+ health_string2json(wb, "\t\t\t", "warn", rc->warning->source, ",\n");
+ health_string2json(wb, "\t\t\t", "warn_parsed", rc->warning->parsed_as, ",\n");
+ }
+
+ if(rc->critical) {
+ health_string2json(wb, "\t\t\t", "crit", rc->critical->source, ",\n");
+ health_string2json(wb, "\t\t\t", "crit_parsed", rc->critical->parsed_as, ",\n");
+ }
+
+ buffer_strcat(wb, "\t\t\t\"green\":");
+ buffer_rrd_value(wb, rc->green);
+ buffer_strcat(wb, ",\n");
+
+ buffer_strcat(wb, "\t\t\t\"red\":");
+ buffer_rrd_value(wb, rc->red);
+ buffer_strcat(wb, ",\n");
+
+ buffer_strcat(wb, "\t\t\t\"value\":");
+ buffer_rrd_value(wb, rc->value);
+ buffer_strcat(wb, "\n");
+
+ buffer_strcat(wb, "\t\t}");
+}
+
+//void health_rrdcalctemplate2json_nolock(BUFFER *wb, RRDCALCTEMPLATE *rt) {
+//
+//}
+
+void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
+ int i;
+
+ rrdhost_rdlock(host);
+ buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
+ "\n\t\"latest_alarm_log_unique_id\": %u,"
+ "\n\t\"status\": %s,"
+ "\n\t\"now\": %lu,"
+ "\n\t\"alarms\": {\n",
+ host->hostname,
+ (host->health_log.next_log_id > 0)?(host->health_log.next_log_id - 1):0,
+ host->health_enabled?"true":"false",
+ (unsigned long)now_realtime_sec());
+
+ RRDCALC *rc;
+ for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
+ if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
+ continue;
+
+ if(likely(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL)))
+ continue;
+
+ if(likely(i)) buffer_strcat(wb, ",\n");
+ health_rrdcalc2json_nolock(host, wb, rc);
+ i++;
+ }
+
+// buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
+// RRDCALCTEMPLATE *rt;
+// for(rt = host->templates; rt ; rt = rt->next)
+// health_rrdcalctemplate2json_nolock(wb, rt);
+
+ buffer_strcat(wb, "\n\t}\n}\n");
+ rrdhost_unlock(host);
+}
+
+
+
diff --git a/src/health_log.c b/src/health_log.c
new file mode 100644
index 000000000..95abcfe5f
--- /dev/null
+++ b/src/health_log.c
@@ -0,0 +1,465 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// health alarm log load/save
+// no need for locking - only one thread is reading / writing the alarms log
+
+inline int health_alarm_log_open(RRDHOST *host) {
+ if(host->health_log_fp)
+ fclose(host->health_log_fp);
+
+ host->health_log_fp = fopen(host->health_log_filename, "a");
+
+ if(host->health_log_fp) {
+ if (setvbuf(host->health_log_fp, NULL, _IOLBF, 0) != 0)
+ error("HEALTH [%s]: cannot set line buffering on health log file '%s'.", host->hostname, host->health_log_filename);
+ return 0;
+ }
+
+ error("HEALTH [%s]: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", host->hostname, host->health_log_filename);
+ return -1;
+}
+
+inline void health_alarm_log_close(RRDHOST *host) {
+ if(host->health_log_fp) {
+ fclose(host->health_log_fp);
+ host->health_log_fp = NULL;
+ }
+}
+
+inline void health_log_rotate(RRDHOST *host) {
+ static size_t rotate_every = 0;
+
+ if(unlikely(rotate_every == 0)) {
+ rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000);
+ if(rotate_every < 100) rotate_every = 100;
+ }
+
+ if(unlikely(host->health_log_entries_written > rotate_every)) {
+ health_alarm_log_close(host);
+
+ char old_filename[FILENAME_MAX + 1];
+ snprintfz(old_filename, FILENAME_MAX, "%s.old", host->health_log_filename);
+
+ if(unlink(old_filename) == -1 && errno != ENOENT)
+ error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, old_filename);
+
+ if(link(host->health_log_filename, old_filename) == -1 && errno != ENOENT)
+ error("HEALTH [%s]: cannot move file '%s' to '%s'.", host->hostname, host->health_log_filename, old_filename);
+
+ if(unlink(host->health_log_filename) == -1 && errno != ENOENT)
+ error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, host->health_log_filename);
+
+ // open it with truncate
+ host->health_log_fp = fopen(host->health_log_filename, "w");
+
+ if(host->health_log_fp)
+ fclose(host->health_log_fp);
+ else
+ error("HEALTH [%s]: cannot truncate health log '%s'", host->hostname, host->health_log_filename);
+
+ host->health_log_fp = NULL;
+
+ host->health_log_entries_written = 0;
+ health_alarm_log_open(host);
+ }
+}
+
+inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
+ health_log_rotate(host);
+
+ if(likely(host->health_log_fp)) {
+ if(unlikely(fprintf(host->health_log_fp
+ , "%c\t%s"
+ "\t%08x\t%08x\t%08x\t%08x\t%08x"
+ "\t%08x\t%08x\t%08x"
+ "\t%08x\t%08x\t%08x"
+ "\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s"
+ "\t%d\t%d\t%d\t%d"
+ "\t%Lf\t%Lf"
+ "\n"
+ , (ae->flags & HEALTH_ENTRY_FLAG_SAVED)?'U':'A'
+ , host->hostname
+
+ , ae->unique_id
+ , ae->alarm_id
+ , ae->alarm_event_id
+ , ae->updated_by_id
+ , ae->updates_id
+
+ , (uint32_t)ae->when
+ , (uint32_t)ae->duration
+ , (uint32_t)ae->non_clear_duration
+ , (uint32_t)ae->flags
+ , (uint32_t)ae->exec_run_timestamp
+ , (uint32_t)ae->delay_up_to_timestamp
+
+ , (ae->name)?ae->name:""
+ , (ae->chart)?ae->chart:""
+ , (ae->family)?ae->family:""
+ , (ae->exec)?ae->exec:""
+ , (ae->recipient)?ae->recipient:""
+ , (ae->source)?ae->source:""
+ , (ae->units)?ae->units:""
+ , (ae->info)?ae->info:""
+
+ , ae->exec_code
+ , ae->new_status
+ , ae->old_status
+ , ae->delay
+
+ , (long double)ae->new_value
+ , (long double)ae->old_value
+ ) < 0))
+ error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.", host->hostname, host->health_log_filename);
+ else {
+ ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
+ host->health_log_entries_written++;
+ }
+ }
+}
+
+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);
+ size_t line = 0, len = 0;
+ ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
+
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+
+ while((s = fgets_trim_len(buf, 65536, fp, &len))) {
+ host->health_log_entries_written++;
+ line++;
+
+ int max_entries = 30, entries = 0;
+ char *pointers[max_entries];
+
+ pointers[entries++] = s++;
+ while(*s) {
+ if(unlikely(*s == '\t')) {
+ *s = '\0';
+ pointers[entries++] = ++s;
+ if(entries >= max_entries) {
+ error("HEALTH [%s]: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", host->hostname, line, filename, max_entries);
+ break;
+ }
+ }
+ else s++;
+ }
+
+ if(likely(*pointers[0] == 'U' || *pointers[0] == 'A')) {
+ ALARM_ENTRY *ae = NULL;
+
+ if(entries < 26) {
+ error("HEALTH [%s]: line %zu of file '%s' should have at least 26 entries, but it has %d. Ignoring it.", host->hostname, line, filename, entries);
+ errored++;
+ continue;
+ }
+
+ // check that we have valid ids
+ uint32_t unique_id = (uint32_t)strtoul(pointers[2], NULL, 16);
+ if(!unique_id) {
+ error("HEALTH [%s]: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", host->hostname, line, filename, unique_id, pointers[2]);
+ errored++;
+ continue;
+ }
+
+ uint32_t alarm_id = (uint32_t)strtoul(pointers[3], NULL, 16);
+ if(!alarm_id) {
+ error("HEALTH [%s]: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", host->hostname, line, filename, alarm_id, pointers[3]);
+ errored++;
+ continue;
+ }
+
+ if(unlikely(*pointers[0] == 'A')) {
+ // make sure it is properly numbered
+ if(unlikely(host->health_log.alarms && unique_id < host->health_log.alarms->unique_id)) {
+ error("HEALTH [%s]: line %zu of file '%s' has alarm log entry %u in wrong order. Ignoring it.", host->hostname, line, filename, unique_id);
+ errored++;
+ continue;
+ }
+
+ ae = callocz(1, sizeof(ALARM_ENTRY));
+ }
+ else if(unlikely(*pointers[0] == 'U')) {
+ // find the original
+ for(ae = host->health_log.alarms; ae; ae = ae->next) {
+ if(unlikely(unique_id == ae->unique_id)) {
+ if(unlikely(*pointers[0] == 'A')) {
+ error("HEALTH [%s]: line %zu of file '%s' adds duplicate alarm log entry %u. Using the later."
+ , host->hostname, line, filename, unique_id);
+ *pointers[0] = 'U';
+ duplicate++;
+ }
+ break;
+ }
+ else if(unlikely(unique_id > ae->unique_id)) {
+ // no need to continue
+ // the linked list is sorted
+ ae = NULL;
+ break;
+ }
+ }
+ }
+
+ // if not found, skip this line
+ if(unlikely(!ae)) {
+ // error("HEALTH [%s]: line %zu of file '%s' updates alarm log entry with unique id %u, but it is not found.", host->hostname, line, filename, unique_id);
+ continue;
+ }
+
+ // check for a possible host missmatch
+ //if(strcmp(pointers[1], host->hostname))
+ // error("HEALTH [%s]: line %zu of file '%s' provides an alarm for host '%s' but this is named '%s'.", host->hostname, line, filename, pointers[1], host->hostname);
+
+ ae->unique_id = unique_id;
+ ae->alarm_id = alarm_id;
+ ae->alarm_event_id = (uint32_t)strtoul(pointers[4], NULL, 16);
+ ae->updated_by_id = (uint32_t)strtoul(pointers[5], NULL, 16);
+ ae->updates_id = (uint32_t)strtoul(pointers[6], NULL, 16);
+
+ ae->when = (uint32_t)strtoul(pointers[7], NULL, 16);
+ ae->duration = (uint32_t)strtoul(pointers[8], NULL, 16);
+ ae->non_clear_duration = (uint32_t)strtoul(pointers[9], NULL, 16);
+
+ ae->flags = (uint32_t)strtoul(pointers[10], NULL, 16);
+ ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
+
+ ae->exec_run_timestamp = (uint32_t)strtoul(pointers[11], NULL, 16);
+ ae->delay_up_to_timestamp = (uint32_t)strtoul(pointers[12], NULL, 16);
+
+ freez(ae->name);
+ ae->name = strdupz(pointers[13]);
+ ae->hash_name = simple_hash(ae->name);
+
+ freez(ae->chart);
+ ae->chart = strdupz(pointers[14]);
+ ae->hash_chart = simple_hash(ae->chart);
+
+ freez(ae->family);
+ ae->family = strdupz(pointers[15]);
+
+ freez(ae->exec);
+ ae->exec = strdupz(pointers[16]);
+ if(!*ae->exec) { freez(ae->exec); ae->exec = NULL; }
+
+ freez(ae->recipient);
+ ae->recipient = strdupz(pointers[17]);
+ if(!*ae->recipient) { freez(ae->recipient); ae->recipient = NULL; }
+
+ freez(ae->source);
+ ae->source = strdupz(pointers[18]);
+ if(!*ae->source) { freez(ae->source); ae->source = NULL; }
+
+ freez(ae->units);
+ ae->units = strdupz(pointers[19]);
+ if(!*ae->units) { freez(ae->units); ae->units = NULL; }
+
+ freez(ae->info);
+ ae->info = strdupz(pointers[20]);
+ if(!*ae->info) { freez(ae->info); ae->info = NULL; }
+
+ ae->exec_code = str2i(pointers[21]);
+ ae->new_status = str2i(pointers[22]);
+ ae->old_status = str2i(pointers[23]);
+ ae->delay = str2i(pointers[24]);
+
+ ae->new_value = str2l(pointers[25]);
+ ae->old_value = str2l(pointers[26]);
+
+ static 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));
+ ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
+
+ // add it to host if not already there
+ if(unlikely(*pointers[0] == 'A')) {
+ ae->next = host->health_log.alarms;
+ host->health_log.alarms = ae;
+ loaded++;
+ }
+ else updated++;
+
+ if(unlikely(ae->unique_id > max_unique_id))
+ max_unique_id = ae->unique_id;
+
+ if(unlikely(ae->alarm_id >= max_alarm_id))
+ 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]);
+ errored++;
+ }
+ }
+
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+
+ 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();
+
+ host->health_log.next_log_id = max_unique_id + 1;
+ host->health_log.next_alarm_id = 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;
+}
+
+inline void health_alarm_log_load(RRDHOST *host) {
+ health_alarm_log_close(host);
+
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s.old", host->health_log_filename);
+ FILE *fp = fopen(filename, "r");
+ if(!fp)
+ error("HEALTH [%s]: cannot open health file: %s", host->hostname, filename);
+ else {
+ health_alarm_log_read(host, fp, filename);
+ fclose(fp);
+ }
+
+ host->health_log_entries_written = 0;
+ fp = fopen(host->health_log_filename, "r");
+ if(!fp)
+ error("HEALTH [%s]: cannot open health file: %s", host->hostname, host->health_log_filename);
+ else {
+ health_alarm_log_read(host, fp, host->health_log_filename);
+ fclose(fp);
+ }
+
+ health_alarm_log_open(host);
+}
+
+
+// ----------------------------------------------------------------------------
+// health alarm log management
+
+inline void health_alarm_log(
+ RRDHOST *host,
+ uint32_t alarm_id,
+ uint32_t alarm_event_id,
+ time_t when,
+ const char *name,
+ const char *chart,
+ const char *family,
+ const char *exec,
+ const char *recipient,
+ time_t duration,
+ calculated_number old_value,
+ calculated_number new_value,
+ int old_status,
+ int new_status,
+ const char *source,
+ const char *units,
+ const char *info,
+ int delay,
+ uint32_t flags
+) {
+ debug(D_HEALTH, "Health adding alarm log entry with id: %u", host->health_log.next_log_id);
+
+ ALARM_ENTRY *ae = callocz(1, sizeof(ALARM_ENTRY));
+ ae->name = strdupz(name);
+ ae->hash_name = simple_hash(ae->name);
+
+ if(chart) {
+ ae->chart = strdupz(chart);
+ ae->hash_chart = simple_hash(ae->chart);
+ }
+
+ if(family)
+ ae->family = strdupz(family);
+
+ if(exec) ae->exec = strdupz(exec);
+ if(recipient) ae->recipient = strdupz(recipient);
+ if(source) ae->source = strdupz(source);
+ if(units) ae->units = strdupz(units);
+ if(info) ae->info = strdupz(info);
+
+ ae->unique_id = host->health_log.next_log_id++;
+ ae->alarm_id = alarm_id;
+ ae->alarm_event_id = alarm_event_id;
+ ae->when = when;
+ ae->old_value = old_value;
+ ae->new_value = new_value;
+
+ static 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));
+
+ ae->old_status = old_status;
+ ae->new_status = new_status;
+ ae->duration = duration;
+ ae->delay = delay;
+ ae->delay_up_to_timestamp = when + delay;
+
+ ae->flags |= flags;
+
+ if(ae->old_status == RRDCALC_STATUS_WARNING || ae->old_status == RRDCALC_STATUS_CRITICAL)
+ ae->non_clear_duration += ae->duration;
+
+ // link it
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ ae->next = host->health_log.alarms;
+ host->health_log.alarms = ae;
+ host->health_log.count++;
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+
+ // match previous alarms
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ ALARM_ENTRY *t;
+ for(t = host->health_log.alarms ; t ; t = t->next) {
+ if(t != ae && t->alarm_id == ae->alarm_id) {
+ if(!(t->flags & HEALTH_ENTRY_FLAG_UPDATED) && !t->updated_by_id) {
+ t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
+ t->updated_by_id = ae->unique_id;
+ ae->updates_id = t->unique_id;
+
+ if((t->new_status == RRDCALC_STATUS_WARNING || t->new_status == RRDCALC_STATUS_CRITICAL) &&
+ (t->old_status == RRDCALC_STATUS_WARNING || t->old_status == RRDCALC_STATUS_CRITICAL))
+ ae->non_clear_duration += t->non_clear_duration;
+
+ health_alarm_log_save(host, t);
+ }
+
+ // no need to continue
+ break;
+ }
+ }
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+
+ health_alarm_log_save(host, ae);
+}
+
+inline void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae) {
+ freez(ae->name);
+ freez(ae->chart);
+ freez(ae->family);
+ freez(ae->exec);
+ freez(ae->recipient);
+ freez(ae->source);
+ freez(ae->units);
+ freez(ae->info);
+ freez(ae->old_value_string);
+ freez(ae->new_value_string);
+ freez(ae);
+}
+
+inline void health_alarm_log_free(RRDHOST *host) {
+ rrdhost_check_wrlock(host);
+
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+
+ ALARM_ENTRY *ae;
+ while((ae = host->health_log.alarms)) {
+ host->health_log.alarms = ae->next;
+ health_alarm_log_free_one_nochecks_nounlink(ae);
+ }
+
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+}
diff --git a/src/inlined.h b/src/inlined.h
index e776f830e..0dc11c950 100644
--- a/src/inlined.h
+++ b/src/inlined.h
@@ -3,6 +3,19 @@
#include "common.h"
+#ifdef KERNEL_32BIT
+typedef uint32_t kernel_uint_t;
+#define str2kernel_uint_t(string) str2uint32_t(string)
+#define KERNEL_UINT_FORMAT "%u"
+#else
+typedef uint64_t kernel_uint_t;
+#define str2kernel_uint_t(string) str2uint64_t(string)
+#define KERNEL_UINT_FORMAT "%" PRIu64
+#endif
+
+#define str2pid_t(string) str2uint32_t(string)
+
+
// for faster execution, allow the compiler to inline
// these functions that are called thousands of times per second
@@ -70,6 +83,26 @@ static inline long str2l(const char *s) {
return n;
}
+static inline uint32_t str2uint32_t(const char *s) {
+ uint32_t n = 0;
+ char c;
+ for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) {
+ n *= 10;
+ n += c - '0';
+ }
+ return n;
+}
+
+static inline uint64_t str2uint64_t(const char *s) {
+ uint64_t n = 0;
+ char c;
+ for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) {
+ n *= 10;
+ n += c - '0';
+ }
+ return n;
+}
+
static inline unsigned long str2ul(const char *s) {
unsigned long n = 0;
char c;
@@ -95,12 +128,24 @@ static inline unsigned long long str2ull(const char *s) {
#undef strcmp
#endif
#define strcmp(a, b) strsame(a, b)
+#endif // NETDATA_STRCMP_OVERRIDE
+
static inline int strsame(const char *a, const char *b) {
if(unlikely(a == b)) return 0;
while(*a && *a == *b) { a++; b++; }
return *a - *b;
}
-#endif // NETDATA_STRSAME
+
+static inline char *strncpyz(char *dst, const char *src, size_t n) {
+ char *p = dst;
+
+ while (*src && n--)
+ *dst++ = *src++;
+
+ *dst = '\0';
+
+ return p;
+}
static inline int read_single_number_file(const char *filename, unsigned long long *result) {
char buffer[30 + 1];
diff --git a/src/ipc.c b/src/ipc.c
index a5ab342d3..1dabf5e19 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -57,7 +57,7 @@ static inline int ipc_sem_get_limits(struct ipc_limits *lim) {
static char filename[FILENAME_MAX + 1] = "";
if(unlikely(!filename[0]))
- snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", netdata_configured_host_prefix);
if(unlikely(!ff)) {
ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
@@ -184,23 +184,27 @@ int do_ipc(int update_every, usec_t dt) {
return 1;
}
- arrays_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.arrays.max");
- semaphores_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.max");
+ arrays_max = rrdvar_custom_host_variable_create(localhost, "ipc.semaphores.arrays.max");
+ semaphores_max = rrdvar_custom_host_variable_create(localhost, "ipc.semaphores.max");
if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
// create the charts
- semaphores = rrdset_find("system.ipc_semaphores");
+ semaphores = rrdset_find_localhost("system.ipc_semaphores");
if(!semaphores) {
- semaphores = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ semaphores = rrdset_create_localhost("system", "ipc_semaphores", NULL, "ipc semaphores", NULL
+ , "IPC Semaphores", "semaphores", 1000, localhost->rrd_update_every
+ , RRDSET_TYPE_AREA);
+ rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- arrays = rrdset_find("system.ipc_semaphore_arrays");
+ arrays = rrdset_find_localhost("system.ipc_semaphore_arrays");
if(!arrays) {
- arrays = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(arrays, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ arrays = rrdset_create_localhost("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL
+ , "IPC Semaphore Arrays", "arrays", 1000, localhost->rrd_update_every
+ , RRDSET_TYPE_AREA);
+ rrddim_add(arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
}
diff --git a/src/locks.h b/src/locks.h
new file mode 100644
index 000000000..76533f636
--- /dev/null
+++ b/src/locks.h
@@ -0,0 +1,294 @@
+#ifndef NETDATA_LOCKS_H
+#define NETDATA_LOCKS_H
+
+// ----------------------------------------------------------------------------
+// mutex
+
+typedef pthread_mutex_t netdata_mutex_t;
+
+#define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+static inline int __netdata_mutex_init(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_init(mutex, NULL);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to initialize (code %d).", ret);
+ return ret;
+}
+
+static inline int __netdata_mutex_lock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_lock(mutex);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to get lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_trylock(mutex);
+ return ret;
+}
+
+static inline int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_unlock(mutex);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to unlock (code %d).", ret);
+ return ret;
+}
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+static inline int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_init(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_lock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_trylock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_unlock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+#define netdata_mutex_init(mutex) netdata_mutex_init_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_lock(mutex) netdata_mutex_lock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_trylock(mutex) netdata_mutex_trylock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_unlock(mutex) netdata_mutex_unlock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex)
+#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex)
+#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex)
+#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex)
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+
+// ----------------------------------------------------------------------------
+// r/w lock
+
+typedef pthread_rwlock_t netdata_rwlock_t;
+
+#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+
+static inline int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_destroy(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to destroy lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_init(rwlock, NULL);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to initialize lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_rdlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to obtain read lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_wrlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to obtain write lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_unlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to release lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_tryrdlock(rwlock);
+ return ret;
+}
+
+static inline int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_trywrlock(rwlock);
+ return ret;
+}
+
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+static inline int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_destroy(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_init(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_rdlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_wrlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_unlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_tryrdlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_trywrlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+#define netdata_rwlock_destroy(rwlock) netdata_rwlock_destroy_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_init(rwlock) netdata_rwlock_init_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_rdlock(rwlock) netdata_rwlock_rdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_wrlock(rwlock) netdata_rwlock_wrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_unlock(rwlock) netdata_rwlock_unlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_tryrdlock(rwlock) netdata_rwlock_tryrdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_trywrlock(rwlock) netdata_rwlock_trywrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define netdata_rwlock_destroy(rwlock) __netdata_rwlock_destroy(rwlock)
+#define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock)
+#define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock)
+#define netdata_rwlock_wrlock(rwlock) __netdata_rwlock_wrlock(rwlock)
+#define netdata_rwlock_unlock(rwlock) __netdata_rwlock_unlock(rwlock)
+#define netdata_rwlock_tryrdlock(rwlock) __netdata_rwlock_tryrdlock(rwlock)
+#define netdata_rwlock_trywrlock(rwlock) __netdata_rwlock_trywrlock(rwlock)
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+#endif //NETDATA_LOCKS_H
diff --git a/src/log.c b/src/log.c
index d4c7fa14d..855ecaee6 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,7 +1,7 @@
#include "common.h"
const char *program_name = "";
-unsigned long long debug_flags = DEBUG;
+uint64_t debug_flags = DEBUG;
int access_log_syslog = 1;
int error_log_syslog = 1;
@@ -257,8 +257,8 @@ void info_int( const char *file, const char *function, const unsigned long line,
log_date(stderr);
va_start( args, fmt );
- if(debug_flags) fprintf(stderr, "%s: INFO: (%04lu@%-10.10s:%-15.15s):", program_name, line, file, function);
- else fprintf(stderr, "%s: INFO: ", program_name);
+ if(debug_flags) fprintf(stderr, "%s: INFO : (%04lu@%-10.10s:%-15.15s): ", program_name, line, file, function);
+ else fprintf(stderr, "%s: INFO : ", program_name);
vfprintf( stderr, fmt, args );
va_end( args );
diff --git a/src/log.h b/src/log.h
index e61ffdd08..d8ff0654b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -1,38 +1,40 @@
#ifndef NETDATA_LOG_H
#define NETDATA_LOG_H 1
-#define D_WEB_BUFFER 0x00000001
-#define D_WEB_CLIENT 0x00000002
-#define D_LISTENER 0x00000004
-#define D_WEB_DATA 0x00000008
-#define D_OPTIONS 0x00000010
-#define D_PROCNETDEV_LOOP 0x00000020
-#define D_RRD_STATS 0x00000040
-#define D_WEB_CLIENT_ACCESS 0x00000080
-#define D_TC_LOOP 0x00000100
-#define D_DEFLATE 0x00000200
-#define D_CONFIG 0x00000400
-#define D_PLUGINSD 0x00000800
-#define D_CHILDS 0x00001000
-#define D_EXIT 0x00002000
-#define D_CHECKS 0x00004000
-#define D_NFACCT_LOOP 0x00008000
-#define D_PROCFILE 0x00010000
-#define D_RRD_CALLS 0x00020000
-#define D_DICTIONARY 0x00040000
-#define D_MEMORY 0x00080000
-#define D_CGROUP 0x00100000
-#define D_REGISTRY 0x00200000
-#define D_VARIABLES 0x00400000
-#define D_HEALTH 0x00800000
-#define D_CONNECT_TO 0x01000000
-#define D_SYSTEM 0x80000000
+#define D_WEB_BUFFER 0x0000000000000001
+#define D_WEB_CLIENT 0x0000000000000002
+#define D_LISTENER 0x0000000000000004
+#define D_WEB_DATA 0x0000000000000008
+#define D_OPTIONS 0x0000000000000010
+#define D_PROCNETDEV_LOOP 0x0000000000000020
+#define D_RRD_STATS 0x0000000000000040
+#define D_WEB_CLIENT_ACCESS 0x0000000000000080
+#define D_TC_LOOP 0x0000000000000100
+#define D_DEFLATE 0x0000000000000200
+#define D_CONFIG 0x0000000000000400
+#define D_PLUGINSD 0x0000000000000800
+#define D_CHILDS 0x0000000000001000
+#define D_EXIT 0x0000000000002000
+#define D_CHECKS 0x0000000000004000
+#define D_NFACCT_LOOP 0x0000000000008000
+#define D_PROCFILE 0x0000000000010000
+#define D_RRD_CALLS 0x0000000000020000
+#define D_DICTIONARY 0x0000000000040000
+#define D_MEMORY 0x0000000000080000
+#define D_CGROUP 0x0000000000100000
+#define D_REGISTRY 0x0000000000200000
+#define D_VARIABLES 0x0000000000400000
+#define D_HEALTH 0x0000000000800000
+#define D_CONNECT_TO 0x0000000001000000
+#define D_RRDHOST 0x0000000002000000
+#define D_LOCKS 0x0000000004000000
+#define D_SYSTEM 0x8000000000000000
//#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
//#define DEBUG 0xffffffff
#define DEBUG (0)
-extern unsigned long long debug_flags;
+extern uint64_t debug_flags;
extern const char *program_name;
diff --git a/src/macos_fw.c b/src/macos_fw.c
index a62aa7a7e..c47da52f1 100644
--- a/src/macos_fw.c
+++ b/src/macos_fw.c
@@ -136,12 +136,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
total_disk_writes += diskstat.bytes_write;
}
- st = rrdset_find_bytype("disk", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk", diskstat.name, NULL, diskstat.name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("disk", diskstat.name, NULL, diskstat.name, "disk.io"
+ , "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every
+ , RRDSET_TYPE_AREA);
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -161,13 +163,15 @@ int do_macos_iokit(int update_every, usec_t dt) {
CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes);
}
- st = rrdset_find_bytype("disk_ops", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_ops", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops"
+ , "Disk Completed I/O Operations", "operations/s", 2001
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -187,12 +191,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write);
}
- st = rrdset_find_bytype("disk_util", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_util", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_util", diskstat.name, NULL, diskstat.name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_util", diskstat.name, NULL, diskstat.name, "disk.util"
+ , "Disk Utilization Time", "% of time working", 2004, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "utilization", NULL, 1, 10000000, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "utilization", NULL, 1, 10000000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -212,13 +218,15 @@ int do_macos_iokit(int update_every, usec_t dt) {
CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write);
}
- st = rrdset_find_bytype("disk_iotime", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_iotime", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime"
+ , "Disk Total I/O Time", "milliseconds/s", 2022, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -236,13 +244,15 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_await", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_await", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_await", diskstat.name, NULL, diskstat.name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_await", diskstat.name, NULL, diskstat.name, "disk.await"
+ , "Average Completed I/O Operation Time", "ms per operation"
+ , 2005, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -254,13 +264,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_avgsz", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_avgsz", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz"
+ , "Average Completed I/O Operation Bandwidth"
+ , "kilobytes per operation", 2006, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -272,12 +285,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_svctm", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_svctm", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm"
+ , "Average Service Time", "ms per operation", 2007
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "svctm", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "svctm", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -301,11 +316,12 @@ int do_macos_iokit(int update_every, usec_t dt) {
}
if (likely(do_io)) {
- st = rrdset_find_bytype("system", "io");
+ st = rrdset_find_bytype_localhost("system", "io");
if (unlikely(!st)) {
- st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "in", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150
+ , update_every, RRDSET_TYPE_AREA);
+ rrddim_add(st, "in", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "out", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -340,17 +356,17 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------------
if (likely(do_space)) {
- st = rrdset_find_bytype("disk_space", mntbuf[i].f_mntonname);
+ st = rrdset_find_bytype_localhost("disk_space", mntbuf[i].f_mntonname);
if (unlikely(!st)) {
snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023,
- update_every,
- RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname
+ , "disk.space", title, "GB", 2023, update_every
+ , RRDSET_TYPE_STACKED);
- rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
- RRDDIM_ABSOLUTE);
+ RRD_ALGORITHM_ABSOLUTE);
} else
rrdset_next(st);
@@ -363,15 +379,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------------
if (likely(do_inodes)) {
- st = rrdset_find_bytype("disk_inodes", mntbuf[i].f_mntonname);
+ st = rrdset_find_bytype_localhost("disk_inodes", mntbuf[i].f_mntonname);
if (unlikely(!st)) {
snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024,
- update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname
+ , "disk.inodes", title, "Inodes", 2024, update_every
+ , RRDSET_TYPE_STACKED);
- rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE);
} else
rrdset_next(st);
@@ -398,12 +415,13 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -413,15 +431,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_packets", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_packets", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets"
+ , "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "multicast_received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "multicast_sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -433,13 +452,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_errors", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_errors", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors"
+ , "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -449,12 +469,13 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_drops", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_drops", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops"
+ , "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -463,14 +484,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_events", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_events", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events"
+ , "Network Interface Events", "events/s", 7006, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/macos_mach_smi.c b/src/macos_mach_smi.c
index d86a03220..da2825513 100644
--- a/src/macos_mach_smi.c
+++ b/src/macos_mach_smi.c
@@ -48,14 +48,15 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
error("DISABLED: system.cpu");
} else {
- st = rrdset_find_bytype("system", "cpu");
+ st = rrdset_find_bytype_localhost("system", "cpu");
if (unlikely(!st)) {
- st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization"
+ , "percentage", 100, update_every, RRDSET_TYPE_STACKED);
- rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rrddim_hide(st, "idle");
}
else rrdset_next(st);
@@ -84,18 +85,19 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
error("DISABLED: mem.pgfaults");
} else {
if (likely(do_ram)) {
- st = rrdset_find("system.ram");
+ st = rrdset_find_localhost("system.ram");
if (unlikely(!st)) {
- st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "active", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "wired", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "throttled", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "compressor", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "inactive", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "purgeable", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "speculative", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "free", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200
+ , update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(st, "active", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "wired", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "throttled", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "compressor", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "inactive", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "purgeable", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "speculative", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -113,12 +115,13 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_swapio)) {
- st = rrdset_find("system.swapio");
+ st = rrdset_find_localhost("system.swapio");
if (unlikely(!st)) {
- st = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "in", NULL, system_pagesize, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "in", NULL, system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -130,20 +133,21 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_pgfaults)) {
- st = rrdset_find("mem.pgfaults");
+ st = rrdset_find_localhost("mem.pgfaults");
if (unlikely(!st)) {
- st = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "memory", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "cow", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "pagein", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "pageout", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "compress", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "decompress", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "zero_fill", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "reactivate", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "purge", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults"
+ , "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "memory", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "cow", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "pagein", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "pageout", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "compress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "decompress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "zero_fill", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "reactivate", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "purge", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/macos_sysctl.c b/src/macos_sysctl.c
index 955b70757..af229fb61 100644
--- a/src/macos_sysctl.c
+++ b/src/macos_sysctl.c
@@ -24,8 +24,6 @@
#define MIN_LOADAVG_UPDATE_EVERY 5
int do_macos_sysctl(int update_every, usec_t dt) {
- (void)dt;
-
static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1,
do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_ecn = -1,
do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1,
@@ -43,10 +41,10 @@ int do_macos_sysctl(int update_every, usec_t dt) {
do_tcp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP packets", 1);
do_tcp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP errors", 1);
do_tcp_handshake = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP handshake issues", 1);
- do_ecn = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
+ do_ecn = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syscookies = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_connaborts = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
do_udp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP packets", 1);
do_udp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP errors", 1);
do_icmp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP packets", 1);
@@ -55,17 +53,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
do_ip_fragsout = config_get_boolean("plugin:macos:sysctl", "ipv4 fragments sent", 1);
do_ip_fragsin = config_get_boolean("plugin:macos:sysctl", "ipv4 fragments assembly", 1);
do_ip_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 errors", 1);
- do_ip6_packets = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsout = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsin = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6 = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_redir = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_echos = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_router = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_neighbor = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_types = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
+ do_ip6_packets = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 packets", CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsout = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments sent", CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsin = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments assembly", CONFIG_BOOLEAN_AUTO);
+ do_ip6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp6 = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_redir = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp redirects", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_echos = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp echos", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_router = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp router", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_neighbor = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp neighbor", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_types = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp types", CONFIG_BOOLEAN_AUTO);
do_uptime = config_get_boolean("plugin:macos:sysctl", "system uptime", 1);
}
@@ -77,7 +75,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
size_t size;
// NEEDED BY: do_loadavg
- static usec_t last_loadavg_usec = 0;
+ static usec_t next_loadavg_dt = 0;
struct loadavg sysload;
// NEEDED BY: do_swap
@@ -210,19 +208,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (last_loadavg_usec <= dt) {
+ if (next_loadavg_dt <= dt) {
if (likely(do_loadavg)) {
- if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
+ if (unlikely(GETSYSCTL_BY_NAME("vm.loadavg", sysload))) {
do_loadavg = 0;
error("DISABLED: system.load");
} else {
- st = rrdset_find_bytype("system", "load");
+ st = rrdset_find_bytype_localhost("system", "load");
if (unlikely(!st)) {
- st = rrdset_create("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(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st = 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(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -233,24 +233,25 @@ int do_macos_sysctl(int update_every, usec_t dt) {
}
}
- last_loadavg_usec = st->update_every * USEC_PER_SEC;
+ next_loadavg_dt = st->update_every * USEC_PER_SEC;
}
- else last_loadavg_usec -= dt;
+ else next_loadavg_dt -= dt;
// --------------------------------------------------------------------
if (likely(do_swap)) {
- if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
+ if (unlikely(GETSYSCTL_BY_NAME("vm.swapusage", swap_usage))) {
do_swap = 0;
error("DISABLED: system.swap");
} else {
- st = rrdset_find("system.swap");
+ st = rrdset_find_localhost("system.swap");
if (unlikely(!st)) {
- st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ 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, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -293,12 +294,13 @@ int do_macos_sysctl(int update_every, usec_t dt) {
iftot.ift_obytes += if2m->ifm_data.ifi_obytes;
}
}
- st = rrdset_find("system.ipv4");
+ st = rrdset_find_localhost("system.ipv4");
if (unlikely(!st)) {
- st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -313,7 +315,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
- if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.tcp.stats", tcpstat))){
do_tcp_packets = 0;
error("DISABLED: ipv4.tcppackets");
do_tcp_errors = 0;
@@ -330,14 +332,13 @@ int do_macos_sysctl(int update_every, usec_t dt) {
error("DISABLED: ipv4.ecnpkts");
} else {
if (likely(do_tcp_packets)) {
- st = rrdset_find("ipv4.tcppackets");
+ st = rrdset_find_localhost("ipv4.tcppackets");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
- "packets/s",
- 2600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets"
+ , "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -349,16 +350,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_tcp_errors)) {
- st = rrdset_find("ipv4.tcperrors");
+ st = rrdset_find_localhost("ipv4.tcperrors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
- "packets/s",
- 2700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s"
+ , 2700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -371,17 +371,16 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_tcp_handshake)) {
- st = rrdset_find("ipv4.tcphandshake");
+ st = rrdset_find_localhost("ipv4.tcphandshake");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
- "IPv4 TCP Handshake Issues",
- "events/s", 2900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues"
+ , "events/s", 2900, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -394,16 +393,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop))) {
- do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpconnaborts");
+ if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop))) {
+ do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpconnaborts");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -416,13 +416,14 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
- do_tcpext_ofo = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpofo");
+ if (do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
+ do_tcpext_ofo = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpofo");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -432,16 +433,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
- do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
+ if (do_tcpext_syscookies == CONFIG_BOOLEAN_YES || (do_tcpext_syscookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
+ do_tcpext_syscookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find("ipv4.tcpsyncookies");
+ st = rrdset_find_localhost("ipv4.tcpsyncookies");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -453,15 +455,16 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
- do_ecn = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.ecnpkts");
+ if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
+ do_ecn = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.ecnpkts");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -477,20 +480,20 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/udp.html
if (likely(do_udp_packets || do_udp_errors)) {
- if (unlikely(GETSYSCTL("net.inet.udp.stats", udpstat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.udp.stats", udpstat))) {
do_udp_packets = 0;
error("DISABLED: ipv4.udppackets");
do_udp_errors = 0;
error("DISABLED: ipv4.udperrors");
} else {
if (likely(do_udp_packets)) {
- st = rrdset_find("ipv4.udppackets");
+ st = rrdset_find_localhost("ipv4.udppackets");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
- "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets"
+ , "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -502,17 +505,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_udp_errors)) {
- st = rrdset_find("ipv4.udperrors");
+ st = rrdset_find_localhost("ipv4.udperrors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
- 2701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s"
+ , 2701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -529,7 +532,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp_packets || do_icmpmsg)) {
- if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.icmp.stats", icmpstat))) {
do_icmp_packets = 0;
error("DISABLED: ipv4.icmp");
error("DISABLED: ipv4.icmp_errors");
@@ -545,14 +548,13 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp_packets)) {
- st = rrdset_find("ipv4.icmp");
+ st = rrdset_find_localhost("ipv4.icmp");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
- 2602,
- update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s"
+ , 2602, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -563,15 +565,14 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find("ipv4.icmp_errors");
+ st = rrdset_find_localhost("ipv4.icmp_errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
- "packets/s",
- 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors"
+ , "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -585,15 +586,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmpmsg)) {
- st = rrdset_find("ipv4.icmpmsg");
+ st = rrdset_find_localhost("ipv4.icmpmsg");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
- "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages"
+ , "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchoReps", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -611,7 +612,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
if (likely(do_ip_packets || do_ip_fragsout || do_ip_fragsin || do_ip_errors)) {
- if (unlikely(GETSYSCTL("net.inet.ip.stats", ipstat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.ip.stats", ipstat))) {
do_ip_packets = 0;
error("DISABLED: ipv4.packets");
do_ip_fragsout = 0;
@@ -622,15 +623,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
error("DISABLED: ipv4.errors");
} else {
if (likely(do_ip_packets)) {
- st = rrdset_find("ipv4.packets");
+ st = rrdset_find_localhost("ipv4.packets");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s",
- 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s"
+ , 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -644,15 +645,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip_fragsout)) {
- st = rrdset_find("ipv4.fragsout");
+ st = rrdset_find_localhost("ipv4.fragsout");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent"
+ , "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -665,16 +666,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip_fragsin)) {
- st = rrdset_find("ipv4.fragsin");
+ st = rrdset_find_localhost("ipv4.fragsin");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsin", NULL, "fragments", NULL,
- "IPv4 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly"
+ , "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -687,21 +687,20 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip_errors)) {
- st = rrdset_find("ipv4.errors");
+ st = rrdset_find_localhost("ipv4.errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s",
- 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -719,7 +718,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
- if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet6.ip6.stats", ip6stat))) {
do_ip6_packets = 0;
error("DISABLED: ipv6.packets");
do_ip6_fragsout = 0;
@@ -729,19 +728,19 @@ int do_macos_sysctl(int update_every, usec_t dt) {
do_ip6_errors = 0;
error("DISABLED: ipv6.errors");
} else {
- if (do_ip6_packets == CONFIG_ONDEMAND_YES || (do_ip6_packets == CONFIG_ONDEMAND_ONDEMAND &&
+ if (do_ip6_packets == CONFIG_BOOLEAN_YES || (do_ip6_packets == CONFIG_BOOLEAN_AUTO &&
(ip6stat.ip6s_localout || ip6stat.ip6s_total ||
ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
- do_ip6_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.packets");
+ do_ip6_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.packets");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000,
- update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s"
+ , 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -754,19 +753,19 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ip6_fragsout == CONFIG_ONDEMAND_YES || (do_ip6_fragsout == CONFIG_ONDEMAND_ONDEMAND &&
+ if (do_ip6_fragsout == CONFIG_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO &&
(ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
ip6stat.ip6s_ofragments))) {
- do_ip6_fragsout = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsout");
+ do_ip6_fragsout = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.fragsout");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent"
+ , "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -778,20 +777,20 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ip6_fragsin == CONFIG_ONDEMAND_YES || (do_ip6_fragsin == CONFIG_ONDEMAND_ONDEMAND &&
+ if (do_ip6_fragsin == CONFIG_BOOLEAN_YES || (do_ip6_fragsin == CONFIG_BOOLEAN_AUTO &&
(ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
- do_ip6_fragsin = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsin");
+ do_ip6_fragsin = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.fragsin");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly"
+ , "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -804,7 +803,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ip6_errors == CONFIG_ONDEMAND_YES || (do_ip6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_ip6_errors == CONFIG_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && (
ip6stat.ip6s_toosmall ||
ip6stat.ip6s_odropped ||
ip6stat.ip6s_badoptions ||
@@ -814,22 +813,22 @@ int do_macos_sysctl(int update_every, usec_t dt) {
ip6stat.ip6s_tooshort ||
ip6stat.ip6s_cantforward ||
ip6stat.ip6s_noroute))) {
- do_ip6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.errors");
+ do_ip6_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -851,7 +850,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp6 || do_icmp6_redir || do_icmp6_errors || do_icmp6_echos || do_icmp6_router || do_icmp6_neighbor || do_icmp6_types)) {
- if (unlikely(GETSYSCTL("net.inet6.icmp6.stats", icmp6stat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet6.icmp6.stats", icmp6stat))) {
do_icmp6 = 0;
error("DISABLED: ipv6.icmp");
} else {
@@ -860,15 +859,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
icmp6_total.msgs_out += icmp6stat.icp6s_outhist[i];
}
icmp6_total.msgs_in += icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort;
- if (do_icmp6 == CONFIG_ONDEMAND_YES || (do_icmp6 == CONFIG_ONDEMAND_ONDEMAND && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
- do_icmp6 = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmp");
+ if (do_icmp6 == CONFIG_BOOLEAN_YES || (do_icmp6 == CONFIG_BOOLEAN_AUTO && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
+ do_icmp6 = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmp");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages",
- "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s"
+ , 10000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -879,15 +878,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_redir == CONFIG_ONDEMAND_YES || (do_icmp6_redir == CONFIG_ONDEMAND_ONDEMAND && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
- do_icmp6_redir = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpredir");
+ if (do_icmp6_redir == CONFIG_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
+ do_icmp6_redir = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmpredir");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects",
- "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects"
+ , "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -898,7 +897,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_errors == CONFIG_ONDEMAND_YES || (do_icmp6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_errors == CONFIG_BOOLEAN_YES || (do_icmp6_errors == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_badcode ||
icmp6stat.icp6s_badlen ||
icmp6stat.icp6s_checksum ||
@@ -910,22 +909,23 @@ int do_macos_sysctl(int update_every, usec_t dt) {
icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
- do_icmp6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmperrors");
+ do_icmp6_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmperrors");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors"
+ , "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -944,20 +944,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_echos == CONFIG_ONDEMAND_YES || (do_icmp6_echos == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_echos == CONFIG_BOOLEAN_YES || (do_icmp6_echos == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
- do_icmp6_echos = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpechos");
+ do_icmp6_echos = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmpechos");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s"
+ , 10200, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -970,20 +971,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_router == CONFIG_ONDEMAND_YES || (do_icmp6_router == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_router == CONFIG_BOOLEAN_YES || (do_icmp6_router == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
- do_icmp6_router = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmprouter");
+ do_icmp6_router = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmprouter");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages"
+ , "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -996,20 +998,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_neighbor == CONFIG_ONDEMAND_YES || (do_icmp6_neighbor == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_neighbor == CONFIG_BOOLEAN_YES || (do_icmp6_neighbor == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
- do_icmp6_neighbor = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpneighbor");
+ do_icmp6_neighbor = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmpneighbor");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages"
+ , "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -1022,7 +1025,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_types == CONFIG_ONDEMAND_YES || (do_icmp6_types == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_types == CONFIG_BOOLEAN_YES || (do_icmp6_types == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[1] ||
icmp6stat.icp6s_inhist[128] ||
icmp6stat.icp6s_inhist[129] ||
@@ -1033,22 +1036,22 @@ int do_macos_sysctl(int update_every, usec_t dt) {
icmp6stat.icp6s_outhist[133] ||
icmp6stat.icp6s_outhist[135] ||
icmp6stat.icp6s_outhist[136]))) {
- do_icmp6_types = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmptypes");
+ do_icmp6_types = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmptypes");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types",
- "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types"
+ , "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -1070,16 +1073,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_uptime)) {
- if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
+ if (unlikely(GETSYSCTL_BY_NAME("kern.boottime", boot_time))) {
do_uptime = 0;
error("DISABLED: system.uptime");
} else {
clock_gettime(CLOCK_REALTIME, &cur_time);
- st = rrdset_find("system.uptime");
+ st = rrdset_find_localhost("system.uptime");
if(unlikely(!st)) {
- st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000
+ , update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -1091,7 +1095,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
return 0;
}
-int getsysctl(const char *name, void *ptr, size_t len)
+int getsysctl_by_name(const char *name, void *ptr, size_t len)
{
size_t nlen = len;
diff --git a/src/main.c b/src/main.c
index ca134fcb0..a72585e28 100644
--- a/src/main.c
+++ b/src/main.c
@@ -10,7 +10,7 @@ void netdata_cleanup_and_exit(int ret) {
debug(D_EXIT, "Called: netdata_cleanup_and_exit()");
// save the database
- rrdset_save_all();
+ rrdhost_save_all();
// unlink the pid
if(pidfile[0]) {
@@ -23,7 +23,8 @@ void netdata_cleanup_and_exit(int ret) {
//kill_childs();
// free database
- rrdset_free_all();
+ sleep(2);
+ rrdhost_free_all();
#endif
info("netdata exiting. Bye bye...");
@@ -34,49 +35,55 @@ struct netdata_static_thread static_threads[] = {
#ifdef INTERNAL_PLUGIN_NFACCT
// nfacct requires root access
// so, we build it as an external plugin with setuid to root
- {"nfacct", "plugins", "nfacct", 1, NULL, NULL, nfacct_main},
+ {"nfacct", CONFIG_SECTION_PLUGINS, "nfacct", 1, NULL, NULL, nfacct_main},
#endif
- {"tc", "plugins", "tc", 1, NULL, NULL, tc_main},
- {"idlejitter", "plugins", "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
+ {"tc", CONFIG_SECTION_PLUGINS, "tc", 1, NULL, NULL, tc_main},
+ {"idlejitter", CONFIG_SECTION_PLUGINS, "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
#if defined(__FreeBSD__)
- {"freebsd", "plugins", "freebsd", 1, NULL, NULL, freebsd_main},
+ {"freebsd", CONFIG_SECTION_PLUGINS, "freebsd", 1, NULL, NULL, freebsd_main},
#elif defined(__APPLE__)
- {"macos", "plugins", "macos", 1, NULL, NULL, macos_main},
+ {"macos", CONFIG_SECTION_PLUGINS, "macos", 1, NULL, NULL, macos_main},
#else
- {"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
- {"diskspace", "plugins", "diskspace", 1, NULL, NULL, proc_diskspace_main},
+ {"proc", CONFIG_SECTION_PLUGINS, "proc", 1, NULL, NULL, proc_main},
+ {"diskspace", CONFIG_SECTION_PLUGINS, "diskspace", 1, NULL, NULL, proc_diskspace_main},
+ {"cgroups", CONFIG_SECTION_PLUGINS, "cgroups", 1, NULL, NULL, cgroups_main},
#endif /* __FreeBSD__, __APPLE__*/
- {"cgroups", "plugins", "cgroups", 1, NULL, NULL, cgroups_main},
- {"check", "plugins", "checks", 0, NULL, NULL, checks_main},
- {"backends", NULL, NULL, 1, NULL, NULL, backends_main},
- {"health", NULL, NULL, 1, NULL, NULL, health_main},
- {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main},
- {"web", NULL, NULL, 1, NULL, NULL, socket_listen_main_multi_threaded},
- {"web-single-threaded", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded},
- {NULL, NULL, NULL, 0, NULL, NULL, NULL}
+ {"check", CONFIG_SECTION_PLUGINS, "checks", 0, NULL, NULL, checks_main},
+ {"backends", NULL, NULL, 1, NULL, NULL, backends_main},
+ {"health", NULL, NULL, 1, NULL, NULL, health_main},
+ {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main},
+ {"web", NULL, NULL, 1, NULL, NULL, socket_listen_main_multi_threaded},
+ {"web-single-threaded", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded},
+ {"push-metrics", NULL, NULL, 0, NULL, NULL, rrdpush_sender_thread},
+ {NULL, NULL, NULL, 0, NULL, NULL, NULL}
};
void web_server_threading_selection(void) {
- int threaded = config_get_boolean("global", "multi threaded web server", 1);
+ web_server_mode = web_server_mode_id(config_get(CONFIG_SECTION_WEB, "mode", web_server_mode_name(web_server_mode)));
+
+ int multi_threaded = (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED);
+ int single_threaded = (web_server_mode == WEB_SERVER_MODE_SINGLE_THREADED);
int i;
for(i = 0; static_threads[i].name ; i++) {
if(static_threads[i].start_routine == socket_listen_main_multi_threaded)
- static_threads[i].enabled = threaded?1:0;
+ static_threads[i].enabled = multi_threaded;
if(static_threads[i].start_routine == socket_listen_main_single_threaded)
- static_threads[i].enabled = threaded?0:1;
+ static_threads[i].enabled = single_threaded;
}
- web_client_timeout = (int) config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
+ web_client_timeout = (int) config_get_number(CONFIG_SECTION_WEB, "disconnect idle clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
- web_donotrack_comply = config_get_boolean("global", "respect web browser do not track policy", web_donotrack_comply);
+ respect_web_browser_do_not_track_policy = config_get_boolean(CONFIG_SECTION_WEB, "respect do not track policy", respect_web_browser_do_not_track_policy);
+ web_x_frame_options = config_get(CONFIG_SECTION_WEB, "x-frame-options response header", "");
+ if(!*web_x_frame_options) web_x_frame_options = NULL;
#ifdef NETDATA_WITH_ZLIB
- web_enable_gzip = config_get_boolean("global", "enable web responses gzip compression", web_enable_gzip);
+ web_enable_gzip = config_get_boolean(CONFIG_SECTION_WEB, "enable gzip compression", web_enable_gzip);
- char *s = config_get("global", "web compression strategy", "default");
+ char *s = config_get(CONFIG_SECTION_WEB, "gzip compression strategy", "default");
if(!strcmp(s, "default"))
web_gzip_strategy = Z_DEFAULT_STRATEGY;
else if(!strcmp(s, "filtered"))
@@ -92,7 +99,7 @@ void web_server_threading_selection(void) {
web_gzip_strategy = Z_DEFAULT_STRATEGY;
}
- web_gzip_level = (int)config_get_number("global", "web compression level", 3);
+ web_gzip_level = (int)config_get_number(CONFIG_SECTION_WEB, "gzip compression level", 3);
if(web_gzip_level < 1) {
error("Invalid compression level %d. Valid levels are 1 (fastest) to 9 (best ratio). Proceeding with level 1 (fastest compression).", web_gzip_level);
web_gzip_level = 1;
@@ -218,12 +225,12 @@ struct option_def options[] = {
{ 'h', "Display this help message.", NULL, NULL},
{ 'P', "File to save a pid while running.", "filename", "do not save pid to a file"},
{ 'i', "The IP address to listen to.", "IP", "all IP addresses IPv4 and IPv6"},
- { 'k', "Check health configuration and exit.", NULL, NULL},
{ 'p', "API/Web port to use.", "port", "19999"},
{ 's', "Prefix for /proc and /sys (for containers).", "path", "no prefix"},
{ 't', "The internal clock of netdata.", "seconds", "1"},
{ 'u', "Run as user.", "username", "netdata"},
{ 'v', "Print netdata version and exit.", NULL, NULL},
+ { 'V', "Print netdata version and exit.", NULL, NULL},
{ 'W', "See Advanced options below.", "options", NULL},
};
@@ -256,7 +263,7 @@ void help(int exitcode) {
" +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->\n"
"\n"
" Copyright (C) 2016-2017, Costa Tsaousis <costa@tsaousis.gr>\n"
- " Released under GNU Public License v3 or later.\n"
+ " Released under GNU General Public License v3 or later.\n"
" All rights reserved.\n"
"\n"
" Home Page : https://my-netdata.io\n"
@@ -332,10 +339,191 @@ static const char *verify_required_directory(const char *dir) {
return dir;
}
-int main(int argc, char **argv)
-{
- char *hostname = "localhost";
- int i, check_config = 0;
+void log_init(void) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/debug.log", netdata_configured_log_dir);
+ stdout_filename = config_get(CONFIG_SECTION_GLOBAL, "debug log", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s/error.log", netdata_configured_log_dir);
+ stderr_filename = config_get(CONFIG_SECTION_GLOBAL, "error log", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s/access.log", netdata_configured_log_dir);
+ stdaccess_filename = config_get(CONFIG_SECTION_GLOBAL, "access log", filename);
+
+ error_log_throttle_period_backup =
+ error_log_throttle_period = config_get_number(CONFIG_SECTION_GLOBAL, "errors flood protection period", error_log_throttle_period);
+ error_log_errors_per_period = (unsigned long)config_get_number(CONFIG_SECTION_GLOBAL, "errors to trigger flood protection", (long long int)error_log_errors_per_period);
+
+ setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get(CONFIG_SECTION_GLOBAL, "errors flood protection period" , ""), 1);
+ setenv("NETDATA_ERRORS_PER_PERIOD", config_get(CONFIG_SECTION_GLOBAL, "errors to trigger flood protection", ""), 1);
+}
+
+static void backwards_compatible_config() {
+ // allow existing configurations to work with the current version of netdata
+
+ if(config_exists(CONFIG_SECTION_GLOBAL, "multi threaded web server")) {
+ int mode = config_get_boolean(CONFIG_SECTION_GLOBAL, "multi threaded web server", 1);
+ web_server_mode = (mode)?WEB_SERVER_MODE_MULTI_THREADED:WEB_SERVER_MODE_SINGLE_THREADED;
+ }
+
+ // move [global] options to the [web] section
+ config_move(CONFIG_SECTION_GLOBAL, "http port listen backlog",
+ CONFIG_SECTION_WEB, "listen backlog");
+
+ config_move(CONFIG_SECTION_GLOBAL, "bind socket to IP",
+ CONFIG_SECTION_WEB, "bind to");
+
+ config_move(CONFIG_SECTION_GLOBAL, "bind to",
+ CONFIG_SECTION_WEB, "bind to");
+
+ config_move(CONFIG_SECTION_GLOBAL, "port",
+ CONFIG_SECTION_WEB, "default port");
+
+ config_move(CONFIG_SECTION_GLOBAL, "default port",
+ CONFIG_SECTION_WEB, "default port");
+
+ config_move(CONFIG_SECTION_GLOBAL, "disconnect idle web clients after seconds",
+ CONFIG_SECTION_WEB, "disconnect idle clients after seconds");
+
+ config_move(CONFIG_SECTION_GLOBAL, "respect web browser do not track policy",
+ CONFIG_SECTION_WEB, "respect do not track policy");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web x-frame-options header",
+ CONFIG_SECTION_WEB, "x-frame-options response header");
+
+ config_move(CONFIG_SECTION_GLOBAL, "enable web responses gzip compression",
+ CONFIG_SECTION_WEB, "enable gzip compression");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web compression strategy",
+ CONFIG_SECTION_WEB, "gzip compression strategy");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web compression level",
+ CONFIG_SECTION_WEB, "gzip compression level");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web files owner",
+ CONFIG_SECTION_WEB, "web files owner");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web files group",
+ CONFIG_SECTION_WEB, "web files group");
+}
+
+static void get_netdata_configured_variables() {
+ backwards_compatible_config();
+
+ // ------------------------------------------------------------------------
+ // get the hostname
+
+ char buf[HOSTNAME_MAX + 1];
+ if(gethostname(buf, HOSTNAME_MAX) == -1)
+ error("Cannot get machine hostname.");
+
+ netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", buf);
+ debug(D_OPTIONS, "hostname set to '%s'", netdata_configured_hostname);
+
+ netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", CONFIG_DIR);
+
+ // ------------------------------------------------------------------------
+ // get default database size
+
+ default_rrd_history_entries = (int) config_get_number(CONFIG_SECTION_GLOBAL, "history", align_entries_to_pagesize(default_rrd_memory_mode, RRD_DEFAULT_HISTORY_ENTRIES));
+
+ long h = align_entries_to_pagesize(default_rrd_memory_mode, default_rrd_history_entries);
+ if(h != default_rrd_history_entries) {
+ config_set_number(CONFIG_SECTION_GLOBAL, "history", h);
+ default_rrd_history_entries = (int)h;
+ }
+
+ if(default_rrd_history_entries < 5 || default_rrd_history_entries > RRD_HISTORY_ENTRIES_MAX) {
+ error("Invalid history entries %d given. Defaulting to %d.", default_rrd_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
+ default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
+ }
+
+ // ------------------------------------------------------------------------
+ // get default database update frequency
+
+ default_rrd_update_every = (int) config_get_number(CONFIG_SECTION_GLOBAL, "update every", UPDATE_EVERY);
+ if(default_rrd_update_every < 1 || default_rrd_update_every > 600) {
+ error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", default_rrd_update_every, UPDATE_EVERY_MAX);
+ default_rrd_update_every = UPDATE_EVERY;
+ }
+
+ // ------------------------------------------------------------------------
+ // let the plugins know the min update_every
+
+ // get system paths
+ netdata_configured_config_dir = config_get(CONFIG_SECTION_GLOBAL, "config directory", CONFIG_DIR);
+ netdata_configured_log_dir = config_get(CONFIG_SECTION_GLOBAL, "log directory", LOG_DIR);
+ netdata_configured_plugins_dir = config_get(CONFIG_SECTION_GLOBAL, "plugins directory", PLUGINS_DIR);
+ netdata_configured_web_dir = config_get(CONFIG_SECTION_GLOBAL, "web files directory", WEB_DIR);
+ netdata_configured_cache_dir = config_get(CONFIG_SECTION_GLOBAL, "cache directory", CACHE_DIR);
+ netdata_configured_varlib_dir = config_get(CONFIG_SECTION_GLOBAL, "lib directory", VARLIB_DIR);
+ netdata_configured_home_dir = config_get(CONFIG_SECTION_GLOBAL, "home directory", CACHE_DIR);
+
+ // ------------------------------------------------------------------------
+ // get default memory mode for the database
+
+ default_rrd_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_GLOBAL, "memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));
+
+ // ------------------------------------------------------------------------
+
+ netdata_configured_host_prefix = config_get(CONFIG_SECTION_GLOBAL, "host access prefix", "");
+
+ // --------------------------------------------------------------------
+ // get KSM settings
+
+#ifdef MADV_MERGEABLE
+ enable_ksm = config_get_boolean(CONFIG_SECTION_GLOBAL, "memory deduplication (ksm)", enable_ksm);
+#endif
+
+ // --------------------------------------------------------------------
+ // get various system parameters
+
+ get_system_HZ();
+ get_system_cpus();
+ get_system_pid_max();
+}
+
+void set_global_environment() {
+ {
+ char b[16];
+ snprintfz(b, 15, "%d", default_rrd_update_every);
+ setenv("NETDATA_UPDATE_EVERY", b, 1);
+ }
+
+ setenv("NETDATA_HOSTNAME" , netdata_configured_hostname, 1);
+ setenv("NETDATA_CONFIG_DIR" , verify_required_directory(netdata_configured_config_dir), 1);
+ setenv("NETDATA_PLUGINS_DIR", verify_required_directory(netdata_configured_plugins_dir), 1);
+ setenv("NETDATA_WEB_DIR" , verify_required_directory(netdata_configured_web_dir), 1);
+ setenv("NETDATA_CACHE_DIR" , verify_required_directory(netdata_configured_cache_dir), 1);
+ setenv("NETDATA_LIB_DIR" , verify_required_directory(netdata_configured_varlib_dir), 1);
+ setenv("NETDATA_LOG_DIR" , verify_required_directory(netdata_configured_log_dir), 1);
+ setenv("HOME" , verify_required_directory(netdata_configured_home_dir), 1);
+ setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
+
+ // avoid flood calls to stat(/etc/localtime)
+ // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
+ setenv("TZ", ":/etc/localtime", 0);
+
+ // set the path we need
+ char path[1024 + 1], *p = getenv("PATH");
+ if(!p) p = "/bin:/usr/bin";
+ snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
+ setenv("PATH", config_get(CONFIG_SECTION_PLUGINS, "PATH environment variable", path), 1);
+
+ // python options
+ p = getenv("PYTHONPATH");
+ if(!p) p = "";
+ setenv("PYTHONPATH", config_get(CONFIG_SECTION_PLUGINS, "PYTHONPATH environment variable", p), 1);
+
+ // disable buffering for python plugins
+ setenv("PYTHONUNBUFFERED", "1", 1);
+
+ // switch to standard locale for plugins
+ setenv("LC_ALL", "C", 1);
+}
+
+int main(int argc, char **argv) {
+ int i;
int config_loaded = 0;
int dont_fork = 0;
size_t wanted_stacksize = 0, stacksize = 0;
@@ -360,12 +548,12 @@ int main(int argc, char **argv)
remove_option(i, &argc, argv);
}
else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) {
- config_set("global", "host access prefix", argv[i+1]);
+ config_set(CONFIG_SECTION_GLOBAL, "host access prefix", argv[i+1]);
fprintf(stderr, "%s: deprecated option -- %s -- please use -s instead.\n", argv[0], argv[i]);
remove_option(i, &argc, argv);
}
else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) {
- config_set("global", "history", argv[i+1]);
+ config_set(CONFIG_SECTION_GLOBAL, "history", argv[i+1]);
fprintf(stderr, "%s: deprecated option -- %s -- This option will be removed with V2.*.\n", argv[0], argv[i]);
remove_option(i, &argc, argv);
}
@@ -395,7 +583,7 @@ int main(int argc, char **argv)
while( (opt = getopt(argc, argv, optstring)) != -1 ) {
switch(opt) {
case 'c':
- if(load_config(optarg, 1) != 1) {
+ if(config_load(optarg, 1) != 1) {
error("Cannot load configuration file %s.", optarg);
exit(1);
}
@@ -411,38 +599,42 @@ int main(int argc, char **argv)
help(0);
break;
case 'i':
- config_set("global", "bind to", optarg);
- break;
- case 'k':
- dont_fork = 1;
- check_config = 1;
+ config_set(CONFIG_SECTION_WEB, "bind to", optarg);
break;
case 'P':
strncpy(pidfile, optarg, FILENAME_MAX);
pidfile[FILENAME_MAX] = '\0';
break;
case 'p':
- config_set("global", "default port", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "default port", optarg);
break;
case 's':
- config_set("global", "host access prefix", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "host access prefix", optarg);
break;
case 't':
- config_set("global", "update every", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "update every", optarg);
break;
case 'u':
- config_set("global", "run as user", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "run as user", optarg);
break;
case 'v':
- // TODO: Outsource version to makefile which can compute version from git.
- printf("netdata %s\n", VERSION);
+ case 'V':
+ printf("%s %s\n", program_name, program_version);
return 0;
case 'W':
{
char* stacksize_string = "stacksize=";
char* debug_flags_string = "debug_flags=";
if(strcmp(optarg, "unittest") == 0) {
- rrd_update_every = 1;
+ default_rrd_update_every = 1;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ if(!config_loaded) config_load(NULL, 0);
+ get_netdata_configured_variables();
+ default_rrd_update_every = 1;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ default_health_enabled = 0;
+ rrd_init("unittest");
+ default_rrdpush_enabled = 0;
if(run_all_mockup_tests()) exit(1);
if(unit_test_storage()) exit(1);
fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
@@ -492,11 +684,11 @@ int main(int argc, char **argv)
}
else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) {
optarg += strlen(stacksize_string);
- config_set("global", "pthread stack size", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "pthread stack size", optarg);
}
else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) {
optarg += strlen(debug_flags_string);
- config_set("global", "debug flags", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "debug flags", optarg);
debug_flags = strtoull(optarg, NULL, 0);
}
}
@@ -508,150 +700,85 @@ int main(int argc, char **argv)
}
}
+#ifdef _SC_OPEN_MAX
+ // close all open file descriptors, except the standard ones
+ // the caller may have left open files (lxc-attach has this issue)
+ {
+ int fd;
+ for(fd = (int) (sysconf(_SC_OPEN_MAX) - 1); fd > 2; fd--)
+ if(fd_is_valid(fd)) close(fd);
+ }
+#endif
+
if(!config_loaded)
- load_config(NULL, 0);
+ config_load(NULL, 0);
+ // ------------------------------------------------------------------------
+ // initialize netdata
{
- char *pmax = config_get("global", "glibc malloc arena max for plugins", "1");
+ char *pmax = config_get(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for plugins", "1");
if(pmax && *pmax)
setenv("MALLOC_ARENA_MAX", pmax, 1);
#if defined(HAVE_C_MALLOPT)
- int i = config_get_number("global", "glibc malloc arena max for netdata", 1);
+ i = (int)config_get_number(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for netdata", 1);
if(i > 0)
mallopt(M_ARENA_MAX, 1);
#endif
- char *config_dir = config_get("global", "config directory", CONFIG_DIR);
-
// prepare configuration environment variables for the plugins
- setenv("NETDATA_CONFIG_DIR" , verify_required_directory(config_dir) , 1);
- setenv("NETDATA_PLUGINS_DIR", verify_required_directory(config_get("global", "plugins directory" , PLUGINS_DIR)), 1);
- setenv("NETDATA_WEB_DIR" , verify_required_directory(config_get("global", "web files directory", WEB_DIR)) , 1);
- setenv("NETDATA_CACHE_DIR" , verify_required_directory(config_get("global", "cache directory" , CACHE_DIR)) , 1);
- setenv("NETDATA_LIB_DIR" , verify_required_directory(config_get("global", "lib directory" , VARLIB_DIR)) , 1);
- setenv("NETDATA_LOG_DIR" , verify_required_directory(config_get("global", "log directory" , LOG_DIR)) , 1);
-
- setenv("NETDATA_HOST_PREFIX", config_get("global", "host access prefix" , "") , 1);
- setenv("HOME" , config_get("global", "home directory" , CACHE_DIR) , 1);
- // disable buffering for python plugins
- setenv("PYTHONUNBUFFERED", "1", 1);
-
- // avoid flood calls to stat(/etc/localtime)
- // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
- setenv("TZ", ":/etc/localtime", 0);
+ get_netdata_configured_variables();
+ set_global_environment();
// work while we are cd into config_dir
// to allow the plugins refer to their config
// files using relative filenames
- if(chdir(config_dir) == -1)
- fatal("Cannot cd to '%s'", config_dir);
-
- char path[1024 + 1], *p = getenv("PATH");
- if(!p) p = "/bin:/usr/bin";
- snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
- setenv("PATH", config_get("plugins", "PATH environment variable", path), 1);
+ if(chdir(netdata_configured_config_dir) == -1)
+ fatal("Cannot cd to '%s'", netdata_configured_config_dir);
}
char *user = NULL;
+
{
- char *flags = config_get("global", "debug flags", "0x00000000");
+ // --------------------------------------------------------------------
+ // get the debugging flags from the configuration file
+
+ char *flags = config_get(CONFIG_SECTION_GLOBAL, "debug flags", "0x0000000000000000");
setenv("NETDATA_DEBUG_FLAGS", flags, 1);
debug_flags = strtoull(flags, NULL, 0);
- debug(D_OPTIONS, "Debug flags set to '0x%8llx'.", debug_flags);
+ debug(D_OPTIONS, "Debug flags set to '0x%" PRIX64 "'.", debug_flags);
if(debug_flags != 0) {
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#ifdef HAVE_SYS_PRCTL_H
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-#endif /* __FreeBSD__ || __APPLE__*/
- }
-
- // --------------------------------------------------------------------
-
-#ifdef MADV_MERGEABLE
- enable_ksm = config_get_boolean("global", "memory deduplication (ksm)", enable_ksm);
-#else
-#warning "Kernel memory deduplication (KSM) is not available"
#endif
+ }
- // --------------------------------------------------------------------
-
- global_host_prefix = config_get("global", "host access prefix", "");
- setenv("NETDATA_HOST_PREFIX", global_host_prefix, 1);
- get_system_HZ();
- get_system_cpus();
- get_system_pid_max();
-
// --------------------------------------------------------------------
+ // get log filenames and settings
- stdout_filename = config_get("global", "debug log", LOG_DIR "/debug.log");
- stderr_filename = config_get("global", "error log", LOG_DIR "/error.log");
- stdaccess_filename = config_get("global", "access log", LOG_DIR "/access.log");
-
- error_log_throttle_period_backup =
- error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
- setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period" , ""), 1);
-
- error_log_errors_per_period = (unsigned long)config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
- setenv("NETDATA_ERRORS_PER_PERIOD" , config_get("global", "errors to trigger flood protection", ""), 1);
-
- if(check_config) {
- stdout_filename = stderr_filename = stdaccess_filename = "system";
- error_log_throttle_period = 0;
- error_log_errors_per_period = 0;
- }
+ log_init();
error_log_limit_unlimited();
- // --------------------------------------------------------------------
-
- rrd_memory_mode = rrd_memory_mode_id(config_get("global", "memory mode", rrd_memory_mode_name(rrd_memory_mode)));
// --------------------------------------------------------------------
-
+ // load stream.conf
{
- char hostnamebuf[HOSTNAME_MAX + 1];
- if(gethostname(hostnamebuf, HOSTNAME_MAX) == -1)
- error("WARNING: Cannot get machine hostname.");
- hostname = config_get("global", "hostname", hostnamebuf);
- debug(D_OPTIONS, "hostname set to '%s'", hostname);
- setenv("NETDATA_HOSTNAME", hostname, 1);
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/stream.conf", netdata_configured_config_dir);
+ appconfig_load(&stream_config, filename, 0);
}
- // --------------------------------------------------------------------
-
- rrd_default_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
- if(rrd_default_history_entries < 5 || rrd_default_history_entries > RRD_HISTORY_ENTRIES_MAX) {
- error("Invalid history entries %d given. Defaulting to %d.", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
- rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
- }
- else {
- debug(D_OPTIONS, "save lines set to %d.", rrd_default_history_entries);
- }
-
- // --------------------------------------------------------------------
-
- rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
- if(rrd_update_every < 1 || rrd_update_every > 600) {
- error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", rrd_update_every, UPDATE_EVERY_MAX);
- rrd_update_every = UPDATE_EVERY;
- }
- else debug(D_OPTIONS, "update timer set to %d.", rrd_update_every);
-
- // let the plugins know the min update_every
- {
- char buf[16];
- snprintfz(buf, 15, "%d", rrd_update_every);
- setenv("NETDATA_UPDATE_EVERY", buf, 1);
- }
// --------------------------------------------------------------------
+ // setup process signals
// block signals while initializing threads.
// this causes the threads to block signals.
@@ -697,7 +824,9 @@ int main(int argc, char **argv)
if(sigaction(SIGUSR2, &sa, NULL) == -1)
error("Failed to change signal handler for SIGUSR2");
+
// --------------------------------------------------------------------
+ // get the required stack size of the threads of netdata
i = pthread_attr_init(&attr);
if(i != 0)
@@ -709,30 +838,44 @@ int main(int argc, char **argv)
else
debug(D_OPTIONS, "initial pthread stack size is %zu bytes", stacksize);
- wanted_stacksize = (size_t)config_get_number("global", "pthread stack size", (long)stacksize);
+ wanted_stacksize = (size_t)config_get_number(CONFIG_SECTION_GLOBAL, "pthread stack size", (long)stacksize);
+
// --------------------------------------------------------------------
+ // check which threads are enabled and initialize them
for (i = 0; static_threads[i].name != NULL ; i++) {
struct netdata_static_thread *st = &static_threads[i];
- if(st->config_name) st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
- if(st->enabled && st->init_routine) st->init_routine();
+ if(st->config_name)
+ st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
+
+ if(st->enabled && st->init_routine)
+ st->init_routine();
}
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
// get the user we should run
+
// IMPORTANT: this is required before web_files_uid()
- user = config_get("global", "run as user" , (getuid() == 0)?NETDATA_USER:"");
+ if(getuid() == 0) {
+ user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER);
+ }
+ else {
+ struct passwd *passwd = getpwuid(getuid());
+ 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
- if(!check_config)
+ if(web_server_mode != WEB_SERVER_MODE_NONE)
create_listen_sockets();
}
@@ -744,20 +887,22 @@ int main(int argc, char **argv)
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#ifdef HAVE_SYS_PRCTL_H
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-#endif /* __FreeBSD__ || __APPLE__*/
+#endif
}
#endif /* NETDATA_INTERNAL_CHECKS */
+
// fork, switch user, create pid file, set process priority
if(become_daemon(dont_fork, user) == -1)
fatal("Cannot daemonize myself.");
info("netdata started on pid %d.", getpid());
+
// ------------------------------------------------------------------------
- // get default pthread stack size
+ // set default pthread stack size - after we have forked
if(stacksize < wanted_stacksize) {
i = pthread_attr_setstacksize(&attr, wanted_stacksize);
@@ -767,29 +912,19 @@ int main(int argc, char **argv)
debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
}
- // ------------------------------------------------------------------------
- // initialize rrd host
-
- rrdhost_init(hostname);
// ------------------------------------------------------------------------
- // initialize the registry
+ // initialize rrd, registry, health, rrdpush, etc.
- registry_init();
-
- // ------------------------------------------------------------------------
- // initialize health monitoring
+ rrd_init(netdata_configured_hostname);
- health_init();
-
- if(check_config)
- exit(1);
// ------------------------------------------------------------------------
// enable log flood protection
error_log_limit_reset();
+
// ------------------------------------------------------------------------
// spawn the threads
@@ -814,6 +949,7 @@ int main(int argc, char **argv)
info("netdata initialization completed. Enjoy real-time performance monitoring!");
+
// ------------------------------------------------------------------------
// block signals while initializing threads.
sigset_t sigset;
diff --git a/src/main.h b/src/main.h
index 49afaef12..38df0fea4 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,8 +1,6 @@
#ifndef NETDATA_MAIN_H
#define NETDATA_MAIN_H 1
-extern volatile sig_atomic_t netdata_exit;
-
/**
* This struct contains information about command line options.
*/
diff --git a/src/plugin_checks.c b/src/plugin_checks.c
index fcc542e68..3a0a83bda 100644
--- a/src/plugin_checks.c
+++ b/src/plugin_checks.c
@@ -11,23 +11,26 @@ void *checks_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- usec_t usec = 0, susec = rrd_update_every * USEC_PER_SEC, loop_usec = 0, total_susec = 0;
+ usec_t usec = 0, susec = localhost->rrd_update_every * USEC_PER_SEC, loop_usec = 0, total_susec = 0;
struct timeval now, last, loop;
RRDSET *check1, *check2, *check3, *apps_cpu = NULL;
- check1 = rrdset_create("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(check1, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check1, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ check1 = rrdset_create_localhost("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds"
+ , "a million !", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(check1, "absolute", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check1, "incremental", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- check2 = rrdset_create("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(check2, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check2, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ check2 = rrdset_create_localhost("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds"
+ , "a million !", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(check2, "absolute", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check2, "incremental", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- check3 = rrdset_create("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference", "microseconds diff", 99999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(check3, "caller", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check3, "netdata", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ check3 = rrdset_create_localhost("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference"
+ , "microseconds diff", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(check3, "caller", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check3, "netdata", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
now_realtime_timeval(&last);
while(1) {
@@ -39,8 +42,8 @@ void *checks_main(void *ptr) {
usec = loop_usec - susec;
debug(D_PROCNETDEV_LOOP, "CHECK: last loop took %llu usec (worked for %llu, sleeped for %llu).", loop_usec, usec, susec);
- if(usec < (rrd_update_every * USEC_PER_SEC / 2ULL)) susec = (rrd_update_every * USEC_PER_SEC) - usec;
- else susec = rrd_update_every * USEC_PER_SEC / 2ULL;
+ if(usec < (localhost->rrd_update_every * USEC_PER_SEC / 2ULL)) susec = (localhost->rrd_update_every * USEC_PER_SEC) - usec;
+ else susec = localhost->rrd_update_every * USEC_PER_SEC / 2ULL;
// --------------------------------------------------------------------
// Calculate loop time
@@ -68,7 +71,7 @@ void *checks_main(void *ptr) {
// --------------------------------------------------------------------
// check chart 3
- if(!apps_cpu) apps_cpu = rrdset_find("apps.cpu");
+ if(!apps_cpu) apps_cpu = rrdset_find_localhost("apps.cpu");
if(check3->counter_done) rrdset_next_usec(check3, loop_usec);
now_realtime_timeval(&loop);
rrddim_set(check3, "caller", (long long) dt_usec(&loop, &check1->last_collected_time));
diff --git a/src/plugin_freebsd.c b/src/plugin_freebsd.c
index bdc3599ea..31ab6e0c4 100644
--- a/src/plugin_freebsd.c
+++ b/src/plugin_freebsd.c
@@ -1,5 +1,62 @@
#include "common.h"
+static struct freebsd_module {
+ const char *name;
+ const char *dim;
+
+ int enabled;
+
+ int (*func)(int update_every, usec_t dt);
+ usec_t duration;
+
+ RRDDIM *rd;
+
+} freebsd_modules[] = {
+
+ // system metrics
+ { .name = "kern.cp_time", .dim = "cp_time", .enabled = 1, .func = do_kern_cp_time },
+ { .name = "vm.loadavg", .dim = "loadavg", .enabled = 1, .func = do_vm_loadavg },
+ { .name = "system.ram", .dim = "system_ram", .enabled = 1, .func = do_system_ram },
+ { .name = "vm.swap_info", .dim = "swap", .enabled = 1, .func = do_vm_swap_info },
+ { .name = "vm.stats.vm.v_swappgs", .dim = "swap_io", .enabled = 1, .func = do_vm_stats_sys_v_swappgs },
+ { .name = "vm.vmtotal", .dim = "vmtotal", .enabled = 1, .func = do_vm_vmtotal },
+ { .name = "vm.stats.vm.v_forks", .dim = "forks", .enabled = 1, .func = do_vm_stats_sys_v_forks },
+ { .name = "vm.stats.sys.v_swtch", .dim = "context_swtch", .enabled = 1, .func = do_vm_stats_sys_v_swtch },
+ { .name = "hw.intrcnt", .dim = "hw_intr", .enabled = 1, .func = do_hw_intcnt },
+ { .name = "vm.stats.sys.v_intr", .dim = "dev_intr", .enabled = 1, .func = do_vm_stats_sys_v_intr },
+ { .name = "vm.stats.sys.v_soft", .dim = "soft_intr", .enabled = 1, .func = do_vm_stats_sys_v_soft },
+ { .name = "net.isr", .dim = "net_isr", .enabled = 1, .func = do_net_isr },
+ { .name = "kern.ipc.sem", .dim = "semaphores", .enabled = 1, .func = do_kern_ipc_sem },
+ { .name = "kern.ipc.shm", .dim = "shared_memory", .enabled = 1, .func = do_kern_ipc_shm },
+ { .name = "kern.ipc.msq", .dim = "message_queues", .enabled = 1, .func = do_kern_ipc_msq },
+ { .name = "uptime", .dim = "uptime", .enabled = 1, .func = do_uptime },
+
+ // memory metrics
+ { .name = "vm.stats.vm.v_pgfaults", .dim = "pgfaults", .enabled = 1, .func = do_vm_stats_sys_v_pgfaults },
+
+ // CPU metrics
+ { .name = "kern.cp_times", .dim = "cp_times", .enabled = 1, .func = do_kern_cp_times },
+
+ // disk metrics
+ { .name = "kern.devstat", .dim = "kern_devstat", .enabled = 1, .func = do_kern_devstat },
+ { .name = "getmntinfo", .dim = "getmntinfo", .enabled = 1, .func = do_getmntinfo },
+
+ // network metrics
+ { .name = "net.inet.tcp.states", .dim = "tcp_states", .enabled = 1, .func = do_net_inet_tcp_states },
+ { .name = "net.inet.tcp.stats", .dim = "tcp_stats", .enabled = 1, .func = do_net_inet_tcp_stats },
+ { .name = "net.inet.udp.stats", .dim = "udp_stats", .enabled = 1, .func = do_net_inet_udp_stats },
+ { .name = "net.inet.icmp.stats", .dim = "icmp_stats", .enabled = 1, .func = do_net_inet_icmp_stats },
+ { .name = "net.inet.ip.stats", .dim = "ip_stats", .enabled = 1, .func = do_net_inet_ip_stats },
+ { .name = "net.inet6.ip6.stats", .dim = "ip6_stats", .enabled = 1, .func = do_net_inet6_ip6_stats },
+ { .name = "net.inet6.icmp6.stats", .dim = "icmp6_stats", .enabled = 1, .func = do_net_inet6_icmp6_stats },
+
+ // network interfaces metrics
+ { .name = "getifaddrs", .dim = "getifaddrs", .enabled = 1, .func = do_getifaddrs },
+
+ // the terminator of this array
+ { .name = NULL, .dim = NULL, .enabled = 0, .func = NULL }
+};
+
void *freebsd_main(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
@@ -11,46 +68,80 @@ void *freebsd_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- // disable (by default) various interface that are not needed
- /*
- config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
- config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
- */
+ int vdo_cpu_netdata = config_get_boolean("plugin:freebsd", "netdata server resources", 1);
- // when ZERO, attempt to do it
- int vdo_cpu_netdata = !config_get_boolean("plugin:freebsd", "netdata server resources", 1);
- int vdo_freebsd_sysctl = !config_get_boolean("plugin:freebsd", "sysctl", 1);
+ // initialize FreeBSD plugin
+ if (freebsd_plugin_init())
+ netdata_exit = 1;
- // keep track of the time each module was called
- unsigned long long sutime_freebsd_sysctl = 0ULL;
+ // check the enabled status for each module
+ int i;
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
- usec_t step = rrd_update_every * USEC_PER_SEC;
- for(;;) {
- usec_t now = now_realtime_usec();
- usec_t next = now - (now % step) + step;
+ pm->enabled = config_get_boolean("plugin:freebsd", pm->name, pm->enabled);
+ pm->duration = 0ULL;
+ pm->rd = NULL;
+ }
- while(now < next) {
- sleep_usec(next - now);
- now = now_realtime_usec();
- }
+ usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+
+ for(;;) {
+ usec_t hb_dt = heartbeat_next(&hb, step);
+ usec_t duration = 0ULL;
if(unlikely(netdata_exit)) break;
// BEGIN -- the job to be done
- if(!vdo_freebsd_sysctl) {
- debug(D_PROCNETDEV_LOOP, "FREEBSD: calling do_freebsd_sysctl().");
- now = now_realtime_usec();
- vdo_freebsd_sysctl = do_freebsd_sysctl(rrd_update_every, (sutime_freebsd_sysctl > 0)?now - sutime_freebsd_sysctl:0ULL);
- sutime_freebsd_sysctl = now;
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
+ if(unlikely(!pm->enabled)) continue;
+
+ debug(D_PROCNETDEV_LOOP, "FREEBSD calling %s.", pm->name);
+
+ pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
+ pm->duration = heartbeat_dt_usec(&hb) - duration;
+ duration += pm->duration;
+
+ if(unlikely(netdata_exit)) break;
}
- if(unlikely(netdata_exit)) break;
// END -- the job is done
// --------------------------------------------------------------------
- if(!vdo_cpu_netdata) {
+ if(vdo_cpu_netdata) {
+ static RRDSET *st = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_find_bytype_localhost("netdata", "plugin_freebsd_modules");
+
+ if(!st) {
+ st = rrdset_create_localhost("netdata", "plugin_freebsd_modules", NULL, "freebsd", NULL
+ , "NetData FreeBSD Plugin Modules Durations", "milliseconds/run", 132001
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
+ if(unlikely(!pm->enabled)) continue;
+
+ pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ }
+ }
+ }
+ else rrdset_next(st);
+
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
+ if(unlikely(!pm->enabled)) continue;
+
+ rrddim_set_by_pointer(st, pm->rd, pm->duration);
+ }
+ rrdset_done(st);
+
global_statistics_charts();
registry_statistics();
}
@@ -62,18 +153,3 @@ void *freebsd_main(void *ptr) {
pthread_exit(NULL);
return NULL;
}
-
-int getsysctl(const char *name, void *ptr, size_t len)
-{
- size_t nlen = len;
-
- if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
- return 1;
- }
- if (unlikely(nlen != len)) {
- error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
- return 1;
- }
- return 0;
-}
diff --git a/src/plugin_freebsd.h b/src/plugin_freebsd.h
index e4767a091..166c64338 100644
--- a/src/plugin_freebsd.h
+++ b/src/plugin_freebsd.h
@@ -3,12 +3,117 @@
#include <sys/sysctl.h>
-#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
-
void *freebsd_main(void *ptr);
-int getsysctl(const char *name, void *ptr, size_t len);
+extern int freebsd_plugin_init();
+
+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_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);
+extern int do_vm_stats_sys_v_swtch(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_forks(int update_every, usec_t dt);
+extern int do_vm_swap_info(int update_every, usec_t dt);
+extern int do_system_ram(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt);
+extern int do_kern_ipc_sem(int update_every, usec_t dt);
+extern int do_kern_ipc_shm(int update_every, usec_t dt);
+extern int do_kern_ipc_msq(int update_every, usec_t dt);
+extern int do_uptime(int update_every, usec_t dt);
+extern int do_net_isr(int update_every, usec_t dt);
+extern int do_net_inet_tcp_states(int update_every, usec_t dt);
+extern int do_net_inet_tcp_stats(int update_every, usec_t dt);
+extern int do_net_inet_udp_stats(int update_every, usec_t dt);
+extern int do_net_inet_icmp_stats(int update_every, usec_t dt);
+extern int do_net_inet_ip_stats(int update_every, usec_t dt);
+extern int do_net_inet6_ip6_stats(int update_every, usec_t dt);
+extern int do_net_inet6_icmp6_stats(int update_every, usec_t dt);
+extern int do_getifaddrs(int update_every, usec_t dt);
+extern int do_getmntinfo(int update_every, usec_t dt);
+extern int do_kern_devstat(int update_every, usec_t dt);
+
+#define GETSYSCTL_MIB(name, mib) getsysctl_mib(name, mib, sizeof(mib)/sizeof(int))
+
+static inline int getsysctl_mib(const char *name, int *mib, size_t len)
+{
+ size_t nlen = len;
+
+ if (unlikely(sysctlnametomib(name, mib, &nlen) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(nlen != len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+ return 1;
+ }
+ return 0;
+}
+
+#define GETSYSCTL_SIMPLE(name, mib, var) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), &(var), sizeof(var))
+#define GETSYSCTL_WSIZE(name, mib, var, size) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), var, size)
+
+static inline int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len)
+{
+ size_t nlen = len;
+
+ if (unlikely(!mib[0]))
+ if (unlikely(getsysctl_mib(name, mib, miblen)))
+ return 1;
+
+ if (unlikely(sysctl(mib, miblen, ptr, &nlen, NULL, 0) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(nlen != len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define GETSYSCTL_SIZE(name, mib, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), NULL, &(size))
+#define GETSYSCTL(name, mib, var, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), &(var), &(size))
+
+static inline int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len)
+{
+ size_t nlen = *len;
+
+ if (unlikely(!mib[0]))
+ if (unlikely(getsysctl_mib(name, mib, miblen)))
+ return 1;
+
+ if (unlikely(sysctl(mib, miblen, ptr, len, NULL, 0) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(ptr != NULL && nlen != *len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)*len, (unsigned long)nlen);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
+
+static inline int getsysctl_by_name(const char *name, void *ptr, size_t len)
+{
+ size_t nlen = len;
-extern int do_freebsd_sysctl(int update_every, usec_t dt);
+ if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(nlen != len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+ return 1;
+ }
+ return 0;
+}
#endif /* NETDATA_PLUGIN_FREEBSD_H */
diff --git a/src/plugin_idlejitter.c b/src/plugin_idlejitter.c
index 7d4a4c189..2ed78160c 100644
--- a/src/plugin_idlejitter.c
+++ b/src/plugin_idlejitter.c
@@ -19,10 +19,11 @@ void *cpuidlejitter_main(void *ptr) {
sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
}
- RRDSET *st = rrdset_find("system.idlejitter");
+ RRDSET *st = rrdset_find_localhost("system.idlejitter");
if(!st) {
- st = rrdset_create("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter", "microseconds lost/s", 9999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "jitter", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter"
+ , "microseconds lost/s", 9999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "jitter", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
struct timeval before, after;
@@ -30,11 +31,13 @@ void *cpuidlejitter_main(void *ptr) {
for(counter = 0; 1 ;counter++) {
usec_t usec = 0, susec = 0;
- while(susec < (rrd_update_every * USEC_PER_SEC)) {
+ if(netdata_exit) break;
- now_realtime_timeval(&before);
+ while(susec < (localhost->rrd_update_every * USEC_PER_SEC)) {
+
+ now_monotonic_timeval(&before);
sleep_usec(sleep_ms * 1000);
- now_realtime_timeval(&after);
+ now_monotonic_timeval(&after);
// calculate the time it took for a full loop
usec = dt_usec(&after, &before);
diff --git a/src/plugin_macos.c b/src/plugin_macos.c
index 3955c1414..4e84a084d 100644
--- a/src/plugin_macos.c
+++ b/src/plugin_macos.c
@@ -11,12 +11,6 @@ void *macos_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- // disable (by default) various interface that are not needed
- /*
- config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
- config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
- */
-
// when ZERO, attempt to do it
int vdo_cpu_netdata = !config_get_boolean("plugin:macos", "netdata server resources", 1);
int vdo_macos_sysctl = !config_get_boolean("plugin:macos", "sysctl", 1);
@@ -28,15 +22,11 @@ void *macos_main(void *ptr) {
unsigned long long sutime_macos_mach_smi = 0ULL;
unsigned long long sutime_macos_iokit = 0ULL;
- usec_t step = rrd_update_every * USEC_PER_SEC;
+ usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;;) {
- usec_t now = now_realtime_usec();
- usec_t next = now - (now % step) + step;
-
- while(now < next) {
- sleep_usec(next - now);
- now = now_realtime_usec();
- }
+ usec_t hb_dt = heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
@@ -44,25 +34,19 @@ void *macos_main(void *ptr) {
if(!vdo_macos_sysctl) {
debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_sysctl().");
- now = now_realtime_usec();
- vdo_macos_sysctl = do_macos_sysctl(rrd_update_every, (sutime_macos_sysctl > 0)?now - sutime_macos_sysctl:0ULL);
- sutime_macos_sysctl = now;
+ vdo_macos_sysctl = do_macos_sysctl(localhost->rrd_update_every, hb_dt);
}
if(unlikely(netdata_exit)) break;
if(!vdo_macos_mach_smi) {
debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_mach_smi().");
- now = now_realtime_usec();
- vdo_macos_mach_smi = do_macos_mach_smi(rrd_update_every, (sutime_macos_mach_smi > 0)?now - sutime_macos_mach_smi:0ULL);
- sutime_macos_mach_smi = now;
+ vdo_macos_mach_smi = do_macos_mach_smi(localhost->rrd_update_every, hb_dt);
}
if(unlikely(netdata_exit)) break;
if(!vdo_macos_iokit) {
debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_iokit().");
- now = now_realtime_usec();
- vdo_macos_iokit = do_macos_iokit(rrd_update_every, (sutime_macos_iokit > 0)?now - sutime_macos_iokit:0ULL);
- sutime_macos_iokit = now;
+ vdo_macos_iokit = do_macos_iokit(localhost->rrd_update_every, hb_dt);
}
if(unlikely(netdata_exit)) break;
diff --git a/src/plugin_macos.h b/src/plugin_macos.h
index a21e5601d..6ccf3e861 100644
--- a/src/plugin_macos.h
+++ b/src/plugin_macos.h
@@ -3,9 +3,9 @@
void *macos_main(void *ptr);
-#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
-extern int getsysctl(const char *name, void *ptr, size_t len);
+extern int getsysctl_by_name(const char *name, void *ptr, size_t len);
extern int do_macos_sysctl(int update_every, usec_t dt);
extern int do_macos_mach_smi(int update_every, usec_t dt);
diff --git a/src/plugin_nfacct.c b/src/plugin_nfacct.c
index 7aae33c0c..4c691be05 100644
--- a/src/plugin_nfacct.c
+++ b/src/plugin_nfacct.c
@@ -1,196 +1,809 @@
#include "common.h"
#ifdef INTERNAL_PLUGIN_NFACCT
+
+#ifdef HAVE_LIBMNL
#include <libmnl/libmnl.h>
-#include <libnetfilter_acct/libnetfilter_acct.h>
-struct mynfacct {
- const char *name;
- uint64_t pkts;
- uint64_t bytes;
- struct nfacct *nfacct;
+static inline size_t mnl_buffer_size() {
+ long s = MNL_SOCKET_BUFFER_SIZE;
+ if(s <= 0) return 8192;
+ return (size_t)s;
+}
+
+// ----------------------------------------------------------------------------
+// DO_NFSTAT - collect netfilter connection tracker statistics via netlink
+// example: https://github.com/formorer/pkg-conntrack-tools/blob/master/src/conntrack.c
+
+#ifdef HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
+#define DO_NFSTAT 1
+
+#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
+#define RRD_TYPE_NET_STAT_CONNTRACK "netlink" // FIXME: should be "conntrack" when merged with the /proc plugin
+
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static struct {
+ int update_every;
+ char *buf;
+ size_t buf_size;
+ struct mnl_socket *mnl;
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+ unsigned int seq;
+ uint32_t portid;
+
+ struct nlattr *tb[CTA_STATS_MAX+1];
+ const char *attr2name[CTA_STATS_MAX+1];
+ kernel_uint_t metrics[CTA_STATS_MAX+1];
+
+ struct nlattr *tb_exp[CTA_STATS_EXP_MAX+1];
+ const char *attr2name_exp[CTA_STATS_EXP_MAX+1];
+ kernel_uint_t metrics_exp[CTA_STATS_EXP_MAX+1];
+} nfstat_root = {
+ .update_every = 1,
+ .buf = NULL,
+ .buf_size = 0,
+ .mnl = NULL,
+ .nlh = NULL,
+ .nfh = NULL,
+ .seq = 0,
+ .portid = 0,
+ .tb = {},
+ .attr2name = {
+ [CTA_STATS_SEARCHED] = "searched",
+ [CTA_STATS_FOUND] = "found",
+ [CTA_STATS_NEW] = "new",
+ [CTA_STATS_INVALID] = "invalid",
+ [CTA_STATS_IGNORE] = "ignore",
+ [CTA_STATS_DELETE] = "delete",
+ [CTA_STATS_DELETE_LIST] = "delete_list",
+ [CTA_STATS_INSERT] = "insert",
+ [CTA_STATS_INSERT_FAILED] = "insert_failed",
+ [CTA_STATS_DROP] = "drop",
+ [CTA_STATS_EARLY_DROP] = "early_drop",
+ [CTA_STATS_ERROR] = "icmp_error",
+ [CTA_STATS_SEARCH_RESTART] = "search_restart",
+ },
+ .metrics = {},
+ .tb_exp = {},
+ .attr2name_exp = {
+ [CTA_STATS_EXP_NEW] = "new",
+ [CTA_STATS_EXP_CREATE] = "created",
+ [CTA_STATS_EXP_DELETE] = "deleted",
+ },
+ .metrics_exp = {}
};
-struct nfacct_list {
- int size;
- int len;
- struct mynfacct data[];
-} *nfacct_list = NULL;
-static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
- if(data) {};
+static int nfstat_init(int update_every) {
+ nfstat_root.update_every = update_every;
- if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
- int size = (nfacct_list) ? nfacct_list->size : 0;
- int len = (nfacct_list) ? nfacct_list->len : 0;
- size++;
+ nfstat_root.buf_size = mnl_buffer_size();
+ nfstat_root.buf = mallocz(nfstat_root.buf_size);
- info("nfacct.plugin: increasing nfacct_list to size %d", size);
+ nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
+ if(!nfstat_root.mnl) {
+ error("NFSTAT: mnl_socket_open() failed");
+ return 1;
+ }
- nfacct_list = reallocz(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
+ nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
- nfacct_list->data[len].nfacct = nfacct_alloc();
- if(!nfacct_list->data[size - 1].nfacct) {
- error("nfacct.plugin: nfacct_alloc() failed.");
- free(nfacct_list);
- nfacct_list = NULL;
- return MNL_CB_OK;
- }
+ if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ error("NFSTAT: mnl_socket_bind() failed");
+ return 1;
+ }
+ nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
+
+ return 0;
+}
- nfacct_list->size = size;
- nfacct_list->len = len;
+static void nfstat_cleanup() {
+ if(nfstat_root.mnl) {
+ mnl_socket_close(nfstat_root.mnl);
+ nfstat_root.mnl = NULL;
}
- if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
- error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
+ freez(nfstat_root.buf);
+ nfstat_root.buf = NULL;
+ nfstat_root.buf_size = 0;
+}
+
+static struct nlmsghdr * nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, uint8_t family, uint32_t seq) {
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (subsys << 8) | type;
+ nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+ nlh->nlmsg_seq = seq;
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = family;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ return nlh;
+}
+
+static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) {
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
return MNL_CB_OK;
+
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ error("NFSTAT: mnl_attr_validate() failed");
+ return MNL_CB_ERROR;
}
- nfacct_list->data[nfacct_list->len].name = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
- nfacct_list->data[nfacct_list->len].pkts = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
- nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int nfstat_callback(const struct nlmsghdr *nlh, void *data) {
+ (void)data;
+
+ struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, nfstat_root.tb);
+
+ // printf("cpu=%-4u\t", ntohs(nfg->res_id));
+
+ int i;
+ // add the metrics of this CPU into the metrics
+ for (i = 0; i < CTA_STATS_MAX+1; i++) {
+ if (nfstat_root.tb[i]) {
+ // printf("%s=%u ", nfstat_root.attr2name[i], ntohl(mnl_attr_get_u32(nfstat_root.tb[i])));
+ nfstat_root.metrics[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb[i]));
+ }
+ }
+ // printf("\n");
- nfacct_list->len++;
return MNL_CB_OK;
}
-void *nfacct_main(void *ptr) {
- struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+static int nfstat_collect_conntrack() {
+ // zero all metrics - we will sum the metrics of all CPUs later
+ int i;
+ for (i = 0; i < CTA_STATS_MAX+1; i++)
+ nfstat_root.metrics[i] = 0;
- info("NFACCT thread created with task id %d", gettid());
+ // prepare the request
+ nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
- if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
- error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
+ // send the request
+ if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
+ error("NFSTAT: mnl_socket_sendto() failed");
+ return 1;
+ }
- if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
- error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
+ // get the reply
+ ssize_t ret;
+ while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
+ if(mnl_cb_run(
+ nfstat_root.buf
+ , (size_t)ret
+ , nfstat_root.nlh->nlmsg_seq
+ , nfstat_root.portid
+ , nfstat_callback
+ , NULL
+ ) <= MNL_CB_STOP)
+ break;
+ }
+
+ // verify we run without issues
+ if (ret == -1) {
+ error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+ return 1;
+ }
- char buf[MNL_SOCKET_BUFFER_SIZE];
- struct mnl_socket *nl = NULL;
- struct nlmsghdr *nlh = NULL;
- unsigned int seq = 0, portid = 0;
+ return 0;
+}
- seq = now_realtime_sec() - 1;
+static int nfexp_stats_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
- nl = mnl_socket_open(NETLINK_NETFILTER);
- if(!nl) {
- error("nfacct.plugin: mnl_socket_open() failed");
- goto cleanup;
+ if (mnl_attr_type_valid(attr, CTA_STATS_EXP_MAX) < 0)
+ return MNL_CB_OK;
+
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ error("NFSTAT EXP: mnl_attr_validate() failed");
+ return MNL_CB_ERROR;
}
- if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
- error("nfacct.plugin: mnl_socket_bind() failed");
- goto cleanup;
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int nfstat_callback_exp(const struct nlmsghdr *nlh, void *data) {
+ (void)data;
+
+ struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*nfg), nfexp_stats_attr_cb, nfstat_root.tb_exp);
+
+ int i;
+ for (i = 0; i < CTA_STATS_EXP_MAX+1; i++) {
+ if (nfstat_root.tb_exp[i]) {
+ nfstat_root.metrics_exp[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb_exp[i]));
+ }
}
- portid = mnl_socket_get_portid(nl);
- // ------------------------------------------------------------------------
+ return MNL_CB_OK;
+}
- struct timeval last, now;
- usec_t usec = 0, susec = 0;
- RRDSET *st = NULL;
+static int nfstat_collect_conntrack_expectations() {
+ // zero all metrics - we will sum the metrics of all CPUs later
+ int i;
+ for (i = 0; i < CTA_STATS_EXP_MAX+1; i++)
+ nfstat_root.metrics_exp[i] = 0;
- now_realtime_timeval(&last);
+ // prepare the request
+ nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
- // ------------------------------------------------------------------------
+ // send the request
+ if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
+ error("NFSTAT: mnl_socket_sendto() failed");
+ return 1;
+ }
- while(1) {
- if(unlikely(netdata_exit)) break;
+ // get the reply
+ ssize_t ret;
+ while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
+ if(mnl_cb_run(
+ nfstat_root.buf
+ , (size_t)ret
+ , nfstat_root.nlh->nlmsg_seq
+ , nfstat_root.portid
+ , nfstat_callback_exp
+ , NULL
+ ) <= MNL_CB_STOP)
+ break;
+ }
- seq++;
+ // verify we run without issues
+ if (ret == -1) {
+ error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nfstat_collect() {
+ nfstat_root.seq++;
+
+ if(nfstat_collect_conntrack())
+ return 1;
+
+ if(nfstat_collect_conntrack_expectations())
+ return 1;
+
+ return 0;
+}
- nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
- if(!nlh) {
- error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
- goto cleanup;
+static void nfstat_send_metrics() {
+
+ {
+ static RRDSET *st_new = NULL;
+ static RRDDIM *rd_new = NULL, *rd_ignore = NULL, *rd_invalid = NULL;
+
+ if(!st_new) {
+ st_new = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_new"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker New Connections"
+ , "connections/s"
+ , 3001
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_new = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ignore = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_IGNORE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_invalid = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_INVALID], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_new);
- if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
- error("nfacct.plugin: mnl_socket_send");
- goto cleanup;
+ rrddim_set_by_pointer(st_new, rd_new, (collected_number) nfstat_root.metrics[CTA_STATS_NEW]);
+ rrddim_set_by_pointer(st_new, rd_ignore, (collected_number) nfstat_root.metrics[CTA_STATS_IGNORE]);
+ rrddim_set_by_pointer(st_new, rd_invalid, (collected_number) nfstat_root.metrics[CTA_STATS_INVALID]);
+
+ rrdset_done(st_new);
+ }
+
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_changes = NULL;
+ static RRDDIM *rd_inserted = NULL, *rd_deleted = NULL, *rd_delete_list = NULL;
+
+ if(!st_changes) {
+ st_changes = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Changes"
+ , "changes/s"
+ , 3002
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_changes, RRDSET_FLAG_DETAIL);
+
+ rd_inserted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_INSERT], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_deleted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_delete_list = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE_LIST], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_changes);
- if(nfacct_list) nfacct_list->len = 0;
+ rrddim_set_by_pointer(st_changes, rd_inserted, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT]);
+ rrddim_set_by_pointer(st_changes, rd_deleted, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE]);
+ rrddim_set_by_pointer(st_changes, rd_delete_list, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE_LIST]);
- int ret;
- while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
- if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
+ rrdset_done(st_changes);
+ }
+
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_search = NULL;
+ static RRDDIM *rd_searched = NULL, *rd_restarted = NULL, *rd_found = NULL;
+
+ if(!st_search) {
+ st_search = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_search"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Searches"
+ , "searches/s"
+ , 3010
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_search, RRDSET_FLAG_DETAIL);
+
+ rd_searched = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCHED], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_restarted = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCH_RESTART], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_found = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_FOUND], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_search);
+
+ rrddim_set_by_pointer(st_search, rd_searched, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCHED]);
+ rrddim_set_by_pointer(st_search, rd_restarted, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCH_RESTART]);
+ rrddim_set_by_pointer(st_search, rd_found, (collected_number) nfstat_root.metrics[CTA_STATS_FOUND]);
- if (ret == -1) {
- error("nfacct.plugin: error communicating with kernel.");
- goto cleanup;
+ rrdset_done(st_search);
+ }
+
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_errors = NULL;
+ static RRDDIM *rd_error = NULL, *rd_insert_failed = NULL, *rd_drop = NULL, *rd_early_drop = NULL;
+
+ if(!st_errors) {
+ st_errors = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Errors"
+ , "events/s"
+ , 3005
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_errors, RRDSET_FLAG_DETAIL);
+
+ rd_error = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_ERROR], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_insert_failed = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_INSERT_FAILED], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_early_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_EARLY_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_errors);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st_errors, rd_error, (collected_number) nfstat_root.metrics[CTA_STATS_ERROR]);
+ rrddim_set_by_pointer(st_errors, rd_insert_failed, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT_FAILED]);
+ rrddim_set_by_pointer(st_errors, rd_drop, (collected_number) nfstat_root.metrics[CTA_STATS_DROP]);
+ rrddim_set_by_pointer(st_errors, rd_early_drop, (collected_number) nfstat_root.metrics[CTA_STATS_EARLY_DROP]);
- now_realtime_timeval(&now);
- usec = dt_usec(&now, &last) - susec;
- debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
+ rrdset_done(st_errors);
+ }
- if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
- else susec = rrd_update_every * 1000000ULL / 2ULL;
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_expect = NULL;
+ static RRDDIM *rd_new = NULL, *rd_created = NULL, *rd_deleted = NULL;
+
+ if(!st_expect) {
+ st_expect = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_expect"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Expectations"
+ , "expectations/s"
+ , 3003
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_expect, RRDSET_FLAG_DETAIL);
+
+ rd_created = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_CREATE], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_deleted = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_new = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else
+ rrdset_next(st_expect);
+ rrddim_set_by_pointer(st_expect, rd_created, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_CREATE]);
+ rrddim_set_by_pointer(st_expect, rd_deleted, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_DELETE]);
+ rrddim_set_by_pointer(st_expect, rd_new, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_NEW]);
- // --------------------------------------------------------------------
+ rrdset_done(st_expect);
+ }
+
+}
+
+#endif // HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
- if(nfacct_list && nfacct_list->len) {
- int i;
- st = rrdset_find_bytype("netfilter", "nfacct_packets");
- if(!st) {
- st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 3206, rrd_update_every, RRDSET_TYPE_STACKED);
+// ----------------------------------------------------------------------------
+// DO_NFACCT - collect netfilter accounting statistics via netlink
- for(i = 0; i < nfacct_list->len ; i++)
- rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+#ifdef HAVE_LIBNETFILTER_ACCT
+#define DO_NFACCT 1
+
+#include <libnetfilter_acct/libnetfilter_acct.h>
- for(i = 0; i < nfacct_list->len ; i++) {
- RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+struct nfacct_data {
+ char *name;
+ uint32_t hash;
- if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
- if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
- }
+ uint64_t pkts;
+ uint64_t bytes;
- rrdset_done(st);
+ RRDDIM *rd_bytes;
+ RRDDIM *rd_packets;
- // ----------------------------------------------------------------
+ int updated;
- st = rrdset_find_bytype("netfilter", "nfacct_bytes");
- if(!st) {
- st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 3207, rrd_update_every, RRDSET_TYPE_STACKED);
+ struct nfacct_data *next;
+};
- for(i = 0; i < nfacct_list->len ; i++)
- rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+static struct {
+ int update_every;
+ char *buf;
+ size_t buf_size;
+ struct mnl_socket *mnl;
+ struct nlmsghdr *nlh;
+ unsigned int seq;
+ uint32_t portid;
+ struct nfacct *nfacct_buffer;
+ struct nfacct_data *nfacct_metrics;
+} nfacct_root = {
+ .update_every = 1,
+ .buf = NULL,
+ .buf_size = 0,
+ .mnl = NULL,
+ .nlh = NULL,
+ .seq = 0,
+ .portid = 0,
+ .nfacct_buffer = NULL,
+ .nfacct_metrics = NULL
+};
- for(i = 0; i < nfacct_list->len ; i++) {
- RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t hash) {
+ struct nfacct_data *d = NULL, *last = NULL;
+ for(d = nfacct_root.nfacct_metrics; d ; last = d, d = d->next) {
+ if(unlikely(d->hash == hash && !strcmp(d->name, name)))
+ return d;
+ }
- if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
- if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
- }
+ d = callocz(1, sizeof(struct nfacct_data));
+ d->name = strdupz(name);
+ d->hash = hash;
- rrdset_done(st);
+ if(!last) {
+ d->next = nfacct_root.nfacct_metrics;
+ nfacct_root.nfacct_metrics = d;
+ }
+ else {
+ d->next = last->next;
+ last->next = d;
+ }
+
+ return d;
+}
+
+static int nfacct_init(int update_every) {
+ nfacct_root.update_every = update_every;
+
+ nfacct_root.buf_size = mnl_buffer_size();
+ nfacct_root.buf = mallocz(nfacct_root.buf_size);
+
+ nfacct_root.nfacct_buffer = nfacct_alloc();
+ if(!nfacct_root.nfacct_buffer) {
+ error("nfacct.plugin: nfacct_alloc() failed.");
+ return 0;
+ }
+
+ nfacct_root.seq = (unsigned int)now_realtime_sec() - 1;
+
+ nfacct_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
+ if(!nfacct_root.mnl) {
+ error("nfacct.plugin: mnl_socket_open() failed");
+ return 1;
+ }
+
+ if(mnl_socket_bind(nfacct_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ error("nfacct.plugin: mnl_socket_bind() failed");
+ return 1;
+ }
+ nfacct_root.portid = mnl_socket_get_portid(nfacct_root.mnl);
+
+ return 0;
+}
+
+static void nfacct_cleanup() {
+ if(nfacct_root.mnl) {
+ mnl_socket_close(nfacct_root.mnl);
+ nfacct_root.mnl = NULL;
+ }
+
+ if(nfacct_root.nfacct_buffer) {
+ nfacct_free(nfacct_root.nfacct_buffer);
+ nfacct_root.nfacct_buffer = NULL;
+ }
+
+ freez(nfacct_root.buf);
+ nfacct_root.buf = NULL;
+ nfacct_root.buf_size = 0;
+
+ // FIXME: cleanup the metrics linked list
+}
+
+static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
+ (void)data;
+
+ if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
+ error("NFACCT: nfacct_nlmsg_parse_payload() failed.");
+ return MNL_CB_OK;
+ }
+
+ const char *name = nfacct_attr_get_str(nfacct_root.nfacct_buffer, NFACCT_ATTR_NAME);
+ uint32_t hash = simple_hash(name);
+
+ struct nfacct_data *d = nfacct_data_get(name, hash);
+
+ d->pkts = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_PKTS);
+ d->bytes = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_BYTES);
+ d->updated = 1;
+
+ return MNL_CB_OK;
+}
+
+static int nfacct_collect() {
+ // mark all old metrics as not-updated
+ struct nfacct_data *d;
+ for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
+ d->updated = 0;
+
+ // prepare the request
+ nfacct_root.seq++;
+ nfacct_root.nlh = nfacct_nlmsg_build_hdr(nfacct_root.buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)nfacct_root.seq);
+ if(!nfacct_root.nlh) {
+ error("NFACCT: nfacct_nlmsg_build_hdr() failed");
+ return 1;
+ }
+
+ // send the request
+ if(mnl_socket_sendto(nfacct_root.mnl, nfacct_root.nlh, nfacct_root.nlh->nlmsg_len) < 0) {
+ error("NFACCT: mnl_socket_sendto() failed");
+ return 1;
+ }
+
+ // get the reply
+ ssize_t ret;
+ while((ret = mnl_socket_recvfrom(nfacct_root.mnl, nfacct_root.buf, nfacct_root.buf_size)) > 0) {
+ if(mnl_cb_run(
+ nfacct_root.buf
+ , (size_t)ret
+ , nfacct_root.seq
+ , nfacct_root.portid
+ , nfacct_callback
+ , NULL
+ ) <= 0)
+ break;
+ }
+
+ // verify we run without issues
+ if (ret == -1) {
+ error("NFACCT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+ return 1;
+ }
+
+ return 0;
+}
+
+static void nfacct_send_metrics() {
+ static RRDSET *st_bytes = NULL, *st_packets = NULL;
+
+ if(!nfacct_root.nfacct_metrics) return;
+ struct nfacct_data *d;
+
+ if(!st_packets) {
+ st_packets = rrdset_create_localhost(
+ "netfilter"
+ , "nfacct_packets"
+ , NULL
+ , "nfacct"
+ , NULL
+ , "Netfilter Accounting Packets"
+ , "packets/s"
+ , 3206
+ , nfacct_root.update_every
+ , RRDSET_TYPE_STACKED
+ );
+ }
+ else rrdset_next(st_packets);
+
+ for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
+ if(likely(d->updated)) {
+ if(unlikely(!d->rd_packets))
+ d->rd_packets = rrddim_add(
+ st_packets
+ , d->name
+ , NULL
+ , 1
+ , nfacct_root.update_every
+ , RRD_ALGORITHM_INCREMENTAL
+ );
+
+ rrddim_set_by_pointer(
+ st_packets
+ , d->rd_packets
+ , (collected_number)d->pkts
+ );
}
+ }
+
+ rrdset_done(st_packets);
+
+ // ----------------------------------------------------------------
+
+ st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
+ if(!st_bytes) {
+ st_bytes = rrdset_create_localhost(
+ "netfilter"
+ , "nfacct_bytes"
+ , NULL
+ , "nfacct"
+ , NULL
+ , "Netfilter Accounting Bandwidth"
+ , "kilobytes/s"
+ , 3207
+ , nfacct_root.update_every
+ , RRDSET_TYPE_STACKED
+ );
+ }
+ else rrdset_next(st_bytes);
+
+ for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
+ if(likely(d->updated)) {
+ if(unlikely(!d->rd_bytes))
+ d->rd_bytes = rrddim_add(
+ st_bytes
+ , d->name
+ , NULL
+ , 1
+ , 1000 * nfacct_root.update_every
+ , RRD_ALGORITHM_INCREMENTAL
+ );
+
+ rrddim_set_by_pointer(
+ st_bytes
+ , d->rd_bytes
+ , (collected_number)d->bytes
+ );
+ }
+ }
+
+ rrdset_done(st_bytes);
+}
+
+#endif // HAVE_LIBNETFILTER_ACCT
+#endif // HAVE_LIBMNL
+
+// ----------------------------------------------------------------------------
+
+void *nfacct_main(void *ptr) {
+ struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+
+ info("NETFILTER thread created with task id %d", gettid());
+
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("NETFILTER: Cannot set pthread cancel type to DEFERRED.");
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("NETFILTER: Cannot set pthread cancel state to ENABLE.");
- // --------------------------------------------------------------------
- usleep(susec);
+ int update_every = (int)config_get_number("plugin:netfilter", "update every", localhost->rrd_update_every);
+ if(update_every < localhost->rrd_update_every)
+ update_every = localhost->rrd_update_every;
- // copy current to last
- memmove(&last, &now, sizeof(struct timeval));
+#ifdef DO_NFACCT
+ int nfacct = !nfacct_init(update_every);
+#endif
+
+#ifdef DO_NFSTAT
+ int nfstat = !nfstat_init(update_every);
+#endif
+
+ // ------------------------------------------------------------------------
+
+ usec_t step = update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+ for(;;) {
+ heartbeat_dt_usec(&hb);
+ heartbeat_next(&hb, step);
+
+ if(unlikely(netdata_exit)) break;
+
+#ifdef DO_NFACCT
+ if(likely(nfacct)) {
+ nfacct = !nfacct_collect();
+
+ if(likely(nfacct))
+ nfacct_send_metrics();
+ }
+#endif
+
+#ifdef DO_NFSTAT
+ if(likely(nfstat)) {
+ nfstat = !nfstat_collect();
+
+ if(likely(nfstat))
+ nfstat_send_metrics();
+ }
+#endif
}
-cleanup:
- info("NFACCT thread exiting");
+ info("NETFILTER thread exiting");
- if(nl) mnl_socket_close(nl);
+#ifdef DO_NFACCT
+ nfacct_cleanup();
+#endif
+
+#ifdef DO_NFSTAT
+ nfstat_cleanup();
+#endif
static_thread->enabled = 0;
pthread_exit(NULL);
return NULL;
}
-#endif
+
+#endif // INTERNAL_PLUGIN_NFACCT
diff --git a/src/plugin_proc.c b/src/plugin_proc.c
index 9b66b7c28..2ca77491d 100644
--- a/src/plugin_proc.c
+++ b/src/plugin_proc.c
@@ -7,7 +7,6 @@ static struct proc_module {
int enabled;
int (*func)(int update_every, usec_t dt);
- usec_t last_run_usec;
usec_t duration;
RRDDIM *rd;
@@ -76,20 +75,17 @@ void *proc_main(void *ptr) {
struct proc_module *pm = &proc_modules[i];
pm->enabled = config_get_boolean("plugin:proc", pm->name, 1);
- pm->last_run_usec = 0ULL;
pm->duration = 0ULL;
pm->rd = NULL;
}
- usec_t step = rrd_update_every * USEC_PER_SEC;
- for(;;) {
- usec_t now = now_monotonic_usec();
- usec_t next = now - (now % step) + step;
+ usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
- while(now < next) {
- sleep_usec(next - now);
- now = now_monotonic_usec();
- }
+ for(;;) {
+ usec_t hb_dt = heartbeat_next(&hb, step);
+ usec_t duration = 0ULL;
if(unlikely(netdata_exit)) break;
@@ -101,11 +97,9 @@ void *proc_main(void *ptr) {
debug(D_PROCNETDEV_LOOP, "PROC calling %s.", pm->name);
- pm->enabled = !pm->func(rrd_update_every, (pm->last_run_usec > 0)?now - pm->last_run_usec:0ULL);
- pm->last_run_usec = now;
-
- now = now_monotonic_usec();
- pm->duration = now - pm->last_run_usec;
+ pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
+ pm->duration = heartbeat_dt_usec(&hb) - duration;
+ duration += pm->duration;
if(unlikely(netdata_exit)) break;
}
@@ -118,16 +112,18 @@ void *proc_main(void *ptr) {
static RRDSET *st = NULL;
if(unlikely(!st)) {
- st = rrdset_find_bytype("netdata", "plugin_proc_modules");
+ st = rrdset_find_bytype_localhost("netdata", "plugin_proc_modules");
if(!st) {
- st = rrdset_create("netdata", "plugin_proc_modules", NULL, "proc", NULL, "NetData Proc Plugin Modules Durations", "milliseconds/run", 132001, rrd_update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("netdata", "plugin_proc_modules", NULL, "proc", NULL
+ , "NetData Proc Plugin Modules Durations", "milliseconds/run", 132001
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
for(i = 0 ; proc_modules[i].name ;i++) {
struct proc_module *pm = &proc_modules[i];
if(unlikely(!pm->enabled)) continue;
- pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
}
}
@@ -163,7 +159,7 @@ int get_numa_node_count(void)
numa_node_count = 0;
char name[FILENAME_MAX + 1];
- snprintfz(name, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/devices/system/node");
+ snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/node");
char *dirname = config_get("plugin:proc:/sys/devices/system/node", "directory to monitor", name);
DIR *dir = opendir(dirname);
diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c
index 43e6dd7c5..37133e044 100644
--- a/src/plugin_proc_diskspace.c
+++ b/src/plugin_proc_diskspace.c
@@ -1,6 +1,8 @@
#include "common.h"
-#define DELAULT_EXLUDED_PATHS "/proc/* /sys/* /var/run/user/* /run/user/*"
+#define DELAULT_EXLUDED_PATHS "/proc/* /sys/* /var/run/user/* /run/user/* /snap/* /var/lib/docker/*"
+#define DEFAULT_EXCLUDED_FILESYSTEMS ""
+#define CONFIG_SECTION_DISKSPACE "plugin:proc:diskspace"
static struct mountinfo *disk_mountinfo_root = NULL;
static int check_for_new_mountpoints_every = 15;
@@ -14,17 +16,19 @@ static inline void mountinfo_reload(int force) {
mountinfo_free(disk_mountinfo_root);
// re-read mountinfo in case something changed
- disk_mountinfo_root = mountinfo_read(1);
+ disk_mountinfo_root = mountinfo_read(0);
last_loaded = now;
}
}
-// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
+// Data to be stored in DICTIONARY dict_mountpoints used by do_disk_space_stats().
// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
struct mount_point_metadata {
int do_space;
int do_inodes;
+ int shown_error;
+ int updated;
size_t collected; // the number of times this has been collected
@@ -39,41 +43,86 @@ struct mount_point_metadata {
RRDDIM *rd_inodes_reserved;
};
+static DICTIONARY *dict_mountpoints = NULL;
+
+#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE); st = NULL; } } while(st)
+
+int mount_point_cleanup(void *entry, void *data) {
+ (void)data;
+
+ struct mount_point_metadata *mp = (struct mount_point_metadata *)entry;
+ if(!mp) return 0;
+
+ if(likely(mp->updated)) {
+ mp->updated = 0;
+ return 0;
+ }
+
+ if(likely(mp->collected)) {
+ mp->collected = 0;
+ mp->updated = 0;
+ mp->shown_error = 0;
+
+ mp->rd_space_avail = NULL;
+ mp->rd_space_used = NULL;
+ mp->rd_space_reserved = NULL;
+
+ mp->rd_inodes_avail = NULL;
+ mp->rd_inodes_used = NULL;
+ mp->rd_inodes_reserved = NULL;
+
+ rrdset_obsolete_and_pointer_null(mp->st_space);
+ rrdset_obsolete_and_pointer_null(mp->st_inodes);
+ }
+
+ return 0;
+}
+
static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
const char *family = mi->mount_point;
const char *disk = mi->persistent_id;
- static DICTIONARY *mount_points = NULL;
static SIMPLE_PATTERN *excluded_mountpoints = NULL;
+ static SIMPLE_PATTERN *excluded_filesystems = NULL;
int do_space, do_inodes;
- if(unlikely(!mount_points)) {
- const char *s;
+ if(unlikely(!dict_mountpoints)) {
SIMPLE_PREFIX_MODE mode = SIMPLE_PATTERN_EXACT;
- if(config_exists("plugin:proc:/proc/diskstats", "exclude space metrics on paths") && !config_exists("plugin:proc:diskspace", "exclude space metrics on paths")) {
- // the config exists in the old section
- s = config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
+ if(config_move("plugin:proc:/proc/diskstats", "exclude space metrics on paths", CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths") != -1) {
+ // old configuration, enable backwards compatibility
mode = SIMPLE_PATTERN_PREFIX;
}
- else
- s = config_get("plugin:proc:diskspace", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
- mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
- excluded_mountpoints = simple_pattern_create(s, mode);
+ excluded_mountpoints = simple_pattern_create(
+ config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths", DELAULT_EXLUDED_PATHS),
+ mode
+ );
+
+ excluded_filesystems = simple_pattern_create(
+ config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on filesystems", DEFAULT_EXCLUDED_FILESYSTEMS),
+ SIMPLE_PATTERN_EXACT
+ );
+
+ dict_mountpoints = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
}
- struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point);
+ struct mount_point_metadata *m = dictionary_get(dict_mountpoints, mi->mount_point);
if(unlikely(!m)) {
char var_name[4096 + 1];
snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point);
- int def_space = config_get_boolean_ondemand("plugin:proc:diskspace", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
- int def_inodes = config_get_boolean_ondemand("plugin:proc:diskspace", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
+ int def_space = config_get_boolean_ondemand(CONFIG_SECTION_DISKSPACE, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
+ int def_inodes = config_get_boolean_ondemand(CONFIG_SECTION_DISKSPACE, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
if(unlikely(simple_pattern_matches(excluded_mountpoints, mi->mount_point))) {
- def_space = CONFIG_ONDEMAND_NO;
- def_inodes = CONFIG_ONDEMAND_NO;
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
+ }
+
+ if(unlikely(simple_pattern_matches(excluded_filesystems, mi->filesystem))) {
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
}
do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
@@ -82,6 +131,8 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
struct mount_point_metadata mp = {
.do_space = do_space,
.do_inodes = do_inodes,
+ .shown_error = 0,
+ .updated = 0,
.collected = 0,
@@ -96,14 +147,12 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
.rd_inodes_reserved = NULL
};
- m = dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
- }
- else {
- do_space = m->do_space;
- do_inodes = m->do_inodes;
+ m = dictionary_set(dict_mountpoints, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
}
- if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO))
+ m->updated = 1;
+
+ if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
return;
if(unlikely(mi->flags & MOUNTINFO_READONLY && !m->collected))
@@ -111,9 +160,18 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
struct statvfs buff_statvfs;
if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
- error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk);
+ if(!m->shown_error) {
+ error("Failed statvfs() for '%s' (disk '%s', filesystem '%s', root '%s')"
+ , mi->mount_point
+ , disk
+ , mi->filesystem?mi->filesystem:""
+ , mi->root?mi->root:""
+ );
+ m->shown_error = 1;
+ }
return;
}
+ m->shown_error = 0;
// logic found at get_fs_usage() in coreutils
unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
@@ -150,19 +208,30 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
int rendered = 0;
- if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
+ if(m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (bavail || breserved_root || bused))) {
if(unlikely(!m->st_space)) {
- m->do_space = CONFIG_ONDEMAND_YES;
- m->st_space = rrdset_find_bytype("disk_space", disk);
+ m->do_space = CONFIG_BOOLEAN_YES;
+ m->st_space = rrdset_find_bytype_localhost("disk_space", disk);
if(unlikely(!m->st_space)) {
char title[4096 + 1];
snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source);
- m->st_space = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
+ m->st_space = rrdset_create_localhost(
+ "disk_space"
+ , disk
+ , NULL
+ , family
+ , "disk.space"
+ , title
+ , "GB"
+ , 2023
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
- m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL, bsize, 1024 * 1024 * 1024, RRDDIM_ABSOLUTE);
- m->rd_space_used = rrddim_add(m->st_space, "used", NULL, bsize, 1024 * 1024 * 1024, RRDDIM_ABSOLUTE);
- m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root", bsize, 1024 * 1024 * 1024, RRDDIM_ABSOLUTE);
+ m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL, (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_used = rrddim_add(m->st_space, "used", NULL, (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root", (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(m->st_space);
@@ -177,19 +246,30 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
// --------------------------------------------------------------------------
- if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
+ if(m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (favail || freserved_root || fused))) {
if(unlikely(!m->st_inodes)) {
- m->do_inodes = CONFIG_ONDEMAND_YES;
- m->st_inodes = rrdset_find_bytype("disk_inodes", disk);
+ m->do_inodes = CONFIG_BOOLEAN_YES;
+ m->st_inodes = rrdset_find_bytype_localhost("disk_inodes", disk);
if(unlikely(!m->st_inodes)) {
char title[4096 + 1];
snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source);
- m->st_inodes = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
+ m->st_inodes = rrdset_create_localhost(
+ "disk_inodes"
+ , disk
+ , NULL
+ , family
+ , "disk.inodes"
+ , title
+ , "Inodes"
+ , 2024
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
- m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
- m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- m->rd_inodes_reserved = rrddim_add(m->st_inodes, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+ m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_inodes_reserved = rrddim_add(m->st_inodes, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(m->st_inodes);
@@ -221,30 +301,23 @@ void *proc_diskspace_main(void *ptr) {
int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1);
- int update_every = (int)config_get_number("plugin:proc:diskspace", "update every", rrd_update_every);
- if(update_every < rrd_update_every)
- update_every = rrd_update_every;
+ 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;
- check_for_new_mountpoints_every = (int)config_get_number("plugin:proc:diskspace", "check for new mount points every", check_for_new_mountpoints_every);
+ check_for_new_mountpoints_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "check for new mount points every", check_for_new_mountpoints_every);
if(check_for_new_mountpoints_every < update_every)
check_for_new_mountpoints_every = update_every;
struct rusage thread;
- usec_t last = 0, dt = 0;
+ usec_t duration = 0;
usec_t step = update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;;) {
- usec_t now = now_monotonic_usec();
- usec_t next = now - (now % step) + step;
-
- dt = (last)?now - last:0;
-
- while(now < next) {
- sleep_usec(next - now);
- now = now_monotonic_usec();
- }
-
- last = now;
+ duration = heartbeat_dt_usec(&hb);
+ /* usec_t hb_dt = */ heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
@@ -270,6 +343,8 @@ void *proc_diskspace_main(void *ptr) {
if(unlikely(netdata_exit)) break;
+ dictionary_get_all(dict_mountpoints, mount_point_cleanup, NULL);
+
if(vdo_cpu_netdata) {
static RRDSET *stcpu_thread = NULL, *st_duration = NULL;
static RRDDIM *rd_user = NULL, *rd_system = NULL, *rd_duration = NULL;
@@ -279,13 +354,23 @@ void *proc_diskspace_main(void *ptr) {
getrusage(RUSAGE_THREAD, &thread);
if(!stcpu_thread) {
- stcpu_thread = rrdset_find("netdata.plugin_diskspace");
- if(!stcpu_thread) stcpu_thread = rrdset_create("netdata", "plugin_diskspace", NULL, "diskspace", NULL
- , "NetData Disk Space Plugin CPU usage", "milliseconds/s", 132020
- , update_every, RRDSET_TYPE_STACKED);
-
- rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ stcpu_thread = rrdset_find_localhost("netdata.plugin_diskspace");
+ if(!stcpu_thread)
+ stcpu_thread = rrdset_create_localhost(
+ "netdata"
+ , "plugin_diskspace"
+ , NULL
+ , "diskspace"
+ , NULL
+ , "NetData Disk Space Plugin CPU usage"
+ , "milliseconds/s"
+ , 132020
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(stcpu_thread);
@@ -297,17 +382,27 @@ void *proc_diskspace_main(void *ptr) {
// ----------------------------------------------------------------
if(!st_duration) {
- st_duration = rrdset_find("netdata.plugin_diskspace_dt");
- if(!st_duration) st_duration = rrdset_create("netdata", "plugin_diskspace_dt", NULL, "diskspace", NULL
- , "NetData Disk Space Plugin Duration", "milliseconds/run", 132021
- , update_every, RRDSET_TYPE_AREA);
-
- rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st_duration = rrdset_find_localhost("netdata.plugin_diskspace_dt");
+ if(!st_duration)
+ st_duration = rrdset_create_localhost(
+ "netdata"
+ , "plugin_diskspace_dt"
+ , NULL
+ , "diskspace"
+ , NULL
+ , "NetData Disk Space Plugin Duration"
+ , "milliseconds/run"
+ , 132021
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(st_duration);
- rrddim_set_by_pointer(st_duration, rd_duration, dt);
+ rrddim_set_by_pointer(st_duration, rd_duration, duration);
rrdset_done(st_duration);
// ----------------------------------------------------------------
diff --git a/src/plugin_tc.c b/src/plugin_tc.c
index 0fa595320..7dcfedb33 100644
--- a/src/plugin_tc.c
+++ b/src/plugin_tc.c
@@ -1,7 +1,6 @@
#include "common.h"
-#define RRD_TYPE_TC "tc"
-#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
+#define RRD_TYPE_TC "tc"
// ----------------------------------------------------------------------------
// /sbin/tc processor
@@ -25,6 +24,9 @@ struct tc_class {
char hasparent;
char isleaf;
+ char isqdisc;
+ char render;
+
unsigned long long bytes;
unsigned long long packets;
unsigned long long dropped;
@@ -68,6 +70,7 @@ struct tc_device {
char enabled_dropped;
char enabled_tokens;
char enabled_ctokens;
+ char enabled_all_classes_qdiscs;
RRDSET *st_bytes;
RRDSET *st_packets;
@@ -184,103 +187,171 @@ static inline void tc_device_classes_cleanup(struct tc_device *d) {
}
static inline void tc_device_commit(struct tc_device *d) {
- static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1;
+ static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1, enabled_all_classes_qdiscs = -1;
if(unlikely(enable_new_interfaces == -1)) {
- enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
- enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- enable_tokens = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_ONDEMAND_NO);
- enable_ctokens = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_ONDEMAND_NO);
+ enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_YES);
+ enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_BOOLEAN_AUTO);
+ enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_BOOLEAN_AUTO);
+ enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_BOOLEAN_AUTO);
+ enable_tokens = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_BOOLEAN_NO);
+ enable_ctokens = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_BOOLEAN_NO);
+ enabled_all_classes_qdiscs = config_get_boolean_ondemand("plugin:tc", "enable show all classes and qdiscs for all interfaces", CONFIG_BOOLEAN_NO);
+ }
+
+ if(unlikely(d->enabled == (char)-1)) {
+ char var_name[CONFIG_MAX_NAME + 1];
+ snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
+
+ d->enabled = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
+ d->enabled_bytes = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
+ d->enabled_packets = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
+ d->enabled_dropped = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
+ d->enabled_tokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
+ d->enabled_ctokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "show all classes for %s", d->id);
+ d->enabled_all_classes_qdiscs = (char)config_get_boolean_ondemand("plugin:tc", var_name, enabled_all_classes_qdiscs);
}
// we only need to add leaf classes
- struct tc_class *c, *x;
+ struct tc_class *c, *x /*, *root = NULL */;
unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0, tokens_sum = 0, ctokens_sum = 0;
- int active_classes = 0;
+ int active_nodes = 0, updated_classes = 0, updated_qdiscs = 0;
+
+ // prepare all classes
+ // we set reasonable defaults for the rest of the code below
- // set all classes
for(c = d->classes ; c ; c = c->next) {
- c->isleaf = 1;
- c->hasparent = 0;
+ c->render = 0; // do not render this class
+
+ c->isleaf = 1; // this is a leaf class
+ c->hasparent = 0; // without a parent
if(unlikely(!c->updated))
- c->unupdated++;
- else
- c->unupdated = 0;
+ c->unupdated++; // increase its unupdated counter
+ else {
+ c->unupdated = 0; // reset its unupdated counter
+
+ // count how many of each kind
+ if(c->isqdisc)
+ updated_qdiscs++;
+ else
+ updated_classes++;
+ }
}
- // mark the classes as leafs and parents
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ if(unlikely(!d->enabled || (!updated_classes && !updated_qdiscs))) {
+ debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. It is not enabled/updated.", d->name?d->name:d->id);
+ tc_device_classes_cleanup(d);
+ return;
+ }
- for(x = d->classes ; x ; x = x->next) {
- if(unlikely(!x->updated)) continue;
+ if(unlikely(updated_classes && updated_qdiscs)) {
+ error("TC: device '%s' has active both classes (%d) and qdiscs (%d). Will render only qdiscs.", d->id, updated_classes, updated_qdiscs);
- if(unlikely(c == x)) continue;
+ // set all classes to !updated
+ for(c = d->classes ; c ; c = c->next)
+ if(unlikely(!c->isqdisc && c->updated))
+ c->updated = 0;
- if(x->parentid && (
- ( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
- (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
- // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
- c->isleaf = 0;
- x->hasparent = 1;
- }
- }
+ updated_classes = 0;
}
- // debugging only
- /*
- if(unlikely(debug_flags & D_TC_LOOP)) {
- for(c = d->classes ; c ; c = c->next) {
- if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device '%s', class %s, OK", d->name, c->id);
- else debug(D_TC_LOOP, "TC: Device '%s', class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
+ // mark the classes as leafs and parents
+ //
+ // TC is hierarchical:
+ // - classes can have other classes in them
+ // - the same is true for qdiscs (i.e. qdiscs have classes, that have other qdiscs)
+ //
+ // we need to present a chart with leaf nodes only, so that the sum
+ // of all dimensions of the chart, will be the total utilization
+ // of the interface.
+ //
+ // here we try to find the ones we need to report
+ // by default all nodes are marked with: isleaf = 1 (see above)
+ //
+ // so, here we remove the isleaf flag from nodes in the middle
+ // and we add the hasparent flag to leaf nodes we found their parent
+ if(likely(!d->enabled_all_classes_qdiscs)) {
+ for(c = d->classes; c; c = c->next) {
+ if(unlikely(!c->updated)) continue;
+
+ //debug(D_TC_LOOP, "TC: In device '%s', %s '%s' has leafid: '%s' and parentid '%s'.",
+ // d->id,
+ // c->isqdisc?"qdisc":"class",
+ // c->id,
+ // c->leafid?c->leafid:"NULL",
+ // c->parentid?c->parentid:"NULL");
+
+ // find if c is leaf or not
+ for(x = d->classes; x; x = x->next) {
+ if(unlikely(!x->updated || c == x || !x->parentid)) continue;
+
+ // classes have both parentid and leafid
+ // qdiscs have only parentid
+ // the following works for both (it is an OR)
+
+ if((c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
+ (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) {
+ // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id);
+ c->isleaf = 0;
+ x->hasparent = 1;
+ }
+ }
}
}
- */
- // we need at least a class
for(c = d->classes ; c ; c = c->next) {
- // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
- if(unlikely(c->updated && c->isleaf && c->hasparent)) {
- active_classes++;
+ if(unlikely(!c->updated)) continue;
+
+ // debug(D_TC_LOOP, "TC: device '%s', %s '%s' isleaf=%d, hasparent=%d", d->id, (c->isqdisc)?"qdisc":"class", c->id, c->isleaf, c->hasparent);
+
+ if(unlikely((c->isleaf && c->hasparent) || d->enabled_all_classes_qdiscs)) {
+ c->render = 1;
+ active_nodes++;
bytes_sum += c->bytes;
packets_sum += c->packets;
dropped_sum += c->dropped;
tokens_sum += c->tokens;
ctokens_sum += c->ctokens;
}
- }
- if(unlikely(!active_classes)) {
- debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
- tc_device_classes_cleanup(d);
- return;
+ //if(unlikely(!c->hasparent)) {
+ // if(root) error("TC: multiple root class/qdisc for device '%s' (old: '%s', new: '%s')", d->id, root->id, c->id);
+ // root = c;
+ // debug(D_TC_LOOP, "TC: found root class/qdisc '%s'", root->id);
+ //}
}
- if(unlikely(d->enabled == (char)-1)) {
- char var_name[CONFIG_MAX_NAME + 1];
- snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
- d->enabled = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
-
- snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
- d->enabled_bytes = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
+#ifdef NETDATA_INTERNAL_CHECKS
+ // dump all the list to see what we know
- snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
- d->enabled_packets = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
-
- snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
- d->enabled_dropped = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
-
- snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
- d->enabled_tokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
+ if(unlikely(debug_flags & D_TC_LOOP)) {
+ for(c = d->classes ; c ; c = c->next) {
+ if(c->render) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", d->name, c->id);
+ else debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, IGNORE (updated: %d, isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->updated, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
+ }
+ }
+#endif
- snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
- d->enabled_ctokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
+ if(unlikely(!active_nodes)) {
+ debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No useful classes/qdiscs.", d->name?d->name:d->id);
+ tc_device_classes_cleanup(d);
+ return;
}
- debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d), classes = %d (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
+ debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d, all_classes_qdiscs: %d/%d), classes: (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
d->name?d->name:d->id,
d->enabled, enable_new_interfaces,
d->enabled_bytes, enable_bytes,
@@ -288,7 +359,7 @@ static inline void tc_device_commit(struct tc_device *d) {
d->enabled_dropped, enable_dropped,
d->enabled_tokens, enable_tokens,
d->enabled_ctokens, enable_ctokens,
- active_classes,
+ d->enabled_all_classes_qdiscs, enabled_all_classes_qdiscs,
bytes_sum,
packets_sum,
dropped_sum,
@@ -296,287 +367,226 @@ static inline void tc_device_commit(struct tc_device *d) {
ctokens_sum
);
- if(likely(d->enabled)) {
- // --------------------------------------------------------------------
- // bytes
+ // --------------------------------------------------------------------
+ // bytes
- if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) {
- d->enabled_bytes = CONFIG_ONDEMAND_YES;
+ if(d->enabled_bytes == CONFIG_BOOLEAN_YES || (d->enabled_bytes == CONFIG_BOOLEAN_AUTO && bytes_sum)) {
+ d->enabled_bytes = CONFIG_BOOLEAN_YES;
- if(unlikely(!d->st_bytes)) {
- d->st_bytes = rrdset_find_bytype(RRD_TYPE_TC, d->id);
- if(unlikely(!d->st_bytes)) {
- debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
- d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);
- }
- }
- else {
- debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_bytes);
+ if(unlikely(!d->st_bytes))
+ d->st_bytes = rrdset_create_localhost(RRD_TYPE_TC, d->id, d->name ? d->name : d->id
+ , d->family ? d->family : d->id, RRD_TYPE_TC ".qos", "Class Usage"
+ , "kilobits/s", 7000, localhost->rrd_update_every
+ , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE
+ : RRDSET_TYPE_STACKED);
- if(unlikely(d->name_updated && d->name && strcmp(d->id, d->name) != 0)) {
- rrdset_set_name(d->st_bytes, d->name);
- d->name_updated = 0;
- }
+ else {
+ rrdset_next(d->st_bytes);
+ if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, d->name);
- // FIXME
- // update the family
- }
+ // FIXME
+ // update the family
+ }
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_bytes)) {
- c->rd_bytes = rrddim_find(d->st_bytes, c->id);
- if(unlikely(!c->rd_bytes)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_bytes->id, c->id, c->name);
+ 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);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
- // new class, we have to add it
- c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_bytes->id, c->id);
- }
+ rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
+ }
+ rrdset_done(d->st_bytes);
+ }
- rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
+ // --------------------------------------------------------------------
+ // packets
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_bytes->id, c->rd_bytes->id, c->name);
- rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
- }
- }
- }
- rrdset_done(d->st_bytes);
- }
+ if(d->enabled_packets == CONFIG_BOOLEAN_YES || (d->enabled_packets == CONFIG_BOOLEAN_AUTO && packets_sum)) {
+ d->enabled_packets = CONFIG_BOOLEAN_YES;
- // --------------------------------------------------------------------
- // packets
-
- if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) {
- d->enabled_packets = CONFIG_ONDEMAND_YES;
+ if(unlikely(!d->st_packets)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
- if(unlikely(!d->st_packets)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ d->st_packets = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010
+ , localhost->rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE
+ : RRDSET_TYPE_STACKED);
+ }
+ else {
+ rrdset_next(d->st_packets);
+
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
-
- d->st_packets = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_packets)) {
- debug(D_TC_LOOP, "TC: Creating new _packets chart for device '%s'", d->name?d->name:d->id);
- d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, RRDSET_TYPE_STACKED);
- }
+ rrdset_set_name(d->st_packets, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _packets chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_packets);
- // FIXME
- // update the family
- }
+ // FIXME
+ // update the family
+ }
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_packets)) {
- c->rd_packets = rrddim_find(d->st_packets, c->id);
- if(unlikely(!c->rd_packets)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_packets->id, c->id, c->name);
+ if(unlikely(!c->rd_packets))
+ c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_packets, c->rd_packets, c->name);
- // new class, we have to add it
- c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_packets->id, c->id);
- }
+ rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
+ }
+ rrdset_done(d->st_packets);
+ }
- rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
+ // --------------------------------------------------------------------
+ // dropped
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_packets->id, c->rd_packets->id, c->name);
- rrddim_set_name(d->st_packets, c->rd_packets, c->name);
- }
- }
- }
- rrdset_done(d->st_packets);
+ if(d->enabled_dropped == CONFIG_BOOLEAN_YES || (d->enabled_dropped == CONFIG_BOOLEAN_AUTO && dropped_sum)) {
+ d->enabled_dropped = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_dropped)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
+
+ d->st_dropped = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s"
+ , 7020, localhost->rrd_update_every
+ , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE
+ : RRDSET_TYPE_STACKED);
}
+ else {
+ rrdset_next(d->st_dropped);
- // --------------------------------------------------------------------
- // dropped
-
- if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) {
- d->enabled_dropped = CONFIG_ONDEMAND_YES;
-
- if(unlikely(!d->st_dropped)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
-
- d->st_dropped = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_dropped)) {
- debug(D_TC_LOOP, "TC: Creating new _dropped chart for device '%s'", d->name?d->name:d->id);
- d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, RRDSET_TYPE_STACKED);
- }
+ rrdset_set_name(d->st_dropped, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _dropped chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_dropped);
- // FIXME
- // update the family
- }
+ // FIXME
+ // update the family
+ }
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_dropped)) {
- c->rd_dropped = rrddim_find(d->st_dropped, c->id);
- if(unlikely(!c->rd_dropped)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_dropped->id, c->id, c->name);
+ if(unlikely(!c->rd_dropped))
+ c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
- // new class, we have to add it
- c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_dropped->id, c->id);
- }
+ rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
+ }
+ rrdset_done(d->st_dropped);
+ }
- rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
+ // --------------------------------------------------------------------
+ // tokens
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_dropped->id, c->rd_dropped->id, c->name);
- rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
- }
- }
- }
- rrdset_done(d->st_dropped);
+ if(d->enabled_tokens == CONFIG_BOOLEAN_YES || (d->enabled_tokens == CONFIG_BOOLEAN_AUTO && tokens_sum)) {
+ d->enabled_tokens = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_tokens)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
+
+ d->st_tokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030
+ , localhost->rrd_update_every, RRDSET_TYPE_LINE);
}
+ else {
+ rrdset_next(d->st_tokens);
- // --------------------------------------------------------------------
- // tokens
-
- if(d->enabled_tokens == CONFIG_ONDEMAND_YES || (d->enabled_tokens == CONFIG_ONDEMAND_ONDEMAND && tokens_sum)) {
- d->enabled_tokens = CONFIG_ONDEMAND_YES;
-
- if(unlikely(!d->st_tokens)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
-
- d->st_tokens = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_tokens)) {
- debug(D_TC_LOOP, "TC: Creating new _tokens chart for device '%s'", d->name?d->name:d->id);
- d->st_tokens = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030, rrd_update_every, RRDSET_TYPE_LINE);
- }
+ rrdset_set_name(d->st_tokens, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _tokens chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_tokens);
- // FIXME
- // update the family
+ // FIXME
+ // update the family
+ }
+
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
+
+ if(unlikely(!c->rd_tokens)) {
+ c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_tokens, c->rd_tokens, c->name);
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens);
+ }
+ rrdset_done(d->st_tokens);
+ }
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_tokens)) {
- c->rd_tokens = rrddim_find(d->st_tokens, c->id);
- if(unlikely(!c->rd_tokens)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_tokens->id, c->id, c->name);
+ // --------------------------------------------------------------------
+ // ctokens
- // new class, we have to add it
- c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_ABSOLUTE);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_tokens->id, c->id);
- }
+ if(d->enabled_ctokens == CONFIG_BOOLEAN_YES || (d->enabled_ctokens == CONFIG_BOOLEAN_AUTO && ctokens_sum)) {
+ d->enabled_ctokens = CONFIG_BOOLEAN_YES;
- rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens);
+ if(unlikely(!d->st_ctokens)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_tokens->id, c->rd_tokens->id, c->name);
- rrddim_set_name(d->st_tokens, c->rd_tokens, c->name);
- }
- }
- }
- rrdset_done(d->st_tokens);
+ d->st_ctokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040
+ , localhost->rrd_update_every, RRDSET_TYPE_LINE);
}
+ else {
+ debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id);
+ rrdset_next(d->st_ctokens);
- // --------------------------------------------------------------------
- // ctokens
-
- if(d->enabled_ctokens == CONFIG_ONDEMAND_YES || (d->enabled_ctokens == CONFIG_ONDEMAND_ONDEMAND && ctokens_sum)) {
- d->enabled_ctokens = CONFIG_ONDEMAND_YES;
-
- if(unlikely(!d->st_ctokens)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
-
- d->st_ctokens = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_ctokens)) {
- debug(D_TC_LOOP, "TC: Creating new _ctokens chart for device '%s'", d->name?d->name:d->id);
- d->st_ctokens = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040, rrd_update_every, RRDSET_TYPE_LINE);
- }
+ rrdset_set_name(d->st_ctokens, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_ctokens);
-
- // FIXME
- // update the family
- }
-
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_ctokens)) {
- c->rd_ctokens = rrddim_find(d->st_ctokens, c->id);
- if(unlikely(!c->rd_ctokens)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_ctokens->id, c->id, c->name);
+ // FIXME
+ // update the family
+ }
- // new class, we have to add it
- c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_ABSOLUTE);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_ctokens->id, c->id);
- }
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- rrddim_set_by_pointer(d->st_ctokens, c->rd_ctokens, c->ctokens);
+ if(unlikely(!c->rd_ctokens))
+ c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name);
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_ctokens->id, c->rd_ctokens->id, c->name);
- rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name);
- }
- }
- }
- rrdset_done(d->st_ctokens);
+ rrddim_set_by_pointer(d->st_ctokens, c->rd_ctokens, c->ctokens);
}
+ rrdset_done(d->st_ctokens);
}
tc_device_classes_cleanup(d);
}
-static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
-{
+static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name) {
+ if(unlikely(!name || !*name)) return;
+
struct tc_class *c = tc_class_index_find(d, id, 0);
if(likely(c)) {
- freez(c->name);
- c->name = NULL;
+ if(likely(c->name)) {
+ if(!strcmp(c->name, name)) return;
+ freez(c->name);
+ c->name = NULL;
+ }
if(likely(name && *name && strcmp(c->id, name) != 0)) {
debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
@@ -587,10 +597,15 @@ static inline void tc_device_set_class_name(struct tc_device *d, char *id, char
}
static inline void tc_device_set_device_name(struct tc_device *d, char *name) {
- freez(d->name);
- d->name = NULL;
+ if(unlikely(!name || !*name)) return;
+
+ if(d->name) {
+ if(!strcmp(d->name, name)) return;
+ freez(d->name);
+ d->name = NULL;
+ }
- if(likely(name && *name && strcmp(d->id, name) != 0)) {
+ if(likely(name && *name && strcmp(d->id, name))) {
debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
d->name = strdupz(name);
d->name_updated = 1;
@@ -639,7 +654,7 @@ static inline struct tc_device *tc_device_create(char *id)
return(d);
}
-static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
+static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char qdisc, char *parentid, char *leafid)
{
struct tc_class *c = tc_class_index_find(n, id, 0);
@@ -655,6 +670,7 @@ static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char
c->id = strdupz(id);
c->hash = simple_hash(c->id);
+ c->isqdisc = qdisc;
if(parentid && *parentid) {
c->parentid = strdupz(parentid);
c->parent_hash = simple_hash(c->parentid);
@@ -767,6 +783,7 @@ void *tc_main(void *ptr) {
uint32_t BEGIN_HASH = simple_hash("BEGIN");
uint32_t END_HASH = simple_hash("END");
+ uint32_t QDISC_HASH = simple_hash("qdisc");
uint32_t CLASS_HASH = simple_hash("class");
uint32_t SENT_HASH = simple_hash("Sent");
uint32_t LENDED_HASH = simple_hash("lended:");
@@ -780,7 +797,7 @@ void *tc_main(void *ptr) {
#endif
uint32_t first_hash;
- snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR));
+ snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", netdata_configured_plugins_dir);
char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
for(;1;) {
@@ -790,7 +807,7 @@ void *tc_main(void *ptr) {
struct tc_device *device = NULL;
struct tc_class *class = NULL;
- snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every);
+ snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, localhost->rrd_update_every);
debug(D_TC_LOOP, "executing '%s'", buffer);
fp = mypopen(buffer, (pid_t *)&tc_child_pid);
@@ -815,25 +832,51 @@ void *tc_main(void *ptr) {
first_hash = simple_hash(words[0]);
- if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
+ if(unlikely(device && ((first_hash == CLASS_HASH && strcmp(words[0], "class") == 0) || (first_hash == QDISC_HASH && strcmp(words[0], "qdisc") == 0)))) {
// debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
- // words[1] : class type
- // words[2] : N:XX
- // words[3] : parent or root
- if(likely(words[1] && words[2] && words[3] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0))) {
- //char *type = words[1]; // the class: htb, fq_codel, etc
+ char *type = words[1]; // the class/qdisc type: htb, fq_codel, etc
+ char *id = words[2]; // the class/qdisc major:minor
+ char *parent = words[3]; // the word 'parent' or 'root'
+ char *parentid = words[4]; // parentid
+ char *leaf = words[5]; // the word 'leaf'
+ char *leafid = words[6]; // leafid
+
+ int parent_is_root = 0;
+ int parent_is_parent = 0;
+ if(likely(parent)) {
+ parent_is_parent = !strcmp(parent, "parent");
- // we are only interested for HTB classes
- //if(strcmp(type, "htb") != 0) continue;
+ if(!parent_is_parent)
+ parent_is_root = !strcmp(parent, "root");
+ }
+
+ if(likely(type && id && (parent_is_root || parent_is_parent))) {
+ char qdisc = 0;
+
+ if(first_hash == QDISC_HASH) {
+ qdisc = 1;
- char *id = words[2]; // the class major:minor
- char *parent = words[3]; // 'parent' or 'root'
- char *parentid = words[4]; // the parent's id
- char *leaf = words[5]; // 'leaf'
- char *leafid = words[6]; // leafid
+ if(!strcmp(type, "ingress")) {
+ // we don't want to get the ingress qdisc
+ // there should be an IFB interface for this
+
+ class = NULL;
+ continue;
+ }
+
+ if(parent_is_parent && parentid) {
+ // eliminate the minor number from parentid
+ // why: parentid is the id of the parent class
+ // but major: is also the id of the parent qdisc
+
+ char *s = parentid;
+ while(*s && *s != ':') s++;
+ if(*s == ':') s[1] = '\0';
+ }
+ }
- if(strcmp(parent, "root") == 0) {
+ if(parent_is_root) {
parentid = NULL;
leafid = NULL;
}
@@ -847,7 +890,7 @@ void *tc_main(void *ptr) {
leafid = leafbuf;
}
- class = tc_class_add(device, id, parentid, leafid);
+ class = tc_class_add(device, id, qdisc, parentid, leafid);
}
else {
// clear the last class
@@ -946,11 +989,13 @@ void *tc_main(void *ptr) {
// debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
getrusage(RUSAGE_THREAD, &thread);
- if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu");
+ if(unlikely(!stcpu)) stcpu = rrdset_find_localhost("netdata.plugin_tc_cpu");
if(unlikely(!stcpu)) {
- stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED);
- rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ stcpu = rrdset_create_localhost("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL
+ , "NetData TC CPU usage", "milliseconds/s", 135000, localhost->rrd_update_every
+ , RRDSET_TYPE_STACKED);
+ rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(stcpu);
@@ -958,10 +1003,12 @@ void *tc_main(void *ptr) {
rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
rrdset_done(stcpu);
- if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time");
+ if(unlikely(!sttime)) sttime = rrdset_find_localhost("netdata.plugin_tc_time");
if(unlikely(!sttime)) {
- sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(sttime, "run_time", "run time", 1, 1, RRDDIM_ABSOLUTE);
+ sttime = rrdset_create_localhost("netdata", "plugin_tc_time", NULL, "tc.helper", NULL
+ , "NetData TC script execution", "milliseconds/run", 135001
+ , localhost->rrd_update_every, RRDSET_TYPE_AREA);
+ rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(sttime);
@@ -1009,7 +1056,7 @@ void *tc_main(void *ptr) {
goto cleanup;
}
- sleep((unsigned int) rrd_update_every);
+ sleep((unsigned int) localhost->rrd_update_every);
}
cleanup:
diff --git a/src/plugins_d.c b/src/plugins_d.c
index 4b83b5281..7fa19eaf0 100644
--- a/src/plugins_d.c
+++ b/src/plugins_d.c
@@ -83,302 +83,315 @@ static int pluginsd_split_words(char *str, char **words, int max_words) {
return i;
}
+inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
+ int enabled = cd->enabled;
-void *pluginsd_worker_thread(void *arg)
-{
- struct plugind *cd = (struct plugind *)arg;
- cd->obsolete = 0;
+ if(!fp || !enabled) {
+ cd->enabled = 0;
+ return 0;
+ }
- char line[PLUGINSD_LINE_MAX + 1];
+ size_t count = 0;
-#ifdef DETACH_PLUGINS_FROM_NETDATA
- usec_t usec = 0, susec = 0;
- struct timeval last = {0, 0} , now = {0, 0};
-#endif
+ char line[PLUGINSD_LINE_MAX + 1];
char *words[MAX_WORDS] = { NULL };
+ /* uint32_t HOST_HASH = simple_hash("HOST"); */
uint32_t BEGIN_HASH = simple_hash("BEGIN");
uint32_t END_HASH = simple_hash("END");
uint32_t FLUSH_HASH = simple_hash("FLUSH");
uint32_t CHART_HASH = simple_hash("CHART");
uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
uint32_t DISABLE_HASH = simple_hash("DISABLE");
-#ifdef DETACH_PLUGINS_FROM_NETDATA
- uint32_t MYPID_HASH = simple_hash("MYPID");
- uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
-#endif
- size_t count = 0;
+ RRDSET *st = NULL;
+ uint32_t hash;
- for(;;) {
+ errno = 0;
+ clearerr(fp);
+
+ if(unlikely(fileno(fp) == -1)) {
+ error("PLUGINSD: %s: file is not a valid stream.", cd->fullfilename);
+ goto cleanup;
+ }
+
+ while(!ferror(fp)) {
if(unlikely(netdata_exit)) break;
- FILE *fp = mypopen(cd->cmd, &cd->pid);
- if(unlikely(!fp)) {
- error("Cannot popen(\"%s\", \"r\").", cd->cmd);
+ char *r = fgets(line, PLUGINSD_LINE_MAX, fp);
+ if(unlikely(!r)) {
+ error("PLUGINSD: %s : read failed.", cd->fullfilename);
break;
}
- info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
+ if(unlikely(netdata_exit)) break;
- RRDSET *st = NULL;
- uint32_t hash;
+ line[PLUGINSD_LINE_MAX] = '\0';
- while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
- if(unlikely(netdata_exit)) break;
+ // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
- line[PLUGINSD_LINE_MAX] = '\0';
+ int w = pluginsd_split_words(line, words, MAX_WORDS);
+ char *s = words[0];
+ if(unlikely(!s || !*s || !w)) {
+ // debug(D_PLUGINSD, "PLUGINSD: empty line");
+ continue;
+ }
- // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
+ // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
- int w = pluginsd_split_words(line, words, MAX_WORDS);
- char *s = words[0];
- if(unlikely(!s || !*s || !w)) {
- // debug(D_PLUGINSD, "PLUGINSD: empty line");
- continue;
- }
+ if(likely(!simple_hash_strcmp(s, "SET", &hash))) {
+ char *dimension = words[1];
+ char *value = words[2];
- // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
+ if(unlikely(!dimension || !*dimension)) {
+ error("PLUGINSD: '%s' is requesting a SET on chart '%s' of host '%s', without a dimension. Disabling it.", cd->fullfilename, st->id, host->hostname);
+ enabled = 0;
+ break;
+ }
- if(likely(!simple_hash_strcmp(s, "SET", &hash))) {
- char *dimension = words[1];
- char *value = words[2];
+ if(unlikely(!value || !*value)) value = NULL;
- if(unlikely(!dimension || !*dimension)) {
- error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>", host->hostname);
+ enabled = 0;
+ break;
+ }
- if(unlikely(!value || !*value)) value = NULL;
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
-
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
+ if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
+ }
+ else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
+ char *id = words[1];
+ char *microseconds_txt = words[2];
- if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
+ if(unlikely(!id)) {
+ error("PLUGINSD: '%s' is requesting a BEGIN without a chart id for host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
}
- else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
- char *id = words[1];
- char *microseconds_txt = words[2];
- if(unlikely(!id)) {
- error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ st = rrdset_find(host, id);
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", cd->fullfilename, id, host->hostname);
+ enabled = 0;
+ break;
+ }
- st = rrdset_find(id);
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ if(likely(st->counter_done)) {
+ usec_t microseconds = 0;
+ if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt);
- if(likely(st->counter_done)) {
- usec_t microseconds = 0;
- if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt);
- if(microseconds) rrdset_next_usec(st, microseconds);
- else rrdset_next(st);
+ if(likely(microseconds)) {
+ if(trust_durations)
+ rrdset_next_usec_unfiltered(st, microseconds);
+ else
+ rrdset_next_usec(st, microseconds);
}
+ else rrdset_next(st);
}
- else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ }
+ else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting an END, without a BEGIN on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
+ rrdset_done(st);
+ st = NULL;
- rrdset_done(st);
- st = NULL;
+ count++;
+ }
+/* else if(likely(hash == HOST_HASH && !strcmp(s, "HOST"))) {
+ char *guid = words[1];
+ char *hostname = words[2];
- count++;
+ if(unlikely(!guid || !*guid)) {
+ error("PLUGINSD: '%s' is requesting HOST with guid '%s' and hostname '%s', without a guid. Disabling it.", cd->fullfilename, guid?guid:"", hostname?hostname:"");
+ enabled = 0;
+ break;
}
- else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
- debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
- st = NULL;
+ if(unlikely(!hostname || !*hostname)) {
+ error("PLUGINSD: '%s' is requesting HOST with guid '%s' and hostname '%s', without a hostname. Disabling it.", cd->fullfilename, guid?guid:"", hostname?hostname:"");
+ enabled = 0;
+ break;
}
- else if(likely(hash == CHART_HASH && !strcmp(s, "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 *id = NULL;
- if(likely(type)) {
- id = strchr(type, '.');
- if(likely(id)) { *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];
-
- if(unlikely(!type || !*type || !id || !*id)) {
- error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
- int priority = 1000;
- if(likely(priority_s)) priority = str2i(priority_s);
-
- int update_every = cd->update_every;
- if(likely(update_every_s)) update_every = str2i(update_every_s);
- if(unlikely(!update_every)) update_every = cd->update_every;
-
- int 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;
-
- st = rrdset_find_bytype(type, id);
- if(unlikely(!st)) {
- debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
- , type, id
- , name?name:""
- , family?family:""
- , context?context:""
- , rrdset_type_name(chart_type)
- , priority
- , update_every
- );
-
- st = rrdset_create(type, id, name, family, context, title, units, priority, update_every, chart_type);
- cd->update_every = update_every;
- }
- else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
+ host = rrdhost_find_or_create(hostname, guid);
+ } */
+ else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
+ debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
+ st = NULL;
+ }
+ else if(likely(hash == CHART_HASH && !strcmp(s, "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 *id = NULL;
+ if(likely(type)) {
+ id = strchr(type, '.');
+ if(likely(id)) { *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];
+
+ 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;
}
- else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
- char *id = words[1];
- char *name = words[2];
- char *algorithm = words[3];
- char *multiplier_s = words[4];
- char *divisor_s = words[5];
- char *options = words[6];
-
- if(unlikely(!id || !*id)) {
- error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
-
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
- long multiplier = 1;
- if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
- if(unlikely(!multiplier)) multiplier = 1;
-
- long divisor = 1;
- if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
- if(unlikely(!divisor)) divisor = 1;
-
- if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
-
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
- , st->id
- , id
- , name?name:""
- , rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
- , multiplier
- , divisor
- , options?options:""
- );
-
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
- rd->flags = 0x00000000;
- if(options && *options) {
- if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
- if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
- if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
- }
- }
- else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
+ int priority = 1000;
+ if(likely(priority_s)) priority = str2i(priority_s);
+
+ int update_every = cd->update_every;
+ if(likely(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;
+
+ st = rrdset_find_bytype(host, type, id);
+ if(unlikely(!st)) {
+ debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
+ , type, id
+ , name?name:""
+ , family?family:""
+ , context?context:""
+ , rrdset_type_name(chart_type)
+ , priority
+ , update_every
+ );
+
+ st = rrdset_create(host, type, id, name, family, context, title, units, priority, update_every, chart_type);
+ cd->update_every = update_every;
}
- else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
- info("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
+ else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
+ }
+ else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
+ char *id = words[1];
+ char *name = words[2];
+ char *algorithm = words[3];
+ char *multiplier_s = words[4];
+ char *divisor_s = words[5];
+ char *options = words[6];
+
+ if(unlikely(!id || !*id)) {
+ error("PLUGINSD: '%s' is requesting a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", cd->fullfilename, host->hostname, st?st->id:"UNSET");
+ enabled = 0;
break;
}
-#ifdef DETACH_PLUGINS_FROM_NETDATA
- else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
- char *pid_s = words[1];
- pid_t pid = strtod(pid_s, NULL, 0);
- if(likely(pid)) cd->pid = pid;
- debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART, on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
}
- else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
- error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
- now_realtime_timeval(&now);
- if(unlikely(!usec && !susec)) {
- // our first run
- susec = cd->rrd_update_every * USEC_PER_SEC;
+ long multiplier = 1;
+ if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
+ if(unlikely(!multiplier)) multiplier = 1;
+
+ long divisor = 1;
+ if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
+ if(unlikely(!divisor)) divisor = 1;
+
+ if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
+ , st->id
+ , id
+ , name?name:""
+ , rrd_algorithm_name(rrd_algorithm_id(algorithm))
+ , multiplier
+ , divisor
+ , options?options:""
+ );
+
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ rd = rrddim_add(st, id, name, multiplier, divisor, rrd_algorithm_id(algorithm));
+ rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
+ rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
+ if(options && *options) {
+ if(strstr(options, "hidden") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
+ if(strstr(options, "noreset") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
+ if(strstr(options, "nooverflow") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
}
- else {
- // second+ run
- usec = dt_usec(&now, &last) - susec;
- error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
- if(unlikely(usec < (rrd_update_every * USEC_PER_SEC / 2ULL))) susec = (rrd_update_every * USEC_PER_SEC) - usec;
- else susec = rrd_update_every * USEC_PER_SEC / 2ULL;
- }
-
- error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
- usleep(susec);
- killpid(cd->pid, SIGCONT);
- memmove(&last, &now, sizeof(struct timeval));
- break;
- }
-#endif
- else {
- error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
}
+ else if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
+ }
+ else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
+ info("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
+ enabled = 0;
+ break;
}
- if(likely(count)) {
- cd->successful_collections += count;
- cd->serial_failures = 0;
+ else {
+ error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata, for host '%s'. Disabling it.", cd->fullfilename, s, host->hostname);
+ enabled = 0;
+ break;
}
- else
- cd->serial_failures++;
+ }
+
+cleanup:
+ cd->enabled = enabled;
+
+ if(likely(count)) {
+ cd->successful_collections += count;
+ cd->serial_failures = 0;
+ }
+ else
+ cd->serial_failures++;
+
+ return count;
+}
+
+void *pluginsd_worker_thread(void *arg) {
+ struct plugind *cd = (struct plugind *)arg;
+ cd->obsolete = 0;
+
+ size_t count = 0;
+
+ for(;;) {
+ if(unlikely(netdata_exit)) break;
+
+ FILE *fp = mypopen(cd->cmd, &cd->pid);
+ if(unlikely(!fp)) {
+ error("Cannot popen(\"%s\", \"r\").", cd->cmd);
+ break;
+ }
+
+ info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
+
+ count = pluginsd_process(localhost, cd, fp, 0);
+ error("PLUGINSD: plugin '%s' disconnected.", cd->fullfilename);
+
+ killpid(cd->pid, SIGTERM);
info("PLUGINSD: '%s' on pid %d stopped after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
// get the return code
int code = mypclose(fp, cd->pid);
-
+
if(unlikely(netdata_exit)) break;
else if(code != 0) {
// the plugin reports failure
@@ -442,24 +455,23 @@ void *pluginsd_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
- int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
- int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
+ int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1);
+ int scan_frequency = (int) config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
DIR *dir = NULL;
struct dirent *file = NULL;
struct plugind *cd;
// enable the apps plugin by default
- // config_get_boolean("plugins", "apps", 1);
+ // config_get_boolean(CONFIG_SECTION_PLUGINS, "apps", 1);
if(scan_frequency < 1) scan_frequency = 1;
for(;;) {
if(unlikely(netdata_exit)) break;
- dir = opendir(dir_name);
+ dir = opendir(netdata_configured_plugins_dir);
if(unlikely(!dir)) {
- error("Cannot open directory '%s'.", dir_name);
+ error("Cannot open directory '%s'.", netdata_configured_plugins_dir);
goto cleanup;
}
@@ -479,7 +491,7 @@ void *pluginsd_main(void *ptr) {
char pluginname[CONFIG_MAX_NAME + 1];
snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
- int enabled = config_get_boolean("plugins", pluginname, automatic_run);
+ int enabled = config_get_boolean(CONFIG_SECTION_PLUGINS, pluginname, automatic_run);
if(unlikely(!enabled)) {
debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name);
@@ -503,10 +515,10 @@ void *pluginsd_main(void *ptr) {
snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
strncpyz(cd->filename, file->d_name, FILENAME_MAX);
- snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
+ snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", netdata_configured_plugins_dir, cd->filename);
cd->enabled = enabled;
- cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
+ cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every);
cd->started_t = now_realtime_sec();
char *def = "";
diff --git a/src/plugins_d.h b/src/plugins_d.h
index 3c74355a3..d34c4030c 100644
--- a/src/plugins_d.h
+++ b/src/plugins_d.h
@@ -11,7 +11,7 @@ struct plugind {
char filename[FILENAME_MAX+1]; // just the filename
char fullfilename[FILENAME_MAX+1]; // with path
- char cmd[PLUGINSD_CMD_MAX+1]; // the command that is executes
+ char cmd[PLUGINSD_CMD_MAX+1]; // the command that it executes
pid_t pid;
pthread_t thread;
@@ -34,5 +34,6 @@ struct plugind {
extern struct plugind *pluginsd_root;
extern void *pluginsd_main(void *ptr);
+extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations);
#endif /* NETDATA_PLUGINS_D_H */
diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c
index 9ccac6dc7..a1b4072dd 100644
--- a/src/proc_diskstats.c
+++ b/src/proc_diskstats.c
@@ -6,6 +6,9 @@
#define DISK_TYPE_PARTITION 2
#define DISK_TYPE_CONTAINER 3
+#define CONFIG_SECTION_DISKSTATS "plugin:proc:/proc/diskstats"
+#define DELAULT_EXLUDED_DISKS "loop* ram*"
+
static struct disk {
char *disk; // the name of the disk (sda, sdb, etc)
unsigned long major;
@@ -25,9 +28,24 @@ static struct disk {
int do_util;
int do_backlog;
+ int updated;
+
+ RRDSET *st_avgsz;
+ RRDSET *st_await;
+ RRDSET *st_backlog;
+ RRDSET *st_io;
+ RRDSET *st_iotime;
+ RRDSET *st_mops;
+ RRDSET *st_ops;
+ RRDSET *st_qops;
+ RRDSET *st_svctm;
+ RRDSET *st_util;
+
struct disk *next;
} *disk_root = NULL;
+#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE); st = NULL; } } while(st)
+
static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
@@ -46,7 +64,7 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
// not found
// create a new disk structure
- d = (struct disk *)mallocz(sizeof(struct disk));
+ d = (struct disk *)callocz(1, sizeof(struct disk));
d->disk = strdupz(disk);
d->major = major;
@@ -72,8 +90,8 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
// get the default path for finding info about the block device
if(unlikely(!path_find_block_device[0])) {
- snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
- snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
+ snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s");
+ snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer));
}
// find if it is a partition
@@ -126,12 +144,12 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
// find the disk sector size
if(unlikely(!path_to_get_hw_sector_size[0])) {
- snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
- snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
+ snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size");
+ snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer));
}
if(unlikely(!path_to_get_hw_sector_size_partitions[0])) {
- snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
- snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
+ snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
+ snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size for partitions", buffer));
}
{
@@ -170,7 +188,7 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
}
static inline int is_major_enabled(int major) {
- static char *major_configs = NULL;
+ static int8_t *major_configs = NULL;
static size_t major_size = 0;
if(major < 0) return 1;
@@ -178,7 +196,7 @@ static inline int is_major_enabled(int major) {
size_t wanted_size = (size_t)major + 1;
if(major_size < wanted_size) {
- major_configs = reallocz(major_configs, wanted_size);
+ major_configs = reallocz(major_configs, wanted_size * sizeof(int8_t));
size_t i;
for(i = major_size; i < wanted_size ; i++)
@@ -190,43 +208,40 @@ static inline int is_major_enabled(int major) {
if(major_configs[major] == -1) {
char buffer[CONFIG_MAX_NAME + 1];
snprintfz(buffer, CONFIG_MAX_NAME, "performance metrics for disks with major %d", major);
- major_configs[major] = (char)config_get_boolean("plugin:proc:/proc/diskstats", buffer, 1);
+ major_configs[major] = (char)config_get_boolean(CONFIG_SECTION_DISKSTATS, buffer, 1);
}
- return major_configs[major];
+ return (int)major_configs[major];
}
int do_proc_diskstats(int update_every, usec_t dt) {
- (void)dt;
-
static procfile *ff = NULL;
- static int global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
- global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
- global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_ONDEMAND,
- global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
- global_do_io = CONFIG_ONDEMAND_ONDEMAND,
- global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
- global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
- global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
- global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
- global_do_util = CONFIG_ONDEMAND_ONDEMAND,
- global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
+ static int global_enable_new_disks_detected_at_runtime = CONFIG_BOOLEAN_YES,
+ global_enable_performance_for_physical_disks = CONFIG_BOOLEAN_AUTO,
+ global_enable_performance_for_virtual_disks = CONFIG_BOOLEAN_AUTO,
+ global_enable_performance_for_partitions = CONFIG_BOOLEAN_NO,
+ global_do_io = CONFIG_BOOLEAN_AUTO,
+ global_do_ops = CONFIG_BOOLEAN_AUTO,
+ global_do_mops = CONFIG_BOOLEAN_AUTO,
+ global_do_iotime = CONFIG_BOOLEAN_AUTO,
+ global_do_qops = CONFIG_BOOLEAN_AUTO,
+ global_do_util = CONFIG_BOOLEAN_AUTO,
+ global_do_backlog = CONFIG_BOOLEAN_AUTO,
globals_initialized = 0;
if(unlikely(!globals_initialized)) {
- global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
-
- global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
- global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
- global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
-
- global_do_io = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
- global_do_ops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
- global_do_mops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
- global_do_iotime = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
- global_do_qops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
- global_do_util = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
- global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
+ global_enable_new_disks_detected_at_runtime = config_get_boolean(CONFIG_SECTION_DISKSTATS, "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
+ global_enable_performance_for_physical_disks = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for physical disks", global_enable_performance_for_physical_disks);
+ global_enable_performance_for_virtual_disks = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
+ global_enable_performance_for_partitions = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for partitions", global_enable_performance_for_partitions);
+
+ global_do_io = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "bandwidth for all disks", global_do_io);
+ global_do_ops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "operations for all disks", global_do_ops);
+ global_do_mops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "merged operations for all disks", global_do_mops);
+ global_do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "i/o time for all disks", global_do_iotime);
+ global_do_qops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "queued operations for all disks", global_do_qops);
+ 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);
globals_initialized = 1;
}
@@ -235,8 +250,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/diskstats");
- ff = procfile_open(config_get("plugin:proc:/proc/diskstats", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/diskstats");
+ ff = procfile_open(config_get(CONFIG_SECTION_DISKSTATS, "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(unlikely(!ff)) return 0;
@@ -318,7 +333,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// get a disk structure for the disk
struct disk *d = get_disk(major, minor, disk);
-
+ d->updated = 1;
// --------------------------------------------------------------------------
// Set its family based on mount point
@@ -331,25 +346,41 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// Check the configuration for the device
if(unlikely(!d->configured)) {
+ d->configured = 1;
+
+ static SIMPLE_PATTERN *excluded_disks = NULL;
+
+ if(unlikely(!excluded_disks)) {
+ excluded_disks = simple_pattern_create(
+ config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DELAULT_EXLUDED_DISKS),
+ SIMPLE_PATTERN_EXACT
+ );
+ }
+
+ int def_enable = global_enable_new_disks_detected_at_runtime;
+
+ if(def_enable != CONFIG_BOOLEAN_NO && simple_pattern_matches(excluded_disks, disk))
+ def_enable = CONFIG_BOOLEAN_NO;
+
char var_name[4096 + 1];
snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
- int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
- if(unlikely(def_enable == CONFIG_ONDEMAND_NO)) {
+ def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable);
+ if(unlikely(def_enable == CONFIG_BOOLEAN_NO)) {
// the user does not want any metrics for this disk
- d->do_io = CONFIG_ONDEMAND_NO;
- d->do_ops = CONFIG_ONDEMAND_NO;
- d->do_mops = CONFIG_ONDEMAND_NO;
- d->do_iotime = CONFIG_ONDEMAND_NO;
- d->do_qops = CONFIG_ONDEMAND_NO;
- d->do_util = CONFIG_ONDEMAND_NO;
- d->do_backlog = CONFIG_ONDEMAND_NO;
+ d->do_io = CONFIG_BOOLEAN_NO;
+ d->do_ops = CONFIG_BOOLEAN_NO;
+ d->do_mops = CONFIG_BOOLEAN_NO;
+ d->do_iotime = CONFIG_BOOLEAN_NO;
+ d->do_qops = CONFIG_BOOLEAN_NO;
+ d->do_util = CONFIG_BOOLEAN_NO;
+ d->do_backlog = CONFIG_BOOLEAN_NO;
}
else {
// this disk is enabled
// check its direct settings
- int def_performance = CONFIG_ONDEMAND_ONDEMAND;
+ int def_performance = CONFIG_BOOLEAN_AUTO;
// since this is 'on demand' we can figure the performance settings
// based on the type of disk
@@ -380,16 +411,16 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// check the user configuration (this will also show our 'on demand' decision)
def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
- int ddo_io = CONFIG_ONDEMAND_NO,
- ddo_ops = CONFIG_ONDEMAND_NO,
- ddo_mops = CONFIG_ONDEMAND_NO,
- ddo_iotime = CONFIG_ONDEMAND_NO,
- ddo_qops = CONFIG_ONDEMAND_NO,
- ddo_util = CONFIG_ONDEMAND_NO,
- ddo_backlog = CONFIG_ONDEMAND_NO;
+ int ddo_io = CONFIG_BOOLEAN_NO,
+ ddo_ops = CONFIG_BOOLEAN_NO,
+ ddo_mops = CONFIG_BOOLEAN_NO,
+ ddo_iotime = CONFIG_BOOLEAN_NO,
+ ddo_qops = CONFIG_BOOLEAN_NO,
+ ddo_util = CONFIG_BOOLEAN_NO,
+ ddo_backlog = CONFIG_BOOLEAN_NO;
// we enable individual performance charts only when def_performance is not disabled
- if(unlikely(def_performance != CONFIG_ONDEMAND_NO)) {
+ if(unlikely(def_performance != CONFIG_BOOLEAN_NO)) {
ddo_io = global_do_io,
ddo_ops = global_do_ops,
ddo_mops = global_do_mops,
@@ -407,144 +438,216 @@ int do_proc_diskstats(int update_every, usec_t dt) {
d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
}
-
- d->configured = 1;
}
- RRDSET *st;
-
// --------------------------------------------------------------------------
// Do performance metrics
- if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
- d->do_io = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
- if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
+ if(d->do_io == CONFIG_BOOLEAN_YES || (d->do_io == CONFIG_BOOLEAN_AUTO && (readsectors || writesectors))) {
+ d->do_io = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_io)) {
+ d->st_io = rrdset_create_localhost(
+ RRD_TYPE_DISK
+ , disk
+ , NULL
+ , family
+ , "disk.io"
+ , "Disk I/O Bandwidth"
+ , "kilobytes/s"
+ , 2000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_io);
- last_readsectors = rrddim_set(st, "reads", readsectors);
- last_writesectors = rrddim_set(st, "writes", writesectors);
- rrdset_done(st);
+ last_readsectors = rrddim_set(d->st_io, "reads", readsectors);
+ last_writesectors = rrddim_set(d->st_io, "writes", writesectors);
+ rrdset_done(d->st_io);
}
// --------------------------------------------------------------------
- if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
- d->do_ops = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_ops", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if(d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes))) {
+ d->do_ops = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_ops)) {
+ d->st_ops = rrdset_create_localhost(
+ "disk_ops"
+ , disk
+ , NULL
+ , family
+ , "disk.ops"
+ , "Disk Completed I/O Operations"
+ , "operations/s"
+ , 2001
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_ops, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_ops);
- last_reads = rrddim_set(st, "reads", reads);
- last_writes = rrddim_set(st, "writes", writes);
- rrdset_done(st);
+ last_reads = rrddim_set(d->st_ops, "reads", reads);
+ last_writes = rrddim_set(d->st_ops, "writes", writes);
+ rrdset_done(d->st_ops);
}
// --------------------------------------------------------------------
- if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
- d->do_qops = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_qops", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ if(d->do_qops == CONFIG_BOOLEAN_YES || (d->do_qops == CONFIG_BOOLEAN_AUTO && queued_ios)) {
+ d->do_qops = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_qops)) {
+ d->st_qops = rrdset_create_localhost(
+ "disk_qops"
+ , disk
+ , NULL
+ , family
+ , "disk.qops"
+ , "Disk Current I/O Operations"
+ , "operations"
+ , 2002
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_qops, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_qops);
- rrddim_set(st, "operations", queued_ios);
- rrdset_done(st);
+ rrddim_set(d->st_qops, "operations", queued_ios);
+ rrdset_done(d->st_qops);
}
// --------------------------------------------------------------------
- if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
- d->do_backlog = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_backlog", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
+ if(d->do_backlog == CONFIG_BOOLEAN_YES || (d->do_backlog == CONFIG_BOOLEAN_AUTO && backlog_ms)) {
+ d->do_backlog = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_backlog)) {
+ d->st_backlog = rrdset_create_localhost(
+ "disk_backlog"
+ , disk
+ , NULL
+ , family
+ , "disk.backlog"
+ , "Disk Backlog"
+ , "backlog (ms)"
+ , 2003
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(d->st_backlog, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_backlog, "backlog", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_backlog);
- rrddim_set(st, "backlog", backlog_ms);
- rrdset_done(st);
+ rrddim_set(d->st_backlog, "backlog", backlog_ms);
+ rrdset_done(d->st_backlog);
}
// --------------------------------------------------------------------
- if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
- d->do_util = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_util", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
+ if(d->do_util == CONFIG_BOOLEAN_YES || (d->do_util == CONFIG_BOOLEAN_AUTO && busy_ms)) {
+ d->do_util = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_util)) {
+ d->st_util = rrdset_create_localhost(
+ "disk_util"
+ , disk
+ , NULL
+ , family
+ , "disk.util"
+ , "Disk Utilization Time"
+ , "% of time working"
+ , 2004
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(d->st_util, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_util, "utilization", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_util);
- last_busy_ms = rrddim_set(st, "utilization", busy_ms);
- rrdset_done(st);
+ last_busy_ms = rrddim_set(d->st_util, "utilization", busy_ms);
+ rrdset_done(d->st_util);
}
// --------------------------------------------------------------------
- if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
- d->do_mops = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_mops", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if(d->do_mops == CONFIG_BOOLEAN_YES || (d->do_mops == CONFIG_BOOLEAN_AUTO && (mreads || mwrites))) {
+ d->do_mops = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_mops)) {
+ d->st_mops = rrdset_create_localhost(
+ "disk_mops"
+ , disk
+ , NULL
+ , family
+ , "disk.mops"
+ , "Disk Merged Operations"
+ , "merged operations/s"
+ , 2021
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_mops, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_mops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_mops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_mops);
- rrddim_set(st, "reads", mreads);
- rrddim_set(st, "writes", mwrites);
- rrdset_done(st);
+ rrddim_set(d->st_mops, "reads", mreads);
+ rrddim_set(d->st_mops, "writes", mwrites);
+ rrdset_done(d->st_mops);
}
// --------------------------------------------------------------------
- if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
- d->do_iotime = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_iotime", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if(d->do_iotime == CONFIG_BOOLEAN_YES || (d->do_iotime == CONFIG_BOOLEAN_AUTO && (readms || writems))) {
+ d->do_iotime = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_iotime)) {
+ d->st_iotime = rrdset_create_localhost(
+ "disk_iotime"
+ , disk
+ , NULL
+ , family
+ , "disk.iotime"
+ , "Disk Total I/O Time"
+ , "milliseconds/s"
+ , 2022
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_iotime, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_iotime);
- last_readms = rrddim_set(st, "reads", readms);
- last_writems = rrddim_set(st, "writes", writems);
- rrdset_done(st);
+ last_readms = rrddim_set(d->st_iotime, "reads", readms);
+ last_writems = rrddim_set(d->st_iotime, "writes", writems);
+ rrdset_done(d->st_iotime);
}
// --------------------------------------------------------------------
@@ -552,54 +655,127 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// only if this is not the first time we run
if(likely(dt)) {
- if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
- (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
- st = rrdset_find_bytype("disk_await", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ if( (d->do_iotime == CONFIG_BOOLEAN_YES || (d->do_iotime == CONFIG_BOOLEAN_AUTO && (readms || writems))) &&
+ (d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes)))) {
+
+ if(unlikely(!d->st_await)) {
+ d->st_await = rrdset_create_localhost(
+ "disk_await"
+ , disk
+ , NULL
+ , family
+ , "disk.await"
+ , "Average Completed I/O Operation Time"
+ , "ms per operation"
+ , 2005
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_await, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_await, "reads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(d->st_await, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_await);
- rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
- rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
- rrdset_done(st);
+ rrddim_set(d->st_await, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
+ rrddim_set(d->st_await, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
+ rrdset_done(d->st_await);
}
- if( (d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
- (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
- st = rrdset_find_bytype("disk_avgsz", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
+ if( (d->do_io == CONFIG_BOOLEAN_YES || (d->do_io == CONFIG_BOOLEAN_AUTO && (readsectors || writesectors))) &&
+ (d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes)))) {
+
+ if(unlikely(!d->st_avgsz)) {
+ d->st_avgsz = rrdset_create_localhost(
+ "disk_avgsz"
+ , disk
+ , NULL
+ , family
+ , "disk.avgsz"
+ , "Average Completed I/O Operation Bandwidth"
+ , "kilobytes per operation"
+ , 2006
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(d->st_avgsz, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_avgsz, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(d->st_avgsz, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_avgsz);
- rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
- rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
- rrdset_done(st);
+ rrddim_set(d->st_avgsz, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
+ rrddim_set(d->st_avgsz, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
+ rrdset_done(d->st_avgsz);
}
- if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
- (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
- st = rrdset_find_bytype("disk_svctm", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ if( (d->do_util == CONFIG_BOOLEAN_YES || (d->do_util == CONFIG_BOOLEAN_AUTO && busy_ms)) &&
+ (d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes)))) {
+
+ if(unlikely(!d->st_svctm)) {
+ d->st_svctm = rrdset_create_localhost(
+ "disk_svctm"
+ , disk
+ , NULL
+ , family
+ , "disk.svctm"
+ , "Average Service Time"
+ , "ms per operation"
+ , 2007
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_svctm, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_svctm, "svctm", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_svctm);
+
+ rrddim_set(d->st_svctm, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
+ rrdset_done(d->st_svctm);
+ }
+ }
+ }
- rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
- rrdset_done(st);
+ // cleanup removed disks
+
+ struct disk *d = disk_root, *last = NULL;
+ while(d) {
+ if(unlikely(!d->updated)) {
+ struct disk *t = d;
+
+ rrdset_obsolete_and_pointer_null(d->st_avgsz);
+ rrdset_obsolete_and_pointer_null(d->st_await);
+ rrdset_obsolete_and_pointer_null(d->st_backlog);
+ rrdset_obsolete_and_pointer_null(d->st_io);
+ rrdset_obsolete_and_pointer_null(d->st_iotime);
+ rrdset_obsolete_and_pointer_null(d->st_mops);
+ rrdset_obsolete_and_pointer_null(d->st_ops);
+ rrdset_obsolete_and_pointer_null(d->st_qops);
+ rrdset_obsolete_and_pointer_null(d->st_svctm);
+ rrdset_obsolete_and_pointer_null(d->st_util);
+
+ if(d == disk_root) {
+ disk_root = d = d->next;
+ last = NULL;
+ }
+ else if(last) {
+ last->next = d = d->next;
}
+
+ freez(t->disk);
+ freez(t->mount_point);
+ freez(t);
+ }
+ else {
+ d->updated = 0;
+ last = d;
+ d = d->next;
}
}
diff --git a/src/proc_interrupts.c b/src/proc_interrupts.c
index f663c0fdd..082e1f57b 100644
--- a/src/proc_interrupts.c
+++ b/src/proc_interrupts.c
@@ -59,7 +59,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/interrupts");
ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(unlikely(!ff))
@@ -146,8 +146,9 @@ int do_proc_interrupts(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("system", "interrupts");
- if(unlikely(!st)) st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
+ 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);
for(l = 0; l < lines ;l++) {
@@ -159,7 +160,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
irr->rd = rrddim_find(st, irr->id);
if(unlikely(!irr->rd))
- irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->rd, irr->name);
@@ -181,11 +182,12 @@ int do_proc_interrupts(int update_every, usec_t dt) {
char id[50+1];
snprintfz(id, 50, "cpu%d_interrupts", c);
- st = rrdset_find_bytype("cpu", id);
+ st = rrdset_find_bytype_localhost("cpu", id);
if(unlikely(!st)) {
char title[100+1];
snprintfz(title, 100, "CPU%d Interrupts", c);
- st = rrdset_create("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s", 1100 + c, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s",
+ 1100 + c, update_every, RRDSET_TYPE_STACKED);
}
else rrdset_next(st);
@@ -195,7 +197,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!irr->cpu[c].rd)) {
irr->cpu[c].rd = rrddim_find(st, irr->id);
if(unlikely(!irr->cpu[c].rd))
- irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->cpu[c].rd, irr->name);
}
diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c
index 4326ffb7d..e7863f114 100644
--- a/src/proc_loadavg.c
+++ b/src/proc_loadavg.c
@@ -6,12 +6,12 @@
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 last_loadavg_usec = 0;
+ static usec_t next_loadavg_dt = 0;
static RRDSET *load_chart = NULL, *processes_chart = NULL;
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/loadavg");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/loadavg");
ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
@@ -47,15 +47,18 @@ int do_proc_loadavg(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(last_loadavg_usec <= dt) {
+ if(next_loadavg_dt <= dt) {
if(likely(do_loadavg)) {
if(unlikely(!load_chart)) {
- load_chart = rrdset_find_byname("system.load");
+ load_chart = rrdset_find_byname_localhost("system.load");
if(unlikely(!load_chart)) {
- load_chart = rrdset_create("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, RRDDIM_ABSOLUTE);
- rrddim_add(load_chart, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(load_chart, "load15", NULL, 1, 1000, RRDDIM_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);
+ 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);
}
}
else
@@ -67,18 +70,20 @@ int do_proc_loadavg(int update_every, usec_t dt) {
rrdset_done(load_chart);
}
- last_loadavg_usec = load_chart->update_every * USEC_PER_SEC;
+ next_loadavg_dt = load_chart->update_every * USEC_PER_SEC;
}
- else last_loadavg_usec -= dt;
+ else next_loadavg_dt -= dt;
// --------------------------------------------------------------------
if(likely(do_all_processes)) {
if(unlikely(!processes_chart)) {
- processes_chart = rrdset_find_byname("system.active_processes");
+ processes_chart = rrdset_find_byname_localhost("system.active_processes");
if(unlikely(!processes_chart)) {
- processes_chart = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
- rrddim_add(processes_chart, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ 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);
}
}
else rrdset_next(processes_chart);
diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c
index 19ba8da3c..6b0219cc9 100644
--- a/src/proc_meminfo.c
+++ b/src/proc_meminfo.c
@@ -55,8 +55,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
if(unlikely(!arl_base)) {
do_ram = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
- do_swap = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "system swap", CONFIG_ONDEMAND_ONDEMAND);
- do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_ONDEMAND_ONDEMAND);
+ do_swap = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "system swap", CONFIG_BOOLEAN_AUTO);
+ do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_BOOLEAN_AUTO);
do_committed = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
do_writeback = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
do_kernel = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
@@ -109,7 +109,7 @@ int do_proc_meminfo(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/meminfo");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/meminfo");
ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
@@ -140,14 +140,15 @@ int do_proc_meminfo(int update_every, usec_t dt) {
unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
if(do_ram) {
- st = rrdset_find("system.ram");
+ st = rrdset_find_localhost("system.ram");
if(!st) {
- st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
+ 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, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "cached", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "buffers", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ 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);
}
else rrdset_next(st);
@@ -162,16 +163,17 @@ int do_proc_meminfo(int update_every, usec_t dt) {
unsigned long long SwapUsed = SwapTotal - SwapFree;
- if(SwapTotal || SwapUsed || SwapFree || do_swap == CONFIG_ONDEMAND_YES) {
- do_swap = CONFIG_ONDEMAND_YES;
+ if(SwapTotal || SwapUsed || SwapFree || do_swap == CONFIG_BOOLEAN_YES) {
+ do_swap = CONFIG_BOOLEAN_YES;
- st = rrdset_find("system.swap");
+ st = rrdset_find_localhost("system.swap");
if(!st) {
- st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ 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, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -182,15 +184,16 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(arl_hwcorrupted->flags & ARL_ENTRY_FLAG_FOUND && (do_hwcorrupt == CONFIG_ONDEMAND_YES || (do_hwcorrupt == CONFIG_ONDEMAND_ONDEMAND && HardwareCorrupted > 0))) {
- do_hwcorrupt = CONFIG_ONDEMAND_YES;
+ 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("mem.hwcorrupt");
+ st = rrdset_find_localhost("mem.hwcorrupt");
if(!st) {
- st = rrdset_create("mem", "hwcorrupt", NULL, "ecc", NULL, "Hardware Corrupted ECC", "MB", 9000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -201,12 +204,13 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_committed) {
- st = rrdset_find("mem.committed");
+ st = rrdset_find_localhost("mem.committed");
if(!st) {
- st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ 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, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -217,16 +221,17 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_writeback) {
- st = rrdset_find("mem.writeback");
+ st = rrdset_find_localhost("mem.writeback");
if(!st) {
- st = rrdset_create("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "Dirty", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "Writeback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "Bounce", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ 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);
}
else rrdset_next(st);
@@ -241,15 +246,16 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_kernel) {
- st = rrdset_find("mem.kernel");
+ st = rrdset_find_localhost("mem.kernel");
if(!st) {
- st = rrdset_create("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
-
- rrddim_add(st, "Slab", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "KernelStack", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "PageTables", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ 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);
}
else rrdset_next(st);
@@ -263,13 +269,14 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_slab) {
- st = rrdset_find("mem.slab");
+ st = rrdset_find_localhost("mem.slab");
if(!st) {
- st = rrdset_create("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ 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, RRDDIM_ABSOLUTE);
- rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "reclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c
index 82661abd4..1b00758d5 100644
--- a/src/proc_net_dev.c
+++ b/src/proc_net_dev.c
@@ -8,6 +8,7 @@ struct netdev {
// flags
int configured;
int enabled;
+ int updated;
int do_bandwidth;
int do_packets;
@@ -18,23 +19,23 @@ struct netdev {
int do_events;
// data collected
- unsigned long long rbytes;
- unsigned long long rpackets;
- unsigned long long rerrors;
- unsigned long long rdrops;
- unsigned long long rfifo;
- unsigned long long rframe;
- unsigned long long rcompressed;
- unsigned long long rmulticast;
-
- unsigned long long tbytes;
- unsigned long long tpackets;
- unsigned long long terrors;
- unsigned long long tdrops;
- unsigned long long tfifo;
- unsigned long long tcollisions;
- unsigned long long tcarrier;
- unsigned long long tcompressed;
+ kernel_uint_t rbytes;
+ kernel_uint_t rpackets;
+ kernel_uint_t rerrors;
+ kernel_uint_t rdrops;
+ kernel_uint_t rfifo;
+ kernel_uint_t rframe;
+ kernel_uint_t rcompressed;
+ kernel_uint_t rmulticast;
+
+ kernel_uint_t tbytes;
+ kernel_uint_t tpackets;
+ kernel_uint_t terrors;
+ kernel_uint_t tdrops;
+ kernel_uint_t tfifo;
+ kernel_uint_t tcollisions;
+ kernel_uint_t tcarrier;
+ kernel_uint_t tcompressed;
// charts
RRDSET *st_bandwidth;
@@ -67,26 +68,73 @@ struct netdev {
struct netdev *next;
};
-static struct netdev *netdev_root = NULL;
+static struct netdev *netdev_root = NULL, *netdev_last_used = NULL;
+
+static size_t netdev_added = 0, netdev_found = 0;
+
+static void netdev_free(struct netdev *d) {
+ if(d->st_bandwidth) rrdset_flag_set(d->st_bandwidth, RRDSET_FLAG_OBSOLETE);
+ if(d->st_packets) rrdset_flag_set(d->st_packets, RRDSET_FLAG_OBSOLETE);
+ if(d->st_errors) rrdset_flag_set(d->st_errors, RRDSET_FLAG_OBSOLETE);
+ if(d->st_drops) rrdset_flag_set(d->st_drops, RRDSET_FLAG_OBSOLETE);
+ if(d->st_fifo) rrdset_flag_set(d->st_fifo, RRDSET_FLAG_OBSOLETE);
+ if(d->st_compressed) rrdset_flag_set(d->st_compressed, RRDSET_FLAG_OBSOLETE);
+ if(d->st_events) rrdset_flag_set(d->st_events, RRDSET_FLAG_OBSOLETE);
+
+ netdev_added--;
+ freez(d->name);
+ freez(d);
+}
+
+static void netdev_cleanup() {
+ if(likely(netdev_found == netdev_added)) return;
+
+ netdev_added = 0;
+ struct netdev *d = netdev_root, *last = NULL;
+ while(d) {
+ if(unlikely(!d->updated)) {
+ // info("Removing network device '%s', linked after '%s'", d->name, last?last->name:"ROOT");
+
+ if(netdev_last_used == d)
+ netdev_last_used = last;
+
+ struct netdev *t = d;
+
+ if(d == netdev_root || !last)
+ netdev_root = d = d->next;
+
+ else
+ last->next = d = d->next;
+
+ t->next = NULL;
+ netdev_free(t);
+ }
+ else {
+ netdev_added++;
+ last = d;
+ d->updated = 0;
+ d = d->next;
+ }
+ }
+}
static struct netdev *get_netdev(const char *name) {
- static struct netdev *last = NULL;
struct netdev *d;
uint32_t hash = simple_hash(name);
// search it, from the last position to the end
- for(d = last ; d ; d = d->next) {
+ for(d = netdev_last_used ; d ; d = d->next) {
if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
- last = d->next;
+ netdev_last_used = d->next;
return d;
}
}
// search it from the beginning to the last position we used
- for(d = netdev_root ; d != last ; d = d->next) {
+ for(d = netdev_root ; d != netdev_last_used ; d = d->next) {
if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
- last = d->next;
+ netdev_last_used = d->next;
return d;
}
}
@@ -96,6 +144,7 @@ static struct netdev *get_netdev(const char *name) {
d->name = strdupz(name);
d->hash = simple_hash(d->name);
d->len = strlen(d->name);
+ netdev_added++;
// link it to the end
if(netdev_root) {
@@ -111,22 +160,21 @@ static struct netdev *get_netdev(const char *name) {
int do_proc_net_dev(int update_every, usec_t dt) {
(void)dt;
-
static SIMPLE_PATTERN *disabled_list = NULL;
static procfile *ff = NULL;
static int enable_new_interfaces = -1;
static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
if(unlikely(enable_new_interfaces == -1)) {
- enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
+ enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+ do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_BOOLEAN_AUTO);
+ 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")
@@ -135,7 +183,7 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/dev");
ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -143,12 +191,16 @@ 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
+ netdev_found = 0;
+
size_t lines = procfile_lines(ff), l;
for(l = 2; l < lines ;l++) {
// require 17 words on each line
if(unlikely(procfile_linewords(ff, l) < 17)) continue;
struct netdev *d = get_netdev(procfile_lineword(ff, l, 0));
+ d->updated = 1;
+ netdev_found++;
if(unlikely(!d->configured)) {
// this is the first time we see this interface
@@ -165,207 +217,293 @@ int do_proc_net_dev(int update_every, usec_t dt) {
snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", d->name);
d->enabled = config_get_boolean_ondemand(var_name, "enabled", d->enabled);
- if(d->enabled == CONFIG_ONDEMAND_NO)
+ 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))
continue;
- d->rbytes = str2ull(procfile_lineword(ff, l, 1));
- d->rpackets = str2ull(procfile_lineword(ff, l, 2));
- d->rerrors = str2ull(procfile_lineword(ff, l, 3));
- d->rdrops = str2ull(procfile_lineword(ff, l, 4));
- d->rfifo = str2ull(procfile_lineword(ff, l, 5));
- d->rframe = str2ull(procfile_lineword(ff, l, 6));
- d->rcompressed = str2ull(procfile_lineword(ff, l, 7));
- d->rmulticast = str2ull(procfile_lineword(ff, l, 8));
-
- d->tbytes = str2ull(procfile_lineword(ff, l, 9));
- d->tpackets = str2ull(procfile_lineword(ff, l, 10));
- d->terrors = str2ull(procfile_lineword(ff, l, 11));
- d->tdrops = str2ull(procfile_lineword(ff, l, 12));
- d->tfifo = str2ull(procfile_lineword(ff, l, 13));
- d->tcollisions = str2ull(procfile_lineword(ff, l, 14));
- d->tcarrier = str2ull(procfile_lineword(ff, l, 15));
- d->tcompressed = str2ull(procfile_lineword(ff, l, 16));
+ if(likely(d->do_bandwidth != CONFIG_BOOLEAN_NO)) {
+ d->rbytes = str2kernel_uint_t(procfile_lineword(ff, l, 1));
+ d->tbytes = str2kernel_uint_t(procfile_lineword(ff, l, 9));
+ }
+
+ if(likely(d->do_packets != CONFIG_BOOLEAN_NO)) {
+ d->rpackets = str2kernel_uint_t(procfile_lineword(ff, l, 2));
+ d->rmulticast = str2kernel_uint_t(procfile_lineword(ff, l, 8));
+ d->tpackets = str2kernel_uint_t(procfile_lineword(ff, l, 10));
+ }
+
+ if(likely(d->do_errors != CONFIG_BOOLEAN_NO)) {
+ d->rerrors = str2kernel_uint_t(procfile_lineword(ff, l, 3));
+ d->terrors = str2kernel_uint_t(procfile_lineword(ff, l, 11));
+ }
+
+ if(likely(d->do_drops != CONFIG_BOOLEAN_NO)) {
+ d->rdrops = str2kernel_uint_t(procfile_lineword(ff, l, 4));
+ d->tdrops = str2kernel_uint_t(procfile_lineword(ff, l, 12));
+ }
+
+ if(likely(d->do_fifo != CONFIG_BOOLEAN_NO)) {
+ d->rfifo = str2kernel_uint_t(procfile_lineword(ff, l, 5));
+ d->tfifo = str2kernel_uint_t(procfile_lineword(ff, l, 13));
+ }
+
+ if(likely(d->do_compressed != CONFIG_BOOLEAN_NO)) {
+ d->rcompressed = str2kernel_uint_t(procfile_lineword(ff, l, 7));
+ d->tcompressed = str2kernel_uint_t(procfile_lineword(ff, l, 16));
+ }
+
+ if(likely(d->do_events != CONFIG_BOOLEAN_NO)) {
+ d->rframe = str2kernel_uint_t(procfile_lineword(ff, l, 6));
+ d->tcollisions = str2kernel_uint_t(procfile_lineword(ff, l, 14));
+ d->tcarrier = str2kernel_uint_t(procfile_lineword(ff, l, 15));
+ }
// --------------------------------------------------------------------
- if(unlikely((d->do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (d->rbytes || d->tbytes))))
- d->do_bandwidth = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_bandwidth == CONFIG_BOOLEAN_AUTO && (d->rbytes || d->tbytes))))
+ d->do_bandwidth = CONFIG_BOOLEAN_YES;
- if(d->do_bandwidth == CONFIG_ONDEMAND_YES) {
+ if(d->do_bandwidth == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_bandwidth)) {
- d->st_bandwidth = rrdset_find_bytype("net", d->name);
- if(!d->st_bandwidth)
- d->st_bandwidth = rrdset_create("net", d->name, NULL, d->name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
-
- d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ d->st_bandwidth = rrdset_create_localhost(
+ "net"
+ , d->name
+ , NULL
+ , d->name
+ , "net.net"
+ , "Bandwidth"
+ , "kilobits/s"
+ , 7000
+ , 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);
}
else rrdset_next(d->st_bandwidth);
- rrddim_set_by_pointer(d->st_bandwidth, d->rd_rbytes, d->rbytes);
- rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, d->tbytes);
+ rrddim_set_by_pointer(d->st_bandwidth, d->rd_rbytes, (collected_number)d->rbytes);
+ rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, (collected_number)d->tbytes);
rrdset_done(d->st_bandwidth);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_packets == CONFIG_ONDEMAND_ONDEMAND && (d->rpackets || d->tpackets || d->rmulticast))))
- d->do_packets = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_packets == CONFIG_BOOLEAN_AUTO && (d->rpackets || d->tpackets || d->rmulticast))))
+ d->do_packets = CONFIG_BOOLEAN_YES;
- if(d->do_packets == CONFIG_ONDEMAND_YES) {
+ if(d->do_packets == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_packets)) {
- d->st_packets = rrdset_find_bytype("net_packets", d->name);
-
- if(!d->st_packets)
- d->st_packets = rrdset_create("net_packets", d->name, NULL, d->name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
- d->st_packets->isdetail = 1;
-
- d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ d->st_packets = rrdset_create_localhost(
+ "net_packets"
+ , d->name
+ , NULL
+ , d->name
+ , "net.packets"
+ , "Packets"
+ , "packets/s"
+ , 7001
+ , 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);
}
else rrdset_next(d->st_packets);
- rrddim_set_by_pointer(d->st_packets, d->rd_rpackets, d->rpackets);
- rrddim_set_by_pointer(d->st_packets, d->rd_tpackets, d->tpackets);
- rrddim_set_by_pointer(d->st_packets, d->rd_rmulticast, d->rmulticast);
+ rrddim_set_by_pointer(d->st_packets, d->rd_rpackets, (collected_number)d->rpackets);
+ rrddim_set_by_pointer(d->st_packets, d->rd_tpackets, (collected_number)d->tpackets);
+ rrddim_set_by_pointer(d->st_packets, d->rd_rmulticast, (collected_number)d->rmulticast);
rrdset_done(d->st_packets);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_errors == CONFIG_ONDEMAND_ONDEMAND && (d->rerrors || d->terrors))))
- d->do_errors = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_errors == CONFIG_BOOLEAN_AUTO && (d->rerrors || d->terrors))))
+ d->do_errors = CONFIG_BOOLEAN_YES;
- if(d->do_errors == CONFIG_ONDEMAND_YES) {
+ if(d->do_errors == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_errors)) {
- d->st_errors = rrdset_find_bytype("net_errors", d->name);
-
- if(!d->st_errors)
- d->st_errors = rrdset_create("net_errors", d->name, NULL, d->name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
-
- d->st_errors->isdetail = 1;
- d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_errors = rrdset_create_localhost(
+ "net_errors"
+ , d->name
+ , NULL
+ , d->name
+ , "net.errors"
+ , "Interface Errors"
+ , "errors/s"
+ , 7002
+ , 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_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_errors);
- rrddim_set_by_pointer(d->st_errors, d->rd_rerrors, d->rerrors);
- rrddim_set_by_pointer(d->st_errors, d->rd_terrors, d->terrors);
+ rrddim_set_by_pointer(d->st_errors, d->rd_rerrors, (collected_number)d->rerrors);
+ rrddim_set_by_pointer(d->st_errors, d->rd_terrors, (collected_number)d->terrors);
rrdset_done(d->st_errors);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_drops == CONFIG_ONDEMAND_ONDEMAND && (d->rdrops || d->tdrops))))
- d->do_drops = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_drops == CONFIG_BOOLEAN_AUTO && (d->rdrops || d->tdrops))))
+ d->do_drops = CONFIG_BOOLEAN_YES;
- if(d->do_drops == CONFIG_ONDEMAND_YES) {
+ if(d->do_drops == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_drops)) {
- d->st_drops = rrdset_find_bytype("net_drops", d->name);
-
- if(!d->st_drops)
- d->st_drops = rrdset_create("net_drops", d->name, NULL, d->name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
-
- d->st_drops->isdetail = 1;
- d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_drops = rrdset_create_localhost(
+ "net_drops"
+ , d->name
+ , NULL
+ , d->name
+ , "net.drops"
+ , "Interface Drops"
+ , "drops/s"
+ , 7003
+ , 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_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_drops);
- rrddim_set_by_pointer(d->st_drops, d->rd_rdrops, d->rdrops);
- rrddim_set_by_pointer(d->st_drops, d->rd_tdrops, d->tdrops);
+ rrddim_set_by_pointer(d->st_drops, d->rd_rdrops, (collected_number)d->rdrops);
+ rrddim_set_by_pointer(d->st_drops, d->rd_tdrops, (collected_number)d->tdrops);
rrdset_done(d->st_drops);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_fifo == CONFIG_ONDEMAND_ONDEMAND && (d->rfifo || d->tfifo))))
- d->do_fifo = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_fifo == CONFIG_BOOLEAN_AUTO && (d->rfifo || d->tfifo))))
+ d->do_fifo = CONFIG_BOOLEAN_YES;
- if(d->do_fifo == CONFIG_ONDEMAND_YES) {
+ if(d->do_fifo == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_fifo)) {
- d->st_fifo = rrdset_find_bytype("net_fifo", d->name);
- if(!d->st_fifo)
- d->st_fifo = rrdset_create("net_fifo", d->name, NULL, d->name, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
-
- d->st_fifo->isdetail = 1;
-
- d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_fifo = rrdset_create_localhost(
+ "net_fifo"
+ , d->name
+ , NULL
+ , d->name
+ , "net.fifo"
+ , "Interface FIFO Buffer Errors"
+ , "errors"
+ , 7004
+ , 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_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_fifo);
- rrddim_set_by_pointer(d->st_fifo, d->rd_rfifo, d->rfifo);
- rrddim_set_by_pointer(d->st_fifo, d->rd_tfifo, d->tfifo);
+ rrddim_set_by_pointer(d->st_fifo, d->rd_rfifo, (collected_number)d->rfifo);
+ rrddim_set_by_pointer(d->st_fifo, d->rd_tfifo, (collected_number)d->tfifo);
rrdset_done(d->st_fifo);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_compressed == CONFIG_ONDEMAND_ONDEMAND && (d->rcompressed || d->tcompressed))))
- d->do_compressed = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_compressed == CONFIG_BOOLEAN_AUTO && (d->rcompressed || d->tcompressed))))
+ d->do_compressed = CONFIG_BOOLEAN_YES;
- if(d->do_compressed == CONFIG_ONDEMAND_YES) {
+ if(d->do_compressed == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_compressed)) {
- d->st_compressed = rrdset_find_bytype("net_compressed", d->name);
- if(!d->st_compressed)
- d->st_compressed = rrdset_create("net_compressed", d->name, NULL, d->name, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
-
- d->st_compressed->isdetail = 1;
- d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_compressed = rrdset_create_localhost(
+ "net_compressed"
+ , d->name
+ , NULL
+ , d->name
+ , "net.compressed"
+ , "Compressed Packets"
+ , "packets/s"
+ , 7005
+ , 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);
}
else rrdset_next(d->st_compressed);
- rrddim_set_by_pointer(d->st_compressed, d->rd_rcompressed, d->rcompressed);
- rrddim_set_by_pointer(d->st_compressed, d->rd_tcompressed, d->tcompressed);
+ rrddim_set_by_pointer(d->st_compressed, d->rd_rcompressed, (collected_number)d->rcompressed);
+ rrddim_set_by_pointer(d->st_compressed, d->rd_tcompressed, (collected_number)d->tcompressed);
rrdset_done(d->st_compressed);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_events == CONFIG_ONDEMAND_ONDEMAND && (d->rframe || d->tcollisions || d->tcarrier))))
- d->do_events = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_events == CONFIG_BOOLEAN_AUTO && (d->rframe || d->tcollisions || d->tcarrier))))
+ d->do_events = CONFIG_BOOLEAN_YES;
- if(d->do_events == CONFIG_ONDEMAND_YES) {
+ if(d->do_events == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_events)) {
- d->st_events = rrdset_find_bytype("net_events", d->name);
- if(!d->st_events)
- d->st_events = rrdset_create("net_events", d->name, NULL, d->name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
- d->st_events->isdetail = 1;
-
- d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
- d->rd_tcarrier = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_events = rrdset_create_localhost(
+ "net_events"
+ , d->name
+ , NULL
+ , d->name
+ , "net.events"
+ , "Network Interface Events"
+ , "events/s"
+ , 7006
+ , 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_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);
}
else rrdset_next(d->st_events);
- rrddim_set_by_pointer(d->st_events, d->rd_rframe, d->rframe);
- rrddim_set_by_pointer(d->st_events, d->rd_tcollisions, d->tcollisions);
- rrddim_set_by_pointer(d->st_events, d->rd_tcarrier, d->tcarrier);
+ rrddim_set_by_pointer(d->st_events, d->rd_rframe, (collected_number)d->rframe);
+ rrddim_set_by_pointer(d->st_events, d->rd_tcollisions, (collected_number)d->tcollisions);
+ rrddim_set_by_pointer(d->st_events, d->rd_tcarrier, (collected_number)d->tcarrier);
rrdset_done(d->st_events);
}
}
+ netdev_cleanup();
+
return 0;
}
diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c
index 34cadaea7..16a3234df 100644
--- a/src/proc_net_ip_vs_stats.c
+++ b/src/proc_net_ip_vs_stats.c
@@ -3,6 +3,7 @@
#define RRD_TYPE_NET_IPVS "ipvs"
int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
+ (void)dt;
static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
static procfile *ff = NULL;
@@ -10,11 +11,9 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
if(do_packets == -1) do_packets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
- if(dt) {};
-
if(!ff) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/ip_vs_stats");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/ip_vs_stats");
ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -41,11 +40,13 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_sockets) {
- st = rrdset_find(RRD_TYPE_NET_IPVS ".sockets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".sockets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS New Connections", "connections/s", 3101, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL
+ , "IPVS New Connections", "connections/s", 3101, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -56,12 +57,13 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_packets) {
- st = rrdset_find(RRD_TYPE_NET_IPVS ".packets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".packets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets", "packets/s", 3102, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets"
+ , "packets/s", 3102, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -73,12 +75,13 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_bandwidth) {
- st = rrdset_find(RRD_TYPE_NET_IPVS ".net");
+ st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".net");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth", "kilobits/s", 3100, update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c
index 8741a71c9..2677a6c17 100644
--- a/src/proc_net_netstat.c
+++ b/src/proc_net_netstat.c
@@ -98,19 +98,19 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
hash_ipext = simple_hash("IpExt");
hash_tcpext = simple_hash("TcpExt");
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
- do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ecn = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
-
- do_tcpext_reorder = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP reorders", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_memory = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP memory pressures", CONFIG_ONDEMAND_ONDEMAND);
+ do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_BOOLEAN_AUTO);
+ do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_BOOLEAN_AUTO);
+ do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_BOOLEAN_AUTO);
+ do_ecn = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "ECN packets", CONFIG_BOOLEAN_AUTO);
+
+ do_tcpext_reorder = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP reorders", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syscookies = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_connaborts = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_memory = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP memory pressures", CONFIG_BOOLEAN_AUTO);
arl_ipext = arl_create("netstat/ipext", NULL, 60);
arl_tcpext = arl_create("netstat/tcpext", NULL, 60);
@@ -118,38 +118,38 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
// IPv4
- if(do_bandwidth != CONFIG_ONDEMAND_NO) {
+ if(do_bandwidth != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InOctets", &ipext_InOctets);
arl_expect(arl_ipext, "OutOctets", &ipext_OutOctets);
}
- if(do_inerrors != CONFIG_ONDEMAND_NO) {
+ if(do_inerrors != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InNoRoutes", &ipext_InNoRoutes);
arl_expect(arl_ipext, "InTruncatedPkts", &ipext_InTruncatedPkts);
arl_expect(arl_ipext, "InCsumErrors", &ipext_InCsumErrors);
}
- if(do_mcast != CONFIG_ONDEMAND_NO) {
+ if(do_mcast != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InMcastOctets", &ipext_InMcastOctets);
arl_expect(arl_ipext, "OutMcastOctets", &ipext_OutMcastOctets);
}
- if(do_mcast_p != CONFIG_ONDEMAND_NO) {
+ if(do_mcast_p != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InMcastPkts", &ipext_InMcastPkts);
arl_expect(arl_ipext, "OutMcastPkts", &ipext_OutMcastPkts);
}
- if(do_bcast != CONFIG_ONDEMAND_NO) {
+ if(do_bcast != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InBcastPkts", &ipext_InBcastPkts);
arl_expect(arl_ipext, "OutBcastPkts", &ipext_OutBcastPkts);
}
- if(do_bcast_p != CONFIG_ONDEMAND_NO) {
+ if(do_bcast_p != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InBcastOctets", &ipext_InBcastOctets);
arl_expect(arl_ipext, "OutBcastOctets", &ipext_OutBcastOctets);
}
- if(do_ecn != CONFIG_ONDEMAND_NO) {
+ if(do_ecn != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InNoECTPkts", &ipext_InNoECTPkts);
arl_expect(arl_ipext, "InECT1Pkts", &ipext_InECT1Pkts);
arl_expect(arl_ipext, "InECT0Pkts", &ipext_InECT0Pkts);
@@ -159,27 +159,27 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
// IPv4 TCP
- if(do_tcpext_reorder != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_reorder != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPFACKReorder", &tcpext_TCPFACKReorder);
arl_expect(arl_tcpext, "TCPSACKReorder", &tcpext_TCPSACKReorder);
arl_expect(arl_tcpext, "TCPRenoReorder", &tcpext_TCPRenoReorder);
arl_expect(arl_tcpext, "TCPTSReorder", &tcpext_TCPTSReorder);
}
- if(do_tcpext_syscookies != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_syscookies != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "SyncookiesSent", &tcpext_SyncookiesSent);
arl_expect(arl_tcpext, "SyncookiesRecv", &tcpext_SyncookiesRecv);
arl_expect(arl_tcpext, "SyncookiesFailed", &tcpext_SyncookiesFailed);
}
- if(do_tcpext_ofo != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_ofo != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPOFOQueue", &tcpext_TCPOFOQueue);
arl_expect(arl_tcpext, "TCPOFODrop", &tcpext_TCPOFODrop);
arl_expect(arl_tcpext, "TCPOFOMerge", &tcpext_TCPOFOMerge);
arl_expect(arl_tcpext, "OfoPruned", &tcpext_OfoPruned);
}
- if(do_tcpext_connaborts != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_connaborts != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPAbortOnData", &tcpext_TCPAbortOnData);
arl_expect(arl_tcpext, "TCPAbortOnClose", &tcpext_TCPAbortOnClose);
arl_expect(arl_tcpext, "TCPAbortOnMemory", &tcpext_TCPAbortOnMemory);
@@ -188,14 +188,14 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
arl_expect(arl_tcpext, "TCPAbortFailed", &tcpext_TCPAbortFailed);
}
- if(do_tcpext_memory != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_memory != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPMemoryPressures", &tcpext_TCPMemoryPressures);
}
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/netstat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/netstat");
ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -206,6 +206,9 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
size_t lines = procfile_lines(ff), l;
size_t words;
+ arl_begin(arl_ipext);
+ arl_begin(arl_tcpext);
+
for(l = 0; l < lines ;l++) {
char *key = procfile_lineword(ff, l, 0);
uint32_t hash = simple_hash(key);
@@ -219,21 +222,21 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
continue;
}
- arl_begin(arl_ipext);
parse_line_pair(ff, arl_ipext, h, l);
RRDSET *st;
// --------------------------------------------------------------------
- if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (ipext_InOctets || ipext_OutOctets))) {
- do_bandwidth = CONFIG_ONDEMAND_YES;
- st = rrdset_find("system.ipv4");
+ 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("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -244,16 +247,17 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_inerrors == CONFIG_ONDEMAND_YES || (do_inerrors == CONFIG_ONDEMAND_ONDEMAND && (ipext_InNoRoutes || ipext_InTruncatedPkts))) {
- do_inerrors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.inerrors");
+ 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("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors", "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", "truncated", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", "checksum", 1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -265,15 +269,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (ipext_InMcastOctets || ipext_OutMcastOctets))) {
- do_mcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.mcast");
+ 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("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMcastOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMcastOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMcastOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -284,15 +289,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (ipext_InBcastOctets || ipext_OutBcastOctets))) {
- do_bcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.bcast");
+ 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("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutBcastOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InBcastOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutBcastOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -303,15 +309,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (ipext_InMcastPkts || ipext_OutMcastPkts))) {
- do_mcast_p = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.mcastpkts");
+ 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("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets", "packets/s", 8600, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -322,15 +329,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bcast_p == CONFIG_ONDEMAND_YES || (do_bcast_p == CONFIG_ONDEMAND_ONDEMAND && (ipext_InBcastPkts || ipext_OutBcastPkts))) {
- do_bcast_p = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.bcastpkts");
+ 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("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets", "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutBcastPkts", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -341,17 +349,18 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (ipext_InCEPkts || ipext_InECT0Pkts || ipext_InECT1Pkts || ipext_InNoECTPkts))) {
- do_ecn = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.ecnpkts");
+ 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("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -371,20 +380,20 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
continue;
}
- arl_begin(arl_tcpext);
parse_line_pair(ff, arl_tcpext, h, l);
RRDSET *st;
// --------------------------------------------------------------------
- if(do_tcpext_memory == CONFIG_ONDEMAND_YES || (do_tcpext_memory == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPMemoryPressures))) {
- do_tcpext_memory = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpmemorypressures");
+ 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("ipv4", "tcpmemorypressures", NULL, "tcp", NULL, "TCP Memory Pressures", "events/s", 3000, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "TCPMemoryPressures", "pressures", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -394,18 +403,19 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPAbortOnData || tcpext_TCPAbortOnClose || tcpext_TCPAbortOnMemory || tcpext_TCPAbortOnTimeout || tcpext_TCPAbortOnLinger || tcpext_TCPAbortFailed))) {
- do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpconnaborts");
+ 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("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -419,16 +429,18 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
}
// --------------------------------------------------------------------
- if(do_tcpext_reorder == CONFIG_ONDEMAND_YES || (do_tcpext_reorder == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPRenoReorder || tcpext_TCPFACKReorder || tcpext_TCPSACKReorder || tcpext_TCPTSReorder))) {
- do_tcpext_reorder = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpreorders");
+ 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("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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPSACKReorder", "sack", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPFACKReorder", "fack", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPRenoReorder", "reno", 1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -441,16 +453,17 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPOFOQueue || tcpext_TCPOFODrop || tcpext_TCPOFOMerge))) {
- do_tcpext_ofo = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpofo");
+ 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("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPOFODrop", "dropped", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPOFOMerge", "merged", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OfoPruned", "pruned", -1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
@@ -463,15 +476,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpext_SyncookiesSent || tcpext_SyncookiesRecv || tcpext_SyncookiesFailed))) {
- do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpsyncookies");
+ 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("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st);
diff --git a/src/proc_net_rpc_nfs.c b/src/proc_net_rpc_nfs.c
index 9dba08d56..0df919635 100644
--- a/src/proc_net_rpc_nfs.c
+++ b/src/proc_net_rpc_nfs.c
@@ -136,7 +136,7 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(!ff) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfs");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/rpc/nfs");
ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -269,13 +269,14 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_net == 2) {
- st = rrdset_find_bytype("nfs", "net");
+ st = rrdset_find_bytype_localhost("nfs", "net");
if(!st) {
- st = rrdset_create("nfs", "net", NULL, "network", NULL, "NFS Client Network", "operations/s", 5007, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("nfs", "net", NULL, "network", NULL, "NFS Client Network", "operations/s", 5007
+ , update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -291,14 +292,15 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_rpc == 2) {
- st = rrdset_find_bytype("nfs", "rpc");
+ st = rrdset_find_bytype_localhost("nfs", "rpc");
if(!st) {
- st = rrdset_create("nfs", "rpc", NULL, "rpc", NULL, "NFS Client Remote Procedure Calls Statistics", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("nfs", "rpc", NULL, "rpc", NULL, "NFS Client Remote Procedure Calls Statistics"
+ , "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "calls", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "retransmits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "auth_refresh", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "retransmits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "auth_refresh", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -312,12 +314,13 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(do_proc2 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfs", "proc2");
+ st = rrdset_find_bytype_localhost("nfs", "proc2");
if(!st) {
- st = rrdset_create("nfs", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Client Remote Procedure Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfs", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Client Remote Procedure Calls"
+ , "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfs_proc2_values[i].present ; i++)
- rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -331,12 +334,13 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(do_proc3 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfs", "proc3");
+ st = rrdset_find_bytype_localhost("nfs", "proc3");
if(!st) {
- st = rrdset_create("nfs", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Client Remote Procedure Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfs", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Client Remote Procedure Calls"
+ , "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfs_proc3_values[i].present ; i++)
- rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -350,12 +354,13 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(do_proc4 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfs", "proc4");
+ st = rrdset_find_bytype_localhost("nfs", "proc4");
if(!st) {
- st = rrdset_create("nfs", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Client Remote Procedure Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfs", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Client Remote Procedure Calls"
+ , "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfs_proc4_values[i].present ; i++)
- rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_rpc_nfsd.c b/src/proc_net_rpc_nfsd.c
index 02a8c8f90..b0ed58d13 100644
--- a/src/proc_net_rpc_nfsd.c
+++ b/src/proc_net_rpc_nfsd.c
@@ -210,15 +210,14 @@ struct nfsd_procs nfsd4_ops_values[] = {
int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
+ (void)dt;
static procfile *ff = NULL;
static int do_rc = -1, do_fh = -1, do_io = -1, do_th = -1, do_ra = -1, do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1, do_proc4ops = -1;
static int ra_warning = 0, th_warning = 0, proc2_warning = 0, proc3_warning = 0, proc4_warning = 0, proc4ops_warning = 0;
- if(dt) {};
-
if(!ff) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfsd");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/rpc/nfsd");
ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfsd", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -493,13 +492,14 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_rc == 2) {
- st = rrdset_find_bytype("nfsd", "readcache");
+ st = rrdset_find_bytype_localhost("nfsd", "readcache");
if(!st) {
- st = rrdset_create("nfsd", "readcache", NULL, "cache", NULL, "NFS Server Read Cache", "reads/s", 5000, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "readcache", NULL, "cache", NULL, "NFS Server Read Cache", "reads/s"
+ , 5000, update_every, RRDSET_TYPE_STACKED);
- rrddim_add(st, "hits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "nocache", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "nocache", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -512,16 +512,17 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_fh == 2) {
- st = rrdset_find_bytype("nfsd", "filehandles");
+ st = rrdset_find_bytype_localhost("nfsd", "filehandles");
if(!st) {
- st = rrdset_create("nfsd", "filehandles", NULL, "filehandles", NULL, "NFS Server File Handles", "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "stale", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "total_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("nfsd", "filehandles", NULL, "filehandles", NULL, "NFS Server File Handles"
+ , "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "stale", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "total_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -536,12 +537,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_io == 2) {
- st = rrdset_find_bytype("nfsd", "io");
+ st = rrdset_find_bytype_localhost("nfsd", "io");
if(!st) {
- st = rrdset_create("nfsd", "io", NULL, "io", NULL, "NFS Server I/O", "kilobytes/s", 5002, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("nfsd", "io", NULL, "io", NULL, "NFS Server I/O", "kilobytes/s", 5002
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "read", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(st, "write", NULL, -1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "read", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "write", NULL, -1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -553,42 +555,47 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_th == 2) {
- st = rrdset_find_bytype("nfsd", "threads");
+ st = rrdset_find_bytype_localhost("nfsd", "threads");
if(!st) {
- st = rrdset_create("nfsd", "threads", NULL, "threads", NULL, "NFS Server Threads", "threads", 5003, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("nfsd", "threads", NULL, "threads", NULL, "NFS Server Threads", "threads", 5003
+ , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "threads", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "threads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
rrddim_set(st, "threads", th_threads);
rrdset_done(st);
- st = rrdset_find_bytype("nfsd", "threads_fullcnt");
+ st = rrdset_find_bytype_localhost("nfsd", "threads_fullcnt");
if(!st) {
- st = rrdset_create("nfsd", "threads_fullcnt", NULL, "threads", NULL, "NFS Server Threads Full Count", "ops/s", 5004, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("nfsd", "threads_fullcnt", NULL, "threads", NULL
+ , "NFS Server Threads Full Count", "ops/s", 5004, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "full_count", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "full_count", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
rrddim_set(st, "full_count", th_fullcnt);
rrdset_done(st);
- st = rrdset_find_bytype("nfsd", "threads_histogram");
+ st = rrdset_find_bytype_localhost("nfsd", "threads_histogram");
if(!st) {
- st = rrdset_create("nfsd", "threads_histogram", NULL, "threads", NULL, "NFS Server Threads Usage Histogram", "percentage", 5005, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "0%-10%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "10%-20%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "20%-30%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "30%-40%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "40%-50%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "50%-60%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "60%-70%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "70%-80%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "80%-90%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "90%-100%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("nfsd", "threads_histogram", NULL, "threads", NULL
+ , "NFS Server Threads Usage Histogram", "percentage", 5005, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "0%-10%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "10%-20%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "20%-30%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "30%-40%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "40%-50%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "50%-60%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "60%-70%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "70%-80%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "80%-90%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "90%-100%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -608,21 +615,22 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ra == 2) {
- st = rrdset_find_bytype("nfsd", "readahead");
+ st = rrdset_find_bytype_localhost("nfsd", "readahead");
if(!st) {
- st = rrdset_create("nfsd", "readahead", NULL, "readahead", NULL, "NFS Server Read Ahead Depth", "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "10%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "20%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "30%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "40%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "50%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "60%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "70%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "80%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "90%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "100%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ st = rrdset_create_localhost("nfsd", "readahead", NULL, "readahead", NULL, "NFS Server Read Ahead Depth"
+ , "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(st, "10%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "20%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "30%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "40%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "50%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "60%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "70%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "80%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "90%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "100%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
}
else rrdset_next(st);
@@ -646,13 +654,14 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_net == 2) {
- st = rrdset_find_bytype("nfsd", "net");
+ st = rrdset_find_bytype_localhost("nfsd", "net");
if(!st) {
- st = rrdset_create("nfsd", "net", NULL, "network", NULL, "NFS Server Network Statistics", "packets/s", 5007, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("nfsd", "net", NULL, "network", NULL, "NFS Server Network Statistics"
+ , "packets/s", 5007, update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -668,14 +677,16 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_rpc == 2) {
- st = rrdset_find_bytype("nfsd", "rpc");
+ st = rrdset_find_bytype_localhost("nfsd", "rpc");
if(!st) {
- st = rrdset_create("nfsd", "rpc", NULL, "rpc", NULL, "NFS Server Remote Procedure Calls Statistics", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "calls", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "bad_format", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "bad_auth", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("nfsd", "rpc", NULL, "rpc", NULL
+ , "NFS Server Remote Procedure Calls Statistics", "calls/s", 5008, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "bad_format", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "bad_auth", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -692,12 +703,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc2 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc2");
+ st = rrdset_find_bytype_localhost("nfsd", "proc2");
if(!st) {
- st = rrdset_create("nfsd", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Server Remote Procedure Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Server Remote Procedure Calls"
+ , "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd_proc2_values[i].present ; i++)
- rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -711,12 +723,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc3 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc3");
+ st = rrdset_find_bytype_localhost("nfsd", "proc3");
if(!st) {
- st = rrdset_create("nfsd", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Server Remote Procedure Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Server Remote Procedure Calls"
+ , "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd_proc3_values[i].present ; i++)
- rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -730,12 +743,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc4 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc4");
+ st = rrdset_find_bytype_localhost("nfsd", "proc4");
if(!st) {
- st = rrdset_create("nfsd", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Server Remote Procedure Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Server Remote Procedure Calls"
+ , "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd_proc4_values[i].present ; i++)
- rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -749,12 +763,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc4ops == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc4ops");
+ st = rrdset_find_bytype_localhost("nfsd", "proc4ops");
if(!st) {
- st = rrdset_create("nfsd", "proc4ops", NULL, "nfsv2ops", NULL, "NFS v4 Server Operations", "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc4ops", NULL, "nfsv2ops", NULL, "NFS v4 Server Operations"
+ , "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd4_ops_values[i].present ; i++)
- rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c
index cd5c250ae..ba7b40013 100644
--- a/src/proc_net_snmp.c
+++ b/src/proc_net_snmp.c
@@ -355,7 +355,7 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/snmp");
ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -392,14 +392,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".packets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets"
+ , "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -413,14 +414,16 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_fragsout) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".fragsout");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL
+ , "IPv4 Fragments Sent", "packets/s", 3010, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -433,14 +436,16 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_fragsin) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".fragsin");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL
+ , "IPv4 Fragments Reassembly", "packets/s", 3011, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -453,19 +458,20 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_errors) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors"
+ , "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -497,12 +503,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_icmp_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".icmp");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmp");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s", 2602, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets"
+ , "packets/s", 2602, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -511,13 +518,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
rrdset_done(st);
- st = rrdset_find(RRD_TYPE_NET_SNMP ".icmp_errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmp_errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmp_errors", NULL, "icmp", NULL
+ , "IPv4 ICMP Errors", "packets/s", 2603, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -543,12 +552,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
if(do_icmpmsg) {
int i;
- st = rrdset_find(RRD_TYPE_NET_SNMP ".icmpmsg");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmpmsg");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages", "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages"
+ , "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
for(i = 0; icmpmsg_data[i].name ;i++)
- rrddim_add(st, icmpmsg_data[i].name, icmpmsg_data[i].label, icmpmsg_data[i].multiplier, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, icmpmsg_data[i].name, icmpmsg_data[i].label, icmpmsg_data[i].multiplier, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -578,11 +588,12 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
if(do_tcp_sockets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcpsock");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections"
+ , "active connections", 2500, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "CurrEstab", "connections", 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -593,12 +604,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_tcp_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcppackets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets"
+ , "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -610,14 +622,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_tcp_errors) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcperrors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors"
+ , "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -630,16 +643,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_tcp_handshake) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcphandshake");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL
+ , "IPv4 TCP Handshake Issues", "events/s", 2900, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutRsts", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -671,12 +686,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/udp.html
if(do_udp_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udppackets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets"
+ , "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -688,17 +704,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_udp_errors) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udperrors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors"
+ , "events/s", 2701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -730,12 +747,14 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_udplite_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udplite");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udplite", NULL, "udplite", NULL, "IPv4 UDPLite Packets", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udplite", NULL, "udplite", NULL
+ , "IPv4 UDPLite Packets", "packets/s", 2603, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -743,16 +762,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
rrddim_set(st, "OutDatagrams", *udplite_OutDatagrams);
rrdset_done(st);
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite_errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udplite_errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udplite_errors", NULL, "udplite", NULL, "IPv4 UDPLite Errors", "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udplite_errors", NULL, "udplite", NULL
+ , "IPv4 UDPLite Errors", "packets/s", 2604, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_snmp6.c b/src/proc_net_snmp6.c
index 51d7121a1..8c4581c1b 100644
--- a/src/proc_net_snmp6.c
+++ b/src/proc_net_snmp6.c
@@ -126,28 +126,28 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
static unsigned long long UdpLite6InCsumErrors = 0ULL;
if(unlikely(!arl_base)) {
- do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
- do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
- do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
- do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_ONDEMAND_ONDEMAND);
- do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_ONDEMAND_ONDEMAND);
- do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_ONDEMAND_ONDEMAND);
- do_udplite_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_ONDEMAND_ONDEMAND);
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_redir = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_echos = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_groupmemb = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_router = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_neighbor = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_mldv2 = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_types = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
- do_ect = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_ONDEMAND_ONDEMAND);
+ do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_BOOLEAN_AUTO);
+ do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_BOOLEAN_AUTO);
+ do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_BOOLEAN_AUTO);
+ do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_BOOLEAN_AUTO);
+ do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_BOOLEAN_AUTO);
+ do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_BOOLEAN_AUTO);
+ do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_BOOLEAN_AUTO);
+ do_udplite_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_BOOLEAN_AUTO);
+ do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_BOOLEAN_AUTO);
+ do_icmp = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_BOOLEAN_AUTO);
+ do_icmp_redir = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_BOOLEAN_AUTO);
+ do_icmp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp_echos = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_BOOLEAN_AUTO);
+ do_icmp_groupmemb = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_BOOLEAN_AUTO);
+ do_icmp_router = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_BOOLEAN_AUTO);
+ do_icmp_neighbor = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_BOOLEAN_AUTO);
+ do_icmp_mldv2 = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_BOOLEAN_AUTO);
+ do_icmp_types = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_BOOLEAN_AUTO);
+ do_ect = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_BOOLEAN_AUTO);
arl_base = arl_create("snmp6", NULL, 60);
arl_expect(arl_base, "Ip6InReceives", &Ip6InReceives);
@@ -246,7 +246,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp6");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/snmp6");
ff = procfile_open(config_get("plugin:proc:/proc/net/snmp6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
@@ -276,14 +276,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (Ip6InOctets || Ip6OutOctets))) {
- do_bandwidth = CONFIG_ONDEMAND_YES;
- st = rrdset_find("system.ipv6");
+ if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (Ip6InOctets || Ip6OutOctets))) {
+ do_bandwidth = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("system.ipv6");
if(unlikely(!st)) {
- st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -294,16 +295,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_packets == CONFIG_ONDEMAND_YES || (do_ip_packets == CONFIG_ONDEMAND_ONDEMAND && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
- do_ip_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".packets");
+ if(do_ip_packets == CONFIG_BOOLEAN_YES || (do_ip_packets == CONFIG_BOOLEAN_AUTO && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
+ do_ip_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".packets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets"
+ , "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -316,16 +318,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_fragsout == CONFIG_ONDEMAND_YES || (do_ip_fragsout == CONFIG_ONDEMAND_ONDEMAND && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
- do_ip_fragsout = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsout");
+ if(do_ip_fragsout == CONFIG_BOOLEAN_YES || (do_ip_fragsout == CONFIG_BOOLEAN_AUTO && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
+ do_ip_fragsout = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".fragsout");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent"
+ , "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -337,23 +340,25 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_fragsin == CONFIG_ONDEMAND_YES || (do_ip_fragsin == CONFIG_ONDEMAND_ONDEMAND
+ if(do_ip_fragsin == CONFIG_BOOLEAN_YES || (do_ip_fragsin == CONFIG_BOOLEAN_AUTO
&& (
Ip6ReasmOKs
|| Ip6ReasmFails
|| Ip6ReasmTimeout
|| Ip6ReasmReqds
))) {
- do_ip_fragsin = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsin");
+ do_ip_fragsin = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".fragsin");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL
+ , "IPv6 Fragments Reassembly", "packets/s", 3011, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -366,7 +371,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_errors == CONFIG_ONDEMAND_YES || (do_ip_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_ip_errors == CONFIG_BOOLEAN_YES || (do_ip_errors == CONFIG_BOOLEAN_AUTO
&& (
Ip6InDiscards
|| Ip6OutDiscards
@@ -377,23 +382,24 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Ip6InTruncatedPkts
|| Ip6InNoRoutes
))) {
- do_ip_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".errors");
+ do_ip_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".errors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -413,14 +419,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udp_packets == CONFIG_ONDEMAND_YES || (do_udp_packets == CONFIG_ONDEMAND_ONDEMAND && (Udp6InDatagrams || Udp6OutDatagrams))) {
- do_udp_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udppackets");
+ if(do_udp_packets == CONFIG_BOOLEAN_YES || (do_udp_packets == CONFIG_BOOLEAN_AUTO && (Udp6InDatagrams || Udp6OutDatagrams))) {
+ do_udp_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udppackets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets"
+ , "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -431,7 +438,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udp_errors == CONFIG_ONDEMAND_YES || (do_udp_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_udp_errors == CONFIG_BOOLEAN_YES || (do_udp_errors == CONFIG_BOOLEAN_AUTO
&& (
Udp6InErrors
|| Udp6NoPorts
@@ -440,18 +447,19 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Udp6InCsumErrors
|| Udp6IgnoredMulti
))) {
- do_udp_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udperrors");
+ do_udp_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udperrors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors"
+ , "events/s", 3701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -466,14 +474,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udplite_packets == CONFIG_ONDEMAND_YES || (do_udplite_packets == CONFIG_ONDEMAND_ONDEMAND && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
- do_udplite_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udplitepackets");
+ if(do_udplite_packets == CONFIG_BOOLEAN_YES || (do_udplite_packets == CONFIG_BOOLEAN_AUTO && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
+ do_udplite_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udplitepackets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL, "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL
+ , "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -484,7 +493,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udplite_errors == CONFIG_ONDEMAND_YES || (do_udplite_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_udplite_errors == CONFIG_BOOLEAN_YES || (do_udplite_errors == CONFIG_BOOLEAN_AUTO
&& (
UdpLite6InErrors
|| UdpLite6NoPorts
@@ -493,17 +502,18 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Udp6InCsumErrors
|| UdpLite6InCsumErrors
))) {
- do_udplite_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
+ do_udplite_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL, "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL
+ , "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -517,15 +527,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
- do_mcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcast");
+ if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
+ do_mcast = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".mcast");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL, "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL
+ , "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -536,15 +548,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
- do_bcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".bcast");
+ if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
+ do_bcast = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".bcast");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL, "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL
+ , "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -555,15 +569,16 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
- do_mcast_p = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcastpkts");
+ if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
+ do_mcast_p = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".mcastpkts");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL, "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL
+ , "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -574,14 +589,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp == CONFIG_ONDEMAND_YES || (do_icmp == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMsgs || Icmp6OutMsgs))) {
- do_icmp = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmp");
+ if(do_icmp == CONFIG_BOOLEAN_YES || (do_icmp == CONFIG_BOOLEAN_AUTO && (Icmp6InMsgs || Icmp6OutMsgs))) {
+ do_icmp = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmp");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages"
+ , "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -592,14 +608,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_redir == CONFIG_ONDEMAND_YES || (do_icmp_redir == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InRedirects || Icmp6OutRedirects))) {
- do_icmp_redir = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpredir");
+ if(do_icmp_redir == CONFIG_BOOLEAN_YES || (do_icmp_redir == CONFIG_BOOLEAN_AUTO && (Icmp6InRedirects || Icmp6OutRedirects))) {
+ do_icmp_redir = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpredir");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects", "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects"
+ , "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -610,7 +627,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_errors == CONFIG_ONDEMAND_YES || (do_icmp_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_errors == CONFIG_BOOLEAN_YES || (do_icmp_errors == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InErrors
|| Icmp6OutErrors
@@ -624,23 +641,24 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Icmp6OutTimeExcds
|| Icmp6OutParmProblems
))) {
- do_icmp_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmperrors");
+ do_icmp_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmperrors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors"
+ , "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -660,22 +678,23 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_echos == CONFIG_ONDEMAND_YES || (do_icmp_echos == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_echos == CONFIG_BOOLEAN_YES || (do_icmp_echos == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InEchos
|| Icmp6OutEchos
|| Icmp6InEchoReplies
|| Icmp6OutEchoReplies
))) {
- do_icmp_echos = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpechos");
+ do_icmp_echos = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpechos");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo"
+ , "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -688,7 +707,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_groupmemb == CONFIG_ONDEMAND_YES || (do_icmp_groupmemb == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_groupmemb == CONFIG_BOOLEAN_YES || (do_icmp_groupmemb == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InGroupMembQueries
|| Icmp6OutGroupMembQueries
@@ -697,17 +716,19 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Icmp6InGroupMembReductions
|| Icmp6OutGroupMembReductions
))) {
- do_icmp_groupmemb = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".groupmemb");
+ do_icmp_groupmemb = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".groupmemb");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL, "IPv6 ICMP Group Membership", "messages/s", 10300, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InQueries", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutQueries", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InResponses", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutResponses", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InReductions", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutReductions", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL
+ , "IPv6 ICMP Group Membership", "messages/s", 10300, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InQueries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutQueries", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InResponses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutResponses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InReductions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutReductions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -722,22 +743,23 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_router == CONFIG_ONDEMAND_YES || (do_icmp_router == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_router == CONFIG_BOOLEAN_YES || (do_icmp_router == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InRouterSolicits
|| Icmp6OutRouterSolicits
|| Icmp6InRouterAdvertisements
|| Icmp6OutRouterAdvertisements
))) {
- do_icmp_router = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmprouter");
+ do_icmp_router = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmprouter");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages"
+ , "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -750,22 +772,24 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_neighbor == CONFIG_ONDEMAND_YES || (do_icmp_neighbor == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_neighbor == CONFIG_BOOLEAN_YES || (do_icmp_neighbor == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InNeighborSolicits
|| Icmp6OutNeighborSolicits
|| Icmp6InNeighborAdvertisements
|| Icmp6OutNeighborAdvertisements
))) {
- do_icmp_neighbor = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
+ do_icmp_neighbor = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL
+ , "IPv6 Neighbor Messages", "messages/s", 10500, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -778,14 +802,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_mldv2 == CONFIG_ONDEMAND_YES || (do_icmp_mldv2 == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
- do_icmp_mldv2 = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
+ if(do_icmp_mldv2 == CONFIG_BOOLEAN_YES || (do_icmp_mldv2 == CONFIG_BOOLEAN_AUTO && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
+ do_icmp_mldv2 = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports", "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports"
+ , "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -796,7 +821,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_types == CONFIG_ONDEMAND_YES || (do_icmp_types == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_types == CONFIG_BOOLEAN_YES || (do_icmp_types == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InType1
|| Icmp6InType128
@@ -809,21 +834,22 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Icmp6OutType135
|| Icmp6OutType143
))) {
- do_icmp_types = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmptypes");
+ do_icmp_types = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmptypes");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types", "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types"
+ , "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -842,22 +868,23 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ect == CONFIG_ONDEMAND_YES || (do_ect == CONFIG_ONDEMAND_ONDEMAND
+ if(do_ect == CONFIG_BOOLEAN_YES || (do_ect == CONFIG_BOOLEAN_AUTO
&& (
Ip6InNoECTPkts
|| Ip6InECT1Pkts
|| Ip6InECT0Pkts
|| Ip6InCEPkts
))) {
- do_ect = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".ect");
+ do_ect = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".ect");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets", "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets"
+ , "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCEPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCEPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_softnet_stat.c b/src/proc_net_softnet_stat.c
index 2f4eb3e66..40946a7a5 100644
--- a/src/proc_net_softnet_stat.c
+++ b/src/proc_net_softnet_stat.c
@@ -24,7 +24,7 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/softnet_stat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/softnet_stat");
ff = procfile_open(config_get("plugin:proc:/proc/net/softnet_stat", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -77,12 +77,13 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("system", "softnet_stat");
+ st = rrdset_find_bytype_localhost("system", "softnet_stat");
if(unlikely(!st)) {
- st = rrdset_create("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat", "events/s", 955, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat"
+ , "events/s", 955, update_every, RRDSET_TYPE_LINE);
for(w = 0; w < allocated_columns ;w++)
if(unlikely(softnet_column_name(w)))
- rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -97,15 +98,16 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
char id[50+1];
snprintfz(id, 50, "cpu%zu_softnet_stat", l);
- st = rrdset_find_bytype("cpu", id);
+ st = rrdset_find_bytype_localhost("cpu", id);
if(unlikely(!st)) {
char title[100+1];
snprintfz(title, 100, "CPU%zu softnet_stat", l);
- st = rrdset_create("cpu", id, NULL, "softnet_stat", NULL, title, "events/s", 4101 + l, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("cpu", id, NULL, "softnet_stat", NULL, title, "events/s", 4101 + l
+ , update_every, RRDSET_TYPE_LINE);
for(w = 0; w < allocated_columns ;w++)
if(unlikely(softnet_column_name(w)))
- rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_stat_conntrack.c b/src/proc_net_stat_conntrack.c
index b9c724983..e04b80a3e 100644
--- a/src/proc_net_stat_conntrack.c
+++ b/src/proc_net_stat_conntrack.c
@@ -16,10 +16,10 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
if(unlikely(do_sockets == -1)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/nf_conntrack");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/stat/nf_conntrack");
nf_conntrack_filename = config_get("plugin:proc:/proc/net/stat/nf_conntrack", "filename to monitor", filename);
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_max");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_max");
nf_conntrack_max_filename = config_get("plugin:proc:/proc/sys/net/netfilter/nf_conntrack_max", "filename to monitor", filename);
usec_since_last_max = get_max_every = config_get_number("plugin:proc:/proc/sys/net/netfilter/nf_conntrack_max", "read every seconds", 10) * USEC_PER_SEC;
@@ -35,7 +35,7 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
do_sockets = 1;
if(!read_full) {
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_count");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_count");
nf_conntrack_count_filename = config_get("plugin:proc:/proc/sys/net/netfilter/nf_conntrack_count", "filename to monitor", filename);
if(read_single_number_file(nf_conntrack_count_filename, &aentries))
@@ -47,7 +47,7 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
if(!do_sockets && !read_full)
return 1;
- rrdvar_max = rrdvar_custom_host_variable_create(&localhost, "netfilter.conntrack.max");
+ rrdvar_max = rrdvar_custom_host_variable_create(localhost, "netfilter.conntrack.max");
}
if(likely(read_full)) {
@@ -130,11 +130,13 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_sockets) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections"
+ , "active connections", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -145,13 +147,15 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_new) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 3001, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections"
+ , "connections/s", 3001, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ignore", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -164,14 +168,16 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_changes) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 3002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delete_list", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "inserted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "delete_list", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -184,14 +190,16 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_expect) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 3003, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations"
+ , "expectations/s", 3003, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "created", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -204,14 +212,16 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_search) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "restarted", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "found", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches"
+ , "searches/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "searched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "restarted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "found", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -224,15 +234,17 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_errors) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 3005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "insert_failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "early_drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s"
+ , 3005, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "icmp_error", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "insert_failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "early_drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_stat_synproxy.c b/src/proc_net_stat_synproxy.c
index 6bb0a3c69..5a1fc30eb 100644
--- a/src/proc_net_stat_synproxy.c
+++ b/src/proc_net_stat_synproxy.c
@@ -10,15 +10,15 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
static procfile *ff = NULL;
if(unlikely(do_entries == -1)) {
- do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
- do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
- do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
+ do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_BOOLEAN_AUTO);
+ do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_BOOLEAN_AUTO);
+ do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_BOOLEAN_AUTO);
+ do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_BOOLEAN_AUTO);
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/stat/synproxy");
ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
@@ -57,14 +57,16 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
- do_entries = CONFIG_ONDEMAND_YES;
+ if((do_entries == CONFIG_BOOLEAN_AUTO && events) || do_entries == CONFIG_BOOLEAN_YES) {
+ do_entries = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 3304, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 3304
+ , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "entries", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -74,14 +76,16 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
- do_syns = CONFIG_ONDEMAND_YES;
+ if((do_syns == CONFIG_BOOLEAN_AUTO && events) || do_syns == CONFIG_BOOLEAN_YES) {
+ do_syns = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 3301, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s"
+ , 3301, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -91,14 +95,16 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
- do_reopened = CONFIG_ONDEMAND_YES;
+ if((do_reopened == CONFIG_BOOLEAN_AUTO && events) || do_reopened == CONFIG_BOOLEAN_YES) {
+ do_reopened = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 3303, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened"
+ , "connections/s", 3303, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reopened", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -108,16 +114,18 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
- do_cookies = CONFIG_ONDEMAND_YES;
+ if((do_cookies == CONFIG_BOOLEAN_AUTO && events) || do_cookies == CONFIG_BOOLEAN_YES) {
+ do_cookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 3302, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 3302
+ , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "valid", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "retransmits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_self_mountinfo.c b/src/proc_self_mountinfo.c
index d07f22510..bb031a9ab 100644
--- a/src/proc_self_mountinfo.c
+++ b/src/proc_self_mountinfo.c
@@ -175,10 +175,10 @@ static inline int is_read_only(const char *s) {
// read the whole mountinfo into a linked list
struct mountinfo *mountinfo_read(int do_statvfs) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", netdata_configured_host_prefix);
procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
- snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", netdata_configured_host_prefix);
ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return NULL;
}
@@ -293,7 +293,7 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
struct mountinfo *mt;
for(mt = root; mt; mt = mt->next) {
- if(unlikely(mt->st_dev == mi->st_dev && !(mi->flags & MOUNTINFO_NO_STAT))) {
+ if(unlikely(mt->st_dev == mi->st_dev && !(mt->flags & MOUNTINFO_IS_SAME_DEV))) {
if(strlen(mi->mount_point) < strlen(mt->mount_point))
mt->flags |= MOUNTINFO_IS_SAME_DEV;
else
@@ -319,7 +319,7 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
}
// check if it has size
- if(do_statvfs) {
+ if(do_statvfs && !(mi->flags & MOUNTINFO_IS_DUMMY)) {
struct statvfs buff_statvfs;
if(unlikely(statvfs(mi->mount_point, &buff_statvfs) < 0)) {
mi->flags |= MOUNTINFO_NO_STAT;
diff --git a/src/proc_softirqs.c b/src/proc_softirqs.c
index c7b10d70d..560e2acb2 100644
--- a/src/proc_softirqs.c
+++ b/src/proc_softirqs.c
@@ -58,7 +58,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/softirqs");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/softirqs");
ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -128,8 +128,9 @@ int do_proc_softirqs(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("system", "softirqs");
- if(unlikely(!st)) st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
+ 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);
for(l = 0; l < lines ;l++) {
@@ -141,7 +142,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
irr->rd = rrddim_find(st, irr->id);
if(unlikely(!irr->rd))
- irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->rd, irr->name);
@@ -163,7 +164,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
char id[50+1];
snprintfz(id, 50, "cpu%d_softirqs", c);
- st = rrdset_find_bytype("cpu", id);
+ st = rrdset_find_bytype_localhost("cpu", id);
if(unlikely(!st)) {
// find if everything is zero
unsigned long long core_sum = 0 ;
@@ -176,7 +177,8 @@ int do_proc_softirqs(int update_every, usec_t dt) {
char title[100+1];
snprintfz(title, 100, "CPU%d softirqs", c);
- st = rrdset_create("cpu", id, NULL, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("cpu", id, NULL, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c
+ , update_every, RRDSET_TYPE_STACKED);
}
else rrdset_next(st);
@@ -186,7 +188,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
if(unlikely(!irr->cpu[c].rd)) {
irr->cpu[c].rd = rrddim_find(st, irr->id);
if(unlikely(!irr->cpu[c].rd))
- irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->cpu[c].rd, irr->name);
}
diff --git a/src/proc_stat.c b/src/proc_stat.c
index f7e6d5bc0..04f0896cd 100644
--- a/src/proc_stat.c
+++ b/src/proc_stat.c
@@ -24,7 +24,7 @@ int do_proc_stat(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/stat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/stat");
ff = procfile_open(config_get("plugin:proc:/proc/stat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -91,24 +91,25 @@ int do_proc_stat(int update_every, usec_t dt) {
}
if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
- st = rrdset_find_bytype(type, id);
+ st = rrdset_find_bytype_localhost(type, id);
if(unlikely(!st)) {
- st = rrdset_create(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
+ 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, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "guest", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "steal", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "softirq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "irq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "iowait", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-
- rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ 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");
}
else rrdset_next(st);
@@ -132,12 +133,13 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_interrupts)) {
- st = rrdset_find_bytype("system", "intr");
+ st = rrdset_find_bytype_localhost("system", "intr");
if(unlikely(!st)) {
- st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -151,11 +153,12 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_context)) {
- st = rrdset_find_bytype("system", "ctxt");
+ st = rrdset_find_bytype_localhost("system", "ctxt");
if(unlikely(!st)) {
- st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -177,12 +180,13 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_forks)) {
- st = rrdset_find_bytype("system", "forks");
+ st = rrdset_find_bytype_localhost("system", "forks");
if(unlikely(!st)) {
- st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -193,12 +197,13 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_processes)) {
- st = rrdset_find_bytype("system", "processes");
+ st = rrdset_find_bytype_localhost("system", "processes");
if(unlikely(!st)) {
- st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("system", "processes", NULL, "processes", NULL, "System Processes", "processes"
+ , 600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/src/proc_sys_kernel_random_entropy_avail.c
index 388406e0b..fea8900d3 100644
--- a/src/proc_sys_kernel_random_entropy_avail.c
+++ b/src/proc_sys_kernel_random_entropy_avail.c
@@ -7,7 +7,7 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/kernel/random/entropy_avail");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sys/kernel/random/entropy_avail");
ff = procfile_open(config_get("plugin:proc:/proc/sys/kernel/random/entropy_avail", "filename to monitor", filename), "", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -17,10 +17,11 @@ 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("system", "entropy");
+ RRDSET *st = rrdset_find_bytype_localhost("system", "entropy");
if(unlikely(!st)) {
- st = rrdset_create("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "entropy", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ 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);
}
else rrdset_next(st);
diff --git a/src/proc_uptime.c b/src/proc_uptime.c
index 9f341a33f..f74cccb97 100644
--- a/src/proc_uptime.c
+++ b/src/proc_uptime.c
@@ -13,7 +13,7 @@ int do_proc_uptime(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/uptime");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/uptime");
ff = procfile_open(config_get("plugin:proc:/proc/uptime", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
@@ -39,11 +39,12 @@ int do_proc_uptime(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(unlikely(!st))
- st = rrdset_find("system.uptime");
+ st = rrdset_find_localhost("system.uptime");
if(unlikely(!st)) {
- st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ 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);
}
else rrdset_next(st);
diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c
index ea917b989..847487363 100644
--- a/src/proc_vmstat.c
+++ b/src/proc_vmstat.c
@@ -25,10 +25,10 @@ int do_proc_vmstat(int update_every, usec_t dt) {
static unsigned long long pswpout = 0ULL;
if(unlikely(!arl_base)) {
- do_swapio = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "swap i/o", CONFIG_ONDEMAND_ONDEMAND);
+ do_swapio = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "swap i/o", CONFIG_BOOLEAN_AUTO);
do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
- do_numa = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "system-wide numa metric summary", CONFIG_ONDEMAND_ONDEMAND);
+ do_numa = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "system-wide numa metric summary", CONFIG_BOOLEAN_AUTO);
arl_base = arl_create("vmstat", NULL, 60);
@@ -39,7 +39,7 @@ int do_proc_vmstat(int update_every, usec_t dt) {
arl_expect(arl_base, "pswpin", &pswpin);
arl_expect(arl_base, "pswpout", &pswpout);
- if(do_numa == CONFIG_ONDEMAND_YES || (do_numa == CONFIG_ONDEMAND_ONDEMAND && get_numa_node_count() >= 2)) {
+ if(do_numa == CONFIG_BOOLEAN_YES || (do_numa == CONFIG_BOOLEAN_AUTO && get_numa_node_count() >= 2)) {
arl_expect(arl_base, "numa_foreign", &numa_foreign);
arl_expect(arl_base, "numa_hint_faults_local", &numa_hint_faults_local);
arl_expect(arl_base, "numa_hint_faults", &numa_hint_faults);
@@ -56,13 +56,13 @@ int do_proc_vmstat(int update_every, usec_t dt) {
// when all the expected metrics are collected.
// Also ARL will not parse their values.
has_numa = 0;
- do_numa = CONFIG_ONDEMAND_NO;
+ do_numa = CONFIG_BOOLEAN_NO;
}
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/vmstat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/vmstat");
ff = procfile_open(config_get("plugin:proc:/proc/vmstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -87,15 +87,16 @@ int do_proc_vmstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(pswpin || pswpout || do_swapio == CONFIG_ONDEMAND_YES) {
- do_swapio = CONFIG_ONDEMAND_YES;
+ if(pswpin || pswpout || do_swapio == CONFIG_BOOLEAN_YES) {
+ do_swapio = CONFIG_BOOLEAN_YES;
static RRDSET *st_swapio = NULL;
if(unlikely(!st_swapio)) {
- st_swapio = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+ st_swapio = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st_swapio);
@@ -109,10 +110,11 @@ 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("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
+ st_io = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st_io, "in", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_io, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_io);
@@ -126,11 +128,12 @@ int do_proc_vmstat(int update_every, usec_t dt) {
if(do_pgfaults) {
static RRDSET *st_pgfaults = NULL;
if(unlikely(!st_pgfaults)) {
- st_pgfaults = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
- st_pgfaults->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_pgfaults);
@@ -149,27 +152,28 @@ int do_proc_vmstat(int update_every, usec_t dt) {
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;
- if(do_numa == CONFIG_ONDEMAND_YES || (do_numa == CONFIG_ONDEMAND_ONDEMAND && has_numa)) {
- do_numa = CONFIG_ONDEMAND_YES;
+ if(do_numa == CONFIG_BOOLEAN_YES || (do_numa == CONFIG_BOOLEAN_AUTO && has_numa)) {
+ do_numa = CONFIG_BOOLEAN_YES;
static RRDSET *st_numa = NULL;
if(unlikely(!st_numa)) {
- st_numa = rrdset_create("mem", "numa", NULL, "numa", NULL, "NUMA events", "events/s", 800, update_every, RRDSET_TYPE_LINE);
- st_numa->isdetail = 1;
+ 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, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "foreign", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "interleave", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "other", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ 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);
// The following stats depend on CONFIG_NUMA_BALANCING in the
// kernel.
- rrddim_add(st_numa, "pte updates", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "huge pte updates", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "hint faults", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "hint faults local", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "pages migrated", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ 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);
}
else rrdset_next(st_numa);
diff --git a/src/procfile.c b/src/procfile.c
index 6f52bf465..3a89e8353 100644
--- a/src/procfile.c
+++ b/src/procfile.c
@@ -15,6 +15,27 @@ size_t procfile_max_lines = PFLINES_INCREASE_STEP;
size_t procfile_max_words = PFWORDS_INCREASE_STEP;
size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER;
+
+// ----------------------------------------------------------------------------
+
+char *procfile_filename(procfile *ff) {
+ if(ff->filename[0]) return ff->filename;
+
+ char buffer[FILENAME_MAX + 1];
+ snprintfz(buffer, FILENAME_MAX, "/proc/self/fd/%d", ff->fd);
+
+ ssize_t l = readlink(buffer, ff->filename, FILENAME_MAX);
+ if(unlikely(l == -1))
+ snprintfz(ff->filename, FILENAME_MAX, "unknown filename for fd %d", ff->fd);
+ else
+ ff->filename[l] = '\0';
+
+ // on non-linux systems, something like this will be needed
+ // fcntl(ff->fd, F_GETPATH, ff->filename)
+
+ return ff->filename;
+}
+
// ----------------------------------------------------------------------------
// An array of words
@@ -106,15 +127,10 @@ static inline void pflines_free(pflines *fl) {
// ----------------------------------------------------------------------------
// The procfile
-#define PF_CHAR_IS_SEPARATOR ' '
-#define PF_CHAR_IS_NEWLINE 'N'
-#define PF_CHAR_IS_WORD 'W'
-#define PF_CHAR_IS_QUOTE 'Q'
-#define PF_CHAR_IS_OPEN 'O'
-#define PF_CHAR_IS_CLOSE 'C'
-
void procfile_close(procfile *ff) {
- debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
+ if(unlikely(!ff)) return;
+
+ debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", procfile_filename(ff));
if(likely(ff->lines)) pflines_free(ff->lines);
if(likely(ff->words)) pfwords_free(ff->words);
@@ -126,113 +142,119 @@ void procfile_close(procfile *ff) {
static inline void procfile_parser(procfile *ff) {
// debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
- register char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data;
- register char *separators = ff->separators;
- char quote = 0;
- size_t l = 0, w = 0, opened = 0;
+ char *s = ff->data // our current position
+ , *e = &ff->data[ff->len] // the terminating null
+ , *t = ff->data; // the first character of a quoted or a parenthesized string
+
+ // the look up array to find our type of character
+ PF_CHAR_TYPE *separators = ff->separators;
+
+ char quote = 0; // the quote character - only when in quoted string
+
+ size_t
+ l = 0 // counts the number of lines we added
+ , w = 0 // counts the number of words we added
+ , opened = 0; // counts the number of open parenthesis
ff->lines = pflines_add(ff->lines, w);
while(likely(s < e)) {
// we are not at the end
+ PF_CHAR_TYPE ct = separators[(unsigned char)(*s)];
- switch(separators[(unsigned char)(*s)]) {
- case PF_CHAR_IS_OPEN:
- if(s == t) {
- opened++;
- t = ++s;
- }
- else if(opened) {
- opened++;
- s++;
- }
- else
- s++;
- break;
-
- case PF_CHAR_IS_CLOSE:
- if(opened) {
- opened--;
-
- if(!opened) {
- *s = '\0';
- ff->words = pfwords_add(ff->words, t);
- ff->lines->lines[l].words++;
- w++;
-
- t = ++s;
- }
- else
- s++;
- }
- else
- s++;
- break;
+ // this is faster than a switch()
+ if(likely(ct == PF_CHAR_IS_WORD)) {
+ s++;
+ }
+ else if(likely(ct == PF_CHAR_IS_SEPARATOR)) {
+ if(unlikely(quote || opened)) {
+ // we are inside a quote
+ s++;
+ continue;
+ }
- case PF_CHAR_IS_QUOTE:
- if(unlikely(!quote && s == t)) {
- // quote opened at the beginning
- quote = *s;
- t = ++s;
- }
- else if(unlikely(quote && quote == *s)) {
- // quote closed
- quote = 0;
+ if(unlikely(s == t)) {
+ // skip all leading white spaces
+ t = ++s;
+ continue;
+ }
- *s = '\0';
- ff->words = pfwords_add(ff->words, t);
- ff->lines->lines[l].words++;
- w++;
+ // end of word
+ *s = '\0';
- t = ++s;
- }
- else
- s++;
- break;
+ ff->words = pfwords_add(ff->words, t);
+ ff->lines->lines[l].words++;
+ w++;
- case PF_CHAR_IS_SEPARATOR:
- if(unlikely(quote || opened)) {
- // we are inside a quote
- s++;
- break;
- }
+ t = ++s;
+ }
+ else if(likely(ct == PF_CHAR_IS_NEWLINE)) {
+ // end of line
+ *s = '\0';
- if(unlikely(s == t)) {
- // skip all leading white spaces
- t = ++s;
- break;
- }
+ ff->words = pfwords_add(ff->words, t);
+ ff->lines->lines[l].words++;
+ w++;
- // end of word
- *s = '\0';
+ // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
- ff->words = pfwords_add(ff->words, t);
- ff->lines->lines[l].words++;
- w++;
+ ff->lines = pflines_add(ff->lines, w);
+ l++;
+ t = ++s;
+ }
+ else if(likely(ct == PF_CHAR_IS_QUOTE)) {
+ if(unlikely(!quote && s == t)) {
+ // quote opened at the beginning
+ quote = *s;
t = ++s;
- break;
+ }
+ else if(unlikely(quote && quote == *s)) {
+ // quote closed
+ quote = 0;
- case PF_CHAR_IS_NEWLINE:
- // end of line
*s = '\0';
-
ff->words = pfwords_add(ff->words, t);
ff->lines->lines[l].words++;
w++;
- // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
-
- ff->lines = pflines_add(ff->lines, w);
- l++;
-
t = ++s;
- break;
+ }
+ else
+ s++;
+ }
+ else if(likely(ct == PF_CHAR_IS_OPEN)) {
+ if(s == t) {
+ opened++;
+ t = ++s;
+ }
+ else if(opened) {
+ opened++;
+ s++;
+ }
+ else
+ s++;
+ }
+ else if(likely(ct == PF_CHAR_IS_CLOSE)) {
+ if(opened) {
+ opened--;
- default:
+ if(!opened) {
+ *s = '\0';
+ ff->words = pfwords_add(ff->words, t);
+ ff->lines->lines[l].words++;
+ w++;
+
+ t = ++s;
+ }
+ else
+ s++;
+ }
+ else
s++;
- break;
}
+ else
+ fatal("Internal Error: procfile_readall() does not handle all the cases.");
}
if(likely(s > t && t < e)) {
@@ -250,26 +272,24 @@ static inline void procfile_parser(procfile *ff) {
}
procfile *procfile_readall(procfile *ff) {
- debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
+ // debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
- ssize_t r = 1;
- ff->len = 0;
-
- while(likely(r > 0)) {
+ ff->len = 0; // zero the used size
+ ssize_t r = 1; // read at least once
+ while(r > 0) {
ssize_t s = ff->len;
ssize_t x = ff->size - s;
if(unlikely(!x)) {
- debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
-
+ debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", procfile_filename(ff));
ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
ff->size += PROCFILE_INCREMENT_BUFFER;
}
- debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
+ debug(D_PROCFILE, "Reading file '%s', from position %zd with length %zd", procfile_filename(ff), s, (ssize_t)(ff->size - s));
r = read(ff->fd, &ff->data[s], ff->size - s);
if(unlikely(r == -1)) {
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", procfile_filename(ff));
procfile_close(ff);
return NULL;
}
@@ -277,9 +297,9 @@ procfile *procfile_readall(procfile *ff) {
ff->len += r;
}
- debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
+ // debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
procfile_close(ff);
return NULL;
}
@@ -294,29 +314,37 @@ procfile *procfile_readall(procfile *ff) {
if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
}
- debug(D_PROCFILE, "File '%s' updated.", ff->filename);
+ // debug(D_PROCFILE, "File '%s' updated.", ff->filename);
return ff;
}
-static void procfile_set_separators(procfile *ff, const char *separators) {
- static char def[256] = { [0 ... 255] = 0 };
+static inline void procfile_set_separators(procfile *ff, const char *separators) {
+ static PF_CHAR_TYPE def[256];
+ static char initilized = 0;
- if(unlikely(!def[255])) {
+ if(unlikely(!initilized)) {
// this is thread safe
- // we check that the last byte is non-zero
- // if it is zero, multiple threads may be executing this at the same time
- // setting in def[] the exact same values
- int i;
- for(i = 0; likely(i < 256) ;i++) {
- if(unlikely(i == '\n' || i == '\r')) def[i] = PF_CHAR_IS_NEWLINE;
- else if(unlikely(isspace(i) || !isprint(i))) def[i] = PF_CHAR_IS_SEPARATOR;
- else def[i] = PF_CHAR_IS_WORD;
+ // if initialized is zero, multiple threads may be executing
+ // this code at the same time, setting in def[] the exact same values
+ int i = 256;
+ while(i--) {
+ if(unlikely(i == '\n' || i == '\r'))
+ def[i] = PF_CHAR_IS_NEWLINE;
+
+ else if(unlikely(isspace(i) || !isprint(i)))
+ def[i] = PF_CHAR_IS_SEPARATOR;
+
+ else
+ def[i] = PF_CHAR_IS_WORD;
}
+
+ initilized = 1;
}
// copy the default
- char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
- while(likely(ffd != ffe)) *ffs++ = *ffd++;
+ PF_CHAR_TYPE *ffs = ff->separators, *ffd = def, *ffe = &def[256];
+ while(ffd != ffe)
+ *ffs++ = *ffd++;
// set the separators
if(unlikely(!separators))
@@ -324,47 +352,50 @@ static void procfile_set_separators(procfile *ff, const char *separators) {
ffs = ff->separators;
const char *s = separators;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
}
void procfile_set_quotes(procfile *ff, const char *quotes) {
+ PF_CHAR_TYPE *ffs = ff->separators;
+
// remove all quotes
- int i;
- for(i = 0; i < 256 ; i++)
- if(unlikely(ff->separators[i] == PF_CHAR_IS_QUOTE))
- ff->separators[i] = PF_CHAR_IS_WORD;
+ int i = 256;
+ while(i--)
+ if(unlikely(ffs[i] == PF_CHAR_IS_QUOTE))
+ ffs[i] = PF_CHAR_IS_WORD;
// if nothing given, return
if(unlikely(!quotes || !*quotes))
return;
// set the quotes
- char *ffs = ff->separators;
const char *s = quotes;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
}
void procfile_set_open_close(procfile *ff, const char *open, const char *close) {
+ PF_CHAR_TYPE *ffs = ff->separators;
+
// remove all open/close
- int i;
- for(i = 0; i < 256 ; i++)
- if(unlikely(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE))
- ff->separators[i] = PF_CHAR_IS_WORD;
+ int i = 256;
+ while(i--)
+ if(unlikely(ffs[i] == PF_CHAR_IS_OPEN || ffs[i] == PF_CHAR_IS_CLOSE))
+ ffs[i] = PF_CHAR_IS_WORD;
// if nothing given, return
if(unlikely(!open || !*open || !close || !*close))
return;
// set the openings
- char *ffs = ff->separators;
const char *s = open;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_OPEN;
+ // set the closings
s = close;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
}
@@ -379,7 +410,9 @@ procfile *procfile_open(const char *filename, const char *separators, uint32_t f
size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
procfile *ff = mallocz(sizeof(procfile) + size);
- strncpyz(ff->filename, filename, FILENAME_MAX);
+
+ //strncpyz(ff->filename, filename, FILENAME_MAX);
+ ff->filename[0] = '\0';
ff->fd = fd;
ff->size = size;
@@ -406,7 +439,8 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa
return NULL;
}
- strncpyz(ff->filename, filename, FILENAME_MAX);
+ //strncpyz(ff->filename, filename, FILENAME_MAX);
+ ff->filename[0] = '\0';
ff->flags = flags;
@@ -423,7 +457,7 @@ void procfile_print(procfile *ff) {
size_t lines = procfile_lines(ff), l;
char *s;
- debug(D_PROCFILE, "File '%s' with %zu lines and %zu words", ff->filename, ff->lines->len, ff->words->len);
+ debug(D_PROCFILE, "File '%s' with %zu lines and %zu words", procfile_filename(ff), ff->lines->len, ff->words->len);
for(l = 0; likely(l < lines) ;l++) {
size_t words = procfile_linewords(ff, l);
diff --git a/src/procfile.h b/src/procfile.h
index a586ba48d..98765697f 100644
--- a/src/procfile.h
+++ b/src/procfile.h
@@ -58,15 +58,25 @@ typedef struct {
#define PROCFILE_FLAG_DEFAULT 0x00000000
#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001
+typedef enum procfile_separator {
+ PF_CHAR_IS_SEPARATOR,
+ PF_CHAR_IS_NEWLINE,
+ PF_CHAR_IS_WORD,
+ PF_CHAR_IS_QUOTE,
+ PF_CHAR_IS_OPEN,
+ PF_CHAR_IS_CLOSE
+} PF_CHAR_TYPE;
+
typedef struct {
- char filename[FILENAME_MAX + 1];
+ char filename[FILENAME_MAX + 1]; // not populated until profile_filename() is called
+
uint32_t flags;
int fd; // the file desriptor
size_t len; // the bytes we have placed into data
size_t size; // the bytes we have allocated for data
pflines *lines;
pfwords *words;
- char separators[256];
+ PF_CHAR_TYPE separators[256];
char data[]; // allocated buffer to keep file contents
} procfile;
@@ -89,6 +99,8 @@ extern void procfile_print(procfile *ff);
extern void procfile_set_quotes(procfile *ff, const char *quotes);
extern void procfile_set_open_close(procfile *ff, const char *open, const char *close);
+extern char *procfile_filename(procfile *ff);
+
// ----------------------------------------------------------------------------
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far
diff --git a/src/registry.c b/src/registry.c
index d223cd6f1..ed9be9848 100644
--- a/src/registry.c
+++ b/src/registry.c
@@ -10,11 +10,11 @@
// REGISTRY concurrency locking
static inline void registry_lock(void) {
- pthread_mutex_lock(&registry.lock);
+ netdata_mutex_lock(&registry.lock);
}
static inline void registry_unlock(void) {
- pthread_mutex_unlock(&registry.lock);
+ netdata_mutex_unlock(&registry.lock);
}
@@ -41,19 +41,19 @@ static inline void registry_set_person_cookie(struct web_client *w, REGISTRY_PER
// ----------------------------------------------------------------------------
// JSON GENERATION
-static inline void registry_json_header(struct web_client *w, const char *action, const char *status) {
+static inline void registry_json_header(RRDHOST *host, struct web_client *w, const char *action, const char *status) {
buffer_flush(w->response.data);
w->response.data->contenttype = CT_APPLICATION_JSON;
buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
- action, status, registry.hostname, registry.machine_guid);
+ action, status, (host == localhost)?registry.hostname:host->hostname, host->machine_guid);
}
static inline void registry_json_footer(struct web_client *w) {
buffer_strcat(w->response.data, "\n}\n");
}
-static inline int registry_json_disabled(struct web_client *w, const char *action) {
- registry_json_header(w, action, REGISTRY_STATUS_DISABLED);
+static inline int registry_json_disabled(RRDHOST *host, struct web_client *w, const char *action) {
+ registry_json_header(host, w, action, REGISTRY_STATUS_DISABLED);
buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
registry.registry_to_announce);
@@ -127,8 +127,8 @@ static inline int registry_person_url_callback_verify_machine_exists(void *entry
// ----------------------------------------------------------------------------
// public HELLO request
-int registry_request_hello_json(struct web_client *w) {
- registry_json_header(w, "hello", REGISTRY_STATUS_OK);
+int registry_request_hello_json(RRDHOST *host, struct web_client *w) {
+ registry_json_header(host, w, "hello", REGISTRY_STATUS_OK);
buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
registry.registry_to_announce);
@@ -143,9 +143,9 @@ int registry_request_hello_json(struct web_client *w) {
#define REGISTRY_VERIFY_COOKIES_GUID "give-me-back-this-cookie-now--please"
// the main method for registering an access
-int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
+int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
if(unlikely(!registry.enabled))
- return registry_json_disabled(w, "access");
+ return registry_json_disabled(host, w, "access");
// ------------------------------------------------------------------------
// verify the browser supports cookies
@@ -167,7 +167,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
REGISTRY_PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when);
if(!p) {
- registry_json_header(w, "access", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "access", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 412;
@@ -177,7 +177,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
registry_set_person_cookie(w, p);
// generate the response
- registry_json_header(w, "access", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "access", REGISTRY_STATUS_OK);
buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
@@ -193,22 +193,22 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
// public DELETE request
// the main method for deleting a URL from a person
-int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
+int registry_request_delete_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
if(!registry.enabled)
- return registry_json_disabled(w, "delete");
+ return registry_json_disabled(host, w, "delete");
registry_lock();
REGISTRY_PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
if(!p) {
- registry_json_header(w, "delete", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "delete", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 412;
}
// generate the response
- registry_json_header(w, "delete", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "delete", REGISTRY_STATUS_OK);
registry_json_footer(w);
registry_unlock();
return 200;
@@ -218,21 +218,21 @@ int registry_request_delete_json(struct web_client *w, char *person_guid, char *
// public SEARCH request
// the main method for searching the URLs of a netdata
-int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
+int registry_request_search_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
if(!registry.enabled)
- return registry_json_disabled(w, "search");
+ return registry_json_disabled(host, w, "search");
registry_lock();
REGISTRY_MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
if(!m) {
- registry_json_header(w, "search", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "search", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 404;
}
- registry_json_header(w, "search", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "search", REGISTRY_STATUS_OK);
buffer_strcat(w->response.data, ",\n\t\"urls\": [");
struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
@@ -248,9 +248,9 @@ int registry_request_search_json(struct web_client *w, char *person_guid, char *
// SWITCH REQUEST
// the main method for switching user identity
-int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
+int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
if(!registry.enabled)
- return registry_json_disabled(w, "switch");
+ return registry_json_disabled(host, w, "switch");
(void)url;
(void)when;
@@ -259,7 +259,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
REGISTRY_PERSON *op = registry_person_find(person_guid);
if(!op) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 430;
@@ -267,7 +267,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
REGISTRY_PERSON *np = registry_person_find(new_person_guid);
if(!np) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 431;
@@ -275,7 +275,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
REGISTRY_MACHINE *m = registry_machine_find(machine_guid);
if(!m) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 432;
@@ -286,7 +286,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
// verify the old person has access to this machine
avl_traverse(&op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
if(!data.count) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 433;
@@ -296,7 +296,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
data.count = 0;
avl_traverse(&np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
if(!data.count) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 434;
@@ -307,7 +307,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
registry_set_person_cookie(w, np);
// generate the response
- registry_json_header(w, "switch", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_OK);
buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid);
registry_json_footer(w);
@@ -323,11 +323,13 @@ void registry_statistics(void) {
static RRDSET *sts = NULL, *stc = NULL, *stm = NULL;
- if(!sts) sts = rrdset_find("netdata.registry_sessions");
+ if(!sts) sts = rrdset_find_localhost("netdata.registry_sessions");
if(!sts) {
- sts = rrdset_create("netdata", "registry_sessions", NULL, "registry", NULL, "NetData Registry Sessions", "session", 131000, rrd_update_every, RRDSET_TYPE_LINE);
+ sts = rrdset_create_localhost("netdata", "registry_sessions", NULL, "registry", NULL
+ , "NetData Registry Sessions", "session", 131000, localhost->rrd_update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(sts, "sessions", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(sts, "sessions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(sts);
@@ -336,15 +338,16 @@ void registry_statistics(void) {
// ------------------------------------------------------------------------
- if(!stc) stc = rrdset_find("netdata.registry_entries");
+ if(!stc) stc = rrdset_find_localhost("netdata.registry_entries");
if(!stc) {
- stc = rrdset_create("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries", "entries", 131100, rrd_update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(stc, "persons", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "machines", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "persons_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "machines_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ stc = rrdset_create_localhost("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries"
+ , "entries", 131100, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(stc, "persons", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "machines", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "persons_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "machines_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(stc);
@@ -357,15 +360,16 @@ void registry_statistics(void) {
// ------------------------------------------------------------------------
- if(!stm) stm = rrdset_find("netdata.registry_mem");
+ if(!stm) stm = rrdset_find_localhost("netdata.registry_mem");
if(!stm) {
- stm = rrdset_create("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB", 131300, rrd_update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(stm, "persons", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "machines", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ stm = rrdset_create_localhost("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB"
+ , 131300, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(stm, "persons", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "machines", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(stm);
diff --git a/src/registry.h b/src/registry.h
index 4947486c4..2c4592b92 100644
--- a/src/registry.h
+++ b/src/registry.h
@@ -60,13 +60,16 @@ extern int registry_init(void);
extern void registry_free(void);
// HTTP requests handled by the registry
-extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
-extern int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
-extern int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
-extern int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when);
-extern int registry_request_hello_json(struct web_client *w);
+extern int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
+extern int registry_request_delete_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
+extern int registry_request_search_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
+extern int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when);
+extern int registry_request_hello_json(RRDHOST *host, struct web_client *w);
// update the registry monitoring charts
extern void registry_statistics(void);
+extern char *registry_get_this_machine_guid(void);
+extern int regenerate_guid(const char *guid, char *result);
+
#endif /* NETDATA_REGISTRY_H */
diff --git a/src/registry_init.c b/src/registry_init.c
index fb61acd08..2a41d36ee 100644
--- a/src/registry_init.c
+++ b/src/registry_init.c
@@ -4,45 +4,52 @@ int registry_init(void) {
char filename[FILENAME_MAX + 1];
// registry enabled?
- registry.enabled = config_get_boolean("registry", "enabled", 0);
+ if(web_server_mode != WEB_SERVER_MODE_NONE) {
+ registry.enabled = config_get_boolean(CONFIG_SECTION_REGISTRY, "enabled", 0);
+ }
+ else {
+ info("Registry is disabled - use the central netdata");
+ config_set_boolean(CONFIG_SECTION_REGISTRY, "enabled", 0);
+ registry.enabled = 0;
+ }
// pathnames
- registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR "/registry");
+ snprintfz(filename, FILENAME_MAX, "%s/registry", netdata_configured_varlib_dir);
+ registry.pathname = config_get(CONFIG_SECTION_REGISTRY, "registry db directory", filename);
if(mkdir(registry.pathname, 0770) == -1 && errno != EEXIST)
fatal("Cannot create directory '%s'.", registry.pathname);
// filenames
snprintfz(filename, FILENAME_MAX, "%s/netdata.public.unique.id", registry.pathname);
- registry.machine_guid_filename = config_get("registry", "netdata unique id file", filename);
- registry_get_this_machine_guid();
+ registry.machine_guid_filename = config_get(CONFIG_SECTION_REGISTRY, "netdata unique id file", filename);
snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname);
- registry.db_filename = config_get("registry", "registry db file", filename);
+ registry.db_filename = config_get(CONFIG_SECTION_REGISTRY, "registry db file", filename);
snprintfz(filename, FILENAME_MAX, "%s/registry-log.db", registry.pathname);
- registry.log_filename = config_get("registry", "registry log file", filename);
+ registry.log_filename = config_get(CONFIG_SECTION_REGISTRY, "registry log file", filename);
// configuration options
- registry.save_registry_every_entries = (unsigned long long)config_get_number("registry", "registry save db every new entries", 1000000);
- registry.persons_expiration = config_get_number("registry", "registry expire idle persons days", 365) * 86400;
- registry.registry_domain = config_get("registry", "registry domain", "");
- registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
- registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", localhost.hostname));
- registry.verify_cookies_redirects = config_get_boolean("registry", "verify browser cookies support", 1);
+ registry.save_registry_every_entries = (unsigned long long)config_get_number(CONFIG_SECTION_REGISTRY, "registry save db every new entries", 1000000);
+ registry.persons_expiration = config_get_number(CONFIG_SECTION_REGISTRY, "registry expire idle persons days", 365) * 86400;
+ registry.registry_domain = config_get(CONFIG_SECTION_REGISTRY, "registry domain", "");
+ registry.registry_to_announce = config_get(CONFIG_SECTION_REGISTRY, "registry to announce", "https://registry.my-netdata.io");
+ registry.hostname = config_get(CONFIG_SECTION_REGISTRY, "registry hostname", config_get(CONFIG_SECTION_GLOBAL, "hostname", "localhost"));
+ registry.verify_cookies_redirects = config_get_boolean(CONFIG_SECTION_REGISTRY, "verify browser cookies support", 1);
setenv("NETDATA_REGISTRY_HOSTNAME", registry.hostname, 1);
setenv("NETDATA_REGISTRY_URL", registry.registry_to_announce, 1);
- registry.max_url_length = (size_t)config_get_number("registry", "max URL length", 1024);
+ registry.max_url_length = (size_t)config_get_number(CONFIG_SECTION_REGISTRY, "max URL length", 1024);
if(registry.max_url_length < 10) {
registry.max_url_length = 10;
- config_set_number("registry", "max URL length", (long long)registry.max_url_length);
+ config_set_number(CONFIG_SECTION_REGISTRY, "max URL length", (long long)registry.max_url_length);
}
- registry.max_name_length = (size_t)config_get_number("registry", "max URL name length", 50);
+ registry.max_name_length = (size_t)config_get_number(CONFIG_SECTION_REGISTRY, "max URL name length", 50);
if(registry.max_name_length < 10) {
registry.max_name_length = 10;
- config_set_number("registry", "max URL name length", (long long)registry.max_name_length);
+ config_set_number(CONFIG_SECTION_REGISTRY, "max URL name length", (long long)registry.max_name_length);
}
// initialize entries counters
@@ -61,7 +68,7 @@ int registry_init(void) {
registry.machines_urls_memory = 0;
// initialize locks
- pthread_mutex_init(&registry.lock, NULL);
+ netdata_mutex_init(&registry.lock);
// create dictionaries
registry.persons = dictionary_create(DICTIONARY_FLAGS);
diff --git a/src/registry_internals.c b/src/registry_internals.c
index d32d549e2..9ec91ba40 100644
--- a/src/registry_internals.c
+++ b/src/registry_internals.c
@@ -7,7 +7,7 @@ struct registry registry;
// parse a GUID and re-generated to be always lower case
// this is used as a protection against the variations of GUIDs
-int registry_regenerate_guid(const char *guid, char *result) {
+int regenerate_guid(const char *guid, char *result) {
uuid_t uuid;
if(unlikely(uuid_parse(guid, uuid) == -1)) {
info("Registry: GUID '%s' is not a valid GUID.", guid);
@@ -18,7 +18,7 @@ int registry_regenerate_guid(const char *guid, char *result) {
#ifdef NETDATA_INTERNAL_CHECKS
if(strcmp(guid, result))
- info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
+ info("GUID '%s' and re-generated GUID '%s' differ!", guid, result);
#endif /* NETDATA_INTERNAL_CHECKS */
}
@@ -96,14 +96,14 @@ REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_gu
url = registry_fix_url(url, NULL);
// make sure the person GUID is valid
- if(registry_regenerate_guid(person_guid, pbuf) == -1) {
+ if(regenerate_guid(person_guid, pbuf) == -1) {
info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
return NULL;
}
person_guid = pbuf;
// make sure the machine GUID is valid
- if(registry_regenerate_guid(machine_guid, mbuf) == -1) {
+ if(regenerate_guid(machine_guid, mbuf) == -1) {
info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
return NULL;
}
@@ -226,7 +226,7 @@ REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid
if(!pu || !p || !m) return NULL;
// make sure the machine GUID is valid
- if(registry_regenerate_guid(request_machine, mbuf) == -1) {
+ if(regenerate_guid(request_machine, mbuf) == -1) {
info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
return NULL;
}
@@ -275,8 +275,10 @@ static inline int is_machine_guid_blacklisted(const char *guid) {
}
char *registry_get_this_machine_guid(void) {
- if(likely(registry.machine_guid[0]))
- return registry.machine_guid;
+ static char guid[GUID_LEN + 1] = "";
+
+ if(likely(guid[0]))
+ return guid;
// read it from disk
int fd = open(registry.machine_guid_filename, O_RDONLY);
@@ -286,38 +288,38 @@ char *registry_get_this_machine_guid(void) {
error("Failed to read machine GUID from '%s'", registry.machine_guid_filename);
else {
buf[GUID_LEN] = '\0';
- if(registry_regenerate_guid(buf, registry.machine_guid) == -1) {
+ if(regenerate_guid(buf, guid) == -1) {
error("Failed to validate machine GUID '%s' from '%s'. Ignoring it - this might mean this netdata will appear as duplicate in the registry.",
buf, registry.machine_guid_filename);
- registry.machine_guid[0] = '\0';
+ guid[0] = '\0';
}
- else if(is_machine_guid_blacklisted(registry.machine_guid))
- registry.machine_guid[0] = '\0';
+ else if(is_machine_guid_blacklisted(guid))
+ guid[0] = '\0';
}
close(fd);
}
// generate a new one?
- if(!registry.machine_guid[0]) {
+ if(!guid[0]) {
uuid_t uuid;
uuid_generate_time(uuid);
- uuid_unparse_lower(uuid, registry.machine_guid);
- registry.machine_guid[GUID_LEN] = '\0';
+ uuid_unparse_lower(uuid, guid);
+ guid[GUID_LEN] = '\0';
// save it
fd = open(registry.machine_guid_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
if(fd == -1)
fatal("Cannot create unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
- if(write(fd, registry.machine_guid, GUID_LEN) != GUID_LEN)
+ if(write(fd, guid, GUID_LEN) != GUID_LEN)
fatal("Cannot write the unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
close(fd);
}
- setenv("NETDATA_REGISTRY_UNIQUE_ID", registry.machine_guid, 1);
+ setenv("NETDATA_REGISTRY_UNIQUE_ID", guid, 1);
- return registry.machine_guid;
+ return guid;
}
diff --git a/src/registry_internals.h b/src/registry_internals.h
index 9c0b74452..433f04a66 100644
--- a/src/registry_internals.h
+++ b/src/registry_internals.h
@@ -14,8 +14,6 @@
struct registry {
int enabled;
- char machine_guid[GUID_LEN + 1];
-
// entries counters / statistics
unsigned long long persons_count;
unsigned long long machines_count;
@@ -58,10 +56,10 @@ struct registry {
avl_tree registry_urls_root_index;
- pthread_mutex_t lock;
+ netdata_mutex_t lock;
};
-extern int registry_regenerate_guid(const char *guid, char *result);
+extern int regenerate_guid(const char *guid, char *result);
#include "registry_url.h"
#include "registry_machine.h"
@@ -70,8 +68,6 @@ extern int registry_regenerate_guid(const char *guid, char *result);
extern struct registry registry;
-extern char *registry_get_this_machine_guid(void);
-
// REGISTRY LOW-LEVEL REQUESTS (in registry-internals.c)
extern REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when);
extern REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
diff --git a/src/registry_machine.c b/src/registry_machine.c
index 3510736df..6dc8200d3 100644
--- a/src/registry_machine.c
+++ b/src/registry_machine.c
@@ -58,7 +58,7 @@ REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
if(likely(machine_guid && *machine_guid)) {
// validate it is a GUID
char buf[GUID_LEN + 1];
- if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
+ if(unlikely(regenerate_guid(machine_guid, buf) == -1))
info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
else {
machine_guid = buf;
diff --git a/src/registry_person.c b/src/registry_person.c
index 5f9099c9a..409c76925 100644
--- a/src/registry_person.c
+++ b/src/registry_person.c
@@ -183,7 +183,7 @@ REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
if(person_guid && *person_guid) {
char buf[GUID_LEN + 1];
// validate it is a GUID
- if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
+ if(unlikely(regenerate_guid(person_guid, buf) == -1))
info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
else {
person_guid = buf;
diff --git a/src/rrd.c b/src/rrd.c
index bd0175efc..a9ff6243d 100644
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -1,7 +1,6 @@
+#define NETDATA_RRD_INTERNALS 1
#include "common.h"
-#define RRD_DEFAULT_GAP_INTERPOLATIONS 1
-
// ----------------------------------------------------------------------------
// globals
@@ -12,402 +11,124 @@
int rrd_delete_unupdated_dimensions = 0;
*/
-int rrd_update_every = UPDATE_EVERY;
-int rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
-int rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
+int default_rrd_update_every = UPDATE_EVERY;
+int default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
+RRD_MEMORY_MODE default_rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
-static int rrdset_compare(void* a, void* b);
-static int rrdset_compare_name(void* a, void* b);
-static int rrdfamily_compare(void *a, void *b);
// ----------------------------------------------------------------------------
-// RRDHOST
-
-RRDHOST localhost = {
- .hostname = "localhost",
- .rrdset_root = NULL,
- .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
- .rrdset_root_index = {
- { NULL, rrdset_compare },
- AVL_LOCK_INITIALIZER
- },
- .rrdset_root_index_name = {
- { NULL, rrdset_compare_name },
- AVL_LOCK_INITIALIZER
- },
- .rrdfamily_root_index = {
- { NULL, rrdfamily_compare },
- AVL_LOCK_INITIALIZER
- },
- .variables_root_index = {
- { NULL, rrdvar_compare },
- AVL_LOCK_INITIALIZER
- },
- .health_log = {
- .next_log_id = 1,
- .next_alarm_id = 1,
- .count = 0,
- .max = 1000,
- .alarms = NULL,
- .alarm_log_rwlock = PTHREAD_RWLOCK_INITIALIZER
- }
-};
-
-void rrdhost_init(char *hostname) {
- localhost.hostname = hostname;
- localhost.health_log.next_log_id =
- localhost.health_log.next_alarm_id = now_realtime_sec();
-}
-
-void rrdhost_rwlock(RRDHOST *host) {
- pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
-}
-
-void rrdhost_rdlock(RRDHOST *host) {
- pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
-}
-
-void rrdhost_unlock(RRDHOST *host) {
- pthread_rwlock_unlock(&host->rrdset_root_rwlock);
-}
-
-void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
- int ret = pthread_rwlock_trywrlock(&host->rrdset_root_rwlock);
-
- if(ret == 0)
- fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
-}
-
-void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
- int ret = pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock);
-
- if(ret == 0)
- fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
-}
-
-// ----------------------------------------------------------------------------
-// RRDFAMILY index
-
-static int rrdfamily_compare(void *a, void *b) {
- if(((RRDFAMILY *)a)->hash_family < ((RRDFAMILY *)b)->hash_family) return -1;
- else if(((RRDFAMILY *)a)->hash_family > ((RRDFAMILY *)b)->hash_family) return 1;
- else return strcmp(((RRDFAMILY *)a)->family, ((RRDFAMILY *)b)->family);
-}
-
-#define rrdfamily_index_add(host, rc) (RRDFAMILY *)avl_insert_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
-#define rrdfamily_index_del(host, rc) (RRDFAMILY *)avl_remove_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
-
-static RRDFAMILY *rrdfamily_index_find(RRDHOST *host, const char *id, uint32_t hash) {
- RRDFAMILY tmp;
- tmp.family = id;
- tmp.hash_family = (hash)?hash:simple_hash(tmp.family);
-
- return (RRDFAMILY *)avl_search_lock(&(host->rrdfamily_root_index), (avl *) &tmp);
-}
-
-RRDFAMILY *rrdfamily_create(const char *id) {
- RRDFAMILY *rc = rrdfamily_index_find(&localhost, id, 0);
- if(!rc) {
- rc = callocz(1, sizeof(RRDFAMILY));
+// RRD - memory modes
- rc->family = strdupz(id);
- rc->hash_family = simple_hash(rc->family);
-
- // initialize the variables index
- avl_init_lock(&rc->variables_root_index, rrdvar_compare);
-
- RRDFAMILY *ret = rrdfamily_index_add(&localhost, rc);
- if(ret != rc)
- fatal("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE");
- }
-
- rc->use_count++;
- return rc;
-}
+inline const char *rrd_memory_mode_name(RRD_MEMORY_MODE id) {
+ switch(id) {
+ case RRD_MEMORY_MODE_RAM:
+ return RRD_MEMORY_MODE_RAM_NAME;
-void rrdfamily_free(RRDFAMILY *rc) {
- rc->use_count--;
- if(!rc->use_count) {
- RRDFAMILY *ret = rrdfamily_index_del(&localhost, rc);
- if(ret != rc)
- fatal("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE");
+ case RRD_MEMORY_MODE_MAP:
+ return RRD_MEMORY_MODE_MAP_NAME;
- if(rc->variables_root_index.avl_tree.root != NULL)
- fatal("RRDFAMILY: INTERNAL ERROR: Variables index of RRDFAMILY '%s' that is freed, is not empty.", rc->family);
+ case RRD_MEMORY_MODE_NONE:
+ return RRD_MEMORY_MODE_NONE_NAME;
- freez((void *)rc->family);
- freez(rc);
+ case RRD_MEMORY_MODE_SAVE:
+ default:
+ return RRD_MEMORY_MODE_SAVE_NAME;
}
}
-// ----------------------------------------------------------------------------
-// RRDSET index
+RRD_MEMORY_MODE rrd_memory_mode_id(const char *name) {
+ if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
+ return RRD_MEMORY_MODE_RAM;
+ else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
+ return RRD_MEMORY_MODE_MAP;
+ else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_NONE_NAME)))
+ return RRD_MEMORY_MODE_NONE;
-static int rrdset_compare(void* a, void* b) {
- if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
- else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
- else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
+ return RRD_MEMORY_MODE_SAVE;
}
-#define rrdset_index_add(host, st) (RRDSET *)avl_insert_lock(&((host)->rrdset_root_index), (avl *)(st))
-#define rrdset_index_del(host, st) (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index), (avl *)(st))
-
-static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
- RRDSET tmp;
- strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
- tmp.hash = (hash)?hash:simple_hash(tmp.id);
-
- return (RRDSET *)avl_search_lock(&(host->rrdset_root_index), (avl *) &tmp);
-}
// ----------------------------------------------------------------------------
-// RRDSET name index
+// RRD - algorithms types
-#define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
+RRD_ALGORITHM rrd_algorithm_id(const char *name) {
+ if(strcmp(name, RRD_ALGORITHM_INCREMENTAL_NAME) == 0)
+ return RRD_ALGORITHM_INCREMENTAL;
-static int rrdset_compare_name(void* a, void* b) {
- RRDSET *A = rrdset_from_avlname(a);
- RRDSET *B = rrdset_from_avlname(b);
+ else if(strcmp(name, RRD_ALGORITHM_ABSOLUTE_NAME) == 0)
+ return RRD_ALGORITHM_ABSOLUTE;
- // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
+ else if(strcmp(name, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME) == 0)
+ return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL;
- if(A->hash_name < B->hash_name) return -1;
- else if(A->hash_name > B->hash_name) return 1;
- else return strcmp(A->name, B->name);
-}
+ else if(strcmp(name, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME) == 0)
+ return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL;
-RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
- void *result;
- // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
- result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
- if(result) return rrdset_from_avlname(result);
- return NULL;
+ else
+ return RRD_ALGORITHM_ABSOLUTE;
}
-RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
- void *result;
- // fprintf(stderr, "DELETING: %s (name: %s)\n", st->id, st->name);
- result = (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index_name), (avl *)(&st->avlname));
- if(result) return rrdset_from_avlname(result);
- return NULL;
-}
+const char *rrd_algorithm_name(RRD_ALGORITHM algorithm) {
+ switch(algorithm) {
+ case RRD_ALGORITHM_ABSOLUTE:
+ default:
+ return RRD_ALGORITHM_ABSOLUTE_NAME;
-static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
- void *result = NULL;
- RRDSET tmp;
- tmp.name = name;
- tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
+ case RRD_ALGORITHM_INCREMENTAL:
+ return RRD_ALGORITHM_INCREMENTAL_NAME;
- // fprintf(stderr, "SEARCHING: %s\n", name);
- result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
- if(result) {
- RRDSET *st = rrdset_from_avlname(result);
- if(strcmp(st->magic, RRDSET_MAGIC))
- error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME;
- // fprintf(stderr, "FOUND: %s\n", name);
- return rrdset_from_avlname(result);
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME;
}
- // fprintf(stderr, "NOT FOUND: %s\n", name);
- return NULL;
}
// ----------------------------------------------------------------------------
-// RRDDIM index
-
-static int rrddim_compare(void* a, void* b) {
- if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
- else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
- else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
-}
-
-#define rrddim_index_add(st, rd) (RRDDIM *)avl_insert_lock(&((st)->dimensions_index), (avl *)(rd))
-#define rrddim_index_del(st,rd ) (RRDDIM *)avl_remove_lock(&((st)->dimensions_index), (avl *)(rd))
+// RRD - chart types
-static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
- RRDDIM tmp;
- strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
- tmp.hash = (hash)?hash:simple_hash(tmp.id);
+inline RRDSET_TYPE rrdset_type_id(const char *name) {
+ if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0))
+ return RRDSET_TYPE_AREA;
- return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
-}
-
-// ----------------------------------------------------------------------------
-// chart types
+ else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0))
+ return RRDSET_TYPE_STACKED;
-int rrdset_type_id(const char *name)
-{
- if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0)) return RRDSET_TYPE_AREA;
- else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0)) return RRDSET_TYPE_STACKED;
- else if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0)) return RRDSET_TYPE_LINE;
- return RRDSET_TYPE_LINE;
+ else // if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0))
+ return RRDSET_TYPE_LINE;
}
-const char *rrdset_type_name(int chart_type)
-{
- static char line[] = RRDSET_TYPE_LINE_NAME;
- static char area[] = RRDSET_TYPE_AREA_NAME;
- static char stacked[] = RRDSET_TYPE_STACKED_NAME;
-
+const char *rrdset_type_name(RRDSET_TYPE chart_type) {
switch(chart_type) {
case RRDSET_TYPE_LINE:
- return line;
+ default:
+ return RRDSET_TYPE_LINE_NAME;
case RRDSET_TYPE_AREA:
- return area;
+ return RRDSET_TYPE_AREA_NAME;
case RRDSET_TYPE_STACKED:
- return stacked;
+ return RRDSET_TYPE_STACKED_NAME;
}
- return line;
-}
-
-// ----------------------------------------------------------------------------
-// load / save
-
-const char *rrd_memory_mode_name(int id)
-{
- static const char ram[] = RRD_MEMORY_MODE_RAM_NAME;
- static const char map[] = RRD_MEMORY_MODE_MAP_NAME;
- static const char save[] = RRD_MEMORY_MODE_SAVE_NAME;
-
- switch(id) {
- case RRD_MEMORY_MODE_RAM:
- return ram;
-
- case RRD_MEMORY_MODE_MAP:
- return map;
-
- case RRD_MEMORY_MODE_SAVE:
- default:
- return save;
- }
-
- return save;
-}
-
-int rrd_memory_mode_id(const char *name)
-{
- if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
- return RRD_MEMORY_MODE_RAM;
- else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
- return RRD_MEMORY_MODE_MAP;
-
- return RRD_MEMORY_MODE_SAVE;
}
-// ----------------------------------------------------------------------------
-// algorithms types
-
-int rrddim_algorithm_id(const char *name)
-{
- if(strcmp(name, RRDDIM_INCREMENTAL_NAME) == 0) return RRDDIM_INCREMENTAL;
- if(strcmp(name, RRDDIM_ABSOLUTE_NAME) == 0) return RRDDIM_ABSOLUTE;
- if(strcmp(name, RRDDIM_PCENT_OVER_ROW_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_ROW_TOTAL;
- if(strcmp(name, RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_DIFF_TOTAL;
- return RRDDIM_ABSOLUTE;
-}
-
-const char *rrddim_algorithm_name(int chart_type)
-{
- static char absolute[] = RRDDIM_ABSOLUTE_NAME;
- static char incremental[] = RRDDIM_INCREMENTAL_NAME;
- static char percentage_of_absolute_row[] = RRDDIM_PCENT_OVER_ROW_TOTAL_NAME;
- static char percentage_of_incremental_row[] = RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME;
-
- switch(chart_type) {
- case RRDDIM_ABSOLUTE:
- return absolute;
-
- case RRDDIM_INCREMENTAL:
- return incremental;
-
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- return percentage_of_absolute_row;
-
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- return percentage_of_incremental_row;
- }
- return absolute;
-}
// ----------------------------------------------------------------------------
-// chart names
+// RRD - cache directory
-char *rrdset_strncpyz_name(char *to, const char *from, size_t length)
-{
- char c, *p = to;
-
- while (length-- && (c = *from++)) {
- if(c != '.' && !isalnum(c))
- c = '_';
-
- *p++ = c;
- }
-
- *p = '\0';
-
- return to;
-}
-
-void rrdset_set_name(RRDSET *st, const char *name)
-{
- if(unlikely(st->name && !strcmp(st->name, name)))
- return;
-
- debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
-
- char b[CONFIG_MAX_VALUE + 1];
- char n[RRD_ID_LENGTH_MAX + 1];
-
- snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
- rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
-
- if(st->name) {
- rrdset_index_del_name(&localhost, st);
- st->name = config_set_default(st->id, "name", b);
- st->hash_name = simple_hash(st->name);
- rrdsetvar_rename_all(st);
- }
- else {
- st->name = config_get(st->id, "name", b);
- st->hash_name = simple_hash(st->name);
- }
-
- pthread_rwlock_wrlock(&st->rwlock);
- RRDDIM *rd;
- for(rd = st->dimensions; rd ;rd = rd->next)
- rrddimvar_rename_all(rd);
- pthread_rwlock_unlock(&st->rwlock);
-
- if(unlikely(rrdset_index_add_name(&localhost, st) != st))
- error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name);
-}
-
-// ----------------------------------------------------------------------------
-// cache directory
-
-char *rrdset_cache_dir(const char *id)
-{
+char *rrdset_cache_dir(RRDHOST *host, const char *id, const char *config_section) {
char *ret = NULL;
- static char *cache_dir = NULL;
- if(!cache_dir) {
- cache_dir = config_get("global", "cache directory", CACHE_DIR);
- int r = mkdir(cache_dir, 0755);
- if(r != 0 && errno != EEXIST)
- error("Cannot create directory '%s'", cache_dir);
- }
-
char b[FILENAME_MAX + 1];
char n[FILENAME_MAX + 1];
rrdset_strncpyz_name(b, id, FILENAME_MAX);
- snprintfz(n, FILENAME_MAX, "%s/%s", cache_dir, b);
- ret = config_get(id, "cache directory", n);
+ snprintfz(n, FILENAME_MAX, "%s/%s", host->cache_dir, b);
+ ret = config_get(config_section, "cache directory", n);
- if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_MAP || host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
int r = mkdir(ret, 0775);
if(r != 0 && errno != EEXIST)
error("Cannot create directory '%s'", ret);
@@ -415,1236 +136,3 @@ char *rrdset_cache_dir(const char *id)
return ret;
}
-
-// ----------------------------------------------------------------------------
-// core functions
-
-void rrdset_reset(RRDSET *st)
-{
- debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
-
- st->last_collected_time.tv_sec = 0;
- st->last_collected_time.tv_usec = 0;
- st->last_updated.tv_sec = 0;
- st->last_updated.tv_usec = 0;
- st->current_entry = 0;
- st->counter = 0;
- st->counter_done = 0;
-
- RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- rd->last_collected_time.tv_sec = 0;
- rd->last_collected_time.tv_usec = 0;
- rd->counter = 0;
- memset(rd->values, 0, rd->entries * sizeof(storage_number));
- }
-}
-static inline long align_entries_to_pagesize(long entries) {
- if(entries < 5) entries = 5;
- if(entries > RRD_HISTORY_ENTRIES_MAX) entries = RRD_HISTORY_ENTRIES_MAX;
-
-#ifdef NETDATA_LOG_ALLOCATIONS
- long page = (size_t)sysconf(_SC_PAGESIZE);
-
- long size = sizeof(RRDDIM) + entries * sizeof(storage_number);
- if(size % page) {
- size -= (size % page);
- size += page;
-
- long n = (size - sizeof(RRDDIM)) / sizeof(storage_number);
- return n;
- }
-
- return entries;
-#else
- return entries;
-#endif
-}
-
-static inline void timeval_align(struct timeval *tv, int update_every) {
- tv->tv_sec -= tv->tv_sec % update_every;
- tv->tv_usec = 500000;
-}
-
-RRDSET *rrdset_create(const char *type, const char *id, const char *name, const char *family, const char *context, const char *title, const char *units, long priority, int update_every, int chart_type)
-{
- if(!type || !type[0]) {
- fatal("Cannot create rrd stats without a type.");
- return NULL;
- }
-
- if(!id || !id[0]) {
- fatal("Cannot create rrd stats without an id.");
- return NULL;
- }
-
- char fullid[RRD_ID_LENGTH_MAX + 1];
- char fullfilename[FILENAME_MAX + 1];
-
- snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
-
- RRDSET *st = rrdset_find(fullid);
- if(st) {
- error("Cannot create rrd stats for '%s', it already exists.", fullid);
- return st;
- }
-
- long rentries = config_get_number(fullid, "history", rrd_default_history_entries);
- long entries = align_entries_to_pagesize(rentries);
- if(entries != rentries) entries = config_set_number(fullid, "history", entries);
-
- int enabled = config_get_boolean(fullid, "enabled", 1);
- if(!enabled) entries = 5;
-
- unsigned long size = sizeof(RRDSET);
- char *cache_dir = rrdset_cache_dir(fullid);
-
- debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
-
- snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
- if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
- if(st) {
- if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
- errno = 0;
- info("Initializing file %s.", fullfilename);
- memset(st, 0, size);
- }
- else if(strcmp(st->id, fullid) != 0) {
- errno = 0;
- error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
- // munmap(st, size);
- // st = NULL;
- memset(st, 0, size);
- }
- else if(st->memsize != size || st->entries != entries) {
- errno = 0;
- error("File %s does not have the desired size. Clearing it.", fullfilename);
- memset(st, 0, size);
- }
- else if(st->update_every != update_every) {
- errno = 0;
- error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
- memset(st, 0, size);
- }
- else if((now_realtime_sec() - st->last_updated.tv_sec) > update_every * entries) {
- errno = 0;
- error("File %s is too old. Clearing it.", fullfilename);
- memset(st, 0, size);
- }
-
- // make sure the database is aligned
- if(st->last_updated.tv_sec)
- timeval_align(&st->last_updated, update_every);
- }
-
- if(st) {
- st->name = NULL;
- st->type = NULL;
- st->family = NULL;
- st->context = NULL;
- st->title = NULL;
- st->units = NULL;
- st->dimensions = NULL;
- st->next = NULL;
- st->mapped = rrd_memory_mode;
- st->variables = NULL;
- st->alarms = NULL;
- memset(&st->rwlock, 0, sizeof(pthread_rwlock_t));
- memset(&st->avl, 0, sizeof(avl));
- memset(&st->avlname, 0, sizeof(avl));
- memset(&st->variables_root_index, 0, sizeof(avl_tree_lock));
- memset(&st->dimensions_index, 0, sizeof(avl_tree_lock));
- }
- else {
- st = callocz(1, size);
- st->mapped = RRD_MEMORY_MODE_RAM;
- }
-
- st->memsize = size;
- st->entries = entries;
- st->update_every = update_every;
-
- if(st->current_entry >= st->entries) st->current_entry = 0;
-
- strcpy(st->cache_filename, fullfilename);
- strcpy(st->magic, RRDSET_MAGIC);
-
- strcpy(st->id, fullid);
- st->hash = simple_hash(st->id);
-
- st->cache_dir = cache_dir;
-
- st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
- st->type = config_get(st->id, "type", type);
- st->family = config_get(st->id, "family", family?family:st->type);
- st->units = config_get(st->id, "units", units?units:"");
-
- st->context = config_get(st->id, "context", context?context:st->id);
- st->hash_context = simple_hash(st->context);
-
- st->priority = config_get_number(st->id, "priority", priority);
- st->enabled = enabled;
-
- st->isdetail = 0;
- st->debug = 0;
-
- // if(!strcmp(st->id, "disk_util.dm-0")) {
- // st->debug = 1;
- // error("enabled debugging for '%s'", st->id);
- // }
- // else error("not enabled debugging for '%s'", st->id);
-
- st->green = NAN;
- st->red = NAN;
-
- st->last_collected_time.tv_sec = 0;
- st->last_collected_time.tv_usec = 0;
- st->counter_done = 0;
-
- st->gap_when_lost_iterations_above = (int) (
- config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
-
- avl_init_lock(&st->dimensions_index, rrddim_compare);
- avl_init_lock(&st->variables_root_index, rrdvar_compare);
-
- pthread_rwlock_init(&st->rwlock, NULL);
- rrdhost_rwlock(&localhost);
-
- if(name && *name) rrdset_set_name(st, name);
- else rrdset_set_name(st, id);
-
- {
- char varvalue[CONFIG_MAX_VALUE + 1];
- char varvalue2[CONFIG_MAX_VALUE + 1];
- snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
- json_escape_string(varvalue2, varvalue, sizeof(varvalue2));
- st->title = config_get(st->id, "title", varvalue2);
- }
-
- st->rrdfamily = rrdfamily_create(st->family);
- st->rrdhost = &localhost;
-
- st->next = localhost.rrdset_root;
- localhost.rrdset_root = st;
-
- if(health_enabled) {
- rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0);
- rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, 0);
- rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, 0);
- rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, 0);
- rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, 0);
- }
-
- if(unlikely(rrdset_index_add(&localhost, st) != st))
- error("RRDSET: INTERNAL ERROR: attempt to index duplicate chart '%s'", st->id);
-
- rrdsetcalc_link_matching(st);
- rrdcalctemplate_link_matching(st);
-
- rrdhost_unlock(&localhost);
-
- return(st);
-}
-
-RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier, long divisor, int algorithm)
-{
- RRDDIM *rd = rrddim_find(st, id);
- if(rd) {
- debug(D_RRD_CALLS, "Cannot create rrd dimension '%s/%s', it already exists.", st->id, name?name:"<NONAME>");
- return rd;
- }
-
- char filename[FILENAME_MAX + 1];
- char fullfilename[FILENAME_MAX + 1];
-
- char varname[CONFIG_MAX_NAME + 1];
- unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
-
- debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
-
- rrdset_strncpyz_name(filename, id, FILENAME_MAX);
- snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
-
- if(rrd_memory_mode != RRD_MEMORY_MODE_RAM)
- rd = (RRDDIM *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 1);
-
- if(rd) {
- struct timeval now;
- now_realtime_timeval(&now);
-
- if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
- errno = 0;
- info("Initializing file %s.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->memsize != size) {
- errno = 0;
- error("File %s does not have the desired size. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->multiplier != multiplier) {
- errno = 0;
- error("File %s does not have the same multiplier. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->divisor != divisor) {
- errno = 0;
- error("File %s does not have the same divisor. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->algorithm != algorithm) {
- errno = 0;
- error("File %s does not have the same algorithm. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->update_every != st->update_every) {
- errno = 0;
- error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(dt_usec(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * USEC_PER_SEC)) {
- errno = 0;
- error("File %s is too old. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(strcmp(rd->id, id) != 0) {
- errno = 0;
- error("File %s contents are not for dimension %s. Clearing it.", fullfilename, id);
- // munmap(rd, size);
- // rd = NULL;
- memset(rd, 0, size);
- }
- }
-
- if(rd) {
- // we have a file mapped for rd
- rd->mapped = rrd_memory_mode;
- rd->flags = 0x00000000;
- rd->variables = NULL;
- rd->next = NULL;
- rd->name = NULL;
- memset(&rd->avl, 0, sizeof(avl));
- }
- else {
- // if we didn't manage to get a mmap'd dimension, just create one
-
- rd = callocz(1, size);
- rd->mapped = RRD_MEMORY_MODE_RAM;
- }
- rd->memsize = size;
-
- strcpy(rd->magic, RRDDIMENSION_MAGIC);
- strcpy(rd->cache_filename, fullfilename);
- strncpyz(rd->id, id, RRD_ID_LENGTH_MAX);
- rd->hash = simple_hash(rd->id);
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
- rd->name = config_get(st->id, varname, (name && *name)?name:rd->id);
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
- rd->algorithm = rrddim_algorithm_id(config_get(st->id, varname, rrddim_algorithm_name(algorithm)));
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
- rd->multiplier = config_get_number(st->id, varname, multiplier);
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
- rd->divisor = config_get_number(st->id, varname, divisor);
- if(!rd->divisor) rd->divisor = 1;
-
- rd->entries = st->entries;
- rd->update_every = st->update_every;
-
- // prevent incremental calculation spikes
- rd->counter = 0;
- rd->updated = 0;
- rd->calculated_value = 0;
- rd->last_calculated_value = 0;
- rd->collected_value = 0;
- rd->last_collected_value = 0;
- rd->collected_volume = 0;
- rd->stored_volume = 0;
- rd->last_stored_value = 0;
- rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
- rd->last_collected_time.tv_sec = 0;
- rd->last_collected_time.tv_usec = 0;
- rd->rrdset = st;
-
- // append this dimension
- pthread_rwlock_wrlock(&st->rwlock);
- if(!st->dimensions)
- st->dimensions = rd;
- else {
- RRDDIM *td = st->dimensions;
- for(; td->next; td = td->next) ;
- td->next = rd;
- }
-
- if(health_enabled) {
- rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, 0);
- rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, 0);
- rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, 0);
- }
-
- pthread_rwlock_unlock(&st->rwlock);
-
- if(unlikely(rrddim_index_add(st, rd) != rd))
- error("RRDDIM: INTERNAL ERROR: attempt to index duplicate dimension '%s' on chart '%s'", rd->id, st->id);
-
- return(rd);
-}
-
-void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name)
-{
- if(unlikely(rd->name && !strcmp(rd->name, name)))
- return;
-
- debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", st->name, rd->name, st->name, name);
-
- char varname[CONFIG_MAX_NAME + 1];
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
- rd->name = config_set_default(st->id, varname, name);
-
- rrddimvar_rename_all(rd);
-}
-
-void rrddim_free(RRDSET *st, RRDDIM *rd)
-{
- debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
-
- if(rd == st->dimensions)
- st->dimensions = rd->next;
- else {
- RRDDIM *i;
- for (i = st->dimensions; i && i->next != rd; i = i->next) ;
-
- if (i && i->next == rd)
- i->next = rd->next;
- else
- error("Request to free dimension '%s.%s' but it is not linked.", st->id, rd->name);
- }
- rd->next = NULL;
-
- while(rd->variables)
- rrddimvar_free(rd->variables);
-
- if(unlikely(rrddim_index_del(st, rd) != rd))
- error("RRDDIM: INTERNAL ERROR: attempt to remove from index dimension '%s' on chart '%s', removed a different dimension.", rd->id, st->id);
-
- // free(rd->annotations);
- if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
- debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
- savememory(rd->cache_filename, rd, rd->memsize);
-
- debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
- munmap(rd, rd->memsize);
- }
- else if(rd->mapped == RRD_MEMORY_MODE_MAP) {
- debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
- munmap(rd, rd->memsize);
- }
- else {
- debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
- freez(rd);
- }
-}
-
-void rrdset_free_all(void)
-{
- info("Freeing all memory...");
-
- rrdhost_rwlock(&localhost);
-
- RRDSET *st;
- for(st = localhost.rrdset_root; st ;) {
- RRDSET *next = st->next;
-
- pthread_rwlock_wrlock(&st->rwlock);
-
- while(st->variables)
- rrdsetvar_free(st->variables);
-
- while(st->alarms)
- rrdsetcalc_unlink(st->alarms);
-
- while(st->dimensions)
- rrddim_free(st, st->dimensions);
-
- if(unlikely(rrdset_index_del(&localhost, st) != st))
- error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
-
- rrdset_index_del_name(&localhost, st);
-
- st->rrdfamily->use_count--;
- if(!st->rrdfamily->use_count)
- rrdfamily_free(st->rrdfamily);
-
- pthread_rwlock_unlock(&st->rwlock);
-
- if(st->mapped == RRD_MEMORY_MODE_SAVE || st->mapped == RRD_MEMORY_MODE_MAP) {
- debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
- munmap(st, st->memsize);
- }
- else
- freez(st);
-
- st = next;
- }
- localhost.rrdset_root = NULL;
-
- rrdhost_unlock(&localhost);
-
- info("Memory cleanup completed...");
-}
-
-void rrdset_save_all(void) {
- info("Saving database...");
-
- RRDSET *st;
- RRDDIM *rd;
-
- // we get an write lock
- // to ensure only one thread is saving the database
- rrdhost_rwlock(&localhost);
-
- for(st = localhost.rrdset_root; st ; st = st->next) {
- pthread_rwlock_rdlock(&st->rwlock);
-
- if(st->mapped == RRD_MEMORY_MODE_SAVE) {
- debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
- savememory(st->cache_filename, st, st->memsize);
- }
-
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(likely(rd->mapped == RRD_MEMORY_MODE_SAVE)) {
- debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
- savememory(rd->cache_filename, rd, rd->memsize);
- }
- }
-
- pthread_rwlock_unlock(&st->rwlock);
- }
-
- rrdhost_unlock(&localhost);
-}
-
-
-RRDSET *rrdset_find(const char *id)
-{
- debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
-
- RRDSET *st = rrdset_index_find(&localhost, id, 0);
- return(st);
-}
-
-RRDSET *rrdset_find_bytype(const char *type, const char *id)
-{
- debug(D_RRD_CALLS, "rrdset_find_bytype() for chart %s.%s", type, id);
-
- char buf[RRD_ID_LENGTH_MAX + 1];
-
- strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
- strcat(buf, ".");
- int len = (int) strlen(buf);
- strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
-
- return(rrdset_find(buf));
-}
-
-RRDSET *rrdset_find_byname(const char *name)
-{
- debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
-
- RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
- return(st);
-}
-
-RRDDIM *rrddim_find(RRDSET *st, const char *id)
-{
- debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
-
- return rrddim_index_find(st, id, 0);
-}
-
-int rrddim_hide(RRDSET *st, const char *id)
-{
- debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
-
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
- return 1;
- }
-
- rd->flags |= RRDDIM_FLAG_HIDDEN;
- return 0;
-}
-
-int rrddim_unhide(RRDSET *st, const char *id)
-{
- debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
-
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
- return 1;
- }
-
- if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
- return 0;
-}
-
-collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
-{
- debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
-
- now_realtime_timeval(&rd->last_collected_time);
- rd->collected_value = value;
- rd->updated = 1;
- rd->counter++;
-
- // fprintf(stderr, "%s.%s %llu " COLLECTED_NUMBER_FORMAT " dt %0.6f" " rate " CALCULATED_NUMBER_FORMAT "\n", st->name, rd->name, st->usec_since_last_update, value, (float)((double)st->usec_since_last_update / (double)1000000), (calculated_number)((value - rd->last_collected_value) * (calculated_number)rd->multiplier / (calculated_number)rd->divisor * 1000000.0 / (calculated_number)st->usec_since_last_update));
-
- return rd->last_collected_value;
-}
-
-collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
-{
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
- return 0;
- }
-
- return rrddim_set_by_pointer(st, rd, value);
-}
-
-void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds)
-{
- if(unlikely(!st->last_collected_time.tv_sec || !microseconds)) {
- // the first entry
- microseconds = st->update_every * USEC_PER_SEC;
- }
- st->usec_since_last_update = microseconds;
-}
-
-void rrdset_next_usec(RRDSET *st, usec_t microseconds)
-{
- struct timeval now;
- now_realtime_timeval(&now);
-
- if(unlikely(!st->last_collected_time.tv_sec)) {
- // the first entry
- microseconds = st->update_every * USEC_PER_SEC;
- }
- else if(unlikely(!microseconds)) {
- // no dt given by the plugin
- microseconds = dt_usec(&now, &st->last_collected_time);
- }
- else {
- // microseconds has the time since the last collection
- usec_t now_usec = timeval_usec(&now);
- usec_t last_usec = timeval_usec(&st->last_collected_time);
- usec_t since_last_usec = dt_usec(&now, &st->last_collected_time);
-
- // verify the microseconds given is good
- if(unlikely(microseconds > since_last_usec)) {
- debug(D_RRD_CALLS, "dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - since_last_usec, st->name, st->id);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(last_usec + microseconds > now_usec + 1000))
- error("dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - since_last_usec, st->name, st->id);
-#endif
-
- microseconds = since_last_usec;
- }
- else if(unlikely(microseconds < since_last_usec * 0.8)) {
- debug(D_RRD_CALLS, "dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, since_last_usec, st->name, st->id);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- error("dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, since_last_usec, st->name, st->id);
-#endif
- microseconds = since_last_usec;
- }
- }
- debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
- st->usec_since_last_update = microseconds;
-}
-
-usec_t rrdset_done(RRDSET *st)
-{
- if(unlikely(netdata_exit)) return 0;
-
- debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
-
- RRDDIM *rd;
-
- int
- pthreadoldcancelstate; // store the old cancelable pthread state, to restore it at the end
-
- char
- store_this_entry = 1, // boolean: 1 = store this entry, 0 = don't store this entry
- first_entry = 0; // boolean: 1 = this is the first entry seen for this chart, 0 = all other entries
-
- unsigned int
- stored_entries = 0; // the number of entries we have stored in the db, during this call to rrdset_done()
-
- usec_t
- last_collect_ut, // the timestamp in microseconds, of the last collected value
- now_collect_ut, // the timestamp in microseconds, of this collected value (this is NOW)
- last_stored_ut, // the timestamp in microseconds, of the last stored entry in the db
- next_store_ut, // the timestamp in microseconds, of the next entry to store in the db
- update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds
-
- if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
- error("Cannot set pthread cancel state to DISABLE.");
-
- // a read lock is OK here
- pthread_rwlock_rdlock(&st->rwlock);
-
-/*
- // enable the chart, if it was disabled
- if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
- st->enabled = 1;
-*/
-
- // check if the chart has a long time to be updated
- if(unlikely(st->usec_since_last_update > st->entries * update_every_ut)) {
- info("%s: took too long to be updated (%0.3Lf secs). Resetting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
- rrdset_reset(st);
- st->usec_since_last_update = update_every_ut;
- first_entry = 1;
- }
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
-
- // set last_collected_time
- if(unlikely(!st->last_collected_time.tv_sec)) {
- // it is the first entry
- // set the last_collected_time to now
- now_realtime_timeval(&st->last_collected_time);
- timeval_align(&st->last_collected_time, st->update_every);
-
- last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - update_every_ut;
-
- // the first entry should not be stored
- store_this_entry = 0;
- first_entry = 1;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
- }
- else {
- // it is not the first entry
- // calculate the proper last_collected_time, using usec_since_last_update
- last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
- usec_t ut = last_collect_ut + st->usec_since_last_update;
- st->last_collected_time.tv_sec = (time_t) (ut / USEC_PER_SEC);
- st->last_collected_time.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
- }
-
- // if this set has not been updated in the past
- // we fake the last_update time to be = now - usec_since_last_update
- if(unlikely(!st->last_updated.tv_sec)) {
- // it has never been updated before
- // set a fake last_updated, in the past using usec_since_last_update
- usec_t ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - st->usec_since_last_update;
- st->last_updated.tv_sec = (time_t) (ut / USEC_PER_SEC);
- st->last_updated.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
-
- // the first entry should not be stored
- store_this_entry = 0;
- first_entry = 1;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
- }
-
- // check if we will re-write the entire data set
- if(unlikely(dt_usec(&st->last_collected_time, &st->last_updated) > st->entries * update_every_ut)) {
- info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Resetting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
- rrdset_reset(st);
-
- st->usec_since_last_update = update_every_ut;
-
- now_realtime_timeval(&st->last_collected_time);
- timeval_align(&st->last_collected_time, st->update_every);
-
- usec_t ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - st->usec_since_last_update;
- st->last_updated.tv_sec = (time_t) (ut / USEC_PER_SEC);
- st->last_updated.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
-
- // the first entry should not be stored
- store_this_entry = 0;
- first_entry = 1;
- }
-
- // these are the 3 variables that will help us in interpolation
- // last_stored_ut = the last time we added a value to the storage
- // now_collect_ut = the time the current value has been collected
- // next_store_ut = the time of the next interpolation point
- last_stored_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec;
- now_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
- next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC;
-
- if(unlikely(st->debug)) {
- debug(D_RRD_STATS, "%s: last_collect_ut = %0.3Lf (last collection time)", st->name, (long double)last_collect_ut/1000000.0);
- debug(D_RRD_STATS, "%s: now_collect_ut = %0.3Lf (current collection time)", st->name, (long double)now_collect_ut/1000000.0);
- debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
- debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
- }
-
- if(unlikely(!st->counter_done)) {
- store_this_entry = 0;
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
- }
- st->counter_done++;
-
- // calculate totals and count the dimensions
- int dimensions;
- st->collected_total = 0;
- for( rd = st->dimensions, dimensions = 0 ; rd ; rd = rd->next, dimensions++ )
- if(likely(rd->updated)) st->collected_total += rd->collected_value;
-
- uint32_t storage_flags = SN_EXISTS;
-
- // process all dimensions to calculate their values
- // based on the collected figures only
- // at this stage we do not interpolate anything
- for( rd = st->dimensions ; rd ; rd = rd->next ) {
-
- if(unlikely(!rd->updated)) {
- rd->calculated_value = 0;
- continue;
- }
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
- " last_collected_value = " COLLECTED_NUMBER_FORMAT
- " collected_value = " COLLECTED_NUMBER_FORMAT
- " last_calculated_value = " CALCULATED_NUMBER_FORMAT
- " calculated_value = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->last_collected_value
- , rd->collected_value
- , rd->last_calculated_value
- , rd->calculated_value
- );
-
- switch(rd->algorithm) {
- case RRDDIM_ABSOLUTE:
- rd->calculated_value = (calculated_number)rd->collected_value
- * (calculated_number)rd->multiplier
- / (calculated_number)rd->divisor;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
- CALCULATED_NUMBER_FORMAT " = "
- COLLECTED_NUMBER_FORMAT
- " * " CALCULATED_NUMBER_FORMAT
- " / " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value
- , (calculated_number)rd->multiplier
- , (calculated_number)rd->divisor
- );
- break;
-
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- if(unlikely(!st->collected_total))
- rd->calculated_value = 0;
- else
- // the percentage of the current value
- // over the total of all dimensions
- rd->calculated_value =
- (calculated_number)100
- * (calculated_number)rd->collected_value
- / (calculated_number)st->collected_total;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
- CALCULATED_NUMBER_FORMAT " = 100"
- " * " COLLECTED_NUMBER_FORMAT
- " / " COLLECTED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value
- , st->collected_total
- );
- break;
-
- case RRDDIM_INCREMENTAL:
- if(unlikely(rd->counter <= 1)) {
- rd->calculated_value = 0;
- continue;
- }
-
- // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
- // to reset the calculation (it will give zero as the calculation for this second)
- if(unlikely(rd->last_collected_value > rd->collected_value)) {
- debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
- , st->name, rd->name
- , rd->last_collected_value
- , rd->collected_value);
- if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
- rd->last_collected_value = rd->collected_value;
- }
-
- rd->calculated_value +=
- (calculated_number)(rd->collected_value - rd->last_collected_value)
- * (calculated_number)rd->multiplier
- / (calculated_number)rd->divisor;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
- CALCULATED_NUMBER_FORMAT " = ("
- COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
- ")"
- " * " CALCULATED_NUMBER_FORMAT
- " / " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value, rd->last_collected_value
- , (calculated_number)rd->multiplier
- , (calculated_number)rd->divisor
- );
- break;
-
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- if(unlikely(rd->counter <= 1)) {
- rd->calculated_value = 0;
- continue;
- }
-
- // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
- // to reset the calculation (it will give zero as the calculation for this second)
- if(unlikely(rd->last_collected_value > rd->collected_value)) {
- debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
- , st->name, rd->name
- , rd->last_collected_value
- , rd->collected_value);
- if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
- rd->last_collected_value = rd->collected_value;
- }
-
- // the percentage of the current increment
- // over the increment of all dimensions together
- if(unlikely(st->collected_total == st->last_collected_total))
- rd->calculated_value = 0;
- else
- rd->calculated_value =
- (calculated_number)100
- * (calculated_number)(rd->collected_value - rd->last_collected_value)
- / (calculated_number)(st->collected_total - st->last_collected_total);
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
- CALCULATED_NUMBER_FORMAT " = 100"
- " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
- " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value, rd->last_collected_value
- , st->collected_total, st->last_collected_total
- );
- break;
-
- default:
- // make the default zero, to make sure
- // it gets noticed when we add new types
- rd->calculated_value = 0;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC "
- CALCULATED_NUMBER_FORMAT " = 0"
- , st->id, rd->name
- , rd->calculated_value
- );
- break;
- }
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
- " last_collected_value = " COLLECTED_NUMBER_FORMAT
- " collected_value = " COLLECTED_NUMBER_FORMAT
- " last_calculated_value = " CALCULATED_NUMBER_FORMAT
- " calculated_value = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->last_collected_value
- , rd->collected_value
- , rd->last_calculated_value
- , rd->calculated_value
- );
-
- }
-
- // at this point we have all the calculated values ready
- // it is now time to interpolate values on a second boundary
-
- if(unlikely(now_collect_ut < next_store_ut)) {
- // this is collected in the same interpolation point
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
-#ifdef NETDATA_INTERNAL_CHECKS
- info("%s is collected in the same interpolation point: short by %llu microseconds", st->name, next_store_ut - now_collect_ut);
-#endif
- }
-
- usec_t first_ut = last_stored_ut;
- long long iterations = (now_collect_ut - last_stored_ut) / (update_every_ut);
- if((now_collect_ut % (update_every_ut)) == 0) iterations++;
-
- for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
-#ifdef NETDATA_INTERNAL_CHECKS
- if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_stored_ut = %llu, next_store_ut = %llu, now_collect_ut = %llu", st->name, first_ut, last_stored_ut, next_store_ut, now_collect_ut); }
-#endif
-
- if(unlikely(st->debug)) {
- debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
- debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
- }
-
- st->last_updated.tv_sec = (time_t) (next_store_ut / USEC_PER_SEC);
- st->last_updated.tv_usec = 0;
-
- for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
- calculated_number new_value;
-
- switch(rd->algorithm) {
- case RRDDIM_INCREMENTAL:
- new_value = (calculated_number)
- ( rd->calculated_value
- * (calculated_number)(next_store_ut - last_collect_ut)
- / (calculated_number)(now_collect_ut - last_collect_ut)
- );
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC2 INC "
- CALCULATED_NUMBER_FORMAT " = "
- CALCULATED_NUMBER_FORMAT
- " * %llu"
- " / %llu"
- , st->id, rd->name
- , new_value
- , rd->calculated_value
- , (next_store_ut - last_stored_ut)
- , (now_collect_ut - last_stored_ut)
- );
-
- rd->calculated_value -= new_value;
- new_value += rd->last_calculated_value;
- rd->last_calculated_value = 0;
- new_value /= (calculated_number)st->update_every;
-
- if(unlikely(next_store_ut - last_stored_ut < update_every_ut)) {
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: COLLECTION POINT IS SHORT " CALCULATED_NUMBER_FORMAT " - EXTRAPOLATING",
- st->id, rd->name
- , (calculated_number)(next_store_ut - last_stored_ut)
- );
- new_value = new_value * (calculated_number)(st->update_every * 1000000) / (calculated_number)(next_store_ut - last_stored_ut);
- }
- break;
-
- case RRDDIM_ABSOLUTE:
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- default:
- if(iterations == 1) {
- // this is the last iteration
- // do not interpolate
- // just show the calculated value
-
- new_value = rd->calculated_value;
- }
- else {
- // we have missed an update
- // interpolate in the middle values
-
- new_value = (calculated_number)
- ( ( (rd->calculated_value - rd->last_calculated_value)
- * (calculated_number)(next_store_ut - last_collect_ut)
- / (calculated_number)(now_collect_ut - last_collect_ut)
- )
- + rd->last_calculated_value
- );
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
- CALCULATED_NUMBER_FORMAT " = ((("
- "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
- " * %llu"
- " / %llu) + " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , new_value
- , rd->calculated_value, rd->last_calculated_value
- , (next_store_ut - first_ut)
- , (now_collect_ut - first_ut), rd->last_calculated_value
- );
- }
- break;
- }
-
- if(unlikely(!store_this_entry)) {
- rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
- continue;
- }
-
- if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
- rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
- rd->last_stored_value = new_value;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
- CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , st->current_entry
- , unpack_storage_number(rd->values[st->current_entry]), new_value
- );
- }
- else {
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
- , st->id, rd->name
- , st->current_entry
- );
- rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
- rd->last_stored_value = NAN;
- }
-
- stored_entries++;
-
- if(unlikely(st->debug)) {
- calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
- calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
- calculated_number accuracy = accuracy_loss(t1, t2);
- debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
- , st->id, rd->name
- , st->current_entry
- , t2
- , get_storage_number_flags(rd->values[st->current_entry])
- , t1
- , accuracy
- , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
- );
-
- rd->collected_volume += t1;
- rd->stored_volume += t2;
- accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
- debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
- , st->id, rd->name
- , st->current_entry
- , rd->stored_volume
- , rd->collected_volume
- , accuracy
- , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
- );
-
- }
- }
- // reset the storage flags for the next point, if any;
- storage_flags = SN_EXISTS;
-
- st->counter++;
- st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
- last_stored_ut = next_store_ut;
- }
-
- st->last_collected_total = st->collected_total;
-
- for( rd = st->dimensions; rd ; rd = rd->next ) {
- if(unlikely(!rd->updated)) continue;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
- rd->last_collected_value = rd->collected_value;
-
- switch(rd->algorithm) {
- case RRDDIM_INCREMENTAL:
- if(unlikely(!first_entry)) {
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value + rd->calculated_value, rd->calculated_value);
- rd->last_calculated_value += rd->calculated_value;
- }
- else {
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS THE FIRST POINT", st->name);
- }
- break;
-
- case RRDDIM_ABSOLUTE:
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
- rd->last_calculated_value = rd->calculated_value;
- break;
- }
-
- rd->calculated_value = 0;
- rd->collected_value = 0;
- rd->updated = 0;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
- " last_collected_value = " COLLECTED_NUMBER_FORMAT
- " collected_value = " COLLECTED_NUMBER_FORMAT
- " last_calculated_value = " CALCULATED_NUMBER_FORMAT
- " calculated_value = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->last_collected_value
- , rd->collected_value
- , rd->last_calculated_value
- , rd->calculated_value
- );
- }
-
- // ALL DONE ABOUT THE DATA UPDATE
- // --------------------------------------------------------------------
-
-/*
- // find if there are any obsolete dimensions (not updated recently)
- if(unlikely(rrd_delete_unupdated_dimensions)) {
-
- for( rd = st->dimensions; likely(rd) ; rd = rd->next )
- if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
- break;
-
- if(unlikely(rd)) {
- RRDDIM *last;
- // there is dimension to free
- // upgrade our read lock to a write lock
- pthread_rwlock_unlock(&st->rwlock);
- pthread_rwlock_wrlock(&st->rwlock);
-
- for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
- // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
-
- if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
- info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
-
- if(unlikely(!last)) {
- st->dimensions = rd->next;
- rd->next = NULL;
- rrddim_free(st, rd);
- rd = st->dimensions;
- continue;
- }
- else {
- last->next = rd->next;
- rd->next = NULL;
- rrddim_free(st, rd);
- rd = last->next;
- continue;
- }
- }
-
- last = rd;
- rd = rd->next;
- }
-
- if(unlikely(!st->dimensions)) {
- info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
- st->enabled = 0;
- }
- }
- }
-*/
-
- pthread_rwlock_unlock(&st->rwlock);
-
- if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
- error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
-
- return(st->usec_since_last_update);
-}
diff --git a/src/rrd.h b/src/rrd.h
index dbaf98650..2f4f2127f 100644
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -3,20 +3,17 @@
#define UPDATE_EVERY 1
#define UPDATE_EVERY_MAX 3600
-extern int rrd_update_every;
#define RRD_DEFAULT_HISTORY_ENTRIES 3600
#define RRD_HISTORY_ENTRIES_MAX (86400*10)
-extern int rrd_default_history_entries;
-// time in seconds to delete unupdated dimensions
-// set to zero to disable this feature
-extern int rrd_delete_unupdated_dimensions;
+extern int default_rrd_update_every;
+extern int default_rrd_history_entries;
-#define RRD_ID_LENGTH_MAX 400
+#define RRD_ID_LENGTH_MAX 200
-#define RRDSET_MAGIC "NETDATA RRD SET FILE V018"
-#define RRDDIMENSION_MAGIC "NETDATA RRD DIMENSION FILE V018"
+#define RRDSET_MAGIC "NETDATA RRD SET FILE V019"
+#define RRDDIMENSION_MAGIC "NETDATA RRD DIMENSION FILE V019"
typedef long long total_number;
#define TOTAL_NUMBER_FORMAT "%lld"
@@ -24,59 +21,61 @@ typedef long long total_number;
// ----------------------------------------------------------------------------
// chart types
+typedef enum rrdset_type {
+ RRDSET_TYPE_LINE = 0,
+ RRDSET_TYPE_AREA = 1,
+ RRDSET_TYPE_STACKED = 2
+} RRDSET_TYPE;
+
#define RRDSET_TYPE_LINE_NAME "line"
#define RRDSET_TYPE_AREA_NAME "area"
#define RRDSET_TYPE_STACKED_NAME "stacked"
-#define RRDSET_TYPE_LINE 0
-#define RRDSET_TYPE_AREA 1
-#define RRDSET_TYPE_STACKED 2
-
-int rrdset_type_id(const char *name);
-const char *rrdset_type_name(int chart_type);
+RRDSET_TYPE rrdset_type_id(const char *name);
+const char *rrdset_type_name(RRDSET_TYPE chart_type);
// ----------------------------------------------------------------------------
// memory mode
+typedef enum rrd_memory_mode {
+ RRD_MEMORY_MODE_NONE = 0,
+ RRD_MEMORY_MODE_RAM = 1,
+ RRD_MEMORY_MODE_MAP = 2,
+ RRD_MEMORY_MODE_SAVE = 3
+} RRD_MEMORY_MODE;
+
+#define RRD_MEMORY_MODE_NONE_NAME "none"
#define RRD_MEMORY_MODE_RAM_NAME "ram"
#define RRD_MEMORY_MODE_MAP_NAME "map"
#define RRD_MEMORY_MODE_SAVE_NAME "save"
-#define RRD_MEMORY_MODE_RAM 0
-#define RRD_MEMORY_MODE_MAP 1
-#define RRD_MEMORY_MODE_SAVE 2
-
-extern int rrd_memory_mode;
+extern RRD_MEMORY_MODE default_rrd_memory_mode;
-extern const char *rrd_memory_mode_name(int id);
-extern int rrd_memory_mode_id(const char *name);
+extern const char *rrd_memory_mode_name(RRD_MEMORY_MODE id);
+extern RRD_MEMORY_MODE rrd_memory_mode_id(const char *name);
// ----------------------------------------------------------------------------
// algorithms types
-#define RRDDIM_ABSOLUTE_NAME "absolute"
-#define RRDDIM_INCREMENTAL_NAME "incremental"
-#define RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
-#define RRDDIM_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
+typedef enum rrd_algorithm {
+ RRD_ALGORITHM_ABSOLUTE = 0,
+ RRD_ALGORITHM_INCREMENTAL = 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL = 2,
+ RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL = 3
+} RRD_ALGORITHM;
-#define RRDDIM_ABSOLUTE 0
-#define RRDDIM_INCREMENTAL 1
-#define RRDDIM_PCENT_OVER_DIFF_TOTAL 2
-#define RRDDIM_PCENT_OVER_ROW_TOTAL 3
-
-extern int rrddim_algorithm_id(const char *name);
-extern const char *rrddim_algorithm_name(int chart_type);
-
-// ----------------------------------------------------------------------------
-// flags
+#define RRD_ALGORITHM_ABSOLUTE_NAME "absolute"
+#define RRD_ALGORITHM_INCREMENTAL_NAME "incremental"
+#define RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
+#define RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
-#define RRDDIM_FLAG_HIDDEN 0x00000001 // this dimension will not be offered to callers
-#define RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS 0x00000002 // do not offer RESET or OVERFLOW info to callers
+extern RRD_ALGORITHM rrd_algorithm_id(const char *name);
+extern const char *rrd_algorithm_name(RRD_ALGORITHM algorithm);
// ----------------------------------------------------------------------------
-// RRD CONTEXT
+// RRD FAMILY
struct rrdfamily {
avl avl;
@@ -90,8 +89,25 @@ struct rrdfamily {
};
typedef struct rrdfamily RRDFAMILY;
+
+// ----------------------------------------------------------------------------
+// flags
+// use this for configuration flags, not for state control
+// flags are set/unset in a manner that is not thread safe
+// and may lead to missing information.
+
+typedef enum rrddim_flags {
+ RRDDIM_FLAG_HIDDEN = 1 << 0, // this dimension will not be offered to callers
+ RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS = 1 << 1 // do not offer RESET or OVERFLOW info to callers
+} RRDDIM_FLAGS;
+
+#define rrddim_flag_check(rd, flag) ((rd)->flags & flag)
+#define rrddim_flag_set(rd, flag) (rd)->flags |= flag
+#define rrddim_flag_clear(rd, flag) (rd)->flags &= ~flag
+
+
// ----------------------------------------------------------------------------
-// RRD DIMENSION
+// RRD DIMENSION - this is a metric
struct rrddim {
// ------------------------------------------------------------------------
@@ -102,18 +118,20 @@ struct rrddim {
// ------------------------------------------------------------------------
// the dimension definition
- char id[RRD_ID_LENGTH_MAX + 1]; // the id of this dimension (for internal identification)
-
+ const char *id; // the id of this dimension (for internal identification)
const char *name; // the name of this dimension (as presented to user)
// this is a pointer to the config structure
// since the config always has a higher priority
// (the user overwrites the name of the charts)
+ // DO NOT FREE THIS - IT IS ALLOCATED IN CONFIG
+
+ RRD_ALGORITHM algorithm; // the algorithm that is applied to add new collected values
+ RRD_MEMORY_MODE rrd_memory_mode; // the memory mode for this dimension
- int algorithm; // the algorithm that is applied to add new collected values
- long multiplier; // the multiplier of the collected values
- long divisor; // the divider of the collected values
+ collected_number multiplier; // the multiplier of the collected values
+ collected_number divisor; // the divider of the collected values
- int mapped; // if set to non zero, this dimension is mapped to a file
+ uint32_t flags; // configuration flags for the dimension
// ------------------------------------------------------------------------
// members for temporary data we need for calculations
@@ -122,17 +140,15 @@ struct rrddim {
// instead of strcmp() every item in the binary index
// we first compare the hashes
- // FIXME
- // we need the hash_name too!
+ uint32_t hash_name; // a simple hash of the name
- uint32_t flags;
+ char *cache_filename; // the filename we load/save from/to this set
- char cache_filename[FILENAME_MAX+1]; // the filename we load/save from/to this set
+ size_t collections_counter; // the number of times we added values to this rrdim
+ size_t unused[10];
- unsigned long counter; // the number of times we added values to this rrdim
-
- int updated; // set to 0 after each calculation, to 1 after each collected value
- // we use this to detect that a dimension is not updated
+ int updated:1; // 1 when the dimension has been updated since the last processing
+ int exposed:1; // 1 when set what have sent this dimension to the central netdata
struct timeval last_collected_time; // when was this dimension last updated
// this is actual date time we updated the last_collected_value
@@ -163,7 +179,7 @@ struct rrddim {
int update_every; // every how many seconds is this updated
- unsigned long memsize; // the memory allocated for this dimension
+ size_t memsize; // the memory allocated for this dimension
char magic[sizeof(RRDDIMENSION_MAGIC) + 1]; // a string to be saved, used to identify our data file
@@ -176,9 +192,34 @@ struct rrddim {
};
typedef struct rrddim RRDDIM;
+// ----------------------------------------------------------------------------
+// these loop macros make sure the linked list is accessed with the right lock
+
+#define rrddim_foreach_read(rd, st) \
+ for(rd = st->dimensions, rrdset_check_rdlock(st); rd ; rd = rd->next)
+
+#define rrddim_foreach_write(rd, st) \
+ for(rd = st->dimensions, rrdset_check_wrlock(st); rd ; rd = rd->next)
+
// ----------------------------------------------------------------------------
-// RRDSET
+// RRDSET - this is a chart
+
+// use this for configuration flags, not for state control
+// flags are set/unset in a manner that is not thread safe
+// and may lead to missing information.
+
+typedef enum rrdset_flags {
+ RRDSET_FLAG_ENABLED = 1 << 0, // enables or disables a chart
+ RRDSET_FLAG_DETAIL = 1 << 1, // if set, the data set should be considered as a detail of another
+ // (the master data set should be the one that has the same family and is not detail)
+ RRDSET_FLAG_DEBUG = 1 << 2, // enables or disables debugging for a chart
+ RRDSET_FLAG_OBSOLETE = 1 << 3 // this is marked by the collector/module as obsolete
+} RRDSET_FLAGS;
+
+#define rrdset_flag_check(st, flag) ((st)->flags & flag)
+#define rrdset_flag_set(st, flag) (st)->flags |= flag
+#define rrdset_flag_clear(st, flag) (st)->flags &= ~flag
struct rrdset {
// ------------------------------------------------------------------------
@@ -197,6 +238,8 @@ struct rrdset {
// since the config always has a higher priority
// (the user overwrites the name of the charts)
+ char *config_section; // the config section for the chart
+
char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
char *family; // grouping sets under the same family
char *title; // title shown to user
@@ -205,7 +248,7 @@ struct rrdset {
char *context; // the template of this data set
uint32_t hash_context;
- int chart_type;
+ RRDSET_TYPE chart_type;
int update_every; // every how many seconds is this updated?
@@ -214,30 +257,29 @@ struct rrdset {
long current_entry; // the entry that is currently being updated
// it goes around in a round-robin fashion
- int enabled;
+ uint32_t flags; // configuration flags
int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored
// netdata will interpolate values for gaps lower than this
long priority;
- int isdetail; // if set, the data set should be considered as a detail of another
- // (the master data set should be the one that has the same family and is not detail)
// ------------------------------------------------------------------------
// members for temporary data we need for calculations
- int mapped; // if set to 1, this is memory mapped
-
- int debug;
+ RRD_MEMORY_MODE rrd_memory_mode; // if set to 1, this is memory mapped
char *cache_dir; // the directory to store dimensions
char cache_filename[FILENAME_MAX+1]; // the filename to store this set
- pthread_rwlock_t rwlock;
+ netdata_rwlock_t rrdset_rwlock; // protects dimensions linked list
+
+ size_t counter; // the number of times we added values to this database
+ size_t counter_done; // the number of times rrdset_done() has been called
- unsigned long counter; // the number of times we added values to this rrd
- unsigned long counter_done; // the number of times we added values to this rrd
+ time_t last_accessed_time; // the last time this RRDSET has been accessed
+ size_t unused[9];
uint32_t hash; // a simple hash on the id, to speed up searching
// we first compare hashes, and only if the hashes are equal we do string comparisons
@@ -283,83 +325,248 @@ struct rrdset {
};
typedef struct rrdset RRDSET;
+#define rrdset_rdlock(st) netdata_rwlock_rdlock(&((st)->rrdset_rwlock))
+#define rrdset_wrlock(st) netdata_rwlock_wrlock(&((st)->rrdset_rwlock))
+#define rrdset_unlock(st) netdata_rwlock_unlock(&((st)->rrdset_rwlock))
+
+
+// ----------------------------------------------------------------------------
+// these loop macros make sure the linked list is accessed with the right lock
+
+#define rrdset_foreach_read(st, host) \
+ for(st = host->rrdset_root, rrdhost_check_rdlock(host); st ; st = st->next)
+
+#define rrdset_foreach_write(st, host) \
+ for(st = host->rrdset_root, rrdhost_check_wrlock(host); st ; st = st->next)
+
+
+// ----------------------------------------------------------------------------
+// RRDHOST flags
+// use this for configuration flags, not for state control
+// flags are set/unset in a manner that is not thread safe
+// and may lead to missing information.
+
+typedef enum rrdhost_flags {
+ RRDHOST_ORPHAN = 1 << 0, // this host is orphan
+ RRDHOST_DELETE_OBSOLETE_FILES = 1 << 1, // delete files of obsolete charts
+ RRDHOST_DELETE_ORPHAN_FILES = 1 << 2 // delete the entire host when orphan
+} RRDHOST_FLAGS;
+
+#define rrdhost_flag_check(host, flag) ((host)->flags & flag)
+#define rrdhost_flag_set(host, flag) (host)->flags |= flag
+#define rrdhost_flag_clear(host, flag) (host)->flags &= ~flag
+
// ----------------------------------------------------------------------------
// RRD HOST
struct rrdhost {
- avl avl;
+ avl avl; // the index of hosts
- char *hostname;
+ // ------------------------------------------------------------------------
+ // host information
- RRDSET *rrdset_root;
- pthread_rwlock_t rrdset_root_rwlock;
+ char *hostname; // the hostname of this host
+ uint32_t hash_hostname; // the hostname hash
- avl_tree_lock rrdset_root_index;
- avl_tree_lock rrdset_root_index_name;
+ char machine_guid[GUID_LEN + 1]; // the unique ID of this host
+ uint32_t hash_machine_guid; // the hash of the unique ID
- avl_tree_lock rrdfamily_root_index;
- avl_tree_lock variables_root_index;
+ char *os; // the O/S type of the host
+
+ uint32_t flags; // flags about this RRDHOST
+
+ int rrd_update_every; // the update frequency of the host
+ long rrd_history_entries; // the number of history entries for the host's charts
+ RRD_MEMORY_MODE rrd_memory_mode; // the memory more for the charts of this host
+
+ char *cache_dir; // the directory to save RRD cache files
+ char *varlib_dir; // the directory to save health log
+
+
+ // ------------------------------------------------------------------------
+ // streaming of data to remote hosts - rrdpush
+
+ int rrdpush_enabled:1; // 1 when this host sends metrics to another netdata
+ char *rrdpush_destination; // where to send metrics to
+ char *rrdpush_api_key; // the api key at the receiving netdata
+ volatile int rrdpush_connected:1; // 1 when the sender is ready to push metrics
+ volatile int rrdpush_spawn:1; // 1 when the sender thread has been spawn
+ volatile int rrdpush_error_shown:1; // 1 when we have logged a communication error
+ int rrdpush_socket; // the fd of the socket to the remote host, or -1
+ pthread_t rrdpush_thread; // the sender thread
+ netdata_mutex_t rrdpush_mutex; // exclusive access to rrdpush_buffer
+ int rrdpush_pipe[2]; // collector to sender thread communication
+ BUFFER *rrdpush_buffer; // collector fills it, sender sends them
+
+
+ // ------------------------------------------------------------------------
+ // streaming of data from remote hosts - rrdpush
+
+ volatile size_t connected_senders; // when remote hosts are streaming to this
+ // host, this is the counter of connected clients
+
+ time_t senders_disconnected_time; // the time the last sender was disconnected
+
+ // ------------------------------------------------------------------------
+ // health monitoring options
+
+ int health_enabled:1; // 1 when this host has health enabled
+ time_t health_delay_up_to; // a timestamp to delay alarms processing up to
+ char *health_default_exec; // the full path of the alarms notifications program
+ char *health_default_recipient; // the default recipient for all alarms
+ char *health_log_filename; // the alarms event log filename
+ size_t health_log_entries_written; // the number of alarm events writtern to the alarms event log
+ FILE *health_log_fp; // the FILE pointer to the open alarms event log file
// all RRDCALCs are primarily allocated and linked here
// RRDCALCs may be linked to charts at any point
// (charts may or may not exist when these are loaded)
RRDCALC *alarms;
- ALARM_LOG health_log;
+ ALARM_LOG health_log; // alarms historical events (event log)
+
+ // templates of alarms
+ // these are used to create alarms when charts
+ // are created or renamed, that match them
RRDCALCTEMPLATE *templates;
+
+
+ // ------------------------------------------------------------------------
+ // the charts of the host
+
+ RRDSET *rrdset_root; // the host charts
+
+
+ // ------------------------------------------------------------------------
+ // locks
+
+ netdata_rwlock_t rrdhost_rwlock; // lock for this RRDHOST (protects rrdset_root linked list)
+
+ avl_tree_lock rrdset_root_index; // the host's charts index (by id)
+ avl_tree_lock rrdset_root_index_name; // the host's charts index (by name)
+
+ avl_tree_lock rrdfamily_root_index; // the host's chart families index
+ avl_tree_lock variables_root_index; // the host's chart variables index
+
+ struct rrdhost *next;
};
typedef struct rrdhost RRDHOST;
-extern RRDHOST localhost;
-extern void rrdhost_init(char *hostname);
+extern RRDHOST *localhost;
+
+#define rrdhost_rdlock(host) netdata_rwlock_rdlock(&((host)->rrdhost_rwlock))
+#define rrdhost_wrlock(host) netdata_rwlock_wrlock(&((host)->rrdhost_rwlock))
+#define rrdhost_unlock(host) netdata_rwlock_unlock(&((host)->rrdhost_rwlock))
+
+// ----------------------------------------------------------------------------
+// these loop macros make sure the linked list is accessed with the right lock
+
+#define rrdhost_foreach_read(var) \
+ for(var = localhost, rrd_check_rdlock(); var ; var = var->next)
+
+#define rrdhost_foreach_write(var) \
+ for(var = localhost, rrd_check_wrlock(); var ; var = var->next)
+
+
+// ----------------------------------------------------------------------------
+// global lock for all RRDHOSTs
+
+extern netdata_rwlock_t rrd_rwlock;
+
+#define rrd_rdlock() netdata_rwlock_rdlock(&rrd_rwlock)
+#define rrd_wrlock() netdata_rwlock_wrlock(&rrd_rwlock)
+#define rrd_unlock() netdata_rwlock_unlock(&rrd_rwlock)
+
+// ----------------------------------------------------------------------------
+
+extern size_t rrd_hosts_available;
+extern time_t rrdhost_free_orphan_time;
+
+extern void rrd_init(char *hostname);
+
+extern RRDHOST *rrdhost_find_by_hostname(const char *hostname, uint32_t hash);
+extern RRDHOST *rrdhost_find_by_guid(const char *guid, uint32_t hash);
+
+extern RRDHOST *rrdhost_find_or_create(
+ const char *hostname
+ , const char *guid
+ , const char *os
+ , int update_every
+ , long history
+ , RRD_MEMORY_MODE mode
+ , int health_enabled
+ , int rrdpush_enabled
+ , char *rrdpush_destination
+ , char *rrdpush_api_key
+);
+
+#if defined(NETDATA_INTERNAL_CHECKS) && defined(NETDATA_VERIFY_LOCKS)
+extern void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line);
+extern void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line);
+extern void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line);
+extern void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line);
+extern void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line);
+extern void __rrd_check_wrlock(const char *file, const char *function, const unsigned long line);
+
+#define rrdhost_check_rdlock(host) __rrdhost_check_rdlock(host, __FILE__, __FUNCTION__, __LINE__)
+#define rrdhost_check_wrlock(host) __rrdhost_check_wrlock(host, __FILE__, __FUNCTION__, __LINE__)
+#define rrdset_check_rdlock(st) __rrdset_check_rdlock(st, __FILE__, __FUNCTION__, __LINE__)
+#define rrdset_check_wrlock(st) __rrdset_check_wrlock(st, __FILE__, __FUNCTION__, __LINE__)
+#define rrd_check_rdlock() __rrd_check_rdlock(__FILE__, __FUNCTION__, __LINE__)
+#define rrd_check_wrlock() __rrd_check_wrlock(__FILE__, __FUNCTION__, __LINE__)
-#ifdef NETDATA_INTERNAL_CHECKS
-#define rrdhost_check_wrlock(host) rrdhost_check_wrlock_int(host, __FILE__, __FUNCTION__, __LINE__)
-#define rrdhost_check_rdlock(host) rrdhost_check_rdlock_int(host, __FILE__, __FUNCTION__, __LINE__)
#else
#define rrdhost_check_rdlock(host) (void)0
#define rrdhost_check_wrlock(host) (void)0
+#define rrdset_check_rdlock(host) (void)0
+#define rrdset_check_wrlock(host) (void)0
+#define rrd_check_rdlock() (void)0
+#define rrd_check_wrlock() (void)0
#endif
-extern void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
-extern void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
-
-extern void rrdhost_rwlock(RRDHOST *host);
-extern void rrdhost_rdlock(RRDHOST *host);
-extern void rrdhost_unlock(RRDHOST *host);
-
// ----------------------------------------------------------------------------
-// RRD SET functions
+// RRDSET functions
-extern char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
extern void rrdset_set_name(RRDSET *st, const char *name);
-extern char *rrdset_cache_dir(const char *id);
+extern RRDSET *rrdset_create(RRDHOST *host
+ , const char *type
+ , const char *id
+ , const char *name
+ , const char *family
+ , const char *context
+ , const char *title
+ , const char *units
+ , long priority
+ , int update_every
+ , RRDSET_TYPE chart_type);
-extern void rrdset_reset(RRDSET *st);
+#define rrdset_create_localhost(type, id, name, family, context, title, units, priority, update_every, chart_type) rrdset_create(localhost, type, id, name, family, context, title, units, priority, update_every, chart_type)
-extern RRDSET *rrdset_create(const char *type
- , const char *id
- , const char *name
- , const char *family
- , const char *context
- , const char *title
- , const char *units
- , long priority
- , int update_every
- , int chart_type);
+extern void rrdhost_free_all(void);
+extern void rrdhost_save_all(void);
+
+extern void rrdhost_cleanup_orphan(RRDHOST *protected);
+extern void rrdhost_free(RRDHOST *host);
+extern void rrdhost_save(RRDHOST *host);
+extern void rrdhost_delete(RRDHOST *host);
+
+extern RRDSET *rrdset_find(RRDHOST *host, const char *id);
+#define rrdset_find_localhost(id) rrdset_find(localhost, id)
-extern void rrdset_free_all(void);
-extern void rrdset_save_all(void);
+extern RRDSET *rrdset_find_bytype(RRDHOST *host, const char *type, const char *id);
+#define rrdset_find_bytype_localhost(type, id) rrdset_find_bytype(localhost, type, id)
-extern RRDSET *rrdset_find(const char *id);
-extern RRDSET *rrdset_find_bytype(const char *type, const char *id);
-extern RRDSET *rrdset_find_byname(const char *name);
+extern RRDSET *rrdset_find_byname(RRDHOST *host, const char *name);
+#define rrdset_find_byname_localhost(name) rrdset_find_byname(localhost, name)
extern void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds);
extern void rrdset_next_usec(RRDSET *st, usec_t microseconds);
#define rrdset_next(st) rrdset_next_usec(st, 0ULL)
-extern usec_t rrdset_done(RRDSET *st);
+extern void rrdset_done(RRDSET *st);
+
+// checks if the RRDSET should be offered to viewers
+#define rrdset_is_available_for_viewers(st) (rrdset_flag_check(st, RRDSET_FLAG_ENABLED) && !rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE) && (st)->dimensions)
// get the total duration in seconds of the round robin database
#define rrdset_duration(st) ((time_t)( (((st)->counter >= ((unsigned long)(st)->entries))?(unsigned long)(st)->entries:(st)->counter) * (st)->update_every ))
@@ -397,11 +604,9 @@ extern usec_t rrdset_done(RRDSET *st);
// ----------------------------------------------------------------------------
// RRD DIMENSION functions
-extern RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier, long divisor, int algorithm);
+extern RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm);
extern void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name);
-extern void rrddim_free(RRDSET *st, RRDDIM *rd);
-
extern RRDDIM *rrddim_find(RRDSET *st, const char *id);
extern int rrddim_hide(RRDSET *st, const char *id);
@@ -410,4 +615,41 @@ extern int rrddim_unhide(RRDSET *st, const char *id);
extern collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
extern collected_number rrddim_set(RRDSET *st, const char *id, collected_number value);
+extern long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries);
+
+
+// ----------------------------------------------------------------------------
+// RRD internal functions
+
+#ifdef NETDATA_RRD_INTERNALS
+
+extern avl_tree_lock rrdhost_root_index;
+
+extern char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
+extern char *rrdset_cache_dir(RRDHOST *host, const char *id, const char *config_section);
+
+extern void rrddim_free(RRDSET *st, RRDDIM *rd);
+
+extern int rrddim_compare(void* a, void* b);
+extern int rrdset_compare(void* a, void* b);
+extern int rrdset_compare_name(void* a, void* b);
+extern int rrdfamily_compare(void *a, void *b);
+
+extern RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id);
+extern void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc);
+
+#define rrdset_index_add(host, st) (RRDSET *)avl_insert_lock(&((host)->rrdset_root_index), (avl *)(st))
+#define rrdset_index_del(host, st) (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index), (avl *)(st))
+extern RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st);
+
+extern void rrdset_free(RRDSET *st);
+extern void rrdset_reset(RRDSET *st);
+extern void rrdset_save(RRDSET *st);
+extern void rrdset_delete(RRDSET *st);
+
+extern void rrdhost_cleanup_obsolete(RRDHOST *host);
+
+#endif /* NETDATA_RRD_INTERNALS */
+
+
#endif /* NETDATA_RRD_H */
diff --git a/src/rrd2json.c b/src/rrd2json.c
index 067475006..4d853930c 100644
--- a/src/rrd2json.c
+++ b/src/rrd2json.c
@@ -2,7 +2,7 @@
void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used)
{
- pthread_rwlock_rdlock(&st->rwlock);
+ rrdset_rdlock(st);
buffer_sprintf(wb,
"\t\t{\n"
@@ -29,7 +29,7 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions
, st->context
, st->title
, st->priority
- , st->enabled?"true":"false"
+ , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?"true":"false"
, st->units
, st->name
, rrdset_type_name(st->chart_type)
@@ -43,8 +43,8 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions
size_t dimensions = 0;
RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(rd->flags & RRDDIM_FLAG_HIDDEN) continue;
+ rrddim_foreach_read(rd, st) {
+ if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) continue;
memory += rd->memsize;
@@ -71,58 +71,99 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions
"\n\t\t}"
);
- pthread_rwlock_unlock(&st->rwlock);
+ rrdset_unlock(st);
}
void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
rrd_stats_api_v1_chart_with_data(st, wb, NULL, NULL);
}
-void rrd_stats_api_v1_charts(BUFFER *wb)
-{
+void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) {
+ static char *custom_dashboard_info_js_filename = NULL;
size_t c, dimensions = 0, memory = 0, alarms = 0;
RRDSET *st;
+ time_t now = now_realtime_sec();
+
+ if(unlikely(!custom_dashboard_info_js_filename))
+ custom_dashboard_info_js_filename = config_get(CONFIG_SECTION_WEB, "custom dashboard_info.js", "");
+
buffer_sprintf(wb, "{\n"
"\t\"hostname\": \"%s\""
+ ",\n\t\"version\": \"%s\""
+ ",\n\t\"os\": \"%s\""
",\n\t\"update_every\": %d"
- ",\n\t\"history\": %d"
+ ",\n\t\"history\": %ld"
+ ",\n\t\"custom_info\": \"%s\""
",\n\t\"charts\": {"
- , localhost.hostname
- , rrd_update_every
- , rrd_default_history_entries
+ , host->hostname
+ , program_version
+ , host->os
+ , host->rrd_update_every
+ , host->rrd_history_entries
+ , custom_dashboard_info_js_filename
);
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
- for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
- if(st->enabled && st->dimensions) {
+ c = 0;
+ rrdhost_rdlock(host);
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
if(c) buffer_strcat(wb, ",");
buffer_strcat(wb, "\n\t\t\"");
buffer_strcat(wb, st->id);
buffer_strcat(wb, "\": ");
rrd_stats_api_v1_chart_with_data(st, wb, &dimensions, &memory);
+
c++;
+ st->last_accessed_time = now;
}
}
RRDCALC *rc;
- for(rc = localhost.alarms; rc ; rc = rc->next) {
+ for(rc = host->alarms; rc ; rc = rc->next) {
if(rc->rrdset)
alarms++;
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+ rrdhost_unlock(host);
buffer_sprintf(wb, "\n\t}"
",\n\t\"charts_count\": %zu"
",\n\t\"dimensions_count\": %zu"
",\n\t\"alarms_count\": %zu"
",\n\t\"rrd_memory_bytes\": %zu"
- "\n}\n"
+ ",\n\t\"hosts_count\": %zu"
+ ",\n\t\"hosts\": ["
, c
, dimensions
, alarms
, memory
+ , rrd_hosts_available
);
+
+ if(unlikely(rrd_hosts_available > 1)) {
+ rrd_rdlock();
+ RRDHOST *h;
+ rrdhost_foreach_read(h) {
+ buffer_sprintf(wb,
+ "%s\n\t\t{"
+ "\n\t\t\t\"hostname\": \"%s\""
+ "\n\t\t}"
+ , (h != localhost) ? "," : ""
+ , h->hostname
+ );
+ }
+ rrd_unlock();
+ }
+ else {
+ buffer_sprintf(wb,
+ "\n\t\t{"
+ "\n\t\t\t\"hostname\": \"%s\""
+ "\n\t\t}"
+ , host->hostname
+ );
+ }
+
+ buffer_sprintf(wb, "\n\t]\n}\n");
}
// ----------------------------------------------------------------------------
@@ -145,35 +186,34 @@ static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable)
#define PROMETHEUS_ELEMENT_MAX 256
-void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb)
-{
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
+void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
- char host[PROMETHEUS_ELEMENT_MAX + 1];
- prometheus_name_copy(host, config_get("global", "hostname", "localhost"), PROMETHEUS_ELEMENT_MAX);
+ char hostname[PROMETHEUS_ELEMENT_MAX + 1];
+ prometheus_name_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
// for each chart
RRDSET *st;
- for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdset_foreach_read(st, host) {
char chart[PROMETHEUS_ELEMENT_MAX + 1];
prometheus_name_copy(chart, st->id, PROMETHEUS_ELEMENT_MAX);
buffer_strcat(wb, "\n");
- if(st->enabled && st->dimensions) {
- pthread_rwlock_rdlock(&st->rwlock);
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
// for each dimension
RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(rd->counter) {
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
char dimension[PROMETHEUS_ELEMENT_MAX + 1];
prometheus_name_copy(dimension, rd->id, PROMETHEUS_ELEMENT_MAX);
// buffer_sprintf(wb, "# HELP %s.%s %s\n", st->id, rd->id, st->units);
switch(rd->algorithm) {
- case RRDDIM_INCREMENTAL:
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
+ case RRD_ALGORITHM_INCREMENTAL:
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
buffer_sprintf(wb, "# TYPE %s_%s counter\n", chart, dimension);
break;
@@ -183,21 +223,20 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb)
}
// calculated_number n = (calculated_number)rd->last_collected_value * (calculated_number)(abs(rd->multiplier)) / (calculated_number)(abs(rd->divisor));
- // buffer_sprintf(wb, "%s.%s " CALCULATED_NUMBER_FORMAT " %llu\n", st->id, rd->id, n,
- // (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000)));
+ // buffer_sprintf(wb, "%s.%s " CALCULATED_NUMBER_FORMAT " %llu\n", st->id, rd->id, n, timeval_msec(&rd->last_collected_time));
buffer_sprintf(wb, "%s_%s{instance=\"%s\"} " COLLECTED_NUMBER_FORMAT " %llu\n",
- chart, dimension, host, rd->last_collected_value,
- (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000)));
+ chart, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time)
+ );
}
}
- pthread_rwlock_unlock(&st->rwlock);
+ rrdset_unlock(st);
}
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+ rrdhost_unlock(host);
}
// ----------------------------------------------------------------------------
@@ -220,28 +259,24 @@ static inline size_t shell_name_copy(char *d, const char *s, size_t usable) {
#define SHELL_ELEMENT_MAX 100
-void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
-{
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
-
- char host[SHELL_ELEMENT_MAX + 1];
- shell_name_copy(host, config_get("global", "hostname", "localhost"), SHELL_ELEMENT_MAX);
+void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
// for each chart
RRDSET *st;
- for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdset_foreach_read(st, host) {
calculated_number total = 0.0;
char chart[SHELL_ELEMENT_MAX + 1];
shell_name_copy(chart, st->id, SHELL_ELEMENT_MAX);
buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name);
- if(st->enabled && st->dimensions) {
- pthread_rwlock_rdlock(&st->rwlock);
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
// for each dimension
RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(rd->counter) {
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
char dimension[SHELL_ELEMENT_MAX + 1];
shell_name_copy(dimension, rd->id, SHELL_ELEMENT_MAX);
@@ -252,7 +287,7 @@ void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
else {
if(rd->multiplier < 0 || rd->divisor < 0) n = -n;
n = roundl(n);
- if(!(rd->flags & RRDDIM_FLAG_HIDDEN)) total += 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);
}
}
@@ -260,14 +295,14 @@ void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
total = roundl(total);
buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"%0.0Lf\" # %s\n", chart, total, st->units);
- pthread_rwlock_unlock(&st->rwlock);
+ rrdset_unlock(st);
}
}
buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n");
RRDCALC *rc;
- for(rc = localhost.alarms; rc ;rc = rc->next) {
+ for(rc = host->alarms; rc ;rc = rc->next) {
if(!rc->rrdset) continue;
char chart[SHELL_ELEMENT_MAX + 1];
@@ -288,159 +323,76 @@ void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status));
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+ rrdhost_unlock(host);
}
// ----------------------------------------------------------------------------
-unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
-{
- time_t now = now_realtime_sec();
+void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
- pthread_rwlock_rdlock(&st->rwlock);
+ buffer_strcat(wb, "{");
- buffer_sprintf(wb,
- "\t\t{\n"
- "\t\t\t\"id\": \"%s\",\n"
- "\t\t\t\"name\": \"%s\",\n"
- "\t\t\t\"type\": \"%s\",\n"
- "\t\t\t\"family\": \"%s\",\n"
- "\t\t\t\"context\": \"%s\",\n"
- "\t\t\t\"title\": \"%s\",\n"
- "\t\t\t\"priority\": %ld,\n"
- "\t\t\t\"enabled\": %d,\n"
- "\t\t\t\"units\": \"%s\",\n"
- "\t\t\t\"url\": \"/data/%s/%s\",\n"
- "\t\t\t\"chart_type\": \"%s\",\n"
- "\t\t\t\"counter\": %lu,\n"
- "\t\t\t\"entries\": %ld,\n"
- "\t\t\t\"first_entry_t\": %ld,\n"
- "\t\t\t\"last_entry\": %lu,\n"
- "\t\t\t\"last_entry_t\": %ld,\n"
- "\t\t\t\"last_entry_secs_ago\": %ld,\n"
- "\t\t\t\"update_every\": %d,\n"
- "\t\t\t\"isdetail\": %d,\n"
- "\t\t\t\"usec_since_last_update\": %llu,\n"
- "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
- "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
- "\t\t\t\"dimensions\": [\n"
- , st->id
- , st->name
- , st->type
- , st->family
- , st->context
- , st->title
- , st->priority
- , st->enabled
- , st->units
- , st->name, options?options:""
- , rrdset_type_name(st->chart_type)
- , st->counter
- , st->entries
- , rrdset_first_entry_t(st)
- , rrdset_last_slot(st)
- , rrdset_last_entry_t(st)
- , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
- , st->update_every
- , st->isdetail
- , st->usec_since_last_update
- , st->collected_total
- , st->last_collected_total
- );
-
- unsigned long memory = st->memsize;
-
- RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
-
- memory += rd->memsize;
+ size_t chart_counter = 0;
+ size_t dimension_counter = 0;
- buffer_sprintf(wb,
- "\t\t\t\t{\n"
- "\t\t\t\t\t\"id\": \"%s\",\n"
- "\t\t\t\t\t\"name\": \"%s\",\n"
- "\t\t\t\t\t\"entries\": %ld,\n"
- "\t\t\t\t\t\"isHidden\": %d,\n"
- "\t\t\t\t\t\"algorithm\": \"%s\",\n"
- "\t\t\t\t\t\"multiplier\": %ld,\n"
- "\t\t\t\t\t\"divisor\": %ld,\n"
- "\t\t\t\t\t\"last_entry_t\": %ld,\n"
- "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"memory\": %lu\n"
- "\t\t\t\t}%s\n"
- , rd->id
- , rd->name
- , rd->entries
- , (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0
- , rrddim_algorithm_name(rd->algorithm)
- , rd->multiplier
- , rd->divisor
- , rd->last_collected_time.tv_sec
- , rd->collected_value
- , rd->calculated_value
- , rd->last_collected_value
- , rd->last_calculated_value
- , rd->memsize
- , rd->next?",":""
+ // for each chart
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
+
+ buffer_sprintf(wb, "%s\n"
+ "\t\"%s\": {\n"
+ "\t\t\"name\":\"%s\",\n"
+ "\t\t\"context\":\"%s\",\n"
+ "\t\t\"units\":\"%s\",\n"
+ "\t\t\"last_updated\": %ld,\n"
+ "\t\t\"dimensions\": {"
+ , chart_counter?",":""
+ , st->id
+ , st->name
+ , st->context
+ , st->units
+ , rrdset_last_entry_t(st)
);
- }
-
- buffer_sprintf(wb,
- "\t\t\t],\n"
- "\t\t\t\"memory\" : %lu\n"
- "\t\t}"
- , memory
- );
- pthread_rwlock_unlock(&st->rwlock);
- return memory;
-}
+ chart_counter++;
+ dimension_counter = 0;
-#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
-#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
+ // for each dimension
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
+
+ buffer_sprintf(wb, "%s\n"
+ "\t\t\t\"%s\": {\n"
+ "\t\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\t\"value\": "
+ , dimension_counter?",":""
+ , rd->id
+ , rd->name
+ );
-void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb)
-{
- buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
- rrd_stats_one_json(st, options, wb);
- buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
-}
+ if(isnan(rd->last_stored_value))
+ buffer_strcat(wb, "null");
+ else
+ buffer_sprintf(wb, CALCULATED_NUMBER_FORMAT, rd->last_stored_value);
-void rrd_stats_all_json(BUFFER *wb)
-{
- unsigned long memory = 0;
- long c;
- RRDSET *st;
+ buffer_strcat(wb, "\n\t\t\t}");
- buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+ dimension_counter++;
+ }
+ }
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
- for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
- if(st->enabled && st->dimensions) {
- if(c) buffer_strcat(wb, ",\n");
- memory += rrd_stats_one_json(st, NULL, wb);
- c++;
+ buffer_strcat(wb, "\n\t\t}\n\t}");
+ rrdset_unlock(st);
}
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
-
- buffer_sprintf(wb, "\n\t],\n"
- "\t\"hostname\": \"%s\",\n"
- "\t\"update_every\": %d,\n"
- "\t\"history\": %d,\n"
- "\t\"memory\": %lu\n"
- "}\n"
- , localhost.hostname
- , rrd_update_every
- , rrd_default_history_entries
- , memory
- );
-}
-
+ buffer_strcat(wb, "\n}");
+ rrdhost_unlock(host);
+}
// ----------------------------------------------------------------------------
@@ -449,6 +401,7 @@ void rrd_stats_all_json(BUFFER *wb)
#define RRDR_RESET 0x02 // the dimension contains / the value is reset
#define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
#define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
+#define RRDR_SELECTED 0x10 // the dimension is selected
// RRDR result options
#define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
@@ -541,13 +494,16 @@ static void rrdr_dump(RRDR *r)
}
*/
-void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
-{
+void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) {
+ rrdset_check_rdlock(r->st);
+
+ if(unlikely(!dims || !*dims)) return;
+
char b[strlen(dims) + 1];
char *o = b, *tok;
strcpy(o, dims);
- long c;
+ long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
RRDDIM *d;
// disable all of them
@@ -561,16 +517,38 @@ void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
// find it and enable it
for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
- if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || !strcmp(d->name, tok))) {
- r->od[c] &= ~RRDR_HIDDEN;
+ if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || (hash == d->hash_name && !strcmp(d->name, tok)))) {
+
+ if(likely(r->od[c] & RRDR_HIDDEN)) {
+ r->od[c] |= RRDR_SELECTED;
+ r->od[c] &= ~RRDR_HIDDEN;
+ dims_selected++;
+ }
// since the user needs this dimension
// make it appear as NONZERO, to return it
// even if the dimension has only zeros
- r->od[c] |= RRDR_NONZERO;
+ // unless option non_zero is set
+ if(likely(!(options & RRDR_OPTION_NONZERO)))
+ r->od[c] |= RRDR_NONZERO;
+
+ // count the visible dimensions
+ if(likely(r->od[c] & RRDR_NONZERO))
+ dims_not_hidden_not_zero++;
}
}
}
+
+ // check if all dimensions are hidden
+ if(unlikely(!dims_not_hidden_not_zero && dims_selected)) {
+ // there are a few selected dimensions
+ // but they are all zero
+ // enable the selected ones
+ // to avoid returning an empty chart
+ for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
+ if(unlikely(r->od[c] & RRDR_SELECTED))
+ r->od[c] |= RRDR_NONZERO;
+ }
}
void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
@@ -624,6 +602,8 @@ void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
{
+ rrdset_check_rdlock(r->st);
+
(void)dims;
if(options & RRDR_OPTION_NONZERO) {
@@ -659,6 +639,8 @@ uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
{
+ rrdset_check_rdlock(r->st);
+
long rows = rrdr_rows(r);
long c, i;
RRDDIM *rd;
@@ -840,6 +822,8 @@ void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t option
static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
{
+ rrdset_check_rdlock(r->st);
+
//info("RRD2JSON(): %s: BEGIN", r->st->id);
int row_annotations = 0, dates, dates_with_new = 0;
char kq[2] = "", // key quote
@@ -893,14 +877,14 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
else {
kq[0] = '"';
sq[0] = '"';
- if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
- dates = JSON_DATES_TIMESTAMP;
- dates_with_new = 0;
- }
- else {
+ if(options & RRDR_OPTION_GOOGLE_JSON) {
dates = JSON_DATES_JS;
dates_with_new = 1;
}
+ else {
+ dates = JSON_DATES_TIMESTAMP;
+ dates_with_new = 0;
+ }
if( options & RRDR_OPTION_OBJECTSROWS )
strcpy(pre_date, " { ");
else
@@ -1066,6 +1050,8 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
{
+ rrdset_check_rdlock(r->st);
+
//info("RRD2CSV(): %s: BEGIN", r->st->id);
long c, i;
RRDDIM *d;
@@ -1171,6 +1157,8 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
}
inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
+ rrdset_check_rdlock(r->st);
+
long c;
RRDDIM *d;
@@ -1321,7 +1309,7 @@ inline static void rrdr_lock_rrdset(RRDR *r) {
return;
}
- pthread_rwlock_rdlock(&r->st->rwlock);
+ rrdset_rdlock(r->st);
r->has_st_lock = 1;
}
@@ -1332,7 +1320,7 @@ inline static void rrdr_unlock_rrdset(RRDR *r) {
}
if(likely(r->has_st_lock)) {
- pthread_rwlock_unlock(&r->st->rwlock);
+ rrdset_unlock(r->st);
r->has_st_lock = 0;
}
}
@@ -1371,7 +1359,7 @@ static RRDR *rrdr_create(RRDSET *st, long n)
rrdr_lock_rrdset(r);
RRDDIM *rd;
- for(rd = st->dimensions ; rd ; rd = rd->next) r->d++;
+ rrddim_foreach_read(rd, st) r->d++;
r->n = n;
@@ -1383,8 +1371,10 @@ static RRDR *rrdr_create(RRDSET *st, long n)
// set the hidden flag on hidden dimensions
int c;
for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
- if(unlikely(rd->flags & RRDDIM_FLAG_HIDDEN)) r->od[c] = RRDR_HIDDEN;
- else r->od[c] = 0;
+ if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)))
+ r->od[c] = RRDR_HIDDEN;
+ else
+ r->od[c] = 0;
}
r->c = -1;
@@ -1396,7 +1386,7 @@ static RRDR *rrdr_create(RRDSET *st, long n)
RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
{
- int debug = st->debug;
+ int debug = rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?1:0;
int absolute_period_requested = -1;
time_t first_entry_t = rrdset_first_entry_t(st);
@@ -1572,6 +1562,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
// initialize them
RRDDIM *rd;
long c;
+ rrdset_check_rdlock(st);
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
last_values[c] = 0;
group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
@@ -1600,7 +1591,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
);
r->group = group;
- r->update_every = group * st->update_every;
+ r->update_every = (int)group * st->update_every;
r->before = now;
r->after = now;
@@ -1752,8 +1743,20 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
return r;
}
-int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *db_after, time_t *db_before, int *value_is_null)
-{
+int rrdset2value_api_v1(
+ RRDSET *st
+ , BUFFER *wb
+ , calculated_number *n
+ , const char *dimensions
+ , long points
+ , long long after
+ , long long before
+ , int group_method
+ , uint32_t options
+ , time_t *db_after
+ , time_t *db_before
+ , int *value_is_null
+) {
RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
if(!r) {
if(value_is_null) *value_is_null = 1;
@@ -1778,7 +1781,7 @@ int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensio
options = rrdr_check_options(r, options, dimensions);
if(dimensions)
- rrdr_disable_not_selected_dimensions(r, dimensions);
+ rrdr_disable_not_selected_dimensions(r, options, dimensions);
if(db_after) *db_after = r->after;
if(db_before) *db_before = r->before;
@@ -1790,8 +1793,20 @@ int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensio
return 200;
}
-int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp)
-{
+int rrdset2anything_api_v1(
+ RRDSET *st
+ , BUFFER *wb
+ , BUFFER *dimensions
+ , uint32_t format
+ , long points
+ , long long after
+ , long long before
+ , int group_method
+ , uint32_t options
+ , time_t *latest_timestamp
+) {
+ st->last_accessed_time = now_realtime_sec();
+
RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
if(!r) {
buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
@@ -1806,7 +1821,7 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
if(dimensions)
- rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
+ rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions));
if(latest_timestamp && rrdr_rows(r) > 0)
*latest_timestamp = r->before;
@@ -1963,325 +1978,3 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
rrdr_free(r);
return 200;
}
-
-time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long points, long group, int group_method, time_t after, time_t before, int only_non_zero)
-{
- int c;
- pthread_rwlock_rdlock(&st->rwlock);
-
-
- // -------------------------------------------------------------------------
- // switch from JSON to google JSON
-
- char kq[2] = "\"";
- char sq[2] = "\"";
- switch(type) {
- case DATASOURCE_DATATABLE_JSON:
- case DATASOURCE_DATATABLE_JSONP:
- kq[0] = '\0';
- sq[0] = '\'';
- break;
-
- case DATASOURCE_JSON:
- default:
- break;
- }
-
-
- // -------------------------------------------------------------------------
- // validate the parameters
-
- if(points < 1) points = 1;
- if(group < 1) group = 1;
-
- if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
- if(after == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
-
- // ---
-
- // our return value (the last timestamp printed)
- // this is required to detect re-transmit in google JSONP
- time_t last_timestamp = 0;
-
-
- // -------------------------------------------------------------------------
- // find how many dimensions we have
-
- int dimensions = 0;
- RRDDIM *rd;
- for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
- if(!dimensions) {
- pthread_rwlock_unlock(&st->rwlock);
- buffer_strcat(wb, "No dimensions yet.");
- return 0;
- }
-
-
- // -------------------------------------------------------------------------
- // prepare various strings, to speed up the loop
-
- char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
- char normal_annotation[201]; snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
- char pre_date[51]; snprintfz(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
- char post_date[21]; snprintfz(post_date, 20, "%s}", sq);
- char pre_value[21]; snprintfz(pre_value, 20, ",{%sv%s:", kq, kq);
- char post_value[21]; strcpy(post_value, "}");
-
-
- // -------------------------------------------------------------------------
- // checks for debugging
-
- if(st->debug) {
- debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
- , st->id
- , rrdset_first_entry_t(st)
- , rrdset_last_entry_t(st)
- , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
- , after
- , before
- , before - after
- , points
- , group
- );
-
- if(before < after)
- debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
-
- if((before - after) > st->entries * st->update_every)
- debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
- }
-
-
- // -------------------------------------------------------------------------
- // temp arrays for keeping values per dimension
-
- calculated_number group_values[dimensions]; // keep sums when grouping
- int print_hidden[dimensions]; // keep hidden flags
- int found_non_zero[dimensions];
- int found_non_existing[dimensions];
-
- // initialize them
- for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- group_values[c] = 0;
- print_hidden[c] = (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0;
- found_non_zero[c] = 0;
- found_non_existing[c] = 0;
- }
-
-
- // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
- // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
- // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
-
- // -------------------------------------------------------------------------
- // remove dimensions that contain only zeros
-
- int max_loop = 1;
- if(only_non_zero) max_loop = 2;
-
- for(; max_loop ; max_loop--) {
-
- // -------------------------------------------------------------------------
- // print the JSON header
-
- buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
- buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
- buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
- buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-
- // print the header for each dimension
- // and update the print_hidden array for the dimensions that should be hidden
- int pc = 0;
- for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- if(!print_hidden[c]) {
- pc++;
- buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
- }
- }
- if(!pc) {
- buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
- }
-
- // print the begin of row data
- buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
-
-
- // -------------------------------------------------------------------------
- // the main loop
-
- int annotate_reset = 0;
- int annotation_count = 0;
-
- long t = rrdset_time2slot(st, before),
- stop_at_t = rrdset_time2slot(st, after),
- stop_now = 0;
-
- t -= t % group;
-
- time_t now = rrdset_slot2time(st, t),
- dt = st->update_every;
-
- long count = 0, printed = 0, group_count = 0;
- last_timestamp = 0;
-
- if(st->debug) debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
- , st->id
- , (uint32_t)after
- , (uint32_t)before
- , points
- , group
- , st->current_entry
- , (uint32_t)rrdset_first_entry_t(st)
- , (uint32_t)rrdset_last_entry_t(st)
- , t
- , stop_at_t
- );
-
- long counter = 0;
- for(; !stop_now ; now -= dt, t--, counter++) {
- if(t < 0) t = st->entries - 1;
- if(t == stop_at_t) stop_now = counter;
-
- int print_this = 0;
-
- if(st->debug) debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
- , st->id
- , t
- , count + 1
- , group_count + 1
- , printed
- , now
- , (group_count + 1 == group)?"PRINT":" - "
- , (now >= after && now <= before)?"RANGE":" - "
- );
-
-
- // make sure we return data in the proper time range
- if(now > before) continue;
- if(now < after) break;
-
- //if(rrdset_slot2time(st, t) != now)
- // error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
-
- count++;
- group_count++;
-
- // check if we have to print this now
- if(group_count == group) {
- if(printed >= points) {
- // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
- break;
- }
-
- // generate the local date time
- struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
- if(!tm) { error("localtime() failed."); continue; }
- if(now > last_timestamp) last_timestamp = now;
-
- if(printed) buffer_strcat(wb, "]},\n");
- buffer_strcat(wb, pre_date);
- buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
- buffer_strcat(wb, post_date);
-
- print_this = 1;
- }
-
- // do the calculations
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- storage_number n = rd->values[t];
- calculated_number value = unpack_storage_number(n);
-
- if(!does_storage_number_exist(n)) {
- value = 0.0;
- found_non_existing[c]++;
- }
- if(did_storage_number_reset(n)) annotate_reset = 1;
-
- switch(group_method) {
- case GROUP_MAX:
- if(abs(value) > abs(group_values[c])) group_values[c] = value;
- break;
-
- case GROUP_SUM:
- group_values[c] += value;
- break;
-
- default:
- case GROUP_AVERAGE:
- group_values[c] += value;
- if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
- break;
- }
- }
-
- if(print_this) {
- if(annotate_reset) {
- annotation_count++;
- buffer_strcat(wb, overflow_annotation);
- annotate_reset = 0;
- }
- else
- buffer_strcat(wb, normal_annotation);
-
- pc = 0;
- for(c = 0 ; c < dimensions ; c++) {
- if(found_non_existing[c] == group_count) {
- // all entries are non-existing
- pc++;
- buffer_strcat(wb, pre_value);
- buffer_strcat(wb, "null");
- buffer_strcat(wb, post_value);
- }
- else if(!print_hidden[c]) {
- pc++;
- buffer_strcat(wb, pre_value);
- buffer_rrd_value(wb, group_values[c]);
- buffer_strcat(wb, post_value);
-
- if(group_values[c]) found_non_zero[c]++;
- }
-
- // reset them for the next loop
- group_values[c] = 0;
- found_non_existing[c] = 0;
- }
-
- // if all dimensions are hidden, print a null
- if(!pc) {
- buffer_strcat(wb, pre_value);
- buffer_strcat(wb, "null");
- buffer_strcat(wb, post_value);
- }
-
- printed++;
- group_count = 0;
- }
- }
-
- if(printed) buffer_strcat(wb, "]}");
- buffer_strcat(wb, "\n ]\n}\n");
-
- if(only_non_zero && max_loop > 1) {
- int changed = 0;
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- group_values[c] = 0;
- found_non_existing[c] = 0;
-
- if(!print_hidden[c] && !found_non_zero[c]) {
- changed = 1;
- print_hidden[c] = 1;
- }
- }
-
- if(changed) buffer_flush(wb);
- else break;
- }
- else break;
-
- } // max_loop
-
- debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %lu bytes", st->name, wb->len);
-
- pthread_rwlock_unlock(&st->rwlock);
- return last_timestamp;
-}
diff --git a/src/rrd2json.h b/src/rrd2json.h
index 7b1401970..f2f03c640 100644
--- a/src/rrd2json.h
+++ b/src/rrd2json.h
@@ -33,9 +33,11 @@
#define ALLMETRICS_FORMAT_SHELL "shell"
#define ALLMETRICS_FORMAT_PROMETHEUS "prometheus"
+#define ALLMETRICS_FORMAT_JSON "json"
#define ALLMETRICS_SHELL 1
#define ALLMETRICS_PROMETHEUS 2
+#define ALLMETRICS_JSON 3
#define GROUP_UNDEFINED 0
#define GROUP_AVERAGE 1
@@ -59,20 +61,17 @@
#define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes
extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
-extern void rrd_stats_api_v1_charts(BUFFER *wb);
-
-extern void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb);
-extern void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb);
-
-extern unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb);
-
-extern void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb);
-
-extern void rrd_stats_all_json(BUFFER *wb);
-
-extern time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long entries_to_show, long group, int group_method, time_t after, time_t before, int only_non_zero);
-
-extern int rrd2format(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp);
-extern int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *db_before, time_t *db_after, int *value_is_null);
+extern void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb);
+
+extern void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb);
+extern void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb);
+extern void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb);
+
+extern int rrdset2anything_api_v1(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points
+ , long long after, long long before, int group_method, uint32_t options
+ , time_t *latest_timestamp);
+extern int rrdset2value_api_v1(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points
+ , long long after, long long before, int group_method, uint32_t options
+ , time_t *db_before, time_t *db_after, int *value_is_null);
#endif /* NETDATA_RRD2JSON_H */
diff --git a/src/rrd2json_api_old.c b/src/rrd2json_api_old.c
new file mode 100644
index 000000000..6710f31cf
--- /dev/null
+++ b/src/rrd2json_api_old.c
@@ -0,0 +1,487 @@
+#include "common.h"
+
+unsigned long rrdset_info2json_api_old(RRDSET *st, char *options, BUFFER *wb) {
+ time_t now = now_realtime_sec();
+
+ rrdset_rdlock(st);
+
+ st->last_accessed_time = now;
+
+ buffer_sprintf(wb,
+ "\t\t{\n"
+ "\t\t\t\"id\": \"%s\",\n"
+ "\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\"type\": \"%s\",\n"
+ "\t\t\t\"family\": \"%s\",\n"
+ "\t\t\t\"context\": \"%s\",\n"
+ "\t\t\t\"title\": \"%s\",\n"
+ "\t\t\t\"priority\": %ld,\n"
+ "\t\t\t\"enabled\": %d,\n"
+ "\t\t\t\"units\": \"%s\",\n"
+ "\t\t\t\"url\": \"/data/%s/%s\",\n"
+ "\t\t\t\"chart_type\": \"%s\",\n"
+ "\t\t\t\"counter\": %lu,\n"
+ "\t\t\t\"entries\": %ld,\n"
+ "\t\t\t\"first_entry_t\": %ld,\n"
+ "\t\t\t\"last_entry\": %lu,\n"
+ "\t\t\t\"last_entry_t\": %ld,\n"
+ "\t\t\t\"last_entry_secs_ago\": %ld,\n"
+ "\t\t\t\"update_every\": %d,\n"
+ "\t\t\t\"isdetail\": %d,\n"
+ "\t\t\t\"usec_since_last_update\": %llu,\n"
+ "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
+ "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
+ "\t\t\t\"dimensions\": [\n"
+ , st->id
+ , st->name
+ , st->type
+ , st->family
+ , st->context
+ , st->title
+ , st->priority
+ , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?1:0
+ , st->units
+ , st->name, options?options:""
+ , rrdset_type_name(st->chart_type)
+ , st->counter
+ , st->entries
+ , rrdset_first_entry_t(st)
+ , rrdset_last_slot(st)
+ , rrdset_last_entry_t(st)
+ , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
+ , st->update_every
+ , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?1:0
+ , st->usec_since_last_update
+ , st->collected_total
+ , st->last_collected_total
+ );
+
+ unsigned long memory = st->memsize;
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+
+ memory += rd->memsize;
+
+ buffer_sprintf(wb,
+ "\t\t\t\t{\n"
+ "\t\t\t\t\t\"id\": \"%s\",\n"
+ "\t\t\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\t\t\"entries\": %ld,\n"
+ "\t\t\t\t\t\"isHidden\": %d,\n"
+ "\t\t\t\t\t\"algorithm\": \"%s\",\n"
+ "\t\t\t\t\t\"multiplier\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"divisor\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"last_entry_t\": %ld,\n"
+ "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"memory\": %lu\n"
+ "\t\t\t\t}%s\n"
+ , rd->id
+ , rd->name
+ , rd->entries
+ , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?1:0
+ , rrd_algorithm_name(rd->algorithm)
+ , rd->multiplier
+ , rd->divisor
+ , rd->last_collected_time.tv_sec
+ , rd->collected_value
+ , rd->calculated_value
+ , rd->last_collected_value
+ , rd->last_calculated_value
+ , rd->memsize
+ , rd->next?",":""
+ );
+ }
+
+ buffer_sprintf(wb,
+ "\t\t\t],\n"
+ "\t\t\t\"memory\" : %lu\n"
+ "\t\t}"
+ , memory
+ );
+
+ rrdset_unlock(st);
+ return memory;
+}
+
+#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
+#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
+
+void rrd_graph2json_api_old(RRDSET *st, char *options, BUFFER *wb)
+{
+ buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+ rrdset_info2json_api_old(st, options, wb);
+ buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
+}
+
+void rrd_all2json_api_old(RRDHOST *host, BUFFER *wb)
+{
+ unsigned long memory = 0;
+ long c = 0;
+ RRDSET *st;
+
+ time_t now = now_realtime_sec();
+
+ buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+
+ rrdhost_rdlock(host);
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
+ if(c) buffer_strcat(wb, ",\n");
+ memory += rrdset_info2json_api_old(st, NULL, wb);
+
+ c++;
+ st->last_accessed_time = now;
+ }
+ }
+ rrdhost_unlock(host);
+
+ buffer_sprintf(wb, "\n\t],\n"
+ "\t\"hostname\": \"%s\",\n"
+ "\t\"update_every\": %d,\n"
+ "\t\"history\": %ld,\n"
+ "\t\"memory\": %lu\n"
+ "}\n"
+ , host->hostname
+ , host->rrd_update_every
+ , host->rrd_history_entries
+ , memory
+ );
+}
+
+time_t rrdset2json_api_old(
+ int type
+ , RRDSET *st
+ , BUFFER *wb
+ , long points
+ , long group
+ , int group_method
+ , time_t after
+ , time_t before
+ , int only_non_zero
+) {
+ int c;
+ rrdset_rdlock(st);
+
+ st->last_accessed_time = now_realtime_sec();
+
+ // -------------------------------------------------------------------------
+ // switch from JSON to google JSON
+
+ char kq[2] = "\"";
+ char sq[2] = "\"";
+ switch(type) {
+ case DATASOURCE_DATATABLE_JSON:
+ case DATASOURCE_DATATABLE_JSONP:
+ kq[0] = '\0';
+ sq[0] = '\'';
+ break;
+
+ case DATASOURCE_JSON:
+ default:
+ break;
+ }
+
+
+ // -------------------------------------------------------------------------
+ // validate the parameters
+
+ if(points < 1) points = 1;
+ if(group < 1) group = 1;
+
+ if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
+ if(after == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
+
+ // ---
+
+ // our return value (the last timestamp printed)
+ // this is required to detect re-transmit in google JSONP
+ time_t last_timestamp = 0;
+
+
+ // -------------------------------------------------------------------------
+ // find how many dimensions we have
+
+ int dimensions = 0;
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) dimensions++;
+ if(!dimensions) {
+ rrdset_unlock(st);
+ buffer_strcat(wb, "No dimensions yet.");
+ return 0;
+ }
+
+
+ // -------------------------------------------------------------------------
+ // prepare various strings, to speed up the loop
+
+ char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
+ char normal_annotation[201]; snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
+ char pre_date[51]; snprintfz(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
+ char post_date[21]; snprintfz(post_date, 20, "%s}", sq);
+ char pre_value[21]; snprintfz(pre_value, 20, ",{%sv%s:", kq, kq);
+ char post_value[21]; strcpy(post_value, "}");
+
+
+ // -------------------------------------------------------------------------
+ // checks for debugging
+
+ if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)) {
+ debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
+ , st->id
+ , rrdset_first_entry_t(st)
+ , rrdset_last_entry_t(st)
+ , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
+ , after
+ , before
+ , before - after
+ , points
+ , group
+ );
+
+ if(before < after)
+ debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
+
+ if((before - after) > st->entries * st->update_every)
+ debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
+ }
+
+
+ // -------------------------------------------------------------------------
+ // temp arrays for keeping values per dimension
+
+ calculated_number group_values[dimensions]; // keep sums when grouping
+ int print_hidden[dimensions]; // keep hidden flags
+ int found_non_zero[dimensions];
+ int found_non_existing[dimensions];
+
+ // initialize them
+ for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ group_values[c] = 0;
+ print_hidden[c] = rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?1:0;
+ found_non_zero[c] = 0;
+ found_non_existing[c] = 0;
+ }
+
+
+ // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
+ // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
+ // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
+
+ // -------------------------------------------------------------------------
+ // remove dimensions that contain only zeros
+
+ int max_loop = 1;
+ if(only_non_zero) max_loop = 2;
+
+ for(; max_loop ; max_loop--) {
+
+ // -------------------------------------------------------------------------
+ // print the JSON header
+
+ buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
+ buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+ buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+ buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+
+ // print the header for each dimension
+ // and update the print_hidden array for the dimensions that should be hidden
+ int pc = 0;
+ for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ if(!print_hidden[c]) {
+ pc++;
+ buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+ }
+ }
+ if(!pc) {
+ buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
+ }
+
+ // print the begin of row data
+ buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
+
+
+ // -------------------------------------------------------------------------
+ // the main loop
+
+ int annotate_reset = 0;
+ int annotation_count = 0;
+
+ long t = rrdset_time2slot(st, before),
+ stop_at_t = rrdset_time2slot(st, after),
+ stop_now = 0;
+
+ t -= t % group;
+
+ time_t now = rrdset_slot2time(st, t),
+ dt = st->update_every;
+
+ long count = 0, printed = 0, group_count = 0;
+ last_timestamp = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
+ , st->id
+ , (uint32_t)after
+ , (uint32_t)before
+ , points
+ , group
+ , st->current_entry
+ , (uint32_t)rrdset_first_entry_t(st)
+ , (uint32_t)rrdset_last_entry_t(st)
+ , t
+ , stop_at_t
+ );
+
+ long counter = 0;
+ for(; !stop_now ; now -= dt, t--, counter++) {
+ if(t < 0) t = st->entries - 1;
+ if(t == stop_at_t) stop_now = counter;
+
+ int print_this = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
+ , st->id
+ , t
+ , count + 1
+ , group_count + 1
+ , printed
+ , now
+ , (group_count + 1 == group)?"PRINT":" - "
+ , (now >= after && now <= before)?"RANGE":" - "
+ );
+
+
+ // make sure we return data in the proper time range
+ if(now > before) continue;
+ if(now < after) break;
+
+ //if(rrdset_slot2time(st, t) != now)
+ // error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
+
+ count++;
+ group_count++;
+
+ // check if we have to print this now
+ if(group_count == group) {
+ if(printed >= points) {
+ // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
+ break;
+ }
+
+ // generate the local date time
+ struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
+ if(!tm) { error("localtime() failed."); continue; }
+ if(now > last_timestamp) last_timestamp = now;
+
+ if(printed) buffer_strcat(wb, "]},\n");
+ buffer_strcat(wb, pre_date);
+ buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ buffer_strcat(wb, post_date);
+
+ print_this = 1;
+ }
+
+ // do the calculations
+ for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ storage_number n = rd->values[t];
+ calculated_number value = unpack_storage_number(n);
+
+ if(!does_storage_number_exist(n)) {
+ value = 0.0;
+ found_non_existing[c]++;
+ }
+ if(did_storage_number_reset(n)) annotate_reset = 1;
+
+ switch(group_method) {
+ case GROUP_MAX:
+ if(abs(value) > abs(group_values[c])) group_values[c] = value;
+ break;
+
+ case GROUP_SUM:
+ group_values[c] += value;
+ break;
+
+ default:
+ case GROUP_AVERAGE:
+ group_values[c] += value;
+ if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
+ break;
+ }
+ }
+
+ if(print_this) {
+ if(annotate_reset) {
+ annotation_count++;
+ buffer_strcat(wb, overflow_annotation);
+ annotate_reset = 0;
+ }
+ else
+ buffer_strcat(wb, normal_annotation);
+
+ pc = 0;
+ for(c = 0 ; c < dimensions ; c++) {
+ if(found_non_existing[c] == group_count) {
+ // all entries are non-existing
+ pc++;
+ buffer_strcat(wb, pre_value);
+ buffer_strcat(wb, "null");
+ buffer_strcat(wb, post_value);
+ }
+ else if(!print_hidden[c]) {
+ pc++;
+ buffer_strcat(wb, pre_value);
+ buffer_rrd_value(wb, group_values[c]);
+ buffer_strcat(wb, post_value);
+
+ if(group_values[c]) found_non_zero[c]++;
+ }
+
+ // reset them for the next loop
+ group_values[c] = 0;
+ found_non_existing[c] = 0;
+ }
+
+ // if all dimensions are hidden, print a null
+ if(!pc) {
+ buffer_strcat(wb, pre_value);
+ buffer_strcat(wb, "null");
+ buffer_strcat(wb, post_value);
+ }
+
+ printed++;
+ group_count = 0;
+ }
+ }
+
+ if(printed) buffer_strcat(wb, "]}");
+ buffer_strcat(wb, "\n ]\n}\n");
+
+ if(only_non_zero && max_loop > 1) {
+ int changed = 0;
+ for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ group_values[c] = 0;
+ found_non_existing[c] = 0;
+
+ if(!print_hidden[c] && !found_non_zero[c]) {
+ changed = 1;
+ print_hidden[c] = 1;
+ }
+ }
+
+ if(changed) buffer_flush(wb);
+ else break;
+ }
+ else break;
+
+ } // max_loop
+
+ debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %zu bytes", st->name, wb->len);
+
+ rrdset_unlock(st);
+ return last_timestamp;
+}
diff --git a/src/rrd2json_api_old.h b/src/rrd2json_api_old.h
new file mode 100644
index 000000000..f8c63814f
--- /dev/null
+++ b/src/rrd2json_api_old.h
@@ -0,0 +1,14 @@
+#ifndef NETDATA_RRD2JSON_API_OLD_H
+#define NETDATA_RRD2JSON_API_OLD_H
+
+extern unsigned long rrdset_info2json_api_old(RRDSET *st, char *options, BUFFER *wb);
+
+extern void rrd_graph2json_api_old(RRDSET *st, char *options, BUFFER *wb);
+
+extern void rrd_all2json_api_old(RRDHOST *host, BUFFER *wb);
+
+extern time_t rrdset2json_api_old(int type, RRDSET *st, BUFFER *wb, long entries_to_show, long group, int group_method
+ , time_t after, time_t before, int only_non_zero);
+
+
+#endif //NETDATA_RRD2JSON_API_OLD_H
diff --git a/src/rrdcalc.c b/src/rrdcalc.c
new file mode 100644
index 000000000..1f1845409
--- /dev/null
+++ b/src/rrdcalc.c
@@ -0,0 +1,415 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDCALC management
+
+inline const char *rrdcalc_status2string(int status) {
+ switch(status) {
+ case RRDCALC_STATUS_REMOVED:
+ return "REMOVED";
+
+ case RRDCALC_STATUS_UNDEFINED:
+ return "UNDEFINED";
+
+ case RRDCALC_STATUS_UNINITIALIZED:
+ return "UNINITIALIZED";
+
+ case RRDCALC_STATUS_CLEAR:
+ return "CLEAR";
+
+ case RRDCALC_STATUS_RAISED:
+ return "RAISED";
+
+ case RRDCALC_STATUS_WARNING:
+ return "WARNING";
+
+ case RRDCALC_STATUS_CRITICAL:
+ return "CRITICAL";
+
+ default:
+ error("Unknown alarm status %d", status);
+ return "UNKNOWN";
+ }
+}
+
+static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
+ debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
+
+ rc->last_status_change = now_realtime_sec();
+ rc->rrdset = st;
+
+ rc->rrdset_next = st->alarms;
+ rc->rrdset_prev = NULL;
+
+ if(rc->rrdset_next)
+ rc->rrdset_next->rrdset_prev = rc;
+
+ st->alarms = rc;
+
+ if(rc->update_every < rc->rrdset->update_every) {
+ error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
+ rc->update_every = rc->rrdset->update_every;
+ }
+
+ if(!isnan(rc->green) && isnan(st->green)) {
+ debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
+ st->green = rc->green;
+ }
+
+ if(!isnan(rc->red) && isnan(st->red)) {
+ debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
+ st->red = rc->red;
+ }
+
+ rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
+ rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+ char fullname[RRDVAR_MAX_LENGTH + 1];
+ snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
+ rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+ snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
+ rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+ if(!rc->units) rc->units = strdupz(st->units);
+
+ {
+ time_t now = now_realtime_sec();
+ health_alarm_log(
+ st->rrdhost,
+ rc->id,
+ rc->next_event_id++,
+ now,
+ rc->name,
+ rc->rrdset->id,
+ rc->rrdset->family,
+ rc->exec,
+ rc->recipient,
+ now - rc->last_status_change,
+ rc->old_value,
+ rc->value,
+ rc->status,
+ RRDCALC_STATUS_UNINITIALIZED,
+ rc->source,
+ rc->units,
+ rc->info,
+ 0,
+ 0
+ );
+ }
+}
+
+static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
+ if( (rc->hash_chart == st->hash && !strcmp(rc->chart, st->id)) ||
+ (rc->hash_chart == st->hash_name && !strcmp(rc->chart, st->name)))
+ return 1;
+
+ return 0;
+}
+
+// this has to be called while the RRDHOST is locked
+inline void rrdsetcalc_link_matching(RRDSET *st) {
+ // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
+
+ RRDCALC *rc;
+ for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
+ if(unlikely(rc->rrdset))
+ continue;
+
+ if(unlikely(rrdcalc_is_matching_this_rrdset(rc, st)))
+ rrdsetcalc_link(st, rc);
+ }
+}
+
+// this has to be called while the RRDHOST is locked
+inline void rrdsetcalc_unlink(RRDCALC *rc) {
+ RRDSET *st = rc->rrdset;
+
+ if(!st) {
+ debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
+ error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
+ return;
+ }
+
+ {
+ time_t now = now_realtime_sec();
+ health_alarm_log(
+ st->rrdhost,
+ rc->id,
+ rc->next_event_id++,
+ now,
+ rc->name,
+ rc->rrdset->id,
+ rc->rrdset->family,
+ rc->exec,
+ rc->recipient,
+ now - rc->last_status_change,
+ rc->old_value,
+ rc->value,
+ rc->status,
+ RRDCALC_STATUS_REMOVED,
+ rc->source,
+ rc->units,
+ rc->info,
+ 0,
+ 0
+ );
+ }
+
+ RRDHOST *host = st->rrdhost;
+
+ debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
+
+ // unlink it
+ if(rc->rrdset_prev)
+ rc->rrdset_prev->rrdset_next = rc->rrdset_next;
+
+ if(rc->rrdset_next)
+ rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
+
+ if(st->alarms == rc)
+ st->alarms = rc->rrdset_next;
+
+ rc->rrdset_prev = rc->rrdset_next = NULL;
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
+ rc->local = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family);
+ rc->family = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
+ rc->hostid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
+ rc->hostname = NULL;
+
+ rc->rrdset = NULL;
+
+ // RRDCALC will remain in RRDHOST
+ // so that if the matching chart is found in the future
+ // it will be applied automatically
+}
+
+RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
+ RRDCALC *rc;
+ uint32_t hash = simple_hash(name);
+
+ for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
+ if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
+ return rc;
+ }
+
+ return NULL;
+}
+
+inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
+ RRDCALC *rc;
+
+ if(unlikely(!chart)) {
+ error("attempt to find RRDCALC '%s' without giving a chart name", name);
+ return 1;
+ }
+
+ if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
+ if(unlikely(!hash_name)) hash_name = simple_hash(name);
+
+ // make sure it does not already exist
+ for(rc = host->alarms; rc ; rc = rc->next) {
+ if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
+ debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
+ error("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
+ if(chart && name) {
+ uint32_t hash_chart = simple_hash(chart);
+ uint32_t hash_name = simple_hash(name);
+
+ // re-use old IDs, by looking them up in the alarm log
+ ALARM_ENTRY *ae;
+ for(ae = host->health_log.alarms; ae ;ae = ae->next) {
+ if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
+ if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
+ return ae->alarm_id;
+ }
+ }
+ }
+
+ return host->health_log.next_alarm_id++;
+}
+
+inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
+ rrdhost_check_rdlock(host);
+
+ if(rc->calculation) {
+ rc->calculation->status = &rc->status;
+ rc->calculation->this = &rc->value;
+ rc->calculation->after = &rc->db_after;
+ rc->calculation->before = &rc->db_before;
+ rc->calculation->rrdcalc = rc;
+ }
+
+ if(rc->warning) {
+ rc->warning->status = &rc->status;
+ rc->warning->this = &rc->value;
+ rc->warning->after = &rc->db_after;
+ rc->warning->before = &rc->db_before;
+ rc->warning->rrdcalc = rc;
+ }
+
+ if(rc->critical) {
+ rc->critical->status = &rc->status;
+ rc->critical->this = &rc->value;
+ rc->critical->after = &rc->db_after;
+ rc->critical->before = &rc->db_before;
+ rc->critical->rrdcalc = rc;
+ }
+
+ // link it to the host
+ if(likely(host->alarms)) {
+ // append it
+ RRDCALC *t;
+ for(t = host->alarms; t && t->next ; t = t->next) ;
+ t->next = rc;
+ }
+ else {
+ host->alarms = rc;
+ }
+
+ // link it to its chart
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ if(rrdcalc_is_matching_this_rrdset(rc, st)) {
+ rrdsetcalc_link(st, rc);
+ break;
+ }
+ }
+}
+
+inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
+
+ debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
+
+ if(rrdcalc_exists(host, chart, rt->name, 0, 0))
+ return NULL;
+
+ RRDCALC *rc = callocz(1, sizeof(RRDCALC));
+ rc->next_event_id = 1;
+ rc->id = rrdcalc_get_unique_id(host, chart, rt->name, &rc->next_event_id);
+ rc->name = strdupz(rt->name);
+ rc->hash = simple_hash(rc->name);
+ rc->chart = strdupz(chart);
+ rc->hash_chart = simple_hash(rc->chart);
+
+ if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
+
+ rc->green = rt->green;
+ rc->red = rt->red;
+ rc->value = NAN;
+ rc->old_value = NAN;
+
+ rc->delay_up_duration = rt->delay_up_duration;
+ rc->delay_down_duration = rt->delay_down_duration;
+ rc->delay_max_duration = rt->delay_max_duration;
+ rc->delay_multiplier = rt->delay_multiplier;
+
+ rc->group = rt->group;
+ rc->after = rt->after;
+ rc->before = rt->before;
+ rc->update_every = rt->update_every;
+ rc->options = rt->options;
+
+ if(rt->exec) rc->exec = strdupz(rt->exec);
+ if(rt->recipient) rc->recipient = strdupz(rt->recipient);
+ if(rt->source) rc->source = strdupz(rt->source);
+ if(rt->units) rc->units = strdupz(rt->units);
+ if(rt->info) rc->info = strdupz(rt->info);
+
+ if(rt->calculation) {
+ rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
+ if(!rc->calculation)
+ error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
+ }
+ if(rt->warning) {
+ rc->warning = expression_parse(rt->warning->source, NULL, NULL);
+ if(!rc->warning)
+ error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
+ }
+ if(rt->critical) {
+ rc->critical = expression_parse(rt->critical->source, NULL, NULL);
+ if(!rc->critical)
+ error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
+ }
+
+ debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
+ (rc->chart)?rc->chart:"NOCHART",
+ rc->name,
+ (rc->exec)?rc->exec:"DEFAULT",
+ (rc->recipient)?rc->recipient:"DEFAULT",
+ rc->green,
+ rc->red,
+ rc->group,
+ rc->after,
+ rc->before,
+ rc->options,
+ (rc->dimensions)?rc->dimensions:"NONE",
+ rc->update_every,
+ (rc->calculation)?rc->calculation->parsed_as:"NONE",
+ (rc->warning)?rc->warning->parsed_as:"NONE",
+ (rc->critical)?rc->critical->parsed_as:"NONE",
+ rc->source,
+ rc->delay_up_duration,
+ rc->delay_down_duration,
+ rc->delay_max_duration,
+ rc->delay_multiplier
+ );
+
+ rrdcalc_create_part2(host, rc);
+ return rc;
+}
+
+void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
+ if(!rc) return;
+
+ debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
+
+ // unlink it from RRDSET
+ if(rc->rrdset) rrdsetcalc_unlink(rc);
+
+ // unlink it from RRDHOST
+ if(unlikely(rc == host->alarms))
+ host->alarms = rc->next;
+
+ else {
+ RRDCALC *t;
+ for(t = host->alarms; t && t->next != rc; t = t->next) ;
+ if(t) {
+ t->next = rc->next;
+ rc->next = NULL;
+ }
+ else
+ error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
+ }
+
+ expression_free(rc->calculation);
+ expression_free(rc->warning);
+ expression_free(rc->critical);
+
+ freez(rc->name);
+ freez(rc->chart);
+ freez(rc->family);
+ freez(rc->dimensions);
+ freez(rc->exec);
+ freez(rc->recipient);
+ freez(rc->source);
+ freez(rc->units);
+ freez(rc->info);
+ freez(rc);
+}
diff --git a/src/rrdcalctemplate.c b/src/rrdcalctemplate.c
new file mode 100644
index 000000000..2c5e2bd16
--- /dev/null
+++ b/src/rrdcalctemplate.c
@@ -0,0 +1,62 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDCALCTEMPLATE management
+
+void rrdcalctemplate_link_matching(RRDSET *st) {
+ RRDCALCTEMPLATE *rt;
+
+ for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
+ if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)
+ && (!rt->family_pattern || simple_pattern_matches(rt->family_pattern, st->family))) {
+ RRDCALC *rc = rrdcalc_create(st->rrdhost, rt, st->id);
+ if(unlikely(!rc))
+ error("Health tried to create alarm from template '%s', but it failed", rt->name);
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ else if(rc->rrdset != st)
+ error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
+#endif
+ }
+ }
+}
+
+inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
+ if(unlikely(!rt)) return;
+
+ debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
+
+ if(host->templates == rt) {
+ host->templates = rt->next;
+ }
+ else {
+ RRDCALCTEMPLATE *t;
+ for (t = host->templates; t && t->next != rt; t = t->next ) ;
+ if(t) {
+ t->next = rt->next;
+ rt->next = NULL;
+ }
+ else
+ error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
+ }
+
+ expression_free(rt->calculation);
+ expression_free(rt->warning);
+ expression_free(rt->critical);
+
+ freez(rt->family_match);
+ simple_pattern_free(rt->family_pattern);
+
+ freez(rt->name);
+ freez(rt->exec);
+ freez(rt->recipient);
+ freez(rt->context);
+ freez(rt->source);
+ freez(rt->units);
+ freez(rt->info);
+ freez(rt->dimensions);
+ freez(rt);
+}
+
+
diff --git a/src/rrddim.c b/src/rrddim.c
new file mode 100644
index 000000000..54a17522f
--- /dev/null
+++ b/src/rrddim.c
@@ -0,0 +1,313 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDDIM index
+
+int rrddim_compare(void* a, void* b) {
+ if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
+ else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
+ else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
+}
+
+#define rrddim_index_add(st, rd) (RRDDIM *)avl_insert_lock(&((st)->dimensions_index), (avl *)(rd))
+#define rrddim_index_del(st,rd ) (RRDDIM *)avl_remove_lock(&((st)->dimensions_index), (avl *)(rd))
+
+static inline RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
+ RRDDIM tmp = {
+ .id = id,
+ .hash = (hash)?hash:simple_hash(id)
+ };
+ return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM - find a dimension
+
+inline RRDDIM *rrddim_find(RRDSET *st, const char *id) {
+ debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
+
+ return rrddim_index_find(st, id, 0);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM rename a dimension
+
+inline void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name) {
+ if(unlikely(!strcmp(rd->name, name)))
+ return;
+
+ debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", st->name, rd->name, st->name, name);
+
+ char varname[CONFIG_MAX_NAME + 1];
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
+ rd->name = config_set_default(st->config_section, varname, name);
+ rd->hash_name = simple_hash(rd->name);
+
+ rrddimvar_rename_all(rd);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM create a dimension
+
+RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm) {
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(rd)) {
+ debug(D_RRD_CALLS, "Cannot create rrd dimension '%s/%s', it already exists.", st->id, name?name:"<NONAME>");
+ return rd;
+ }
+
+ char filename[FILENAME_MAX + 1];
+ char fullfilename[FILENAME_MAX + 1];
+
+ char varname[CONFIG_MAX_NAME + 1];
+ unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
+
+ debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
+
+ rrdset_strncpyz_name(filename, id, FILENAME_MAX);
+ snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ rd = (RRDDIM *)mymmap(fullfilename, size, ((st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 1);
+ if(likely(rd)) {
+ // we have a file mapped for rd
+
+ memset(&rd->avl, 0, sizeof(avl));
+ rd->id = NULL;
+ rd->name = NULL;
+ rd->cache_filename = NULL;
+ rd->variables = NULL;
+ rd->next = NULL;
+ rd->rrdset = NULL;
+
+ struct timeval now;
+ now_realtime_timeval(&now);
+
+ if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
+ errno = 0;
+ info("Initializing file %s.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->memsize != size) {
+ errno = 0;
+ error("File %s does not have the desired size. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->multiplier != multiplier) {
+ errno = 0;
+ error("File %s does not have the same multiplier. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->divisor != divisor) {
+ errno = 0;
+ error("File %s does not have the same divisor. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->update_every != st->update_every) {
+ errno = 0;
+ error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(dt_usec(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * USEC_PER_SEC)) {
+ errno = 0;
+ error("File %s is too old. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+
+ if(rd->algorithm && rd->algorithm != algorithm)
+ error("File %s does not have the expected algorithm (expected %u '%s', found %u '%s'). Previous values may be wrong."
+ , fullfilename, algorithm, rrd_algorithm_name(algorithm), rd->algorithm,
+ rrd_algorithm_name(rd->algorithm));
+
+ // make sure we have the right memory mode
+ // even if we cleared the memory
+ rd->rrd_memory_mode = st->rrd_memory_mode;
+ }
+ }
+
+ if(unlikely(!rd)) {
+ // if we didn't manage to get a mmap'd dimension, just create one
+ rd = callocz(1, size);
+ rd->rrd_memory_mode = (st->rrd_memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_RAM;
+ }
+
+ rd->memsize = size;
+
+ strcpy(rd->magic, RRDDIMENSION_MAGIC);
+
+ rd->id = strdupz(id);
+ rd->hash = simple_hash(rd->id);
+
+ rd->cache_filename = strdupz(fullfilename);
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
+ rd->name = config_get(st->config_section, varname, (name && *name)?name:rd->id);
+ rd->hash_name = simple_hash(rd->name);
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
+ rd->algorithm = rrd_algorithm_id(config_get(st->config_section, varname, rrd_algorithm_name(algorithm)));
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
+ rd->multiplier = config_get_number(st->config_section, varname, multiplier);
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
+ rd->divisor = config_get_number(st->config_section, varname, divisor);
+ if(!rd->divisor) rd->divisor = 1;
+
+ rd->entries = st->entries;
+ rd->update_every = st->update_every;
+
+ // prevent incremental calculation spikes
+ rd->collections_counter = 0;
+ rd->updated = 0;
+ rd->flags = 0x00000000;
+
+ rd->calculated_value = 0;
+ rd->last_calculated_value = 0;
+ rd->collected_value = 0;
+ rd->last_collected_value = 0;
+ rd->collected_volume = 0;
+ rd->stored_volume = 0;
+ rd->last_stored_value = 0;
+ rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+ rd->last_collected_time.tv_sec = 0;
+ rd->last_collected_time.tv_usec = 0;
+ rd->rrdset = st;
+
+ // append this dimension
+ rrdset_wrlock(st);
+ if(!st->dimensions)
+ st->dimensions = rd;
+ else {
+ RRDDIM *td = st->dimensions;
+ for(; td->next; td = td->next) ;
+ td->next = rd;
+ }
+
+ if(st->rrdhost->health_enabled) {
+ rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, 0);
+ rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, 0);
+ rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, 0);
+ }
+
+ rrdset_unlock(st);
+
+ if(unlikely(rrddim_index_add(st, rd) != rd))
+ error("RRDDIM: INTERNAL ERROR: attempt to index duplicate dimension '%s' on chart '%s'", rd->id, st->id);
+
+ return(rd);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM remove / free a dimension
+
+void rrddim_free(RRDSET *st, RRDDIM *rd)
+{
+ debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
+
+ if(rd == st->dimensions)
+ st->dimensions = rd->next;
+ else {
+ RRDDIM *i;
+ for (i = st->dimensions; i && i->next != rd; i = i->next) ;
+
+ if (i && i->next == rd)
+ i->next = rd->next;
+ else
+ error("Request to free dimension '%s.%s' but it is not linked.", st->id, rd->name);
+ }
+ rd->next = NULL;
+
+ while(rd->variables)
+ rrddimvar_free(rd->variables);
+
+ if(unlikely(rrddim_index_del(st, rd) != rd))
+ error("RRDDIM: INTERNAL ERROR: attempt to remove from index dimension '%s' on chart '%s', removed a different dimension.", rd->id, st->id);
+
+ // free(rd->annotations);
+
+ switch(rd->rrd_memory_mode) {
+ case RRD_MEMORY_MODE_SAVE:
+ debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ savememory(rd->cache_filename, rd, rd->memsize);
+ // continue to map mode - no break;
+
+ case RRD_MEMORY_MODE_MAP:
+ debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
+ freez((void *)rd->id);
+ freez(rd->cache_filename);
+ munmap(rd, rd->memsize);
+ break;
+
+ case RRD_MEMORY_MODE_NONE:
+ case RRD_MEMORY_MODE_RAM:
+ debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
+ freez((void *)rd->id);
+ freez(rd->cache_filename);
+ freez(rd);
+ break;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM - set dimension options
+
+int rrddim_hide(RRDSET *st, const char *id) {
+ debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
+
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+ return 1;
+ }
+
+ rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
+ return 0;
+}
+
+int rrddim_unhide(RRDSET *st, const char *id) {
+ debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
+
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+ return 1;
+ }
+
+ rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
+ return 0;
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM - collect values for a dimension
+
+inline collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value) {
+ debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
+
+ now_realtime_timeval(&rd->last_collected_time);
+ rd->collected_value = value;
+ rd->updated = 1;
+
+ rd->collections_counter++;
+
+ // fprintf(stderr, "%s.%s %llu " COLLECTED_NUMBER_FORMAT " dt %0.6f" " rate " CALCULATED_NUMBER_FORMAT "\n", st->name, rd->name, st->usec_since_last_update, value, (float)((double)st->usec_since_last_update / (double)1000000), (calculated_number)((value - rd->last_collected_value) * (calculated_number)rd->multiplier / (calculated_number)rd->divisor * 1000000.0 / (calculated_number)st->usec_since_last_update));
+
+ return rd->last_collected_value;
+}
+
+collected_number rrddim_set(RRDSET *st, const char *id, collected_number value) {
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+ return 0;
+ }
+
+ return rrddim_set_by_pointer(st, rd, value);
+}
diff --git a/src/rrddimvar.c b/src/rrddimvar.c
new file mode 100644
index 000000000..f6eb6d8ef
--- /dev/null
+++ b/src/rrddimvar.c
@@ -0,0 +1,210 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDDIMVAR management
+// DIMENSION VARIABLES
+
+#define RRDDIMVAR_ID_MAX 1024
+
+static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+
+ // CHART VARIABLES FOR THIS DIMENSION
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id);
+ rs->var_local_id = NULL;
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name);
+ rs->var_local_name = NULL;
+
+ // FAMILY VARIABLES FOR THIS DIMENSION
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id);
+ rs->var_family_id = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
+ rs->var_family_name = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid);
+ rs->var_family_contextid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname);
+ rs->var_family_contextname = NULL;
+
+ // HOST VARIABLES FOR THIS DIMENSION
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid);
+ rs->var_host_chartidid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname);
+ rs->var_host_chartidname = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid);
+ rs->var_host_chartnameid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename);
+ rs->var_host_chartnamename = NULL;
+
+ // KEYS
+
+ freez(rs->key_id);
+ rs->key_id = NULL;
+
+ freez(rs->key_name);
+ rs->key_name = NULL;
+
+ freez(rs->key_fullidid);
+ rs->key_fullidid = NULL;
+
+ freez(rs->key_fullidname);
+ rs->key_fullidname = NULL;
+
+ freez(rs->key_contextid);
+ rs->key_contextid = NULL;
+
+ freez(rs->key_contextname);
+ rs->key_contextname = NULL;
+
+ freez(rs->key_fullnameid);
+ rs->key_fullnameid = NULL;
+
+ freez(rs->key_fullnamename);
+ rs->key_fullnamename = NULL;
+}
+
+static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
+ rrddimvar_free_variables(rs);
+
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+
+ char buffer[RRDDIMVAR_ID_MAX + 1];
+
+ // KEYS
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
+ rs->key_id = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
+ rs->key_name = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
+ rs->key_fullidid = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
+ rs->key_fullidname = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
+ rs->key_contextid = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
+ rs->key_contextname = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
+ rs->key_fullnameid = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
+ rs->key_fullnamename = strdupz(buffer);
+
+ // CHART VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $id
+ // - $name
+
+ rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value);
+ rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value);
+
+ // FAMILY VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $id (only the first, when multiple overlap)
+ // - $name (only the first, when multiple overlap)
+ // - $chart-context.id
+ // - $chart-context.name
+
+ rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value);
+ rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value);
+ rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value);
+ rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value);
+
+ // HOST VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $chart-id.id
+ // - $chart-id.name
+ // - $chart-name.id
+ // - $chart-name.name
+
+ rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value);
+ rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value);
+ rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value);
+ rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value);
+}
+
+RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
+ RRDSET *st = rd->rrdset;
+
+ debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", st->id, st->name, rd->id, (prefix)?prefix:"", rd->name, (suffix)?suffix:"");
+
+ if(!prefix) prefix = "";
+ if(!suffix) suffix = "";
+
+ RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
+
+ rs->prefix = strdupz(prefix);
+ rs->suffix = strdupz(suffix);
+
+ rs->type = type;
+ rs->value = value;
+ rs->options = options;
+ rs->rrddim = rd;
+
+ rs->next = rd->variables;
+ rd->variables = rs;
+
+ rrddimvar_create_variables(rs);
+
+ return rs;
+}
+
+void rrddimvar_rename_all(RRDDIM *rd) {
+ RRDSET *st = rd->rrdset;
+ debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+
+ RRDDIMVAR *rs, *next = rd->variables;
+ while((rs = next)) {
+ next = rs->next;
+ rrddimvar_create_variables(rs);
+ }
+}
+
+void rrddimvar_free(RRDDIMVAR *rs) {
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+ debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", st->id, st->name, rd->id, rd->name, rs->prefix, rs->suffix);
+
+ rrddimvar_free_variables(rs);
+
+ if(rd->variables == rs) {
+ debug(D_VARIABLES, "RRDDIMSET removing first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+ rd->variables = rs->next;
+ }
+ else {
+ debug(D_VARIABLES, "RRDDIMSET removing non-first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+ RRDDIMVAR *t;
+ for (t = rd->variables; t && t->next != rs; t = t->next) ;
+ if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
+ else t->next = rs->next;
+ }
+
+ freez(rs->prefix);
+ freez(rs->suffix);
+ freez(rs);
+}
+
diff --git a/src/rrdfamily.c b/src/rrdfamily.c
new file mode 100644
index 000000000..fc203e915
--- /dev/null
+++ b/src/rrdfamily.c
@@ -0,0 +1,58 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDFAMILY index
+
+int rrdfamily_compare(void *a, void *b) {
+ if(((RRDFAMILY *)a)->hash_family < ((RRDFAMILY *)b)->hash_family) return -1;
+ else if(((RRDFAMILY *)a)->hash_family > ((RRDFAMILY *)b)->hash_family) return 1;
+ else return strcmp(((RRDFAMILY *)a)->family, ((RRDFAMILY *)b)->family);
+}
+
+#define rrdfamily_index_add(host, rc) (RRDFAMILY *)avl_insert_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
+#define rrdfamily_index_del(host, rc) (RRDFAMILY *)avl_remove_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
+
+static RRDFAMILY *rrdfamily_index_find(RRDHOST *host, const char *id, uint32_t hash) {
+ RRDFAMILY tmp;
+ tmp.family = id;
+ tmp.hash_family = (hash)?hash:simple_hash(tmp.family);
+
+ return (RRDFAMILY *)avl_search_lock(&(host->rrdfamily_root_index), (avl *) &tmp);
+}
+
+RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id) {
+ RRDFAMILY *rc = rrdfamily_index_find(host, id, 0);
+ if(!rc) {
+ rc = callocz(1, sizeof(RRDFAMILY));
+
+ rc->family = strdupz(id);
+ rc->hash_family = simple_hash(rc->family);
+
+ // initialize the variables index
+ avl_init_lock(&rc->variables_root_index, rrdvar_compare);
+
+ RRDFAMILY *ret = rrdfamily_index_add(host, rc);
+ if(ret != rc)
+ fatal("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE");
+ }
+
+ rc->use_count++;
+ return rc;
+}
+
+void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc) {
+ rc->use_count--;
+ if(!rc->use_count) {
+ RRDFAMILY *ret = rrdfamily_index_del(host, rc);
+ if(ret != rc)
+ fatal("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE");
+
+ if(rc->variables_root_index.avl_tree.root != NULL)
+ fatal("RRDFAMILY: INTERNAL ERROR: Variables index of RRDFAMILY '%s' that is freed, is not empty.", rc->family);
+
+ freez((void *)rc->family);
+ freez(rc);
+ }
+}
+
diff --git a/src/rrdhost.c b/src/rrdhost.c
new file mode 100644
index 000000000..a2310330d
--- /dev/null
+++ b/src/rrdhost.c
@@ -0,0 +1,583 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+RRDHOST *localhost = NULL;
+size_t rrd_hosts_available = 0;
+netdata_rwlock_t rrd_rwlock = NETDATA_RWLOCK_INITIALIZER;
+
+time_t rrdset_free_obsolete_time = 3600;
+time_t rrdhost_free_orphan_time = 3600;
+
+// ----------------------------------------------------------------------------
+// RRDHOST index
+
+int rrdhost_compare(void* a, void* b) {
+ if(((RRDHOST *)a)->hash_machine_guid < ((RRDHOST *)b)->hash_machine_guid) return -1;
+ else if(((RRDHOST *)a)->hash_machine_guid > ((RRDHOST *)b)->hash_machine_guid) return 1;
+ else return strcmp(((RRDHOST *)a)->machine_guid, ((RRDHOST *)b)->machine_guid);
+}
+
+avl_tree_lock rrdhost_root_index = {
+ .avl_tree = { NULL, rrdhost_compare },
+ .rwlock = AVL_LOCK_INITIALIZER
+};
+
+RRDHOST *rrdhost_find_by_guid(const char *guid, uint32_t hash) {
+ debug(D_RRDHOST, "Searching in index for host with guid '%s'", guid);
+
+ RRDHOST tmp;
+ strncpyz(tmp.machine_guid, guid, GUID_LEN);
+ tmp.hash_machine_guid = (hash)?hash:simple_hash(tmp.machine_guid);
+
+ return (RRDHOST *)avl_search_lock(&(rrdhost_root_index), (avl *) &tmp);
+}
+
+RRDHOST *rrdhost_find_by_hostname(const char *hostname, uint32_t hash) {
+ if(unlikely(!strcmp(hostname, "localhost")))
+ return localhost;
+
+ if(unlikely(!hash)) hash = simple_hash(hostname);
+
+ rrd_rdlock();
+ RRDHOST *host;
+ rrdhost_foreach_read(host) {
+ if(unlikely((hash == host->hash_hostname && !strcmp(hostname, host->hostname)))) {
+ rrd_unlock();
+ return host;
+ }
+ }
+ rrd_unlock();
+
+ return NULL;
+}
+
+#define rrdhost_index_add(rrdhost) (RRDHOST *)avl_insert_lock(&(rrdhost_root_index), (avl *)(rrdhost))
+#define rrdhost_index_del(rrdhost) (RRDHOST *)avl_remove_lock(&(rrdhost_root_index), (avl *)(rrdhost))
+
+
+// ----------------------------------------------------------------------------
+// RRDHOST - internal helpers
+
+static inline void rrdhost_init_hostname(RRDHOST *host, const char *hostname) {
+ freez(host->hostname);
+ host->hostname = strdupz(hostname);
+ host->hash_hostname = simple_hash(host->hostname);
+}
+
+static inline void rrdhost_init_os(RRDHOST *host, const char *os) {
+ freez(host->os);
+ host->os = strdupz(os?os:"unknown");
+}
+
+static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_guid) {
+ strncpy(host->machine_guid, machine_guid, GUID_LEN);
+ host->machine_guid[GUID_LEN] = '\0';
+ host->hash_machine_guid = simple_hash(host->machine_guid);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDHOST - add a host
+
+RRDHOST *rrdhost_create(const char *hostname,
+ const char *guid,
+ const char *os,
+ int update_every,
+ long entries,
+ RRD_MEMORY_MODE memory_mode,
+ int health_enabled,
+ int rrdpush_enabled,
+ char *rrdpush_destination,
+ char *rrdpush_api_key,
+ int is_localhost
+) {
+ debug(D_RRDHOST, "Host '%s': adding with guid '%s'", hostname, guid);
+
+ rrd_check_wrlock();
+
+ RRDHOST *host = callocz(1, sizeof(RRDHOST));
+
+ host->rrd_update_every = (update_every > 0)?update_every:1;
+ host->rrd_history_entries = align_entries_to_pagesize(memory_mode, entries);
+ host->rrd_memory_mode = memory_mode;
+ host->health_enabled = (memory_mode == RRD_MEMORY_MODE_NONE)? 0 : health_enabled;
+ host->rrdpush_enabled = (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key);
+ host->rrdpush_destination = (host->rrdpush_enabled)?strdupz(rrdpush_destination):NULL;
+ host->rrdpush_api_key = (host->rrdpush_enabled)?strdupz(rrdpush_api_key):NULL;
+
+ host->rrdpush_pipe[0] = -1;
+ host->rrdpush_pipe[1] = -1;
+ host->rrdpush_socket = -1;
+
+ netdata_mutex_init(&host->rrdpush_mutex);
+ netdata_rwlock_init(&host->rrdhost_rwlock);
+
+ rrdhost_init_hostname(host, hostname);
+ rrdhost_init_machine_guid(host, guid);
+ rrdhost_init_os(host, os);
+
+ avl_init_lock(&(host->rrdset_root_index), rrdset_compare);
+ avl_init_lock(&(host->rrdset_root_index_name), rrdset_compare_name);
+ avl_init_lock(&(host->rrdfamily_root_index), rrdfamily_compare);
+ avl_init_lock(&(host->variables_root_index), rrdvar_compare);
+
+ if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete obsolete charts files", 1))
+ rrdhost_flag_set(host, RRDHOST_DELETE_OBSOLETE_FILES);
+
+ if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete orphan hosts files", 1) && !is_localhost)
+ rrdhost_flag_set(host, RRDHOST_DELETE_ORPHAN_FILES);
+
+
+ // ------------------------------------------------------------------------
+ // initialize health variables
+
+ host->health_log.next_log_id = 1;
+ host->health_log.next_alarm_id = 1;
+ host->health_log.max = 1000;
+ host->health_log.next_log_id =
+ host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
+
+ long n = config_get_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", host->health_log.max);
+ if(n < 10) {
+ error("Host '%s': health configuration has invalid max log entries %ld. Using default %u", host->hostname, n, host->health_log.max);
+ config_set_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", (long)host->health_log.max);
+ }
+ else
+ host->health_log.max = (unsigned int)n;
+
+ netdata_rwlock_init(&host->health_log.alarm_log_rwlock);
+
+ char filename[FILENAME_MAX + 1];
+
+ if(is_localhost) {
+
+ host->cache_dir = strdupz(netdata_configured_cache_dir);
+ host->varlib_dir = strdupz(netdata_configured_varlib_dir);
+
+ }
+ else {
+ // this is not localhost - append our GUID to localhost path
+
+ snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_cache_dir, host->machine_guid);
+ host->cache_dir = strdupz(filename);
+
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_MAP || host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ int r = mkdir(host->cache_dir, 0775);
+ if(r != 0 && errno != EEXIST)
+ error("Host '%s': cannot create directory '%s'", host->hostname, host->cache_dir);
+ }
+
+ snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_varlib_dir, host->machine_guid);
+ host->varlib_dir = strdupz(filename);
+
+ if(host->health_enabled) {
+ int r = mkdir(host->varlib_dir, 0775);
+ if(r != 0 && errno != EEXIST)
+ error("Host '%s': cannot create directory '%s'", host->hostname, host->varlib_dir);
+ }
+
+ }
+
+ if(host->health_enabled) {
+ snprintfz(filename, FILENAME_MAX, "%s/health", host->varlib_dir);
+ int r = mkdir(filename, 0775);
+ if(r != 0 && errno != EEXIST)
+ error("Host '%s': cannot create directory '%s'", host->hostname, filename);
+ }
+
+ snprintfz(filename, FILENAME_MAX, "%s/health/health-log.db", host->varlib_dir);
+ host->health_log_filename = strdupz(filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_plugins_dir);
+ host->health_default_exec = strdupz(config_get(CONFIG_SECTION_HEALTH, "script to execute on alarm", filename));
+ host->health_default_recipient = strdup("root");
+
+
+ // ------------------------------------------------------------------------
+ // load health configuration
+
+ if(host->health_enabled) {
+ health_alarm_log_load(host);
+ health_alarm_log_open(host);
+
+ rrdhost_wrlock(host);
+ health_readdir(host, health_config_dir());
+ rrdhost_unlock(host);
+ }
+
+
+ // ------------------------------------------------------------------------
+ // link it and add it to the index
+
+ if(is_localhost) {
+ host->next = localhost;
+ localhost = host;
+ }
+ else {
+ if(localhost) {
+ host->next = localhost->next;
+ localhost->next = host;
+ }
+ else localhost = host;
+ }
+
+ RRDHOST *t = rrdhost_index_add(host);
+
+ if(t != host) {
+ error("Host '%s': cannot add host with machine guid '%s' to index. It already exists as host '%s' with machine guid '%s'.", host->hostname, host->machine_guid, t->hostname, t->machine_guid);
+ rrdhost_free(host);
+ host = NULL;
+ }
+ else {
+ info("Host '%s' with guid '%s' initialized"
+ ", os %s"
+ ", update every %d"
+ ", memory mode %s"
+ ", history entries %ld"
+ ", streaming %s"
+ " (to '%s' with api key '%s')"
+ ", health %s"
+ ", cache_dir '%s'"
+ ", varlib_dir '%s'"
+ ", health_log '%s'"
+ ", alarms default handler '%s'"
+ ", alarms default recipient '%s'"
+ , host->hostname
+ , host->machine_guid
+ , host->os
+ , host->rrd_update_every
+ , rrd_memory_mode_name(host->rrd_memory_mode)
+ , host->rrd_history_entries
+ , host->rrdpush_enabled?"enabled":"disabled"
+ , host->rrdpush_destination?host->rrdpush_destination:""
+ , host->rrdpush_api_key?host->rrdpush_api_key:""
+ , host->health_enabled?"enabled":"disabled"
+ , host->cache_dir
+ , host->varlib_dir
+ , host->health_log_filename
+ , host->health_default_exec
+ , host->health_default_recipient
+ );
+ }
+
+ rrd_hosts_available++;
+
+ return host;
+}
+
+RRDHOST *rrdhost_find_or_create(
+ const char *hostname
+ , const char *guid
+ , const char *os
+ , int update_every
+ , long history
+ , RRD_MEMORY_MODE mode
+ , int health_enabled
+ , int rrdpush_enabled
+ , char *rrdpush_destination
+ , char *rrdpush_api_key
+) {
+ debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
+
+ rrd_wrlock();
+ RRDHOST *host = rrdhost_find_by_guid(guid, 0);
+ if(!host) {
+ host = rrdhost_create(
+ hostname
+ , guid
+ , os
+ , update_every
+ , history
+ , mode
+ , health_enabled
+ , rrdpush_enabled
+ , rrdpush_destination
+ , rrdpush_api_key
+ , 0
+ );
+ }
+ else {
+ host->health_enabled = health_enabled;
+
+ if(strcmp(host->hostname, hostname)) {
+ char *t = host->hostname;
+ host->hostname = strdupz(hostname);
+ host->hash_hostname = simple_hash(host->hostname);
+ freez(t);
+ }
+
+ if(host->rrd_update_every != update_every)
+ error("Host '%s' has an update frequency of %d seconds, but the wanted one is %d seconds.", host->hostname, host->rrd_update_every, update_every);
+
+ if(host->rrd_history_entries != history)
+ error("Host '%s' has history of %ld entries, but the wanted one is %ld entries.", host->hostname, host->rrd_history_entries, history);
+
+ if(host->rrd_memory_mode != mode)
+ error("Host '%s' has memory mode '%s', but the wanted one is '%s'.", host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
+ }
+ rrd_unlock();
+
+ rrdhost_cleanup_orphan(host);
+
+ return host;
+}
+
+static inline int rrdhost_should_be_deleted(RRDHOST *host, RRDHOST *protected, time_t now) {
+ if(host != protected
+ && host != localhost
+ && !host->connected_senders
+ && host->senders_disconnected_time
+ && host->senders_disconnected_time + rrdhost_free_orphan_time < now)
+ return 1;
+
+ return 0;
+}
+
+void rrdhost_cleanup_orphan(RRDHOST *protected) {
+ time_t now = now_realtime_sec();
+
+ rrd_wrlock();
+
+ RRDHOST *host;
+
+restart_after_removal:
+ rrdhost_foreach_write(host) {
+ if(rrdhost_should_be_deleted(host, protected, now)) {
+ info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", host->hostname, host->machine_guid);
+
+ if(rrdset_flag_check(host, RRDHOST_ORPHAN))
+ rrdhost_delete(host);
+ else
+ rrdhost_save(host);
+
+ rrdhost_free(host);
+ goto restart_after_removal;
+ }
+ }
+
+ rrd_unlock();
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST global / startup initialization
+
+void rrd_init(char *hostname) {
+ rrdset_free_obsolete_time = config_get_number(CONFIG_SECTION_GLOBAL, "cleanup obsolete charts after seconds", rrdset_free_obsolete_time);
+
+ health_init();
+ registry_init();
+ rrdpush_init();
+
+ debug(D_RRDHOST, "Initializing localhost with hostname '%s'", hostname);
+ rrd_wrlock();
+ localhost = rrdhost_create(
+ hostname
+ , registry_get_this_machine_guid()
+ , os_type
+ , default_rrd_update_every
+ , default_rrd_history_entries
+ , default_rrd_memory_mode
+ , default_health_enabled
+ , default_rrdpush_enabled
+ , default_rrdpush_destination
+ , default_rrdpush_api_key
+ , 1
+ );
+ rrd_unlock();
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - lock validations
+// there are only used when NETDATA_INTERNAL_CHECKS is set
+
+void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking read lock on host '%s'", host->hostname);
+
+ int ret = netdata_rwlock_trywrlock(&host->rrdhost_rwlock);
+ if(ret == 0)
+ fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
+}
+
+void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking write lock on host '%s'", host->hostname);
+
+ int ret = netdata_rwlock_tryrdlock(&host->rrdhost_rwlock);
+ if(ret == 0)
+ fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
+}
+
+void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking read lock on all RRDs");
+
+ int ret = netdata_rwlock_trywrlock(&rrd_rwlock);
+ if(ret == 0)
+ fatal("RRDs should be read-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
+}
+
+void __rrd_check_wrlock(const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking write lock on all RRDs");
+
+ int ret = netdata_rwlock_tryrdlock(&rrd_rwlock);
+ if(ret == 0)
+ fatal("RRDs should be write-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - free
+
+void rrdhost_free(RRDHOST *host) {
+ if(!host) return;
+
+ info("Freeing all memory for host '%s'...", host->hostname);
+
+ rrd_check_wrlock(); // make sure the RRDs are write locked
+
+ // stop a possibly running thread
+ rrdpush_sender_thread_stop(host);
+
+ rrdhost_wrlock(host); // lock this RRDHOST
+
+ // ------------------------------------------------------------------------
+ // release its children resources
+
+ while(host->rrdset_root) rrdset_free(host->rrdset_root);
+
+ while(host->alarms) rrdcalc_free(host, host->alarms);
+ while(host->templates) rrdcalctemplate_free(host, host->templates);
+ health_alarm_log_free(host);
+
+
+ // ------------------------------------------------------------------------
+ // remove it from the indexes
+
+ if(rrdhost_index_del(host) != host)
+ error("RRDHOST '%s' removed from index, deleted the wrong entry.", host->hostname);
+
+
+ // ------------------------------------------------------------------------
+ // unlink it from the host
+
+ if(host == localhost) {
+ localhost = host->next;
+ }
+ else {
+ // find the previous one
+ RRDHOST *h;
+ for(h = localhost; h && h->next != host ; h = h->next) ;
+
+ // bypass it
+ if(h) h->next = host->next;
+ else error("Request to free RRDHOST '%s': cannot find it", host->hostname);
+ }
+
+ // ------------------------------------------------------------------------
+ // free it
+
+ freez(host->os);
+ freez(host->cache_dir);
+ freez(host->varlib_dir);
+ freez(host->rrdpush_api_key);
+ freez(host->rrdpush_destination);
+ freez(host->health_default_exec);
+ freez(host->health_default_recipient);
+ freez(host->health_log_filename);
+ freez(host->hostname);
+ rrdhost_unlock(host);
+ netdata_rwlock_destroy(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_destroy(&host->rrdhost_rwlock);
+ freez(host);
+
+ rrd_hosts_available--;
+}
+
+void rrdhost_free_all(void) {
+ rrd_wrlock();
+ while(localhost) rrdhost_free(localhost);
+ rrd_unlock();
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - save
+
+void rrdhost_save(RRDHOST *host) {
+ if(!host) return;
+
+ info("Saving database of host '%s'...", host->hostname);
+
+ RRDSET *st;
+
+ // we get a write lock
+ // to ensure only one thread is saving the database
+ rrdhost_wrlock(host);
+
+ rrdset_foreach_write(st, host) {
+ rrdset_rdlock(st);
+ rrdset_save(st);
+ rrdset_unlock(st);
+ }
+
+ rrdhost_unlock(host);
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - delete files
+
+void rrdhost_delete(RRDHOST *host) {
+ if(!host) return;
+
+ info("Deleting database of host '%s'...", host->hostname);
+
+ RRDSET *st;
+
+ // we get a write lock
+ // to ensure only one thread is saving the database
+ rrdhost_wrlock(host);
+
+ rrdset_foreach_write(st, host) {
+ rrdset_rdlock(st);
+ rrdset_delete(st);
+ rrdset_unlock(st);
+ }
+
+ rrdhost_unlock(host);
+}
+
+void rrdhost_save_all(void) {
+ info("Saving database [%zu hosts(s)]...", rrd_hosts_available);
+
+ rrd_rdlock();
+
+ RRDHOST *host;
+ rrdhost_foreach_read(host)
+ rrdhost_save(host);
+
+ rrd_unlock();
+}
+
+void rrdhost_cleanup_obsolete(RRDHOST *host) {
+ time_t now = now_realtime_sec();
+
+ RRDSET *st;
+
+restart_after_removal:
+ rrdset_foreach_write(st, host) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)
+ && st->last_accessed_time + rrdset_free_obsolete_time < now
+ && st->last_updated.tv_sec + rrdset_free_obsolete_time < now
+ && st->last_collected_time.tv_sec + rrdset_free_obsolete_time < now
+ )) {
+
+ rrdset_rdlock(st);
+
+ if(rrdhost_flag_check(host, RRDHOST_DELETE_OBSOLETE_FILES))
+ rrdset_delete(st);
+ else
+ rrdset_save(st);
+
+ rrdset_unlock(st);
+
+ rrdset_free(st);
+ goto restart_after_removal;
+ }
+ }
+}
diff --git a/src/rrdpush.c b/src/rrdpush.c
new file mode 100644
index 000000000..72e6d8a73
--- /dev/null
+++ b/src/rrdpush.c
@@ -0,0 +1,761 @@
+#include "common.h"
+
+/*
+ * rrdpush
+ *
+ * 3 threads are involved for all stream operations
+ *
+ * 1. a random data collection thread, calling rrdset_done_push()
+ * this is called for each chart.
+ *
+ * the output of this work is kept in a BUFFER in RRDHOST
+ * the sender thread is signalled via a pipe (also in RRDHOST)
+ *
+ * 2. a sender thread running at the sending netdata
+ * this is spawned automatically on the first chart to be pushed
+ *
+ * It tries to push the metrics to the remote netdata, as fast
+ * as possible (i.e. immediately after they are collected).
+ *
+ * 3. a receiver thread, running at the receiving netdata
+ * this is spawned automatically when the sender connects to
+ * the receiver.
+ *
+ */
+
+#define START_STREAMING_PROMPT "Hit me baby, push them over..."
+
+int default_rrdpush_enabled = 0;
+char *default_rrdpush_destination = NULL;
+char *default_rrdpush_api_key = NULL;
+
+int rrdpush_init() {
+ default_rrdpush_enabled = appconfig_get_boolean(&stream_config, CONFIG_SECTION_STREAM, "enabled", default_rrdpush_enabled);
+ default_rrdpush_destination = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "destination", "");
+ default_rrdpush_api_key = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "api key", "");
+ rrdhost_free_orphan_time = config_get_number(CONFIG_SECTION_GLOBAL, "cleanup orphan hosts after seconds", rrdhost_free_orphan_time);
+
+ if(default_rrdpush_enabled && (!default_rrdpush_destination || !*default_rrdpush_destination || !default_rrdpush_api_key || !*default_rrdpush_api_key)) {
+ error("STREAM [send]: cannot enable sending thread - information is missing.");
+ default_rrdpush_enabled = 0;
+ }
+
+ return default_rrdpush_enabled;
+}
+
+#define CONNECTED_TO_SIZE 100
+
+// data collection happens from multiple threads
+// each of these threads calls rrdset_done()
+// which in turn calls rrdset_done_push()
+// which uses this pipe to notify the streaming thread
+// that there are more data ready to be sent
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+// to have the remote netdata re-sync the charts
+// to its current clock, we send for this many
+// iterations a BEGIN line without microseconds
+// this is for the first iterations of each chart
+static unsigned int remote_clock_resync_iterations = 60;
+
+#define rrdpush_lock(host) netdata_mutex_lock(&((host)->rrdpush_mutex))
+#define rrdpush_unlock(host) netdata_mutex_unlock(&((host)->rrdpush_mutex))
+
+// checks if the current chart definition has been sent
+static inline int need_to_send_chart_definition(RRDSET *st) {
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st)
+ if(!rd->exposed)
+ return 1;
+
+ return 0;
+}
+
+// sends the current chart definition
+static inline void send_chart_definition(RRDSET *st) {
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "CHART '%s' '%s' '%s' '%s' '%s' '%s' '%s' %ld %d\n"
+ , st->id
+ , st->name
+ , st->title
+ , st->units
+ , st->family
+ , st->context
+ , rrdset_type_name(st->chart_type)
+ , st->priority
+ , st->update_every
+ );
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "DIMENSION '%s' '%s' '%s' " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " '%s %s'\n"
+ , rd->id
+ , rd->name
+ , rrd_algorithm_name(rd->algorithm)
+ , rd->multiplier
+ , rd->divisor
+ , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?"hidden":""
+ , rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)?"noreset":""
+ );
+ rd->exposed = 1;
+ }
+}
+
+// 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->counter_done > remote_clock_resync_iterations)?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"
+ , rd->id
+ , rd->collected_value
+ );
+ }
+
+ buffer_strcat(st->rrdhost->rrdpush_buffer, "END\n");
+}
+
+void rrdpush_sender_thread_spawn(RRDHOST *host);
+
+void rrdset_done_push(RRDSET *st) {
+ RRDHOST *host = st->rrdhost;
+
+ if(unlikely(!rrdset_flag_check(st, RRDSET_FLAG_ENABLED)))
+ return;
+
+ rrdpush_lock(host);
+
+ if(unlikely(host->rrdpush_enabled && !host->rrdpush_spawn))
+ rrdpush_sender_thread_spawn(host);
+
+ if(unlikely(!host->rrdpush_buffer || !host->rrdpush_connected)) {
+ if(unlikely(!host->rrdpush_error_shown))
+ error("STREAM %s [send]: not ready - discarding collected metrics.", host->hostname);
+
+ host->rrdpush_error_shown = 1;
+
+ rrdpush_unlock(host);
+ return;
+ }
+ else if(unlikely(host->rrdpush_error_shown)) {
+ info("STREAM %s [send]: ready - sending metrics...", host->hostname);
+ host->rrdpush_error_shown = 0;
+ }
+
+ if(need_to_send_chart_definition(st))
+ send_chart_definition(st);
+
+ send_chart_metrics(st);
+
+ // signal the sender there are more data
+ if(write(host->rrdpush_pipe[PIPE_WRITE], " ", 1) == -1)
+ error("STREAM %s [send]: cannot write to internal pipe", host->hostname);
+
+ rrdpush_unlock(host);
+}
+
+// ----------------------------------------------------------------------------
+// rrdpush sender thread
+
+// resets all the chart, so that their definitions
+// will be resent to the central netdata
+static void rrdpush_sender_thread_reset_all_charts(RRDHOST *host) {
+ rrdhost_rdlock(host);
+
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+
+ // make it re-align the current time
+ // on the remote host
+ st->counter_done = 0;
+
+ rrdset_rdlock(st);
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st)
+ rd->exposed = 0;
+
+ rrdset_unlock(st);
+ }
+
+ rrdhost_unlock(host);
+}
+
+static inline void rrdpush_sender_thread_data_flush(RRDHOST *host) {
+ rrdpush_lock(host);
+
+ if(buffer_strlen(host->rrdpush_buffer))
+ error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", host->hostname, buffer_strlen(host->rrdpush_buffer));
+
+ buffer_flush(host->rrdpush_buffer);
+
+ rrdpush_sender_thread_reset_all_charts(host);
+
+ rrdpush_unlock(host);
+}
+
+static void rrdpush_sender_thread_cleanup_locked_all(RRDHOST *host) {
+ host->rrdpush_connected = 0;
+
+ if(host->rrdpush_socket != -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+
+ // close the pipe
+ if(host->rrdpush_pipe[PIPE_READ] != -1) {
+ close(host->rrdpush_pipe[PIPE_READ]);
+ host->rrdpush_pipe[PIPE_READ] = -1;
+ }
+
+ if(host->rrdpush_pipe[PIPE_WRITE] != -1) {
+ close(host->rrdpush_pipe[PIPE_WRITE]);
+ host->rrdpush_pipe[PIPE_WRITE] = -1;
+ }
+
+ buffer_free(host->rrdpush_buffer);
+ host->rrdpush_buffer = NULL;
+
+ host->rrdpush_spawn = 0;
+
+ rrdhost_flag_set(host, RRDHOST_ORPHAN);
+}
+
+void rrdpush_sender_thread_stop(RRDHOST *host) {
+ rrdpush_lock(host);
+ rrdhost_wrlock(host);
+
+ if(host->rrdpush_spawn) {
+ info("STREAM %s [send]: stopping sending thread...", host->hostname);
+ pthread_cancel(host->rrdpush_thread);
+ rrdpush_sender_thread_cleanup_locked_all(host);
+ }
+
+ rrdhost_unlock(host);
+ rrdpush_unlock(host);
+}
+
+void *rrdpush_sender_thread(void *ptr) {
+ RRDHOST *host = (RRDHOST *)ptr;
+
+ info("STREAM %s [send]: thread created (task id %d)", host->hostname, gettid());
+
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel type to DEFERRED.", host->hostname);
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname);
+
+ int timeout = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "timeout seconds", 60);
+ int default_port = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "default port", 19999);
+ size_t max_size = (size_t)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "buffer size bytes", 1024 * 1024);
+ unsigned int reconnect_delay = (unsigned int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "reconnect delay seconds", 5);
+ remote_clock_resync_iterations = (unsigned int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "initial clock resync iterations", remote_clock_resync_iterations);
+ char connected_to[CONNECTED_TO_SIZE + 1] = "";
+
+ if(!host->rrdpush_enabled || !host->rrdpush_destination || !*host->rrdpush_destination || !host->rrdpush_api_key || !*host->rrdpush_api_key)
+ goto cleanup;
+
+ // initialize rrdpush globals
+ host->rrdpush_buffer = buffer_create(1);
+ host->rrdpush_connected = 0;
+ if(pipe(host->rrdpush_pipe) == -1) fatal("STREAM %s [send]: cannot create required pipe.", host->hostname);
+
+ // initialize local variables
+ size_t begin = 0;
+ size_t reconnects_counter = 0;
+ size_t sent_bytes = 0;
+ size_t sent_connection = 0;
+
+ struct timeval tv = {
+ .tv_sec = timeout,
+ .tv_usec = 0
+ };
+
+ struct pollfd fds[2], *ifd, *ofd;
+ nfds_t fdmax;
+
+ ifd = &fds[0];
+ ofd = &fds[1];
+
+ for(; host->rrdpush_enabled && !netdata_exit ;) {
+
+ if(unlikely(host->rrdpush_socket == -1)) {
+ // stop appending data into rrdpush_buffer
+ // they will be lost, so there is no point to do it
+ host->rrdpush_connected = 0;
+
+ info("STREAM %s [send to %s]: connecting...", host->hostname, host->rrdpush_destination);
+ host->rrdpush_socket = connect_to_one_of(host->rrdpush_destination, default_port, &tv, &reconnects_counter, connected_to, CONNECTED_TO_SIZE);
+
+ if(unlikely(host->rrdpush_socket == -1)) {
+ error("STREAM %s [send to %s]: failed to connect", host->hostname, host->rrdpush_destination);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ info("STREAM %s [send to %s]: initializing communication...", host->hostname, connected_to);
+
+ char http[1000 + 1];
+ snprintfz(http, 1000,
+ "STREAM key=%s&hostname=%s&machine_guid=%s&os=%s&update_every=%d HTTP/1.1\r\n"
+ "User-Agent: netdata-push-service/%s\r\n"
+ "Accept: */*\r\n\r\n"
+ , host->rrdpush_api_key
+ , host->hostname
+ , host->machine_guid
+ , host->os
+ , default_rrd_update_every
+ , program_version
+ );
+
+ if(send_timeout(host->rrdpush_socket, http, strlen(http), 0, timeout) == -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ error("STREAM %s [send to %s]: failed to send http header to netdata", host->hostname, connected_to);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, connected_to);
+
+ if(recv_timeout(host->rrdpush_socket, http, 1000, 0, timeout) == -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ error("STREAM %s [send to %s]: failed to initialize communication", host->hostname, connected_to);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ if(strncmp(http, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT))) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ error("STREAM %s [send to %s]: server is not replying properly.", host->hostname, connected_to);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ info("STREAM %s [send to %s]: established communication - sending metrics...", host->hostname, connected_to);
+
+ if(fcntl(host->rrdpush_socket, F_SETFL, O_NONBLOCK) < 0)
+ error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", host->hostname, connected_to);
+
+ rrdpush_sender_thread_data_flush(host);
+ sent_connection = 0;
+
+ // allow appending data into rrdpush_buffer
+ host->rrdpush_connected = 1;
+ }
+
+ ifd->fd = host->rrdpush_pipe[PIPE_READ];
+ ifd->events = POLLIN;
+ ifd->revents = 0;
+
+ ofd->fd = host->rrdpush_socket;
+ ofd->revents = 0;
+ if(begin < buffer_strlen(host->rrdpush_buffer)) {
+ ofd->events = POLLOUT;
+ fdmax = 2;
+ }
+ else {
+ ofd->events = 0;
+ fdmax = 1;
+ }
+
+ if(netdata_exit) break;
+ int retval = poll(fds, fdmax, timeout * 1000);
+ if(netdata_exit) break;
+
+ if(unlikely(retval == -1)) {
+ if(errno == EAGAIN || errno == EINTR)
+ continue;
+
+ error("STREAM %s [send to %s]: failed to poll().", host->hostname, connected_to);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ break;
+ }
+ else if(unlikely(!retval)) {
+ // timeout
+ continue;
+ }
+
+ if(ifd->revents & POLLIN) {
+ char buffer[1000 + 1];
+ if(read(host->rrdpush_pipe[PIPE_READ], buffer, 1000) == -1)
+ 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)) {
+
+ // 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);
+
+ rrdpush_lock(host);
+
+ ssize_t ret = send(host->rrdpush_socket, &host->rrdpush_buffer->buffer[begin], buffer_strlen(host->rrdpush_buffer) - begin, MSG_DONTWAIT);
+ if(ret == -1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ 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 {
+ sent_connection += ret;
+ sent_bytes += ret;
+ begin += ret;
+ if(begin == buffer_strlen(host->rrdpush_buffer)) {
+ // we send it all
+
+ buffer_flush(host->rrdpush_buffer);
+ begin = 0;
+ }
+ }
+
+ 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
+ }
+
+ // protection from overflow
+ if(host->rrdpush_buffer->len > max_size) {
+ errno = 0;
+ error("STREAM %s [send to %s]: too many data pending - buffer is %zu bytes long, %zu unsent - we have sent %zu bytes in total, %zu on this connection. Closing connection to flush the data.", host->hostname, connected_to, host->rrdpush_buffer->len, host->rrdpush_buffer->len - begin, sent_bytes, sent_connection);
+ if(host->rrdpush_socket != -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+ }
+ }
+
+cleanup:
+ debug(D_WEB_CLIENT, "STREAM %s [send]: sending thread exits.", host->hostname);
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname);
+
+ rrdpush_lock(host);
+ rrdhost_wrlock(host);
+ rrdpush_sender_thread_cleanup_locked_all(host);
+ rrdhost_unlock(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);
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// rrdpush receiver thread
+
+int rrdpush_receive(int fd, const char *key, const char *hostname, const char *machine_guid, const char *os, int update_every, char *client_ip, char *client_port) {
+ RRDHOST *host;
+ int history = default_rrd_history_entries;
+ RRD_MEMORY_MODE mode = default_rrd_memory_mode;
+ int health_enabled = default_health_enabled;
+ int rrdpush_enabled = default_rrdpush_enabled;
+ char *rrdpush_destination = default_rrdpush_destination;
+ char *rrdpush_api_key = default_rrdpush_api_key;
+ time_t alarms_delay = 60;
+
+ update_every = (int)appconfig_get_number(&stream_config, machine_guid, "update every", update_every);
+ if(update_every < 0) update_every = 1;
+
+ history = (int)appconfig_get_number(&stream_config, key, "default history", history);
+ history = (int)appconfig_get_number(&stream_config, machine_guid, "history", history);
+ if(history < 5) history = 5;
+
+ mode = rrd_memory_mode_id(appconfig_get(&stream_config, key, "default memory mode", rrd_memory_mode_name(mode)));
+ mode = rrd_memory_mode_id(appconfig_get(&stream_config, machine_guid, "memory mode", rrd_memory_mode_name(mode)));
+
+ health_enabled = appconfig_get_boolean_ondemand(&stream_config, key, "health enabled by default", health_enabled);
+ health_enabled = appconfig_get_boolean_ondemand(&stream_config, machine_guid, "health enabled", health_enabled);
+
+ alarms_delay = appconfig_get_number(&stream_config, key, "default postpone alarms on connect seconds", alarms_delay);
+ alarms_delay = appconfig_get_number(&stream_config, machine_guid, "postpone alarms on connect seconds", alarms_delay);
+
+ rrdpush_enabled = appconfig_get_boolean(&stream_config, key, "default proxy enabled", rrdpush_enabled);
+ rrdpush_enabled = appconfig_get_boolean(&stream_config, machine_guid, "proxy enabled", rrdpush_enabled);
+
+ rrdpush_destination = appconfig_get(&stream_config, key, "default proxy destination", rrdpush_destination);
+ rrdpush_destination = appconfig_get(&stream_config, machine_guid, "proxy destination", rrdpush_destination);
+
+ rrdpush_api_key = appconfig_get(&stream_config, key, "default proxy api key", rrdpush_api_key);
+ rrdpush_api_key = appconfig_get(&stream_config, machine_guid, "proxy api key", rrdpush_api_key);
+
+ if(!strcmp(machine_guid, "localhost"))
+ host = localhost;
+ else
+ host = rrdhost_find_or_create(
+ hostname
+ , machine_guid
+ , os
+ , update_every
+ , history
+ , mode
+ , (health_enabled != CONFIG_BOOLEAN_NO)
+ , (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key)
+ , rrdpush_destination
+ , rrdpush_api_key
+ );
+
+ if(!host) {
+ close(fd);
+ error("STREAM %s [receive from [%s]:%s]: failed to find/create host structure.", hostname, client_ip, client_port);
+ return 1;
+ }
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ info("STREAM %s [receive from [%s]:%s]: client willing to stream metrics for host '%s' with machine_guid '%s': update every = %d, history = %ld, memory mode = %s, health %s"
+ , hostname
+ , client_ip
+ , client_port
+ , host->hostname
+ , host->machine_guid
+ , host->rrd_update_every
+ , 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")
+ );
+#endif // NETDATA_INTERNAL_CHECKS
+
+ struct plugind cd = {
+ .enabled = 1,
+ .update_every = default_rrd_update_every,
+ .pid = 0,
+ .serial_failures = 0,
+ .successful_collections = 0,
+ .obsolete = 0,
+ .started_t = now_realtime_sec(),
+ .next = NULL,
+ };
+
+ // put the client IP and port into the buffers used by plugins.d
+ snprintfz(cd.id, CONFIG_MAX_NAME, "%s:%s", client_ip, client_port);
+ snprintfz(cd.filename, FILENAME_MAX, "%s:%s", client_ip, client_port);
+ snprintfz(cd.fullfilename, FILENAME_MAX, "%s:%s", client_ip, client_port);
+ snprintfz(cd.cmd, PLUGINSD_CMD_MAX, "%s:%s", client_ip, client_port);
+
+ info("STREAM %s [receive from [%s]:%s]: initializing communication...", host->hostname, client_ip, client_port);
+ if(send_timeout(fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
+ error("STREAM %s [receive from [%s]:%s]: cannot send ready command.", host->hostname, client_ip, client_port);
+ close(fd);
+ return 0;
+ }
+
+ // remove the non-blocking flag from the socket
+ if(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK) == -1)
+ error("STREAM %s [receive from [%s]:%s]: cannot remove the non-blocking flag from socket %d", host->hostname, client_ip, client_port, fd);
+
+ // convert the socket to a FILE *
+ FILE *fp = fdopen(fd, "r");
+ if(!fp) {
+ error("STREAM %s [receive from [%s]:%s]: failed to get a FILE for FD %d.", host->hostname, client_ip, client_port, fd);
+ close(fd);
+ return 0;
+ }
+
+ rrdhost_wrlock(host);
+ host->connected_senders++;
+ if(health_enabled != CONFIG_BOOLEAN_NO)
+ host->health_delay_up_to = now_realtime_sec() + alarms_delay;
+ rrdhost_unlock(host);
+
+ // call the plugins.d processor to receive the metrics
+ info("STREAM %s [receive from [%s]:%s]: receiving metrics...", host->hostname, client_ip, client_port);
+ size_t count = pluginsd_process(host, &cd, fp, 1);
+ error("STREAM %s [receive from [%s]:%s]: disconnected (completed updates %zu).", host->hostname, client_ip, client_port, count);
+
+ rrdhost_wrlock(host);
+ host->senders_disconnected_time = now_realtime_sec();
+ host->connected_senders--;
+ if(!host->connected_senders) {
+ if(health_enabled == CONFIG_BOOLEAN_AUTO)
+ host->health_enabled = 0;
+ }
+ rrdhost_unlock(host);
+
+ rrdpush_sender_thread_stop(host);
+
+ // cleanup
+ fclose(fp);
+
+ return (int)count;
+}
+
+struct rrdpush_thread {
+ int fd;
+ char *key;
+ char *hostname;
+ char *machine_guid;
+ char *os;
+ char *client_ip;
+ char *client_port;
+ int update_every;
+};
+
+void *rrdpush_receiver_thread(void *ptr) {
+ struct rrdpush_thread *rpt = (struct rrdpush_thread *)ptr;
+
+ if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("STREAM %s [receive]: cannot set pthread cancel type to DEFERRED.", rpt->hostname);
+
+ if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [receive]: cannot set pthread cancel state to ENABLE.", rpt->hostname);
+
+
+ info("STREAM %s [%s]:%s: receive thread created (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
+ rrdpush_receive(rpt->fd, rpt->key, rpt->hostname, rpt->machine_guid, rpt->os, rpt->update_every, rpt->client_ip, rpt->client_port);
+ info("STREAM %s [receive from [%s]:%s]: receive thread ended (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
+
+ freez(rpt->key);
+ freez(rpt->hostname);
+ freez(rpt->machine_guid);
+ freez(rpt->os);
+ freez(rpt->client_ip);
+ freez(rpt->client_port);
+ freez(rpt);
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void rrdpush_sender_thread_spawn(RRDHOST *host) {
+ rrdhost_wrlock(host);
+
+ if(!host->rrdpush_spawn) {
+ if(pthread_create(&host->rrdpush_thread, NULL, rrdpush_sender_thread, (void *) host))
+ error("STREAM %s [send]: failed to create new thread for client.", host->hostname);
+
+ else if(pthread_detach(host->rrdpush_thread))
+ error("STREAM %s [send]: cannot request detach newly created thread.", host->hostname);
+
+ rrdhost_flag_clear(host, RRDHOST_ORPHAN);
+ host->rrdpush_spawn = 1;
+ }
+
+ rrdhost_unlock(host);
+}
+
+int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url) {
+ (void)host;
+
+ info("STREAM [receive from [%s]:%s]: new client connection.", w->client_ip, w->client_port);
+
+ char *key = NULL, *hostname = NULL, *machine_guid = NULL, *os = "unknown";
+ int update_every = default_rrd_update_every;
+ char buf[GUID_LEN + 1];
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ if(!strcmp(name, "key"))
+ key = value;
+ else if(!strcmp(name, "hostname"))
+ hostname = value;
+ else if(!strcmp(name, "machine_guid"))
+ machine_guid = value;
+ else if(!strcmp(name, "update_every"))
+ update_every = (int)strtoul(value, NULL, 0);
+ else if(!strcmp(name, "os"))
+ os = value;
+ }
+
+ if(!key || !*key) {
+ error("STREAM [receive from [%s]:%s]: request without an API key. Forbidding access.", w->client_ip, w->client_port);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "You need an API key for this request.");
+ return 401;
+ }
+
+ if(!hostname || !*hostname) {
+ error("STREAM [receive from [%s]:%s]: request without a hostname. Forbidding access.", w->client_ip, w->client_port);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "You need to send a hostname too.");
+ return 400;
+ }
+
+ if(!machine_guid || !*machine_guid) {
+ error("STREAM [receive from [%s]:%s]: request without a machine GUID. Forbidding access.", w->client_ip, w->client_port);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "You need to send a machine GUID too.");
+ return 400;
+ }
+
+ if(regenerate_guid(key, buf) == -1) {
+ error("STREAM [receive from [%s]:%s]: API key '%s' is not valid GUID. Forbidding access.", w->client_ip, w->client_port, key);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your API key is invalid.");
+ return 401;
+ }
+
+ if(regenerate_guid(machine_guid, buf) == -1) {
+ error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not GUID. Forbidding access.", w->client_ip, w->client_port, key);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your machine GUID is invalid.");
+ return 404;
+ }
+
+ if(!appconfig_get_boolean(&stream_config, key, "enabled", 0)) {
+ error("STREAM [receive from [%s]:%s]: API key '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your API key is not permitted access.");
+ return 401;
+ }
+
+ if(!appconfig_get_boolean(&stream_config, machine_guid, "enabled", 1)) {
+ error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your machine guide is not permitted access.");
+ return 404;
+ }
+
+ struct rrdpush_thread *rpt = mallocz(sizeof(struct rrdpush_thread));
+ rpt->fd = w->ifd;
+ rpt->key = strdupz(key);
+ rpt->hostname = strdupz(hostname);
+ rpt->machine_guid = strdupz(machine_guid);
+ rpt->os = strdupz(os);
+ rpt->client_ip = strdupz(w->client_ip);
+ rpt->client_port = strdupz(w->client_port);
+ rpt->update_every = update_every;
+ pthread_t thread;
+
+ debug(D_SYSTEM, "STREAM [receive from [%s]:%s]: starting receiving thread.", w->client_ip, w->client_port);
+
+ if(pthread_create(&thread, NULL, rrdpush_receiver_thread, (void *)rpt))
+ error("STREAM [receive from [%s]:%s]: failed to create new thread for client.", w->client_ip, w->client_port);
+
+ else if(pthread_detach(thread))
+ error("STREAM [receive from [%s]:%s]: cannot request detach newly created thread.", w->client_ip, w->client_port);
+
+ // prevent the caller from closing the streaming socket
+ if(w->ifd == w->ofd)
+ w->ifd = w->ofd = -1;
+ else
+ w->ifd = -1;
+
+ buffer_flush(w->response.data);
+ return 200;
+}
diff --git a/src/rrdpush.h b/src/rrdpush.h
new file mode 100644
index 000000000..dddbe758b
--- /dev/null
+++ b/src/rrdpush.h
@@ -0,0 +1,15 @@
+#ifndef NETDATA_RRDPUSH_H
+#define NETDATA_RRDPUSH_H
+
+extern int default_rrdpush_enabled;
+extern char *default_rrdpush_destination;
+extern char *default_rrdpush_api_key;
+
+extern int rrdpush_init();
+extern void rrdset_done_push(RRDSET *st);
+extern void *rrdpush_sender_thread(void *ptr);
+
+extern int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url);
+extern void rrdpush_sender_thread_stop(RRDHOST *host);
+
+#endif //NETDATA_RRDPUSH_H
diff --git a/src/rrdset.c b/src/rrdset.c
new file mode 100644
index 000000000..c847b9690
--- /dev/null
+++ b/src/rrdset.c
@@ -0,0 +1,1310 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+#define RRD_DEFAULT_GAP_INTERPOLATIONS 1
+
+void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRD_CALLS, "Checking read lock on chart '%s'", st->id);
+
+ int ret = netdata_rwlock_trywrlock(&st->rrdset_rwlock);
+ if(ret == 0)
+ fatal("RRDSET '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
+}
+
+void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRD_CALLS, "Checking write lock on chart '%s'", st->id);
+
+ int ret = netdata_rwlock_tryrdlock(&st->rrdset_rwlock);
+ if(ret == 0)
+ fatal("RRDSET '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET index
+
+int rrdset_compare(void* a, void* b) {
+ if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
+ else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
+ else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
+}
+
+static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
+ RRDSET tmp;
+ strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
+ tmp.hash = (hash)?hash:simple_hash(tmp.id);
+
+ return (RRDSET *)avl_search_lock(&(host->rrdset_root_index), (avl *) &tmp);
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET name index
+
+#define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
+
+int rrdset_compare_name(void* a, void* b) {
+ RRDSET *A = rrdset_from_avlname(a);
+ RRDSET *B = rrdset_from_avlname(b);
+
+ // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
+
+ if(A->hash_name < B->hash_name) return -1;
+ else if(A->hash_name > B->hash_name) return 1;
+ else return strcmp(A->name, B->name);
+}
+
+RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
+ void *result;
+ // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
+ result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
+ if(result) return rrdset_from_avlname(result);
+ return NULL;
+}
+
+RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
+ void *result;
+ // fprintf(stderr, "DELETING: %s (name: %s)\n", st->id, st->name);
+ result = (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index_name), (avl *)(&st->avlname));
+ if(result) return rrdset_from_avlname(result);
+ return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - find charts
+
+static inline RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
+ void *result = NULL;
+ RRDSET tmp;
+ tmp.name = name;
+ tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
+
+ // fprintf(stderr, "SEARCHING: %s\n", name);
+ result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
+ if(result) {
+ RRDSET *st = rrdset_from_avlname(result);
+ if(strcmp(st->magic, RRDSET_MAGIC))
+ error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
+
+ // fprintf(stderr, "FOUND: %s\n", name);
+ return rrdset_from_avlname(result);
+ }
+ // fprintf(stderr, "NOT FOUND: %s\n", name);
+ return NULL;
+}
+
+inline RRDSET *rrdset_find(RRDHOST *host, const char *id) {
+ debug(D_RRD_CALLS, "rrdset_find() for chart '%s' in host '%s'", id, host->hostname);
+ RRDSET *st = rrdset_index_find(host, id, 0);
+ return(st);
+}
+
+inline RRDSET *rrdset_find_bytype(RRDHOST *host, const char *type, const char *id) {
+ debug(D_RRD_CALLS, "rrdset_find_bytype() for chart '%s.%s' in host '%s'", type, id, host->hostname);
+
+ char buf[RRD_ID_LENGTH_MAX + 1];
+ strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
+ strcat(buf, ".");
+ int len = (int) strlen(buf);
+ strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
+
+ return(rrdset_find(host, buf));
+}
+
+inline RRDSET *rrdset_find_byname(RRDHOST *host, const char *name) {
+ debug(D_RRD_CALLS, "rrdset_find_byname() for chart '%s' in host '%s'", name, host->hostname);
+ RRDSET *st = rrdset_index_find_name(host, name, 0);
+ return(st);
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - rename charts
+
+char *rrdset_strncpyz_name(char *to, const char *from, size_t length) {
+ char c, *p = to;
+
+ while (length-- && (c = *from++)) {
+ if(c != '.' && !isalnum(c))
+ c = '_';
+
+ *p++ = c;
+ }
+
+ *p = '\0';
+
+ return to;
+}
+
+void rrdset_set_name(RRDSET *st, const char *name) {
+ if(unlikely(st->name && !strcmp(st->name, name)))
+ return;
+
+ debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
+
+ char b[CONFIG_MAX_VALUE + 1];
+ char n[RRD_ID_LENGTH_MAX + 1];
+
+ snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
+ rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
+
+ if(st->name) {
+ rrdset_index_del_name(st->rrdhost, st);
+ st->name = config_set_default(st->config_section, "name", b);
+ st->hash_name = simple_hash(st->name);
+ rrdsetvar_rename_all(st);
+ }
+ else {
+ st->name = config_get(st->config_section, "name", b);
+ st->hash_name = simple_hash(st->name);
+ }
+
+ rrdset_wrlock(st);
+ RRDDIM *rd;
+ rrddim_foreach_write(rd, st)
+ rrddimvar_rename_all(rd);
+ rrdset_unlock(st);
+
+ if(unlikely(rrdset_index_add_name(st->rrdhost, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - reset a chart
+
+void rrdset_reset(RRDSET *st) {
+ debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
+
+ st->last_collected_time.tv_sec = 0;
+ st->last_collected_time.tv_usec = 0;
+ st->last_updated.tv_sec = 0;
+ st->last_updated.tv_usec = 0;
+ st->current_entry = 0;
+ st->counter = 0;
+ st->counter_done = 0;
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ rd->last_collected_time.tv_sec = 0;
+ rd->last_collected_time.tv_usec = 0;
+ rd->collections_counter = 0;
+ memset(rd->values, 0, rd->entries * sizeof(storage_number));
+ }
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - helpers for rrdset_create()
+
+inline long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries) {
+ if(unlikely(entries < 5)) entries = 5;
+ if(unlikely(entries > RRD_HISTORY_ENTRIES_MAX)) entries = RRD_HISTORY_ENTRIES_MAX;
+
+ if(unlikely(mode == RRD_MEMORY_MODE_NONE || mode == RRD_MEMORY_MODE_RAM))
+ return entries;
+
+ long page = (size_t)sysconf(_SC_PAGESIZE);
+ long size = sizeof(RRDDIM) + entries * sizeof(storage_number);
+ if(unlikely(size % page)) {
+ size -= (size % page);
+ size += page;
+
+ long n = (size - sizeof(RRDDIM)) / sizeof(storage_number);
+ return n;
+ }
+
+ return entries;
+}
+
+static inline void last_collected_time_align(struct timeval *tv, int update_every) {
+ tv->tv_sec -= tv->tv_sec % update_every;
+ tv->tv_usec = 500000;
+}
+
+static inline void last_updated_time_align(struct timeval *tv, int update_every) {
+ tv->tv_sec -= tv->tv_sec % update_every;
+ tv->tv_usec = 0;
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - free a chart
+
+void rrdset_free(RRDSET *st) {
+ if(unlikely(!st)) return;
+
+ rrdhost_check_wrlock(st->rrdhost); // make sure we have a write lock on the host
+ rrdset_wrlock(st); // lock this RRDSET
+
+ // info("Removing chart '%s' ('%s')", st->id, st->name);
+
+ // ------------------------------------------------------------------------
+ // remove it from the indexes
+
+ if(unlikely(rrdset_index_del(st->rrdhost, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
+
+ rrdset_index_del_name(st->rrdhost, st);
+
+ // ------------------------------------------------------------------------
+ // free its children structures
+
+ while(st->variables) rrdsetvar_free(st->variables);
+ while(st->alarms) rrdsetcalc_unlink(st->alarms);
+ while(st->dimensions) rrddim_free(st, st->dimensions);
+
+ rrdfamily_free(st->rrdhost, st->rrdfamily);
+
+ // ------------------------------------------------------------------------
+ // unlink it from the host
+
+ if(st == st->rrdhost->rrdset_root) {
+ st->rrdhost->rrdset_root = st->next;
+ }
+ else {
+ // find the previous one
+ RRDSET *s;
+ for(s = st->rrdhost->rrdset_root; s && s->next != st ; s = s->next) ;
+
+ // bypass it
+ if(s) s->next = st->next;
+ else error("Request to free RRDSET '%s': cannot find it under host '%s'", st->id, st->rrdhost->hostname);
+ }
+
+ rrdset_unlock(st);
+
+ // ------------------------------------------------------------------------
+ // free it
+
+ netdata_rwlock_destroy(&st->rrdset_rwlock);
+
+ // free directly allocated members
+ freez(st->config_section);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
+ munmap(st, st->memsize);
+ }
+ else
+ freez(st);
+}
+
+void rrdset_save(RRDSET *st) {
+ RRDDIM *rd;
+
+ rrdset_check_rdlock(st);
+
+ // info("Saving chart '%s' ('%s')", st->id, st->name);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ debug(D_RRD_STATS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
+ savememory(st->cache_filename, st, st->memsize);
+ }
+
+ rrddim_foreach_read(rd, st) {
+ if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
+ debug(D_RRD_STATS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ savememory(rd->cache_filename, rd, rd->memsize);
+ }
+ }
+}
+
+void rrdset_delete(RRDSET *st) {
+ RRDDIM *rd;
+
+ rrdset_check_rdlock(st);
+
+ // info("Deleting chart '%s' ('%s')", st->id, st->name);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ debug(D_RRD_STATS, "Deleting stats '%s' to '%s'.", st->name, st->cache_filename);
+ unlink(st->cache_filename);
+ }
+
+ rrddim_foreach_read(rd, st) {
+ if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
+ debug(D_RRD_STATS, "Deleting dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ unlink(rd->cache_filename);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - create a chart
+
+static inline RRDSET *rrdset_find_on_create(RRDHOST *host, const char *fullid) {
+ RRDSET *st = rrdset_find(host, fullid);
+ if(unlikely(st)) {
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+ debug(D_RRD_CALLS, "RRDSET '%s', already exists.", fullid);
+ return st;
+ }
+
+ return NULL;
+}
+
+RRDSET *rrdset_create(
+ RRDHOST *host
+ , const char *type
+ , const char *id
+ , const char *name
+ , const char *family
+ , const char *context
+ , const char *title
+ , const char *units
+ , long priority
+ , int update_every
+ , RRDSET_TYPE chart_type
+) {
+ if(!type || !type[0]) {
+ fatal("Cannot create rrd stats without a type.");
+ return NULL;
+ }
+
+ if(!id || !id[0]) {
+ fatal("Cannot create rrd stats without an id.");
+ return NULL;
+ }
+
+ // ------------------------------------------------------------------------
+ // check if it already exists
+
+ char fullid[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
+
+ RRDSET *st = rrdset_find_on_create(host, fullid);
+ if(st) return st;
+
+ rrdhost_wrlock(host);
+
+ st = rrdset_find_on_create(host, fullid);
+ if(st) {
+ rrdhost_unlock(host);
+ return st;
+ }
+
+ char fullfilename[FILENAME_MAX + 1];
+
+ // ------------------------------------------------------------------------
+ // compose the config_section for this chart
+
+ char config_section[RRD_ID_LENGTH_MAX + 1];
+ if(host == localhost)
+ strcpy(config_section, fullid);
+ else
+ snprintfz(config_section, RRD_ID_LENGTH_MAX, "%s/%s", host->machine_guid, fullid);
+
+ // ------------------------------------------------------------------------
+ // get the options from the config, we need to create it
+
+ long rentries = config_get_number(config_section, "history", host->rrd_history_entries);
+ long entries = align_entries_to_pagesize(host->rrd_memory_mode, rentries);
+ if(entries != rentries) entries = config_set_number(config_section, "history", entries);
+
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE && entries != rentries)
+ entries = config_set_number(config_section, "history", 10);
+
+ int enabled = config_get_boolean(config_section, "enabled", 1);
+ if(!enabled) entries = 5;
+
+ unsigned long size = sizeof(RRDSET);
+ char *cache_dir = rrdset_cache_dir(host, fullid, config_section);
+
+ time_t now = now_realtime_sec();
+
+ // ------------------------------------------------------------------------
+ // load it or allocate it
+
+ debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
+
+ snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || host->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ st = (RRDSET *) mymmap(fullfilename, size, ((host->rrd_memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 0);
+ if(st) {
+ memset(&st->avl, 0, sizeof(avl));
+ memset(&st->avlname, 0, sizeof(avl));
+ memset(&st->variables_root_index, 0, sizeof(avl_tree_lock));
+ memset(&st->dimensions_index, 0, sizeof(avl_tree_lock));
+ memset(&st->rrdset_rwlock, 0, sizeof(netdata_rwlock_t));
+
+ st->name = NULL;
+ st->type = NULL;
+ st->family = NULL;
+ st->context = NULL;
+ st->title = NULL;
+ st->units = NULL;
+ st->dimensions = NULL;
+ st->next = NULL;
+ st->variables = NULL;
+ st->alarms = NULL;
+ st->flags = 0x00000000;
+
+ if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
+ errno = 0;
+ info("Initializing file %s.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if(strcmp(st->id, fullid) != 0) {
+ errno = 0;
+ error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
+ // munmap(st, size);
+ // st = NULL;
+ memset(st, 0, size);
+ }
+ else if(st->memsize != size || st->entries != entries) {
+ errno = 0;
+ error("File %s does not have the desired size. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if(st->update_every != update_every) {
+ errno = 0;
+ error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if((now - st->last_updated.tv_sec) > update_every * entries) {
+ errno = 0;
+ error("File %s is too old. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if(st->last_updated.tv_sec > now + update_every) {
+ errno = 0;
+ error("File %s refers to the future. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+
+ // make sure the database is aligned
+ if(st->last_updated.tv_sec)
+ last_updated_time_align(&st->last_updated, update_every);
+
+
+ // make sure we have the right memory mode
+ // even if we cleared the memory
+ st->rrd_memory_mode = host->rrd_memory_mode;
+ }
+ }
+
+ if(unlikely(!st)) {
+ st = callocz(1, size);
+ st->rrd_memory_mode = (host->rrd_memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_RAM;
+ }
+
+ st->config_section = strdup(config_section);
+ st->rrdhost = host;
+ st->memsize = size;
+ st->entries = entries;
+ st->update_every = update_every;
+
+ if(st->current_entry >= st->entries) st->current_entry = 0;
+
+ strcpy(st->cache_filename, fullfilename);
+ strcpy(st->magic, RRDSET_MAGIC);
+
+ strcpy(st->id, fullid);
+ st->hash = simple_hash(st->id);
+
+ st->cache_dir = cache_dir;
+
+ 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);
+ st->units = config_get(st->config_section, "units", units?units:"");
+
+ st->context = config_get(st->config_section, "context", context?context:st->id);
+ st->hash_context = simple_hash(st->context);
+
+ st->priority = config_get_number(st->config_section, "priority", priority);
+ if(enabled)
+ rrdset_flag_set(st, RRDSET_FLAG_ENABLED);
+ else
+ rrdset_flag_clear(st, RRDSET_FLAG_ENABLED);
+
+ rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
+ rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+
+ // if(!strcmp(st->id, "disk_util.dm-0")) {
+ // st->debug = 1;
+ // error("enabled debugging for '%s'", st->id);
+ // }
+ // else error("not enabled debugging for '%s'", st->id);
+
+ st->green = NAN;
+ st->red = NAN;
+
+ st->last_collected_time.tv_sec = 0;
+ st->last_collected_time.tv_usec = 0;
+ st->counter_done = 0;
+
+ st->gap_when_lost_iterations_above = (int) (
+ config_get_number(st->config_section, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
+
+ avl_init_lock(&st->dimensions_index, rrddim_compare);
+ avl_init_lock(&st->variables_root_index, rrdvar_compare);
+
+ netdata_rwlock_init(&st->rrdset_rwlock);
+
+ if(name && *name) rrdset_set_name(st, name);
+ else rrdset_set_name(st, id);
+
+ {
+ char varvalue[CONFIG_MAX_VALUE + 1];
+ char varvalue2[CONFIG_MAX_VALUE + 1];
+ snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
+ json_escape_string(varvalue2, varvalue, sizeof(varvalue2));
+ st->title = config_get(st->config_section, "title", varvalue2);
+ }
+
+ st->rrdfamily = rrdfamily_create(host, st->family);
+
+ st->next = host->rrdset_root;
+ host->rrdset_root = st;
+
+ if(host->health_enabled) {
+ rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0);
+ rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, 0);
+ rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, 0);
+ rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, 0);
+ rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, 0);
+ }
+
+ if(unlikely(rrdset_index_add(host, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempt to index duplicate chart '%s'", st->id);
+
+ rrdsetcalc_link_matching(st);
+ rrdcalctemplate_link_matching(st);
+
+ rrdhost_cleanup_obsolete(host);
+
+ rrdhost_unlock(host);
+
+ return(st);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - data collection iteration control
+
+inline void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds) {
+
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // the first entry
+ microseconds = st->update_every * USEC_PER_SEC;
+ }
+ else if(unlikely(!microseconds)) {
+ // no dt given by the plugin
+ struct timeval now;
+ now_realtime_timeval(&now);
+ microseconds = dt_usec(&now, &st->last_collected_time);
+ }
+
+ st->usec_since_last_update = microseconds;
+}
+
+inline void rrdset_next_usec(RRDSET *st, usec_t microseconds) {
+ struct timeval now;
+ now_realtime_timeval(&now);
+
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // the first entry
+ microseconds = st->update_every * USEC_PER_SEC;
+ }
+ else if(unlikely(!microseconds)) {
+ // no dt given by the plugin
+ microseconds = dt_usec(&now, &st->last_collected_time);
+ }
+ else {
+ // microseconds has the time since the last collection
+//#ifdef NETDATA_INTERNAL_CHECKS
+// usec_t now_usec = timeval_usec(&now);
+// usec_t last_usec = timeval_usec(&st->last_collected_time);
+//#endif
+ susec_t since_last_usec = dt_usec_signed(&now, &st->last_collected_time);
+
+ if(unlikely(since_last_usec < 0)) {
+ // oops! the database is in the future
+ error("Database for chart '%s' on host '%s' is %lld microseconds in the future. Adjusting it to current time.", st->id, st->rrdhost->hostname, -since_last_usec);
+
+ st->last_collected_time.tv_sec = now.tv_sec - st->update_every;
+ st->last_collected_time.tv_usec = now.tv_usec;
+ last_collected_time_align(&st->last_collected_time, st->update_every);
+
+ st->last_updated.tv_sec = now.tv_sec - st->update_every;
+ st->last_updated.tv_usec = now.tv_usec;
+ last_updated_time_align(&st->last_updated, st->update_every);
+
+ microseconds = st->update_every * USEC_PER_SEC;
+ since_last_usec = st->update_every * USEC_PER_SEC;
+ }
+
+ // verify the microseconds given is good
+ if(unlikely(microseconds > (usec_t)since_last_usec)) {
+ debug(D_RRD_CALLS, "dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - (usec_t)since_last_usec, st->name, st->id);
+
+//#ifdef NETDATA_INTERNAL_CHECKS
+// if(unlikely(last_usec + microseconds > now_usec + 1000))
+// error("dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - (usec_t)since_last_usec, st->name, st->id);
+//#endif
+
+ microseconds = (usec_t)since_last_usec;
+ }
+ else if(unlikely(microseconds < (usec_t)since_last_usec * 0.8)) {
+ debug(D_RRD_CALLS, "dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, (usec_t)since_last_usec, st->name, st->id);
+
+//#ifdef NETDATA_INTERNAL_CHECKS
+// error("dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, (usec_t)since_last_usec, st->name, st->id);
+//#endif
+ microseconds = (usec_t)since_last_usec;
+ }
+ }
+ debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
+
+ st->usec_since_last_update = microseconds;
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - process the collected values for all dimensions of a chart
+
+static inline void rrdset_init_last_collected_time(RRDSET *st) {
+ now_realtime_timeval(&st->last_collected_time);
+ last_collected_time_align(&st->last_collected_time, st->update_every);
+}
+
+static inline usec_t rrdset_update_last_collected_time(RRDSET *st) {
+ usec_t last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
+ usec_t ut = last_collect_ut + st->usec_since_last_update;
+ st->last_collected_time.tv_sec = (time_t) (ut / USEC_PER_SEC);
+ st->last_collected_time.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
+ return last_collect_ut;
+}
+
+static inline void rrdset_init_last_updated_time(RRDSET *st) {
+ // copy the last collected time to last updated time
+ st->last_updated.tv_sec = st->last_collected_time.tv_sec;
+ st->last_updated.tv_usec = st->last_collected_time.tv_usec;
+ last_updated_time_align(&st->last_updated, st->update_every);
+}
+
+static inline void rrdset_done_push_exclusive(RRDSET *st) {
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // it is the first entry
+ // set the last_collected_time to now
+ rrdset_init_last_collected_time(st);
+ }
+ else {
+ // it is not the first entry
+ // calculate the proper last_collected_time, using usec_since_last_update
+ rrdset_update_last_collected_time(st);
+ }
+
+ st->counter_done++;
+
+ rrdset_rdlock(st);
+ rrdset_done_push(st);
+ rrdset_unlock(st);
+}
+
+void rrdset_done(RRDSET *st) {
+ if(unlikely(netdata_exit)) return;
+
+ if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
+ if(unlikely(st->rrdhost->rrdpush_enabled))
+ rrdset_done_push_exclusive(st);
+
+ return;
+ }
+
+ debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
+
+ RRDDIM *rd;
+
+ int
+ pthreadoldcancelstate; // store the old cancelable pthread state, to restore it at the end
+
+ char
+ store_this_entry = 1, // boolean: 1 = store this entry, 0 = don't store this entry
+ first_entry = 0; // boolean: 1 = this is the first entry seen for this chart, 0 = all other entries
+
+ unsigned int
+ stored_entries = 0; // the number of entries we have stored in the db, during this call to rrdset_done()
+
+ usec_t
+ last_collect_ut, // the timestamp in microseconds, of the last collected value
+ now_collect_ut, // the timestamp in microseconds, of this collected value (this is NOW)
+ last_stored_ut, // the timestamp in microseconds, of the last stored entry in the db
+ next_store_ut, // the timestamp in microseconds, of the next entry to store in the db
+ update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds
+
+ if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
+ error("Cannot set pthread cancel state to DISABLE.");
+
+ // a read lock is OK here
+ rrdset_rdlock(st);
+
+/*
+ // enable the chart, if it was disabled
+ if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
+ st->enabled = 1;
+*/
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))) {
+ error("Chart '%s' has the OBSOLETE flag set, but it is collected.", st->id);
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+ }
+
+ // check if the chart has a long time to be updated
+ if(unlikely(st->usec_since_last_update > st->entries * update_every_ut)) {
+ info("%s: took too long to be updated (%0.3Lf secs). Resetting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
+ rrdset_reset(st);
+ st->usec_since_last_update = update_every_ut;
+ first_entry = 1;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
+
+ // set last_collected_time
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // it is the first entry
+ // set the last_collected_time to now
+ rrdset_init_last_collected_time(st);
+
+ last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - update_every_ut;
+
+ // the first entry should not be stored
+ store_this_entry = 0;
+ first_entry = 1;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
+ }
+ else {
+ // it is not the first entry
+ // calculate the proper last_collected_time, using usec_since_last_update
+ last_collect_ut = rrdset_update_last_collected_time(st);
+ }
+
+ // if this set has not been updated in the past
+ // we fake the last_update time to be = now - usec_since_last_update
+ if(unlikely(!st->last_updated.tv_sec)) {
+ // it has never been updated before
+ // set a fake last_updated, in the past using usec_since_last_update
+ rrdset_init_last_updated_time(st);
+
+ // the first entry should not be stored
+ store_this_entry = 0;
+ first_entry = 1;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: initializing last_updated to last_collected_time - %llu microseconds. Will not store the next entry.", st->name, st->usec_since_last_update);
+ }
+
+ // check if we will re-write the entire data set
+ if(unlikely(dt_usec(&st->last_collected_time, &st->last_updated) > st->entries * update_every_ut)) {
+ info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Resetting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
+ rrdset_reset(st);
+ rrdset_init_last_updated_time(st);
+
+ st->usec_since_last_update = update_every_ut;
+
+ // the first entry should not be stored
+ store_this_entry = 0;
+ first_entry = 1;
+ }
+
+ // these are the 3 variables that will help us in interpolation
+ // last_stored_ut = the last time we added a value to the storage
+ // now_collect_ut = the time the current value has been collected
+ // next_store_ut = the time of the next interpolation point
+ last_stored_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec;
+ now_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
+ next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) {
+ debug(D_RRD_STATS, "%s: last_collect_ut = %0.3Lf (last collection time)", st->name, (long double)last_collect_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: now_collect_ut = %0.3Lf (current collection time)", st->name, (long double)now_collect_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
+ }
+
+ if(unlikely(!st->counter_done)) {
+ store_this_entry = 0;
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
+ }
+ st->counter_done++;
+
+ if(unlikely(st->rrdhost->rrdpush_enabled))
+ rrdset_done_push(st);
+
+ // calculate totals and count the dimensions
+ int dimensions = 0;
+ st->collected_total = 0;
+ rrddim_foreach_read(rd, st) {
+ dimensions++;
+ if(likely(rd->updated))
+ st->collected_total += rd->collected_value;
+ }
+
+ uint32_t storage_flags = SN_EXISTS;
+
+ // process all dimensions to calculate their values
+ // based on the collected figures only
+ // at this stage we do not interpolate anything
+ rrddim_foreach_read(rd, st) {
+
+ if(unlikely(!rd->updated)) {
+ rd->calculated_value = 0;
+ continue;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: START "
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
+ " collected_value = " COLLECTED_NUMBER_FORMAT
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->last_collected_value
+ , rd->collected_value
+ , rd->last_calculated_value
+ , rd->calculated_value
+ );
+
+ switch(rd->algorithm) {
+ case RRD_ALGORITHM_ABSOLUTE:
+ rd->calculated_value = (calculated_number)rd->collected_value
+ * (calculated_number)rd->multiplier
+ / (calculated_number)rd->divisor;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
+ CALCULATED_NUMBER_FORMAT " = "
+ COLLECTED_NUMBER_FORMAT
+ " * " CALCULATED_NUMBER_FORMAT
+ " / " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value
+ , (calculated_number)rd->multiplier
+ , (calculated_number)rd->divisor
+ );
+ break;
+
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ if(unlikely(!st->collected_total))
+ rd->calculated_value = 0;
+ else
+ // the percentage of the current value
+ // over the total of all dimensions
+ rd->calculated_value =
+ (calculated_number)100
+ * (calculated_number)rd->collected_value
+ / (calculated_number)st->collected_total;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
+ CALCULATED_NUMBER_FORMAT " = 100"
+ " * " COLLECTED_NUMBER_FORMAT
+ " / " COLLECTED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value
+ , st->collected_total
+ );
+ break;
+
+ case RRD_ALGORITHM_INCREMENTAL:
+ if(unlikely(rd->collections_counter <= 1)) {
+ rd->calculated_value = 0;
+ continue;
+ }
+
+ // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
+ // to reset the calculation (it will give zero as the calculation for this second)
+ if(unlikely(rd->last_collected_value > rd->collected_value)) {
+ debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+ , st->name, rd->name
+ , rd->last_collected_value
+ , rd->collected_value);
+
+ if(!(rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)))
+ storage_flags = SN_EXISTS_RESET;
+
+ rd->last_collected_value = rd->collected_value;
+ }
+
+ rd->calculated_value +=
+ (calculated_number)(rd->collected_value - rd->last_collected_value)
+ * (calculated_number)rd->multiplier
+ / (calculated_number)rd->divisor;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
+ CALCULATED_NUMBER_FORMAT " = ("
+ COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
+ ")"
+ " * " CALCULATED_NUMBER_FORMAT
+ " / " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value, rd->last_collected_value
+ , (calculated_number)rd->multiplier
+ , (calculated_number)rd->divisor
+ );
+ break;
+
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ if(unlikely(rd->collections_counter <= 1)) {
+ rd->calculated_value = 0;
+ continue;
+ }
+
+ // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
+ // to reset the calculation (it will give zero as the calculation for this second)
+ if(unlikely(rd->last_collected_value > rd->collected_value)) {
+ debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+ , st->name, rd->name
+ , rd->last_collected_value
+ , rd->collected_value);
+
+ if(!(rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)))
+ storage_flags = SN_EXISTS_RESET;
+
+ rd->last_collected_value = rd->collected_value;
+ }
+
+ // the percentage of the current increment
+ // over the increment of all dimensions together
+ if(unlikely(st->collected_total == st->last_collected_total))
+ rd->calculated_value = 0;
+ else
+ rd->calculated_value =
+ (calculated_number)100
+ * (calculated_number)(rd->collected_value - rd->last_collected_value)
+ / (calculated_number)(st->collected_total - st->last_collected_total);
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
+ CALCULATED_NUMBER_FORMAT " = 100"
+ " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+ " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value, rd->last_collected_value
+ , st->collected_total, st->last_collected_total
+ );
+ break;
+
+ default:
+ // make the default zero, to make sure
+ // it gets noticed when we add new types
+ rd->calculated_value = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC "
+ CALCULATED_NUMBER_FORMAT " = 0"
+ , st->id, rd->name
+ , rd->calculated_value
+ );
+ break;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: PHASE2 "
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
+ " collected_value = " COLLECTED_NUMBER_FORMAT
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->last_collected_value
+ , rd->collected_value
+ , rd->last_calculated_value
+ , rd->calculated_value
+ );
+
+ }
+
+ // at this point we have all the calculated values ready
+ // it is now time to interpolate values on a second boundary
+
+ if(unlikely(now_collect_ut < next_store_ut)) {
+ // this is collected in the same interpolation point
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
+
+//#ifdef NETDATA_INTERNAL_CHECKS
+// info("%s is collected in the same interpolation point: short by %llu microseconds", st->name, next_store_ut - now_collect_ut);
+//#endif
+ }
+
+ usec_t first_ut = last_stored_ut;
+ long long iterations = (now_collect_ut - last_stored_ut) / (update_every_ut);
+ if((now_collect_ut % (update_every_ut)) == 0) iterations++;
+
+ for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
+//#ifdef NETDATA_INTERNAL_CHECKS
+// if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_stored_ut = %llu, next_store_ut = %llu, now_collect_ut = %llu", st->name, first_ut, last_stored_ut, next_store_ut, now_collect_ut); }
+//#endif
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) {
+ debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
+ }
+
+ st->last_updated.tv_sec = (time_t) (next_store_ut / USEC_PER_SEC);
+ st->last_updated.tv_usec = 0;
+
+ rrddim_foreach_read(rd, st) {
+ calculated_number new_value;
+
+ switch(rd->algorithm) {
+ case RRD_ALGORITHM_INCREMENTAL:
+ new_value = (calculated_number)
+ ( rd->calculated_value
+ * (calculated_number)(next_store_ut - last_collect_ut)
+ / (calculated_number)(now_collect_ut - last_collect_ut)
+ );
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC2 INC "
+ CALCULATED_NUMBER_FORMAT " = "
+ CALCULATED_NUMBER_FORMAT
+ " * %llu"
+ " / %llu"
+ , st->id, rd->name
+ , new_value
+ , rd->calculated_value
+ , (next_store_ut - last_stored_ut)
+ , (now_collect_ut - last_stored_ut)
+ );
+
+ rd->calculated_value -= new_value;
+ new_value += rd->last_calculated_value;
+ rd->last_calculated_value = 0;
+ new_value /= (calculated_number)st->update_every;
+
+ if(unlikely(next_store_ut - last_stored_ut < update_every_ut)) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: COLLECTION POINT IS SHORT " CALCULATED_NUMBER_FORMAT " - EXTRAPOLATING",
+ st->id, rd->name
+ , (calculated_number)(next_store_ut - last_stored_ut)
+ );
+ new_value = new_value * (calculated_number)(st->update_every * 1000000) / (calculated_number)(next_store_ut - last_stored_ut);
+ }
+ break;
+
+ case RRD_ALGORITHM_ABSOLUTE:
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ default:
+ if(iterations == 1) {
+ // this is the last iteration
+ // do not interpolate
+ // just show the calculated value
+
+ new_value = rd->calculated_value;
+ }
+ else {
+ // we have missed an update
+ // interpolate in the middle values
+
+ new_value = (calculated_number)
+ ( ( (rd->calculated_value - rd->last_calculated_value)
+ * (calculated_number)(next_store_ut - last_collect_ut)
+ / (calculated_number)(now_collect_ut - last_collect_ut)
+ )
+ + rd->last_calculated_value
+ );
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
+ CALCULATED_NUMBER_FORMAT " = ((("
+ "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
+ " * %llu"
+ " / %llu) + " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , new_value
+ , rd->calculated_value, rd->last_calculated_value
+ , (next_store_ut - first_ut)
+ , (now_collect_ut - first_ut), rd->last_calculated_value
+ );
+ }
+ break;
+ }
+
+ if(unlikely(!store_this_entry)) {
+ rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+ continue;
+ }
+
+ if(likely(rd->updated && rd->collections_counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
+ rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
+ rd->last_stored_value = new_value;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
+ CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , st->current_entry
+ , unpack_storage_number(rd->values[st->current_entry]), new_value
+ );
+ }
+ else {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
+ , st->id, rd->name
+ , st->current_entry
+ );
+ rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+ rd->last_stored_value = NAN;
+ }
+
+ stored_entries++;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) {
+ calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
+ calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
+ calculated_number accuracy = accuracy_loss(t1, t2);
+ debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
+ , st->id, rd->name
+ , st->current_entry
+ , t2
+ , get_storage_number_flags(rd->values[st->current_entry])
+ , t1
+ , accuracy
+ , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
+ );
+
+ rd->collected_volume += t1;
+ rd->stored_volume += t2;
+ accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
+ debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
+ , st->id, rd->name
+ , st->current_entry
+ , rd->stored_volume
+ , rd->collected_volume
+ , accuracy
+ , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
+ );
+
+ }
+ }
+ // reset the storage flags for the next point, if any;
+ storage_flags = SN_EXISTS;
+
+ st->counter++;
+ st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
+ last_stored_ut = next_store_ut;
+ }
+
+ st->last_collected_total = st->collected_total;
+
+ rrddim_foreach_read(rd, st) {
+ if(unlikely(!rd->updated))
+ continue;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
+
+ rd->last_collected_value = rd->collected_value;
+
+ switch(rd->algorithm) {
+ case RRD_ALGORITHM_INCREMENTAL:
+ if(unlikely(!first_entry)) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value + rd->calculated_value, rd->calculated_value);
+ rd->last_calculated_value += rd->calculated_value;
+ }
+ else {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: THIS IS THE FIRST POINT", st->name);
+ }
+ break;
+
+ case RRD_ALGORITHM_ABSOLUTE:
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
+ rd->last_calculated_value = rd->calculated_value;
+ break;
+ }
+
+ rd->calculated_value = 0;
+ rd->collected_value = 0;
+ rd->updated = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: END "
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
+ " collected_value = " COLLECTED_NUMBER_FORMAT
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->last_collected_value
+ , rd->collected_value
+ , rd->last_calculated_value
+ , rd->calculated_value
+ );
+ }
+
+ // ALL DONE ABOUT THE DATA UPDATE
+ // --------------------------------------------------------------------
+
+/*
+ // find if there are any obsolete dimensions (not updated recently)
+ if(unlikely(rrd_delete_unupdated_dimensions)) {
+
+ for( rd = st->dimensions; likely(rd) ; rd = rd->next )
+ if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
+ break;
+
+ if(unlikely(rd)) {
+ RRDDIM *last;
+ // there is dimension to free
+ // upgrade our read lock to a write lock
+ rrdset_unlock(st);
+ rrdset_wrlock(st);
+
+ for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
+ // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
+
+ if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
+ info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
+
+ if(unlikely(!last)) {
+ st->dimensions = rd->next;
+ rd->next = NULL;
+ rrddim_free(st, rd);
+ rd = st->dimensions;
+ continue;
+ }
+ else {
+ last->next = rd->next;
+ rd->next = NULL;
+ rrddim_free(st, rd);
+ rd = last->next;
+ continue;
+ }
+ }
+
+ last = rd;
+ rd = rd->next;
+ }
+
+ if(unlikely(!st->dimensions)) {
+ info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
+ st->enabled = 0;
+ }
+ }
+ }
+*/
+
+ rrdset_unlock(st);
+
+ if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
+ error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
+}
diff --git a/src/rrdsetvar.c b/src/rrdsetvar.c
new file mode 100644
index 000000000..03d7aeced
--- /dev/null
+++ b/src/rrdsetvar.c
@@ -0,0 +1,120 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDSETVAR management
+// CHART VARIABLES
+
+static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
+ RRDSET *st = rs->rrdset;
+
+ // CHART
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local);
+ rs->var_local = NULL;
+
+ // FAMILY
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family);
+ rs->var_family = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host);
+ rs->var_host = NULL;
+
+ // HOST
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
+ rs->var_family_name = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name);
+ rs->var_host_name = NULL;
+
+ // KEYS
+
+ freez(rs->key_fullid);
+ rs->key_fullid = NULL;
+
+ freez(rs->key_fullname);
+ rs->key_fullname = NULL;
+}
+
+static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
+ rrdsetvar_free_variables(rs);
+
+ RRDSET *st = rs->rrdset;
+
+ // KEYS
+
+ char buffer[RRDVAR_MAX_LENGTH + 1];
+ snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
+ rs->key_fullid = strdupz(buffer);
+
+ snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
+ rs->key_fullname = strdupz(buffer);
+
+ // CHART
+
+ rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
+
+ // FAMILY
+
+ rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value);
+ rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value);
+
+ // HOST
+
+ rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value);
+ rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value);
+
+}
+
+RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
+ debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
+ RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
+
+ rs->variable = strdupz(variable);
+ rs->type = type;
+ rs->value = value;
+ rs->options = options;
+ rs->rrdset = st;
+
+ rs->next = st->variables;
+ st->variables = rs;
+
+ rrdsetvar_create_variables(rs);
+
+ return rs;
+}
+
+void rrdsetvar_rename_all(RRDSET *st) {
+ debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
+
+ RRDSETVAR *rs, *next = st->variables;
+ while((rs = next)) {
+ next = rs->next;
+ rrdsetvar_create_variables(rs);
+ }
+
+ rrdsetcalc_link_matching(st);
+}
+
+void rrdsetvar_free(RRDSETVAR *rs) {
+ RRDSET *st = rs->rrdset;
+ debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
+
+ if(st->variables == rs) {
+ st->variables = rs->next;
+ }
+ else {
+ RRDSETVAR *t;
+ for (t = st->variables; t && t->next != rs; t = t->next);
+ if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
+ else t->next = rs->next;
+ }
+
+ rrdsetvar_free_variables(rs);
+
+ freez(rs->variable);
+ freez(rs);
+}
+
diff --git a/src/rrdvar.c b/src/rrdvar.c
new file mode 100644
index 000000000..2223d7c9a
--- /dev/null
+++ b/src/rrdvar.c
@@ -0,0 +1,265 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDVAR management
+
+inline int rrdvar_fix_name(char *variable) {
+ int fixed = 0;
+ while(*variable) {
+ if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
+ *variable++ = '_';
+ fixed++;
+ }
+ else
+ variable++;
+ }
+
+ return fixed;
+}
+
+int rrdvar_compare(void* a, void* b) {
+ if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
+ else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
+ else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
+}
+
+static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
+ RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
+ if(ret != rv)
+ debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
+
+ return ret;
+}
+
+static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
+ RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
+ if(!ret)
+ error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
+
+ return ret;
+}
+
+static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
+ RRDVAR tmp;
+ tmp.name = (char *)name;
+ tmp.hash = (hash)?hash:simple_hash(tmp.name);
+
+ return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
+}
+
+inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
+ (void)host;
+
+ if(!rv) return;
+
+ if(tree) {
+ debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
+ if(unlikely(!rrdvar_index_del(tree, rv)))
+ error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
+ }
+
+ freez(rv->name);
+ freez(rv);
+}
+
+inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) {
+ char *variable = strdupz(name);
+ rrdvar_fix_name(variable);
+ uint32_t hash = simple_hash(variable);
+
+ RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
+ if(unlikely(!rv)) {
+ debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
+
+ rv = callocz(1, sizeof(RRDVAR));
+ rv->name = variable;
+ rv->hash = hash;
+ rv->type = type;
+ rv->value = value;
+
+ RRDVAR *ret = rrdvar_index_add(tree, rv);
+ if(unlikely(ret != rv)) {
+ debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
+ rrdvar_free(NULL, NULL, rv);
+ rv = NULL;
+ }
+ else
+ debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
+ }
+ else {
+ debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
+
+ // already exists
+ freez(variable);
+
+ // this is important
+ // it must return NULL - not the existing variable - or double-free will happen
+ rv = NULL;
+ }
+
+ return rv;
+}
+
+// ----------------------------------------------------------------------------
+// CUSTOM VARIABLES
+
+RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
+ calculated_number *v = callocz(1, sizeof(calculated_number));
+ *v = NAN;
+ RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v);
+ if(unlikely(!rv)) {
+ free(v);
+ error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name);
+
+ char *variable = strdupz(name);
+ rrdvar_fix_name(variable);
+ uint32_t hash = simple_hash(variable);
+
+ rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
+ }
+
+ return rv;
+}
+
+void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) {
+ char *variable = strdupz(name);
+ rrdvar_fix_name(variable);
+ uint32_t hash = simple_hash(variable);
+
+ RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
+ freez(variable);
+
+ if(!rv) {
+ error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname);
+ return;
+ }
+
+ if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) {
+ error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname);
+ return;
+ }
+
+ if(!rrdvar_index_del(&host->variables_root_index, rv)) {
+ error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname);
+ return;
+ }
+
+ freez(rv->name);
+ freez(rv->value);
+ freez(rv);
+}
+
+void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) {
+ if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED)
+ error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value);
+ else {
+ calculated_number *v = rv->value;
+ *v = value;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// RRDVAR lookup
+
+static calculated_number rrdvar2number(RRDVAR *rv) {
+ switch(rv->type) {
+ case RRDVAR_TYPE_CALCULATED_ALLOCATED:
+ case RRDVAR_TYPE_CALCULATED: {
+ calculated_number *n = (calculated_number *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_TIME_T: {
+ time_t *n = (time_t *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_COLLECTED: {
+ collected_number *n = (collected_number *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_TOTAL: {
+ total_number *n = (total_number *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_INT: {
+ int *n = (int *)rv->value;
+ return *n;
+ }
+
+ default:
+ error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type);
+ return NAN;
+ }
+}
+
+int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
+ RRDSET *st = rc->rrdset;
+ RRDVAR *rv;
+
+ if(!st) return 0;
+
+ rv = rrdvar_index_find(&st->variables_root_index, variable, hash);
+ if(rv) {
+ *result = rrdvar2number(rv);
+ return 1;
+ }
+
+ rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash);
+ if(rv) {
+ *result = rrdvar2number(rv);
+ return 1;
+ }
+
+ rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash);
+ if(rv) {
+ *result = rrdvar2number(rv);
+ return 1;
+ }
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// RRDVAR to JSON
+
+struct variable2json_helper {
+ BUFFER *buf;
+ size_t counter;
+};
+
+static int single_variable2json(void *entry, void *data) {
+ struct variable2json_helper *helper = (struct variable2json_helper *)data;
+ RRDVAR *rv = (RRDVAR *)entry;
+ calculated_number value = rrdvar2number(rv);
+
+ if(unlikely(isnan(value) || isinf(value)))
+ buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
+ else
+ buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
+
+ helper->counter++;
+
+ return 0;
+}
+
+void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
+ struct variable2json_helper helper = {
+ .buf = buf,
+ .counter = 0
+ };
+
+ buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", st->id, st->name, st->context);
+ avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
+ helper.counter = 0;
+ avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
+ helper.counter = 0;
+ avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_strcat(buf, "\n\t}\n}\n");
+}
+
diff --git a/src/simple_pattern.c b/src/simple_pattern.c
index 7e4424297..f72a42d06 100644
--- a/src/simple_pattern.c
+++ b/src/simple_pattern.c
@@ -169,7 +169,7 @@ static inline int match_pattern(struct simple_pattern *m, const char *str, size_
int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) {
struct simple_pattern *m, *root = (struct simple_pattern *)list;
- if(unlikely(!root)) return 0;
+ if(unlikely(!root || !str || !*str)) return 0;
size_t len = strlen(str);
for(m = root; m ; m = m->next)
@@ -184,8 +184,8 @@ int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) {
static inline void free_pattern(struct simple_pattern *m) {
if(!m) return;
- if(m->next) free_pattern(m->next);
- if(m->child) free_pattern(m->child);
+ free_pattern(m->child);
+ free_pattern(m->next);
freez((void *)m->match);
freez(m);
}
@@ -193,5 +193,5 @@ static inline void free_pattern(struct simple_pattern *m) {
void simple_pattern_free(SIMPLE_PATTERN *list) {
if(!list) return;
- free_pattern(((struct simple_pattern *)list)->next);
+ free_pattern(((struct simple_pattern *)list));
}
diff --git a/src/socket.c b/src/socket.c
index 643811e44..400c1ef4e 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -160,8 +160,10 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(fd != -1) {
- if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)timeout, sizeof(struct timeval)) < 0)
- error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
+ if(timeout) {
+ if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0)
+ error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
+ }
if(connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
error("Failed to connect to '%s', port '%s'", hostBfr, servBfr);
@@ -177,3 +179,98 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
return fd;
}
+
+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) {
+ int sock = -1;
+
+ const char *s = destination;
+ while(*s) {
+ const char *e = s;
+
+ // skip separators, moving both s(tart) and e(nd)
+ while(isspace(*e) || *e == ',') s = ++e;
+
+ // move e(nd) to the first separator
+ while(*e && !isspace(*e) && *e != ',') e++;
+
+ // is there anything?
+ if(!*s || s == e) break;
+
+ char buf[e - s + 1];
+ strncpyz(buf, s, e - s);
+ if(reconnects_counter) *reconnects_counter += 1;
+ sock = connect_to(buf, default_port, timeout);
+ if(sock != -1) {
+ if(connected_to && connected_to_size) {
+ strncpy(connected_to, buf, connected_to_size);
+ connected_to[connected_to_size - 1] = '\0';
+ }
+ break;
+ }
+ s = e;
+ }
+
+ return sock;
+}
+
+ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
+ for(;;) {
+ struct pollfd fd = {
+ .fd = sockfd,
+ .events = POLLIN,
+ .revents = 0
+ };
+
+ errno = 0;
+ int retval = poll(&fd, 1, timeout * 1000);
+
+ if(retval == -1) {
+ // failed
+
+ if(errno == EINTR || errno == EAGAIN)
+ continue;
+
+ return -1;
+ }
+
+ if(!retval) {
+ // timeout
+ return 0;
+ }
+
+ if(fd.events & POLLIN) break;
+ }
+
+ return recv(sockfd, buf, len, flags);
+}
+
+ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
+ for(;;) {
+ struct pollfd fd = {
+ .fd = sockfd,
+ .events = POLLOUT,
+ .revents = 0
+ };
+
+ errno = 0;
+ int retval = poll(&fd, 1, timeout * 1000);
+
+ if(retval == -1) {
+ // failed
+
+ if(errno == EINTR || errno == EAGAIN)
+ continue;
+
+ return -1;
+ }
+
+ if(!retval) {
+ // timeout
+ return 0;
+ }
+
+ if(fd.events & POLLOUT) break;
+ }
+
+ return send(sockfd, buf, len, flags);
+}
diff --git a/src/socket.h b/src/socket.h
index 791c0ce54..89c154a61 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -6,5 +6,9 @@
#define NETDATA_SOCKET_H
extern int connect_to(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);
+extern ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
#endif //NETDATA_SOCKET_H
diff --git a/src/sys_devices_system_edac_mc.c b/src/sys_devices_system_edac_mc.c
index c764615f1..c41ad7faa 100644
--- a/src/sys_devices_system_edac_mc.c
+++ b/src/sys_devices_system_edac_mc.c
@@ -23,7 +23,7 @@ static struct mc *mc_root = NULL;
static void find_all_mc() {
char name[FILENAME_MAX + 1];
- snprintfz(name, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/devices/system/edac/mc");
+ snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/edac/mc");
char *dirname = config_get("plugin:proc:/sys/devices/system/edac/mc", "directory to monitor", name);
DIR *dir = opendir(dirname);
@@ -76,11 +76,11 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
struct mc *m;
if(unlikely(do_ce == -1)) {
- do_ce = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory correctable errors", CONFIG_ONDEMAND_ONDEMAND);
- do_ue = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory uncorrectable errors", CONFIG_ONDEMAND_ONDEMAND);
+ do_ce = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory correctable errors", CONFIG_BOOLEAN_AUTO);
+ do_ue = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory uncorrectable errors", CONFIG_BOOLEAN_AUTO);
}
- if(do_ce != CONFIG_ONDEMAND_NO) {
+ if(do_ce != CONFIG_BOOLEAN_NO) {
for(m = mc_root; m; m = m->next) {
if(m->ce_count_filename) {
m->ce_updated = 0;
@@ -102,7 +102,7 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
}
}
- if(do_ue != CONFIG_ONDEMAND_NO) {
+ if(do_ue != CONFIG_BOOLEAN_NO) {
for(m = mc_root; m; m = m->next) {
if(m->ue_count_filename) {
m->ue_updated = 0;
@@ -126,20 +126,20 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ce == CONFIG_ONDEMAND_YES || (do_ce == CONFIG_ONDEMAND_ONDEMAND && ce_sum > 0)) {
- do_ce = CONFIG_ONDEMAND_YES;
+ if(do_ce == CONFIG_BOOLEAN_YES || (do_ce == CONFIG_BOOLEAN_AUTO && ce_sum > 0)) {
+ do_ce = CONFIG_BOOLEAN_YES;
static RRDSET *ce_st = NULL;
if(unlikely(!ce_st)) {
- ce_st = rrdset_find("mem.ecc_ce");
+ ce_st = rrdset_find_localhost("mem.ecc_ce");
if(unlikely(!ce_st))
- ce_st = rrdset_create("mem", "ecc_ce", NULL, "ecc", NULL, "ECC Memory Correctable Errors", "errors",
- 6600, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
+ m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(ce_st);
@@ -153,21 +153,21 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ue == CONFIG_ONDEMAND_YES || (do_ue == CONFIG_ONDEMAND_ONDEMAND && ue_sum > 0)) {
- do_ue = CONFIG_ONDEMAND_YES;
+ if(do_ue == CONFIG_BOOLEAN_YES || (do_ue == CONFIG_BOOLEAN_AUTO && ue_sum > 0)) {
+ do_ue = CONFIG_BOOLEAN_YES;
static RRDSET *ue_st = NULL;
if(unlikely(!ue_st)) {
- ue_st = rrdset_find("mem.ecc_ue");
+ ue_st = rrdset_find_localhost("mem.ecc_ue");
if(unlikely(!ue_st))
- ue_st = rrdset_create("mem", "ecc_ue", NULL, "ecc", NULL, "ECC Memory Uncorrectable Errors", "errors",
- 6610, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_INCREMENTAL);
+ m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(ue_st);
diff --git a/src/sys_devices_system_node.c b/src/sys_devices_system_node.c
index 18c3fcd3a..a7690e7b7 100644
--- a/src/sys_devices_system_node.c
+++ b/src/sys_devices_system_node.c
@@ -12,7 +12,7 @@ static struct node *numa_root = NULL;
static int find_all_nodes() {
int numa_node_count = 0;
char name[FILENAME_MAX + 1];
- snprintfz(name, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/devices/system/node");
+ snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/node");
char *dirname = config_get("plugin:proc:/sys/devices/system/node", "directory to monitor", name);
DIR *dir = opendir(dirname);
@@ -60,26 +60,34 @@ static int find_all_nodes() {
int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
(void)dt;
- static int numa_node_count = 0;
+ static uint32_t hash_local_node = 0, hash_numa_foreign = 0, hash_interleave_hit = 0, hash_other_node = 0, hash_numa_hit = 0, hash_numa_miss = 0;
+ static int do_numastat = -1, numa_node_count = 0;
+ struct node *m;
if(unlikely(numa_root == NULL)) {
- numa_node_count = find_all_nodes(update_every);
+ numa_node_count = find_all_nodes();
if(unlikely(numa_root == NULL))
return 1;
}
- static int do_numastat = -1;
- struct node *m;
-
if(unlikely(do_numastat == -1)) {
- do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_ONDEMAND_ONDEMAND);
+ do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_BOOLEAN_AUTO);
+
+ hash_local_node = simple_hash("local_node");
+ hash_numa_foreign = simple_hash("numa_foreign");
+ hash_interleave_hit = simple_hash("interleave_hit");
+ hash_other_node = simple_hash("other_node");
+ hash_numa_hit = simple_hash("numa_hit");
+ hash_numa_miss = simple_hash("numa_miss");
}
- if(do_numastat == CONFIG_ONDEMAND_YES || (do_numastat == CONFIG_ONDEMAND_ONDEMAND && numa_node_count >= 2)) {
+ if(do_numastat == CONFIG_BOOLEAN_YES || (do_numastat == CONFIG_BOOLEAN_AUTO && numa_node_count >= 2)) {
for(m = numa_root; m; m = m->next) {
if(m->numastat_filename) {
+
if(unlikely(!m->numastat_ff)) {
m->numastat_ff = procfile_open(m->numastat_filename, " ", PROCFILE_FLAG_DEFAULT);
+
if(unlikely(!m->numastat_ff))
continue;
}
@@ -88,37 +96,61 @@ int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
if(unlikely(!m->numastat_ff || procfile_lines(m->numastat_ff) < 1 || procfile_linewords(m->numastat_ff, 0) < 1))
continue;
- procfile *ff = m->numastat_ff;
-
- RRDSET *st = m->numastat_st;
- if(unlikely(!st)) {
- st = rrdset_create("mem", m->name, NULL, "numa", NULL, "NUMA events", "events/s", 1000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ if(unlikely(!m->numastat_st)) {
+ m->numastat_st = rrdset_create_localhost(
+ "mem"
+ , m->name
+ , NULL
+ , "numa"
+ , NULL
+ , "NUMA events"
+ , "events/s"
+ , 1000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(m->numastat_st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(m->numastat_st, "numa_hit", "hit", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "numa_miss", "miss", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "local_node", "local", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "numa_foreign", "foreign", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "interleave_hit", "interleave", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "other_node", "other", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "local_node", "local", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "numa_foreign", "foreign", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "interleave_hit", "interleave", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "other_node", "other", 1, 1, RRDDIM_INCREMENTAL);
-
- m->numastat_st = st;
}
- else rrdset_next(st);
+ else rrdset_next(m->numastat_st);
- uint32_t lines = procfile_lines(ff), l;
+ size_t lines = procfile_lines(m->numastat_ff), l;
for(l = 0; l < lines; l++) {
- uint32_t words = procfile_linewords(ff, l);
+ size_t words = procfile_linewords(m->numastat_ff, l);
+
if(unlikely(words < 2)) {
- if(unlikely(words)) error("Cannot read %s numastat line %u. Expected 2 params, read %u.", m->name, l, words);
+ if(unlikely(words))
+ error("Cannot read %s numastat line %zu. Expected 2 params, read %zu.", m->name, l, words);
continue;
}
- char *name = procfile_lineword(ff, l, 0);
- char *value = procfile_lineword(ff, l, 1);
- if (unlikely(!name || !*name || !value || !*value)) continue;
+ char *name = procfile_lineword(m->numastat_ff, l, 0);
+ char *value = procfile_lineword(m->numastat_ff, l, 1);
- rrddim_set(st, name, strtoull(value, NULL, 10));
+ if (unlikely(!name || !*name || !value || !*value))
+ continue;
+
+ uint32_t hash = simple_hash(name);
+ if(likely(
+ (hash == hash_numa_hit && !strcmp(name, "numa_hit"))
+ || (hash == hash_numa_miss && !strcmp(name, "numa_miss"))
+ || (hash == hash_local_node && !strcmp(name, "local_node"))
+ || (hash == hash_numa_foreign && !strcmp(name, "numa_foreign"))
+ || (hash == hash_interleave_hit && !strcmp(name, "interleave_hit"))
+ || (hash == hash_other_node && !strcmp(name, "other_node"))
+ ))
+ rrddim_set(m->numastat_st, name, (collected_number)str2kernel_uint_t(value));
}
- rrdset_done(st);
+
+ rrdset_done(m->numastat_st);
}
}
}
diff --git a/src/sys_fs_cgroup.c b/src/sys_fs_cgroup.c
index 2b7254f47..8f31527de 100644
--- a/src/sys_fs_cgroup.c
+++ b/src/sys_fs_cgroup.c
@@ -8,22 +8,22 @@
static long system_page_size = 4096; // system will be queried via sysconf() in configuration()
-static int cgroup_enable_cpuacct_stat = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_memory = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_detailed_memory = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_memory_failcnt = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_swap = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_io = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_ops = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_throttle_io = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_throttle_ops = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_merged_ops = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_queued_ops = CONFIG_ONDEMAND_ONDEMAND;
-
-static int cgroup_enable_systemd_services = CONFIG_ONDEMAND_YES;
-static int cgroup_enable_systemd_services_detailed_memory = CONFIG_ONDEMAND_NO;
-static int cgroup_used_memory_without_cache = CONFIG_ONDEMAND_YES;
+static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_memory = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_detailed_memory = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_swap = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_io = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_ops = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_throttle_io = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_throttle_ops = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_merged_ops = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_AUTO;
+
+static int cgroup_enable_systemd_services = CONFIG_BOOLEAN_YES;
+static int cgroup_enable_systemd_services_detailed_memory = CONFIG_BOOLEAN_NO;
+static int cgroup_used_memory_without_cache = CONFIG_BOOLEAN_YES;
static int cgroup_search_in_devices = 1;
@@ -49,7 +49,9 @@ static SIMPLE_PATTERN *enabled_cgroup_paths = NULL;
static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
-static char *cgroups_rename_script = PLUGINS_DIR "/cgroup-name.sh";
+static char *cgroups_rename_script = NULL;
+
+static int cgroups_check = 0;
static uint32_t Read_hash = 0;
static uint32_t Write_hash = 0;
@@ -64,9 +66,9 @@ void read_cgroup_plugin_configuration() {
user_hash = simple_hash("user");
system_hash = simple_hash("system");
- cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", rrd_update_every);
- if(cgroup_update_every < rrd_update_every)
- cgroup_update_every = rrd_update_every;
+ cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", localhost->rrd_update_every);
+ if(cgroup_update_every < localhost->rrd_update_every)
+ cgroup_update_every = localhost->rrd_update_every;
cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every * cgroup_update_every);
if(cgroup_check_for_new_every < cgroup_update_every)
@@ -105,7 +107,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/cpuacct";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
@@ -115,7 +117,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/blkio";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
@@ -125,7 +127,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/memory";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
@@ -135,7 +137,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/devices";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
cgroup_root_max = (int)config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
@@ -145,6 +147,8 @@ void read_cgroup_plugin_configuration() {
enabled_cgroup_patterns = simple_pattern_create(
config_get("plugin:cgroups", "enable by default cgroups matching",
+ " /system.slice/docker-*.scope "
+ " /qemu.slice/*.scope " // #1949
" !*.mount "
" !*.partition "
" !*.scope "
@@ -156,18 +160,18 @@ void read_cgroup_plugin_configuration() {
" !/docker "
" !/libvirt "
" !/lxc "
- " !/lxc/*/ns " // #1397
+ " !/lxc/*/ns " // #1397
" !/machine "
" !/qemu "
" !/system "
" !/systemd "
" !/user "
- " * " // enable anything else
+ " * " // enable anything else
), SIMPLE_PATTERN_EXACT);
enabled_cgroup_paths = simple_pattern_create(
config_get("plugin:cgroups", "search for cgroups in subpaths matching",
- " !*-qemu " // #345
+ " !*-qemu " // #345
" !/init.scope "
" !/system "
" !/systemd "
@@ -176,10 +180,14 @@ void read_cgroup_plugin_configuration() {
" * "
), SIMPLE_PATTERN_EXACT);
- cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", cgroups_rename_script);
+ 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);
enabled_cgroup_renames = simple_pattern_create(
config_get("plugin:cgroups", "run script to rename cgroups matching",
+ " /qemu.slice/*.scope " // #1949
+ " *docker* "
+ " *lxc* "
" !/ "
" !*.mount "
" !*.partition "
@@ -207,7 +215,7 @@ void read_cgroup_plugin_configuration() {
struct blkio {
int updated;
- int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
int delay_counter;
char *filename;
@@ -232,10 +240,10 @@ struct memory {
int updated_msw_usage_in_bytes;
int updated_failcnt;
- int enabled_detailed; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
- int enabled_usage_in_bytes; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
- int enabled_msw_usage_in_bytes; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
- int enabled_failcnt; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled_detailed; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
+ int enabled_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
+ int enabled_msw_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
+ int enabled_failcnt; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
int delay_counter_detailed;
int delay_counter_failcnt;
@@ -294,7 +302,7 @@ struct memory {
// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
struct cpuacct_stat {
int updated;
- int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
char *filename;
@@ -305,7 +313,7 @@ struct cpuacct_stat {
// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
struct cpuacct_usage {
int updated;
- int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
char *filename;
@@ -403,12 +411,14 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
cp->updated = 0;
+ cgroups_check = 1;
return;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
cp->updated = 0;
+ cgroups_check = 1;
return;
}
@@ -433,8 +443,8 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
cp->updated = 1;
- if(unlikely(cp->enabled == CONFIG_ONDEMAND_ONDEMAND && (cp->user || cp->system)))
- cp->enabled = CONFIG_ONDEMAND_YES;
+ if(unlikely(cp->enabled == CONFIG_BOOLEAN_AUTO && (cp->user || cp->system)))
+ cp->enabled = CONFIG_BOOLEAN_YES;
}
}
@@ -445,12 +455,14 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
ca->updated = 0;
+ cgroups_check = 1;
return;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
ca->updated = 0;
+ cgroups_check = 1;
return;
}
@@ -462,8 +474,8 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
unsigned long i = procfile_linewords(ff, 0);
if(unlikely(i == 0)) {
- return;
ca->updated = 0;
+ return;
}
// we may have 1 more CPU reported
@@ -488,15 +500,15 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
ca->updated = 1;
- if(unlikely(ca->enabled == CONFIG_ONDEMAND_ONDEMAND && total))
- ca->enabled = CONFIG_ONDEMAND_YES;
+ if(unlikely(ca->enabled == CONFIG_BOOLEAN_AUTO && total))
+ ca->enabled = CONFIG_BOOLEAN_YES;
}
}
static inline void cgroup_read_blkio(struct blkio *io) {
static procfile *ff = NULL;
- if(unlikely(io->enabled == CONFIG_ONDEMAND_ONDEMAND && io->delay_counter > 0)) {
+ if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO && io->delay_counter > 0)) {
io->delay_counter--;
return;
}
@@ -505,12 +517,14 @@ static inline void cgroup_read_blkio(struct blkio *io) {
ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
io->updated = 0;
+ cgroups_check = 1;
return;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
io->updated = 0;
+ cgroups_check = 1;
return;
}
@@ -554,9 +568,9 @@ static inline void cgroup_read_blkio(struct blkio *io) {
io->updated = 1;
- if(unlikely(io->enabled == CONFIG_ONDEMAND_ONDEMAND)) {
+ if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO)) {
if(unlikely(io->Read || io->Write))
- io->enabled = CONFIG_ONDEMAND_YES;
+ io->enabled = CONFIG_BOOLEAN_YES;
else
io->delay_counter = cgroup_recheck_zero_blkio_every_iterations;
}
@@ -568,7 +582,7 @@ static inline void cgroup_read_memory(struct memory *mem) {
// read detailed ram usage
if(likely(mem->filename_detailed)) {
- if(unlikely(mem->enabled_detailed == CONFIG_ONDEMAND_ONDEMAND && mem->delay_counter_detailed > 0)) {
+ if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO && mem->delay_counter_detailed > 0)) {
mem->delay_counter_detailed--;
goto memory_next;
}
@@ -576,12 +590,14 @@ static inline void cgroup_read_memory(struct memory *mem) {
ff = procfile_reopen(ff, mem->filename_detailed, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
mem->updated_detailed = 0;
+ cgroups_check = 1;
goto memory_next;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
mem->updated_detailed = 0;
+ cgroups_check = 1;
goto memory_next;
}
@@ -627,9 +643,9 @@ static inline void cgroup_read_memory(struct memory *mem) {
mem->updated_detailed = 1;
- if(unlikely(mem->enabled_detailed == CONFIG_ONDEMAND_ONDEMAND)) {
+ if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO)) {
if(mem->cache || mem->dirty || mem->rss || mem->rss_huge || mem->mapped_file || mem->writeback || mem->swap || mem->pgpgin || mem->pgpgout || mem->pgfault || mem->pgmajfault)
- mem->enabled_detailed = CONFIG_ONDEMAND_YES;
+ mem->enabled_detailed = CONFIG_BOOLEAN_YES;
else
mem->delay_counter_detailed = cgroup_recheck_zero_mem_detailed_every_iterations;
}
@@ -640,30 +656,30 @@ memory_next:
// read usage_in_bytes
if(likely(mem->filename_usage_in_bytes)) {
mem->updated_usage_in_bytes = !read_single_number_file(mem->filename_usage_in_bytes, &mem->usage_in_bytes);
- if(unlikely(mem->updated_usage_in_bytes && mem->enabled_usage_in_bytes == CONFIG_ONDEMAND_ONDEMAND && mem->usage_in_bytes))
- mem->enabled_usage_in_bytes = CONFIG_ONDEMAND_YES;
+ if(unlikely(mem->updated_usage_in_bytes && mem->enabled_usage_in_bytes == CONFIG_BOOLEAN_AUTO && mem->usage_in_bytes))
+ mem->enabled_usage_in_bytes = CONFIG_BOOLEAN_YES;
}
// read msw_usage_in_bytes
if(likely(mem->filename_msw_usage_in_bytes)) {
mem->updated_msw_usage_in_bytes = !read_single_number_file(mem->filename_msw_usage_in_bytes, &mem->msw_usage_in_bytes);
- if(unlikely(mem->updated_msw_usage_in_bytes && mem->enabled_msw_usage_in_bytes == CONFIG_ONDEMAND_ONDEMAND && mem->msw_usage_in_bytes))
- mem->enabled_msw_usage_in_bytes = CONFIG_ONDEMAND_YES;
+ if(unlikely(mem->updated_msw_usage_in_bytes && mem->enabled_msw_usage_in_bytes == CONFIG_BOOLEAN_AUTO && mem->msw_usage_in_bytes))
+ mem->enabled_msw_usage_in_bytes = CONFIG_BOOLEAN_YES;
}
// read failcnt
if(likely(mem->filename_failcnt)) {
- if(unlikely(mem->enabled_failcnt == CONFIG_ONDEMAND_ONDEMAND && mem->delay_counter_failcnt > 0)) {
+ if(unlikely(mem->enabled_failcnt == CONFIG_BOOLEAN_AUTO && mem->delay_counter_failcnt > 0)) {
mem->updated_failcnt = 0;
mem->delay_counter_failcnt--;
}
else {
mem->updated_failcnt = !read_single_number_file(mem->filename_failcnt, &mem->failcnt);
- if(unlikely(mem->updated_failcnt && mem->enabled_failcnt == CONFIG_ONDEMAND_ONDEMAND)) {
+ if(unlikely(mem->updated_failcnt && mem->enabled_failcnt == CONFIG_BOOLEAN_AUTO)) {
if(unlikely(!mem->failcnt))
mem->delay_counter_failcnt = cgroup_recheck_zero_mem_failcnt_every_iterations;
else
- mem->enabled_failcnt = CONFIG_ONDEMAND_YES;
+ mem->enabled_failcnt = CONFIG_BOOLEAN_YES;
}
}
}
@@ -877,6 +893,21 @@ static inline struct cgroup *cgroup_add(const char *id) {
static inline void cgroup_free(struct cgroup *cg) {
debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
+ if(cg->st_cpu) rrdset_flag_set(cg->st_cpu, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_cpu_per_core) rrdset_flag_set(cg->st_cpu_per_core, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem) rrdset_flag_set(cg->st_mem, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_writeback) rrdset_flag_set(cg->st_writeback, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem_activity) rrdset_flag_set(cg->st_mem_activity, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_pgfaults) rrdset_flag_set(cg->st_pgfaults, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem_usage) rrdset_flag_set(cg->st_mem_usage, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem_failcnt) rrdset_flag_set(cg->st_mem_failcnt, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_io) rrdset_flag_set(cg->st_io, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_serviced_ops) rrdset_flag_set(cg->st_serviced_ops, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_throttle_io) rrdset_flag_set(cg->st_throttle_io, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_throttle_serviced_ops) rrdset_flag_set(cg->st_throttle_serviced_ops, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_queued_ops) rrdset_flag_set(cg->st_queued_ops, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_merged_ops) rrdset_flag_set(cg->st_merged_ops, RRDSET_FLAG_OBSOLETE);
+
freez(cg->cpuacct_usage.cpu_percpu);
freez(cg->cpuacct_stat.filename);
@@ -1070,7 +1101,7 @@ static inline void find_all_cgroups() {
if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
if(find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
cgroup_enable_cpuacct_stat =
- cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_NO;
+ cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
error("disabled CGROUP cpu statistics.");
}
}
@@ -1082,7 +1113,7 @@ static inline void find_all_cgroups() {
cgroup_enable_blkio_throttle_io =
cgroup_enable_blkio_throttle_ops =
cgroup_enable_blkio_merged_ops =
- cgroup_enable_blkio_queued_ops = CONFIG_ONDEMAND_NO;
+ cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_NO;
error("disabled CGROUP blkio statistics.");
}
}
@@ -1092,7 +1123,7 @@ static inline void find_all_cgroups() {
cgroup_enable_memory =
cgroup_enable_detailed_memory =
cgroup_enable_swap =
- cgroup_enable_memory_failcnt = CONFIG_ONDEMAND_NO;
+ cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_NO;
error("disabled CGROUP memory statistics.");
}
}
@@ -1146,7 +1177,7 @@ static inline void find_all_cgroups() {
snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
if(likely(stat(filename, &buf) != -1)) {
cg->memory.filename_detailed = strdupz(filename);
- cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_ONDEMAND_YES)?CONFIG_ONDEMAND_YES:CONFIG_ONDEMAND_ONDEMAND;
+ cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_AUTO;
debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_detailed);
}
else
@@ -1262,18 +1293,19 @@ static inline void find_all_cgroups() {
#define CHART_TITLE_MAX 300
-void update_services_charts(int update_every,
- int do_cpu,
- int do_mem_usage,
- int do_mem_detailed,
- int do_mem_failcnt,
- int do_swap_usage,
- int do_io,
- int do_io_ops,
- int do_throttle_io,
- int do_throttle_ops,
- int do_queued_ops,
- int do_merged_ops
+void update_systemd_services_charts(
+ int update_every
+ , int do_cpu
+ , int do_mem_usage
+ , int do_mem_detailed
+ , int do_mem_failcnt
+ , int do_swap_usage
+ , int do_io
+ , int do_io_ops
+ , int do_throttle_io
+ , int do_throttle_ops
+ , int do_queued_ops
+ , int do_merged_ops
) {
static RRDSET
*st_cpu = NULL,
@@ -1309,12 +1341,21 @@ void update_services_charts(int update_every,
if(likely(do_cpu)) {
if(unlikely(!st_cpu)) {
char title[CHART_TITLE_MAX + 1];
+ snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
+
+ st_cpu = rrdset_create_localhost(
+ "services"
+ , "cpu"
+ , NULL
+ , "cpu"
+ , "services.cpu"
+ , title
+ , "%"
+ , CHART_PRIORITY_SYSTEMD_SERVICES
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
- st_cpu = rrdset_find_bytype("services", "cpu");
- if(likely(!st_cpu)) {
- snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
- st_cpu = rrdset_create("services", "cpu", NULL, "cpu", "services.cpu", title, "%", CHART_PRIORITY_SYSTEMD_SERVICES, update_every, RRDSET_TYPE_STACKED);
- }
}
else
rrdset_next(st_cpu);
@@ -1322,9 +1363,21 @@ void update_services_charts(int update_every,
if(likely(do_mem_usage)) {
if(unlikely(!st_mem_usage)) {
- st_mem_usage = rrdset_find_bytype("services", "mem_usage");
- if(likely(!st_mem_usage))
- st_mem_usage = rrdset_create("services", "mem_usage", NULL, "mem", "services.mem_usage", (cgroup_used_memory_without_cache)?"Systemd Services Used Memory without Cache":"Systemd Services Used Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 10, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_usage = rrdset_create_localhost(
+ "services"
+ , "mem_usage"
+ , NULL
+ , "mem"
+ , "services.mem_usage"
+ , (cgroup_used_memory_without_cache) ? "Systemd Services Used Memory without Cache"
+ : "Systemd Services Used Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 10
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_usage);
@@ -1332,65 +1385,152 @@ void update_services_charts(int update_every,
if(likely(do_mem_detailed)) {
if(unlikely(!st_mem_detailed_rss)) {
- st_mem_detailed_rss = rrdset_find_bytype("services", "mem_rss");
- if(likely(!st_mem_detailed_rss))
- st_mem_detailed_rss = rrdset_create("services", "mem_rss", NULL, "mem", "services.mem_rss", "Systemd Services RSS Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 20, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_rss = rrdset_create_localhost(
+ "services"
+ , "mem_rss"
+ , NULL
+ , "mem"
+ , "services.mem_rss"
+ , "Systemd Services RSS Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 20
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_rss);
if(unlikely(!st_mem_detailed_mapped)) {
- st_mem_detailed_mapped = rrdset_find_bytype("services", "mem_mapped");
- if(likely(!st_mem_detailed_mapped))
- st_mem_detailed_mapped = rrdset_create("services", "mem_mapped", NULL, "mem", "services.mem_mapped", "Systemd Services Mapped Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 30, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_mapped = rrdset_create_localhost(
+ "services"
+ , "mem_mapped"
+ , NULL
+ , "mem"
+ , "services.mem_mapped"
+ , "Systemd Services Mapped Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 30
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_mapped);
if(unlikely(!st_mem_detailed_cache)) {
- st_mem_detailed_cache = rrdset_find_bytype("services", "mem_cache");
- if(likely(!st_mem_detailed_cache))
- st_mem_detailed_cache = rrdset_create("services", "mem_cache", NULL, "mem", "services.mem_cache", "Systemd Services Cache Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 40, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_cache = rrdset_create_localhost(
+ "services"
+ , "mem_cache"
+ , NULL
+ , "mem"
+ , "services.mem_cache"
+ , "Systemd Services Cache Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 40
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_cache);
if(unlikely(!st_mem_detailed_writeback)) {
- st_mem_detailed_writeback = rrdset_find_bytype("services", "mem_writeback");
- if(likely(!st_mem_detailed_writeback))
- st_mem_detailed_writeback = rrdset_create("services", "mem_writeback", NULL, "mem", "services.mem_writeback", "Systemd Services Writeback Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 50, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_writeback = rrdset_create_localhost(
+ "services"
+ , "mem_writeback"
+ , NULL
+ , "mem"
+ , "services.mem_writeback"
+ , "Systemd Services Writeback Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 50
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_writeback);
if(unlikely(!st_mem_detailed_pgfault)) {
- st_mem_detailed_pgfault = rrdset_find_bytype("services", "mem_pgfault");
- if(likely(!st_mem_detailed_pgfault))
- st_mem_detailed_pgfault = rrdset_create("services", "mem_pgfault", NULL, "mem", "services.mem_pgfault", "Systemd Services Memory Minor Page Faults", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 60, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgfault = rrdset_create_localhost(
+ "services"
+ , "mem_pgfault"
+ , NULL
+ , "mem"
+ , "services.mem_pgfault"
+ , "Systemd Services Memory Minor Page Faults"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 60
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
else
rrdset_next(st_mem_detailed_pgfault);
if(unlikely(!st_mem_detailed_pgmajfault)) {
- st_mem_detailed_pgmajfault = rrdset_find_bytype("services", "mem_pgmajfault");
- if(likely(!st_mem_detailed_pgmajfault))
- st_mem_detailed_pgmajfault = rrdset_create("services", "mem_pgmajfault", NULL, "mem", "services.mem_pgmajfault", "Systemd Services Memory Major Page Faults", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 70, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgmajfault = rrdset_create_localhost(
+ "services"
+ , "mem_pgmajfault"
+ , NULL
+ , "mem"
+ , "services.mem_pgmajfault"
+ , "Systemd Services Memory Major Page Faults"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 70
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_pgmajfault);
if(unlikely(!st_mem_detailed_pgpgin)) {
- st_mem_detailed_pgpgin = rrdset_find_bytype("services", "mem_pgpgin");
- if(likely(!st_mem_detailed_pgpgin))
- st_mem_detailed_pgpgin = rrdset_create("services", "mem_pgpgin", NULL, "mem", "services.mem_pgpgin", "Systemd Services Memory Charging Activity", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 80, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgpgin = rrdset_create_localhost(
+ "services"
+ , "mem_pgpgin"
+ , NULL
+ , "mem"
+ , "services.mem_pgpgin"
+ , "Systemd Services Memory Charging Activity"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 80
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_pgpgin);
if(unlikely(!st_mem_detailed_pgpgout)) {
- st_mem_detailed_pgpgout = rrdset_find_bytype("services", "mem_pgpgout");
- if(likely(!st_mem_detailed_pgpgout))
- st_mem_detailed_pgpgout = rrdset_create("services", "mem_pgpgout", NULL, "mem", "services.mem_pgpgout", "Systemd Services Memory Uncharging Activity", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 90, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgpgout = rrdset_create_localhost(
+ "services"
+ , "mem_pgpgout"
+ , NULL
+ , "mem"
+ , "services.mem_pgpgout"
+ , "Systemd Services Memory Uncharging Activity"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 90
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_pgpgout);
@@ -1398,9 +1538,20 @@ void update_services_charts(int update_every,
if(likely(do_mem_failcnt)) {
if(unlikely(!st_mem_failcnt)) {
- st_mem_failcnt = rrdset_find_bytype("services", "mem_failcnt");
- if(likely(!st_mem_failcnt))
- st_mem_failcnt = rrdset_create("services", "mem_failcnt", NULL, "mem", "services.mem_failcnt", "Systemd Services Memory Limit Failures", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 110, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_failcnt = rrdset_create_localhost(
+ "services"
+ , "mem_failcnt"
+ , NULL
+ , "mem"
+ , "services.mem_failcnt"
+ , "Systemd Services Memory Limit Failures"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 110
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_failcnt);
@@ -1408,9 +1559,20 @@ void update_services_charts(int update_every,
if(likely(do_swap_usage)) {
if(unlikely(!st_swap_usage)) {
- st_swap_usage = rrdset_find_bytype("services", "swap_usage");
- if(likely(!st_swap_usage))
- st_swap_usage = rrdset_create("services", "swap_usage", NULL, "swap", "services.swap_usage", "Systemd Services Swap Memory Used", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 100, update_every, RRDSET_TYPE_STACKED);
+
+ st_swap_usage = rrdset_create_localhost(
+ "services"
+ , "swap_usage"
+ , NULL
+ , "swap"
+ , "services.swap_usage"
+ , "Systemd Services Swap Memory Used"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 100
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_swap_usage);
@@ -1418,17 +1580,39 @@ void update_services_charts(int update_every,
if(likely(do_io)) {
if(unlikely(!st_io_read)) {
- st_io_read = rrdset_find_bytype("services", "io_read");
- if(likely(!st_io_read))
- st_io_read = rrdset_create("services", "io_read", NULL, "disk", "services.io_read", "Systemd Services Disk Read Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 120, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_read = rrdset_create_localhost(
+ "services"
+ , "io_read"
+ , NULL
+ , "disk"
+ , "services.io_read"
+ , "Systemd Services Disk Read Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 120
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_read);
if(unlikely(!st_io_write)) {
- st_io_write = rrdset_find_bytype("services", "io_write");
- if(likely(!st_io_write))
- st_io_write = rrdset_create("services", "io_write", NULL, "disk", "services.io_write", "Systemd Services Disk Write Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 130, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_write = rrdset_create_localhost(
+ "services"
+ , "io_write"
+ , NULL
+ , "disk"
+ , "services.io_write"
+ , "Systemd Services Disk Write Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 130
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_write);
@@ -1436,17 +1620,39 @@ void update_services_charts(int update_every,
if(likely(do_io_ops)) {
if(unlikely(!st_io_serviced_read)) {
- st_io_serviced_read = rrdset_find_bytype("services", "io_ops_read");
- if(likely(!st_io_serviced_read))
- st_io_serviced_read = rrdset_create("services", "io_ops_read", NULL, "disk", "services.io_ops_read", "Systemd Services Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 140, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_serviced_read = rrdset_create_localhost(
+ "services"
+ , "io_ops_read"
+ , NULL
+ , "disk"
+ , "services.io_ops_read"
+ , "Systemd Services Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 140
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_serviced_read);
if(unlikely(!st_io_serviced_write)) {
- st_io_serviced_write = rrdset_find_bytype("services", "io_ops_write");
- if(likely(!st_io_serviced_write))
- st_io_serviced_write = rrdset_create("services", "io_ops_write", NULL, "disk", "services.io_ops_write", "Systemd Services Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 150, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_serviced_write = rrdset_create_localhost(
+ "services"
+ , "io_ops_write"
+ , NULL
+ , "disk"
+ , "services.io_ops_write"
+ , "Systemd Services Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 150
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_serviced_write);
@@ -1454,17 +1660,39 @@ void update_services_charts(int update_every,
if(likely(do_throttle_io)) {
if(unlikely(!st_throttle_io_read)) {
- st_throttle_io_read = rrdset_find_bytype("services", "throttle_io_read");
- if(likely(!st_throttle_io_read))
- st_throttle_io_read = rrdset_create("services", "throttle_io_read", NULL, "disk", "services.throttle_io_read", "Systemd Services Throttle Disk Read Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 160, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_io_read = rrdset_create_localhost(
+ "services"
+ , "throttle_io_read"
+ , NULL
+ , "disk"
+ , "services.throttle_io_read"
+ , "Systemd Services Throttle Disk Read Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 160
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_io_read);
if(unlikely(!st_throttle_io_write)) {
- st_throttle_io_write = rrdset_find_bytype("services", "throttle_io_write");
- if(likely(!st_throttle_io_write))
- st_throttle_io_write = rrdset_create("services", "throttle_io_write", NULL, "disk", "services.throttle_io_write", "Systemd Services Throttle Disk Write Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 170, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_io_write = rrdset_create_localhost(
+ "services"
+ , "throttle_io_write"
+ , NULL
+ , "disk"
+ , "services.throttle_io_write"
+ , "Systemd Services Throttle Disk Write Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 170
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_io_write);
@@ -1472,17 +1700,39 @@ void update_services_charts(int update_every,
if(likely(do_throttle_ops)) {
if(unlikely(!st_throttle_ops_read)) {
- st_throttle_ops_read = rrdset_find_bytype("services", "throttle_io_ops_read");
- if(likely(!st_throttle_ops_read))
- st_throttle_ops_read = rrdset_create("services", "throttle_io_ops_read", NULL, "disk", "services.throttle_io_ops_read", "Systemd Services Throttle Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 180, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_ops_read = rrdset_create_localhost(
+ "services"
+ , "throttle_io_ops_read"
+ , NULL
+ , "disk"
+ , "services.throttle_io_ops_read"
+ , "Systemd Services Throttle Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 180
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_ops_read);
if(unlikely(!st_throttle_ops_write)) {
- st_throttle_ops_write = rrdset_find_bytype("services", "throttle_io_ops_write");
- if(likely(!st_throttle_ops_write))
- st_throttle_ops_write = rrdset_create("services", "throttle_io_ops_write", NULL, "disk", "services.throttle_io_ops_write", "Systemd Services Throttle Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 190, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_ops_write = rrdset_create_localhost(
+ "services"
+ , "throttle_io_ops_write"
+ , NULL
+ , "disk"
+ , "services.throttle_io_ops_write"
+ , "Systemd Services Throttle Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 190
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_ops_write);
@@ -1490,17 +1740,39 @@ void update_services_charts(int update_every,
if(likely(do_queued_ops)) {
if(unlikely(!st_queued_ops_read)) {
- st_queued_ops_read = rrdset_find_bytype("services", "queued_io_ops_read");
- if(likely(!st_queued_ops_read))
- st_queued_ops_read = rrdset_create("services", "queued_io_ops_read", NULL, "disk", "services.queued_io_ops_read", "Systemd Services Queued Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 200, update_every, RRDSET_TYPE_STACKED);
+
+ st_queued_ops_read = rrdset_create_localhost(
+ "services"
+ , "queued_io_ops_read"
+ , NULL
+ , "disk"
+ , "services.queued_io_ops_read"
+ , "Systemd Services Queued Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 200
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_queued_ops_read);
if(unlikely(!st_queued_ops_write)) {
- st_queued_ops_write = rrdset_find_bytype("services", "queued_io_ops_write");
- if(likely(!st_queued_ops_write))
- st_queued_ops_write = rrdset_create("services", "queued_io_ops_write", NULL, "disk", "services.queued_io_ops_write", "Systemd Services Queued Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 210, update_every, RRDSET_TYPE_STACKED);
+
+ st_queued_ops_write = rrdset_create_localhost(
+ "services"
+ , "queued_io_ops_write"
+ , NULL
+ , "disk"
+ , "services.queued_io_ops_write"
+ , "Systemd Services Queued Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 210
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_queued_ops_write);
@@ -1508,17 +1780,39 @@ void update_services_charts(int update_every,
if(likely(do_merged_ops)) {
if(unlikely(!st_merged_ops_read)) {
- st_merged_ops_read = rrdset_find_bytype("services", "merged_io_ops_read");
- if(likely(!st_merged_ops_read))
- st_merged_ops_read = rrdset_create("services", "merged_io_ops_read", NULL, "disk", "services.merged_io_ops_read", "Systemd Services Merged Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 220, update_every, RRDSET_TYPE_STACKED);
+
+ st_merged_ops_read = rrdset_create_localhost(
+ "services"
+ , "merged_io_ops_read"
+ , NULL
+ , "disk"
+ , "services.merged_io_ops_read"
+ , "Systemd Services Merged Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 220
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_merged_ops_read);
if(unlikely(!st_merged_ops_write)) {
- st_merged_ops_write = rrdset_find_bytype("services", "merged_io_ops_write");
- if(likely(!st_merged_ops_write))
- st_merged_ops_write = rrdset_create("services", "merged_io_ops_write", NULL, "disk", "services.merged_io_ops_write", "Systemd Services Merged Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 230, update_every, RRDSET_TYPE_STACKED);
+
+ st_merged_ops_write = rrdset_create_localhost(
+ "services"
+ , "merged_io_ops_write"
+ , NULL
+ , "disk"
+ , "services.merged_io_ops_write"
+ , "Systemd Services Merged Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 230
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_merged_ops_write);
@@ -1532,134 +1826,142 @@ void update_services_charts(int update_every,
if(likely(do_cpu && cg->cpuacct_stat.updated)) {
if(unlikely(!cg->rd_cpu))
- cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRDDIM_INCREMENTAL);
+ cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
}
if(likely(do_mem_usage && cg->memory.updated_usage_in_bytes)) {
if(unlikely(!cg->rd_mem_usage))
- cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_set_by_pointer(st_mem_usage, cg->rd_mem_usage, cg->memory.usage_in_bytes - ((cgroup_used_memory_without_cache)?cg->memory.cache:0));
}
if(likely(do_mem_detailed && cg->memory.updated_detailed)) {
if(unlikely(!cg->rd_mem_detailed_rss))
- cg->rd_mem_detailed_rss = rrddim_add(st_mem_detailed_rss, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_rss = rrddim_add(st_mem_detailed_rss, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_rss, cg->rd_mem_detailed_rss, cg->memory.rss + cg->memory.rss_huge);
if(unlikely(!cg->rd_mem_detailed_mapped))
- cg->rd_mem_detailed_mapped = rrddim_add(st_mem_detailed_mapped, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_mapped = rrddim_add(st_mem_detailed_mapped, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_mapped, cg->rd_mem_detailed_mapped, cg->memory.mapped_file);
if(unlikely(!cg->rd_mem_detailed_cache))
- cg->rd_mem_detailed_cache = rrddim_add(st_mem_detailed_cache, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_cache = rrddim_add(st_mem_detailed_cache, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_cache, cg->rd_mem_detailed_cache, cg->memory.cache);
if(unlikely(!cg->rd_mem_detailed_writeback))
- cg->rd_mem_detailed_writeback = rrddim_add(st_mem_detailed_writeback, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_writeback = rrddim_add(st_mem_detailed_writeback, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_writeback, cg->rd_mem_detailed_writeback, cg->memory.writeback);
if(unlikely(!cg->rd_mem_detailed_pgfault))
- cg->rd_mem_detailed_pgfault = rrddim_add(st_mem_detailed_pgfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgfault = rrddim_add(st_mem_detailed_pgfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgfault, cg->rd_mem_detailed_pgfault, cg->memory.pgfault);
if(unlikely(!cg->rd_mem_detailed_pgmajfault))
- cg->rd_mem_detailed_pgmajfault = rrddim_add(st_mem_detailed_pgmajfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgmajfault = rrddim_add(st_mem_detailed_pgmajfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgmajfault, cg->rd_mem_detailed_pgmajfault, cg->memory.pgmajfault);
if(unlikely(!cg->rd_mem_detailed_pgpgin))
- cg->rd_mem_detailed_pgpgin = rrddim_add(st_mem_detailed_pgpgin, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgpgin = rrddim_add(st_mem_detailed_pgpgin, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgpgin, cg->rd_mem_detailed_pgpgin, cg->memory.pgpgin);
if(unlikely(!cg->rd_mem_detailed_pgpgout))
- cg->rd_mem_detailed_pgpgout = rrddim_add(st_mem_detailed_pgpgout, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgpgout = rrddim_add(st_mem_detailed_pgpgout, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgpgout, cg->rd_mem_detailed_pgpgout, cg->memory.pgpgout);
}
if(likely(do_mem_failcnt && cg->memory.updated_failcnt)) {
if(unlikely(!cg->rd_mem_failcnt))
- cg->rd_mem_failcnt = rrddim_add(st_mem_failcnt, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_mem_failcnt = rrddim_add(st_mem_failcnt, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_mem_failcnt, cg->rd_mem_failcnt, cg->memory.failcnt);
}
if(likely(do_swap_usage && cg->memory.updated_msw_usage_in_bytes)) {
if(unlikely(!cg->rd_swap_usage))
- cg->rd_swap_usage = rrddim_add(st_swap_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_swap_usage = rrddim_add(st_swap_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_set_by_pointer(st_swap_usage, cg->rd_swap_usage, cg->memory.msw_usage_in_bytes);
}
if(likely(do_io && cg->io_service_bytes.updated)) {
if(unlikely(!cg->rd_io_service_bytes_read))
- cg->rd_io_service_bytes_read = rrddim_add(st_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_io_service_bytes_read = rrddim_add(st_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_read, cg->rd_io_service_bytes_read, cg->io_service_bytes.Read);
if(unlikely(!cg->rd_io_service_bytes_write))
- cg->rd_io_service_bytes_write = rrddim_add(st_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_io_service_bytes_write = rrddim_add(st_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_write, cg->rd_io_service_bytes_write, cg->io_service_bytes.Write);
}
if(likely(do_io_ops && cg->io_serviced.updated)) {
if(unlikely(!cg->rd_io_serviced_read))
- cg->rd_io_serviced_read = rrddim_add(st_io_serviced_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_serviced_read = rrddim_add(st_io_serviced_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_serviced_read, cg->rd_io_serviced_read, cg->io_serviced.Read);
if(unlikely(!cg->rd_io_serviced_write))
- cg->rd_io_serviced_write = rrddim_add(st_io_serviced_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_serviced_write = rrddim_add(st_io_serviced_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_serviced_write, cg->rd_io_serviced_write, cg->io_serviced.Write);
}
if(likely(do_throttle_io && cg->throttle_io_service_bytes.updated)) {
if(unlikely(!cg->rd_throttle_io_read))
- cg->rd_throttle_io_read = rrddim_add(st_throttle_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_read = rrddim_add(st_throttle_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_io_read, cg->rd_throttle_io_read, cg->throttle_io_service_bytes.Read);
if(unlikely(!cg->rd_throttle_io_write))
- cg->rd_throttle_io_write = rrddim_add(st_throttle_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_write = rrddim_add(st_throttle_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_io_write, cg->rd_throttle_io_write, cg->throttle_io_service_bytes.Write);
}
if(likely(do_throttle_ops && cg->throttle_io_serviced.updated)) {
if(unlikely(!cg->rd_throttle_io_serviced_read))
- cg->rd_throttle_io_serviced_read = rrddim_add(st_throttle_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_serviced_read = rrddim_add(st_throttle_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_ops_read, cg->rd_throttle_io_serviced_read, cg->throttle_io_serviced.Read);
if(unlikely(!cg->rd_throttle_io_serviced_write))
- cg->rd_throttle_io_serviced_write = rrddim_add(st_throttle_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_serviced_write = rrddim_add(st_throttle_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_ops_write, cg->rd_throttle_io_serviced_write, cg->throttle_io_serviced.Write);
}
if(likely(do_queued_ops && cg->io_queued.updated)) {
if(unlikely(!cg->rd_io_queued_read))
- cg->rd_io_queued_read = rrddim_add(st_queued_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_queued_read = rrddim_add(st_queued_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_queued_ops_read, cg->rd_io_queued_read, cg->io_queued.Read);
if(unlikely(!cg->rd_io_queued_write))
- cg->rd_io_queued_write = rrddim_add(st_queued_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_queued_write = rrddim_add(st_queued_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_queued_ops_write, cg->rd_io_queued_write, cg->io_queued.Write);
}
if(likely(do_merged_ops && cg->io_merged.updated)) {
if(unlikely(!cg->rd_io_merged_read))
- cg->rd_io_merged_read = rrddim_add(st_merged_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_merged_read = rrddim_add(st_merged_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_merged_ops_read, cg->rd_io_merged_read, cg->io_merged.Read);
if(unlikely(!cg->rd_io_merged_write))
- cg->rd_io_merged_write = rrddim_add(st_merged_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_merged_write = rrddim_add(st_merged_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_merged_ops_write, cg->rd_io_merged_write, cg->io_merged.Write);
}
@@ -1756,33 +2058,43 @@ void update_cgroup_charts(int update_every) {
continue;
if(likely(cgroup_enable_systemd_services && cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) {
- if(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_ONDEMAND_YES) services_do_cpu++;
+ if(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES) services_do_cpu++;
if(cgroup_enable_systemd_services_detailed_memory && cg->memory.updated_detailed && cg->memory.enabled_detailed) services_do_mem_detailed++;
- if(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_ONDEMAND_YES) services_do_mem_usage++;
- if(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_ONDEMAND_YES) services_do_mem_failcnt++;
- if(cg->memory.updated_msw_usage_in_bytes && cg->memory.enabled_msw_usage_in_bytes == CONFIG_ONDEMAND_YES) services_do_swap_usage++;
-
- if(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_ONDEMAND_YES) services_do_io++;
- if(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_ONDEMAND_YES) services_do_io_ops++;
- if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_ONDEMAND_YES) services_do_throttle_io++;
- if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_ONDEMAND_YES) services_do_throttle_ops++;
- if(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_ONDEMAND_YES) services_do_queued_ops++;
- if(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_ONDEMAND_YES) services_do_merged_ops++;
+ if(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES) services_do_mem_usage++;
+ if(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES) services_do_mem_failcnt++;
+ if(cg->memory.updated_msw_usage_in_bytes && cg->memory.enabled_msw_usage_in_bytes == CONFIG_BOOLEAN_YES) services_do_swap_usage++;
+
+ if(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES) services_do_io++;
+ if(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES) services_do_io_ops++;
+ if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES) services_do_throttle_io++;
+ if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES) services_do_throttle_ops++;
+ if(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES) services_do_queued_ops++;
+ if(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES) services_do_merged_ops++;
continue;
}
type[0] = '\0';
- if(likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_cpu)) {
- cg->st_cpu = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu");
- if(likely(!cg->st_cpu)) {
- snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
- cg->st_cpu = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", CHART_PRIORITY_CONTAINERS, update_every, RRDSET_TYPE_STACKED);
- }
- rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
+
+ cg->st_cpu = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "cpu"
+ , NULL
+ , "cpu"
+ , "cgroup.cpu"
+ , title
+ , "%"
+ , CHART_PRIORITY_CONTAINERS
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_cpu);
@@ -1792,84 +2104,128 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_cpu);
}
- if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_BOOLEAN_YES)) {
char id[RRD_ID_LENGTH_MAX + 1];
unsigned int i;
if(unlikely(!cg->st_cpu_per_core)) {
- cg->st_cpu_per_core = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu_per_core");
- if(likely(!cg->st_cpu_per_core)) {
- snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) Per Core for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
- cg->st_cpu_per_core = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", CHART_PRIORITY_CONTAINERS + 100, update_every, RRDSET_TYPE_STACKED);
- }
+ snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) Per Core for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
+
+ cg->st_cpu_per_core = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "cpu_per_core"
+ , NULL
+ , "cpu"
+ , "cgroup.cpu_per_core"
+ , title
+ , "%"
+ , CHART_PRIORITY_CONTAINERS + 100
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
for(i = 0; i < cg->cpuacct_usage.cpus; i++) {
- snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
- rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
+ snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
+ rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRD_ALGORITHM_INCREMENTAL);
}
}
else
rrdset_next(cg->st_cpu_per_core);
for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
- snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
+ snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
rrddim_set(cg->st_cpu_per_core, id, cg->cpuacct_usage.cpu_percpu[i]);
}
rrdset_done(cg->st_cpu_per_core);
}
- if(likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_mem)) {
- cg->st_mem = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem");
- if(likely(!cg->st_mem)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
- cg->st_mem = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", CHART_PRIORITY_CONTAINERS + 210, update_every, RRDSET_TYPE_STACKED);
- }
+ snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
+
+ cg->st_mem = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem"
+ , NULL
+ , "mem"
+ , "cgroup.mem"
+ , title
+ , "MB"
+ , CHART_PRIORITY_CONTAINERS + 210
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
if(cg->memory.detailed_has_swap)
- rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
+ rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_mem);
rrddim_set(cg->st_mem, "cache", cg->memory.cache);
rrddim_set(cg->st_mem, "rss", cg->memory.rss);
+
if(cg->memory.detailed_has_swap)
rrddim_set(cg->st_mem, "swap", cg->memory.swap);
+
rrddim_set(cg->st_mem, "rss_huge", cg->memory.rss_huge);
rrddim_set(cg->st_mem, "mapped_file", cg->memory.mapped_file);
rrdset_done(cg->st_mem);
if(unlikely(!cg->st_writeback)) {
- cg->st_writeback = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "writeback");
- if(likely(!cg->st_writeback)) {
- snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
- cg->st_writeback = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", CHART_PRIORITY_CONTAINERS + 300, update_every, RRDSET_TYPE_AREA);
- }
+ snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
+
+ cg->st_writeback = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "writeback"
+ , NULL
+ , "mem"
+ , "cgroup.writeback"
+ , title
+ , "MB"
+ , CHART_PRIORITY_CONTAINERS + 300
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
if(cg->memory.detailed_has_dirty)
- rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
+ rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_writeback);
if(cg->memory.detailed_has_dirty)
rrddim_set(cg->st_writeback, "dirty", cg->memory.dirty);
+
rrddim_set(cg->st_writeback, "writeback", cg->memory.writeback);
rrdset_done(cg->st_writeback);
if(unlikely(!cg->st_mem_activity)) {
- cg->st_mem_activity = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_activity");
- if(likely(!cg->st_mem_activity)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
- cg->st_mem_activity = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s", CHART_PRIORITY_CONTAINERS + 400, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
+
+ cg->st_mem_activity = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem_activity"
+ , NULL
+ , "mem"
+ , "cgroup.mem_activity"
+ , title
+ , "MB/s"
+ , CHART_PRIORITY_CONTAINERS + 400
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_mem_activity);
@@ -1879,13 +2235,23 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_mem_activity);
if(unlikely(!cg->st_pgfaults)) {
- cg->st_pgfaults = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "pgfaults");
- if(likely(!cg->st_pgfaults)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
- cg->st_pgfaults = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", CHART_PRIORITY_CONTAINERS + 500, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
+
+ cg->st_pgfaults = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "pgfaults"
+ , NULL
+ , "mem"
+ , "cgroup.pgfaults"
+ , title
+ , "MB/s"
+ , CHART_PRIORITY_CONTAINERS + 500
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_pgfaults);
@@ -1895,15 +2261,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_pgfaults);
}
- if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_mem_usage)) {
- cg->st_mem_usage = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_usage");
- if(likely(!cg->st_mem_usage)) {
- snprintfz(title, CHART_TITLE_MAX, "Used Memory %sfor cgroup %s", (cgroup_used_memory_without_cache && cg->memory.updated_detailed)?"without Cache ":"", cg->chart_title);
- cg->st_mem_usage = rrdset_create(type, "mem_usage", NULL, "mem", "cgroup.mem_usage", title, "MB", CHART_PRIORITY_CONTAINERS + 200, update_every, RRDSET_TYPE_STACKED);
- }
- rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ snprintfz(title, CHART_TITLE_MAX, "Used Memory %sfor cgroup %s", (cgroup_used_memory_without_cache && cg->memory.updated_detailed)?"without Cache ":"", cg->chart_title);
+
+ cg->st_mem_usage = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem_usage"
+ , NULL
+ , "mem"
+ , "cgroup.mem_usage"
+ , title
+ , "MB"
+ , CHART_PRIORITY_CONTAINERS + 200
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_mem_usage);
@@ -1913,14 +2289,24 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_mem_usage);
}
- if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_mem_failcnt)) {
- cg->st_mem_failcnt = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_failcnt");
- if(likely(!cg->st_mem_failcnt)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures for cgroup %s", cg->chart_title);
- cg->st_mem_failcnt = rrdset_create(type, "mem_failcnt", NULL, "mem", "cgroup.mem_failcnt", title, "count", CHART_PRIORITY_CONTAINERS + 250, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures for cgroup %s", cg->chart_title);
+
+ cg->st_mem_failcnt = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem_failcnt"
+ , NULL
+ , "mem"
+ , "cgroup.mem_failcnt"
+ , title
+ , "count"
+ , CHART_PRIORITY_CONTAINERS + 250
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_mem_failcnt);
@@ -1929,15 +2315,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_mem_failcnt);
}
- if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_io)) {
- cg->st_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "io");
- if(likely(!cg->st_io)) {
- snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
- cg->st_io = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_AREA);
- }
- rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_io = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "io"
+ , NULL
+ , "disk"
+ , "cgroup.io"
+ , title
+ , "KB/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_io);
@@ -1947,15 +2343,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_io);
}
- if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_serviced_ops)) {
- cg->st_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "serviced_ops");
- if(likely(!cg->st_serviced_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_serviced_ops = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_serviced_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "serviced_ops"
+ , NULL
+ , "disk"
+ , "cgroup.serviced_ops"
+ , title
+ , "operations/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_serviced_ops);
@@ -1965,15 +2371,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_serviced_ops);
}
- if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_throttle_io)) {
- cg->st_throttle_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_io");
- if(likely(!cg->st_throttle_io)) {
- snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
- cg->st_throttle_io = rrdset_create(type, "throttle_io", NULL, "disk", "cgroup.throttle_io", title, "KB/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_AREA);
- }
- rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_throttle_io = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "throttle_io"
+ , NULL
+ , "disk"
+ , "cgroup.throttle_io"
+ , title
+ , "KB/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_throttle_io);
@@ -1983,15 +2399,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_throttle_io);
}
- if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_throttle_serviced_ops)) {
- cg->st_throttle_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_serviced_ops");
- if(likely(!cg->st_throttle_serviced_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_throttle_serviced_ops = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_throttle_serviced_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "throttle_serviced_ops"
+ , NULL
+ , "disk"
+ , "cgroup.throttle_serviced_ops"
+ , title
+ , "operations/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_throttle_serviced_ops);
@@ -2001,15 +2427,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_throttle_serviced_ops);
}
- if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_queued_ops)) {
- cg->st_queued_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "queued_ops");
- if(likely(!cg->st_queued_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_queued_ops = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", CHART_PRIORITY_CONTAINERS + 2000, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_queued_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "queued_ops"
+ , NULL
+ , "disk"
+ , "cgroup.queued_ops"
+ , title
+ , "operations"
+ , CHART_PRIORITY_CONTAINERS + 2000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_queued_ops);
@@ -2019,15 +2455,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_queued_ops);
}
- if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_merged_ops)) {
- cg->st_merged_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "merged_ops");
- if(likely(!cg->st_merged_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_merged_ops = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 2100, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_merged_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "merged_ops"
+ , NULL
+ , "disk"
+ , "cgroup.merged_ops"
+ , title
+ , "operations/s"
+ , CHART_PRIORITY_CONTAINERS + 2100
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_merged_ops);
@@ -2039,18 +2485,10 @@ void update_cgroup_charts(int update_every) {
}
if(likely(cgroup_enable_systemd_services))
- update_services_charts(update_every,
- services_do_cpu,
- services_do_mem_usage,
- services_do_mem_detailed,
- services_do_mem_failcnt,
- services_do_swap_usage,
- services_do_io,
- services_do_io_ops,
- services_do_throttle_io,
- services_do_throttle_ops,
- services_do_queued_ops,
- services_do_merged_ops
+ update_systemd_services_charts(update_every, services_do_cpu, services_do_mem_usage, services_do_mem_detailed
+ , services_do_mem_failcnt, services_do_swap_usage, services_do_io
+ , services_do_io_ops, services_do_throttle_io, services_do_throttle_ops
+ , services_do_queued_ops, services_do_merged_ops
);
debug(D_CGROUP, "done updating cgroups charts");
@@ -2079,24 +2517,21 @@ void *cgroups_main(void *ptr) {
RRDSET *stcpu_thread = NULL;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
usec_t step = cgroup_update_every * USEC_PER_SEC;
- usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_next = 0;
+ usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_dt = 0;
for(;;) {
- usec_t now = now_monotonic_usec();
- usec_t next = now - (now % step) + step;
-
- while(now < next) {
- sleep_usec(next - now);
- now = now_monotonic_usec();
- }
-
+ usec_t hb_dt = heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
// BEGIN -- the job to be done
- if(unlikely(now >= find_next)) {
+ find_dt += hb_dt;
+ if(unlikely(find_dt >= find_every || cgroups_check)) {
find_all_cgroups();
- find_next = now + find_every;
+ find_dt = 0;
+ cgroups_check = 0;
}
read_all_cgroups(cgroup_root);
@@ -2110,12 +2545,22 @@ void *cgroups_main(void *ptr) {
getrusage(RUSAGE_THREAD, &thread);
if(unlikely(!stcpu_thread)) {
- stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
- if(unlikely(!stcpu_thread))
- stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "cgroups", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, cgroup_update_every, RRDSET_TYPE_STACKED);
- rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ stcpu_thread = rrdset_create_localhost(
+ "netdata"
+ , "plugin_cgroups_cpu"
+ , NULL
+ , "cgroups"
+ , NULL
+ , "NetData CGroups Plugin CPU usage"
+ , "milliseconds/s"
+ , 132000
+ , cgroup_update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(stcpu_thread);
diff --git a/src/sys_kernel_mm_ksm.c b/src/sys_kernel_mm_ksm.c
index 83da74429..76d808538 100644
--- a/src/sys_kernel_mm_ksm.c
+++ b/src/sys_kernel_mm_ksm.c
@@ -20,40 +20,39 @@ KSM_NAME_VALUE values[] = {
};
int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
+ (void)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(dt) {};
-
if(page_size == -1)
page_size = sysconf(_SC_PAGESIZE);
if(!ff_pages_shared) {
- snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/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) {
- snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/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) {
- snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/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) {
- snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/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) {
- snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/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);
}
@@ -91,15 +90,16 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find("mem.ksm");
+ st = rrdset_find_localhost("mem.ksm");
if(!st) {
- st = rrdset_create("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ 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);
}
else rrdset_next(st);
@@ -110,12 +110,13 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
rrddim_set(st, "to_scan", pages_to_scan * page_size);
rrdset_done(st);
- st = rrdset_find("mem.ksm_savings");
+ st = rrdset_find_localhost("mem.ksm_savings");
if(!st) {
- st = rrdset_create("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB", 5001, update_every, RRDSET_TYPE_AREA);
+ 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, RRDDIM_ABSOLUTE);
- rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ 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);
@@ -123,11 +124,12 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
rrddim_set(st, "offered", offered * page_size);
rrdset_done(st);
- st = rrdset_find("mem.ksm_ratios");
+ st = rrdset_find_localhost("mem.ksm_ratios");
if(!st) {
- st = rrdset_create("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness", "percentage", 5002, update_every, RRDSET_TYPE_LINE);
+ 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, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "savings", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/unit_test.c b/src/unit_test.c
index 4e2f10c0a..0866d215c 100644
--- a/src/unit_test.c
+++ b/src/unit_test.c
@@ -282,7 +282,7 @@ struct test test1 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
10, // feed entries
9, // result entries
test1_feed, // feed
@@ -318,7 +318,7 @@ struct test test2 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
10, // feed entries
9, // result entries
test2_feed, // feed
@@ -353,7 +353,7 @@ struct test test3 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test3_feed, // feed
@@ -388,7 +388,7 @@ struct test test4 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test4_feed, // feed
@@ -423,7 +423,7 @@ struct test test5 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test5_feed, // feed
@@ -464,7 +464,7 @@ struct test test6 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
16, // feed entries
4, // result entries
test6_feed, // feed
@@ -499,7 +499,7 @@ struct test test7 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
18, // result entries
test7_feed, // feed
@@ -530,7 +530,7 @@ struct test test8 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
6, // feed entries
10, // result entries
test8_feed, // feed
@@ -571,7 +571,7 @@ struct test test9 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
16, // feed entries
4, // result entries
test9_feed, // feed
@@ -606,7 +606,7 @@ struct test test10 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
7, // result entries
test10_feed, // feed
@@ -649,7 +649,7 @@ struct test test11 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm
10, // feed entries
9, // result entries
test11_feed, // feed
@@ -692,7 +692,7 @@ struct test test12 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm
10, // feed entries
9, // result entries
test12_feed, // feed
@@ -727,7 +727,7 @@ struct test test13 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm
10, // feed entries
7, // result entries
test13_feed, // feed
@@ -762,7 +762,7 @@ struct test test14 = {
30, // update_every
8, // multiplier
1000000000, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
8, // result entries
test14_feed, // feed
@@ -794,7 +794,7 @@ struct test test14b = {
30, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
8, // result entries
test14b_feed, // feed
@@ -826,7 +826,7 @@ struct test test14c = {
30, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test14c_feed, // feed
@@ -869,7 +869,7 @@ struct test test15 = {
1, // update_every
8, // multiplier
1024, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test15_feed, // feed
@@ -884,21 +884,22 @@ int run_test(struct test *test)
{
fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
- rrd_memory_mode = RRD_MEMORY_MODE_RAM;
- rrd_update_every = test->update_every;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ default_rrd_update_every = test->update_every;
char name[101];
snprintfz(name, 100, "unittest-%s", test->name);
// create the chart
- RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, test->update_every, RRDSET_TYPE_LINE);
+ RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1
+ , test->update_every, RRDSET_TYPE_LINE);
RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
RRDDIM *rd2 = NULL;
if(test->feed2)
rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
- st->debug = 1;
+ rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
// feed it with the test data
time_t time_now = 0, time_start = now_realtime_sec();
@@ -977,15 +978,16 @@ int run_test(struct test *test)
static int test_variable_renames(void) {
fprintf(stderr, "Creating chart\n");
- RRDSET *st = rrdset_create("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");
- RRDDIM *rd1 = rrddim_add(st, "DIM1", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ RRDDIM *rd1 = rrddim_add(st, "DIM1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd1->id, rd1->name);
fprintf(stderr, "Creating dimension DIM2\n");
- RRDDIM *rd2 = rrddim_add(st, "DIM2", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ RRDDIM *rd2 = rrddim_add(st, "DIM2", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd2->id, rd2->name);
fprintf(stderr, "Renaming chart to CHARTNAME1\n");
@@ -1089,26 +1091,27 @@ int unit_test(long delay, long shift)
snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
//debug_flags = 0xffffffff;
- rrd_memory_mode = RRD_MEMORY_MODE_RAM;
- rrd_update_every = 1;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ default_rrd_update_every = 1;
int do_abs = 1;
int do_inc = 1;
int do_abst = 0;
int do_absi = 0;
- RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
- st->debug = 1;
+ RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
RRDDIM *rdabs = NULL;
RRDDIM *rdinc = NULL;
RRDDIM *rdabst = NULL;
RRDDIM *rdabsi = NULL;
- if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
- if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
- if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
- if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL);
+ if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
long increment = 1000;
collected_number i = 0;
diff --git a/src/web_api_old.c b/src/web_api_old.c
new file mode 100644
index 000000000..373e7e9f8
--- /dev/null
+++ b/src/web_api_old.c
@@ -0,0 +1,237 @@
+#include "common.h"
+
+int web_client_api_old_data_request(RRDHOST *host, struct web_client *w, char *url, int datasource_type) {
+ if(!url || !*url) {
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Incomplete request.");
+ return 400;
+ }
+
+ RRDSET *st = NULL;
+
+ char *args = strchr(url, '?');
+ if(args) {
+ *args='\0';
+ args = &args[1];
+ }
+
+ // get the name of the data to show
+ char *tok = mystrsep(&url, "/");
+ if(!tok) tok = "";
+
+ // do we have such a data set?
+ if(*tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+ st = rrdset_find_byname(host, tok);
+ if(!st) st = rrdset_find(host, tok);
+ }
+
+ if(!st) {
+ // we don't have it
+ // try to send a file with that name
+ buffer_flush(w->response.data);
+ return(mysendfile(w, tok));
+ }
+
+ // we have it
+ debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
+
+ // how many entries does the client want?
+ int lines = (int)st->entries;
+ int group_count = 1;
+ time_t after = 0, before = 0;
+ int group_method = GROUP_AVERAGE;
+ int nonzero = 0;
+
+ if(url) {
+ // parse the lines required
+ tok = mystrsep(&url, "/");
+ if(tok) lines = str2i(tok);
+ if(lines < 1) lines = 1;
+ }
+ if(url) {
+ // parse the group count required
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) group_count = str2i(tok);
+ if(group_count < 1) group_count = 1;
+ //if(group_count > save_history / 20) group_count = save_history / 20;
+ }
+ if(url) {
+ // parse the grouping method required
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) {
+ if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
+ else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
+ else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
+ else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
+ }
+ }
+ if(url) {
+ // parse after time
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) after = str2ul(tok);
+ if(after < 0) after = 0;
+ }
+ if(url) {
+ // parse before time
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) before = str2ul(tok);
+ if(before < 0) before = 0;
+ }
+ if(url) {
+ // parse nonzero
+ tok = mystrsep(&url, "/");
+ if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
+ }
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+
+ char *google_version = "0.6";
+ char *google_reqId = "0";
+ char *google_sig = "0";
+ char *google_out = "json";
+ char *google_responseHandler = "google.visualization.Query.setResponse";
+ char *google_outFileName = NULL;
+ time_t last_timestamp_in_data = 0;
+ if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
+
+ w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
+
+ while(args) {
+ tok = mystrsep(&args, "&");
+ if(tok && *tok) {
+ char *name = mystrsep(&tok, "=");
+ if(name && *name && strcmp(name, "tqx") == 0) {
+ char *key = mystrsep(&tok, ":");
+ char *value = mystrsep(&tok, ";");
+ if(key && value && *key && *value) {
+ if(strcmp(key, "version") == 0)
+ google_version = value;
+
+ else if(strcmp(key, "reqId") == 0)
+ google_reqId = value;
+
+ else if(strcmp(key, "sig") == 0)
+ google_sig = value;
+
+ else if(strcmp(key, "out") == 0)
+ google_out = value;
+
+ else if(strcmp(key, "responseHandler") == 0)
+ google_responseHandler = value;
+
+ else if(strcmp(key, "outFileName") == 0)
+ google_outFileName = value;
+ }
+ }
+ }
+ }
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
+ w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
+ );
+
+ if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+ last_timestamp_in_data = strtoul(google_sig, NULL, 0);
+
+ // check the client wants json
+ if(strcmp(google_out, "json") != 0) {
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
+ google_responseHandler, google_version, google_reqId, google_out);
+ return 200;
+ }
+ }
+ }
+
+ if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
+ google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
+ }
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
+ w->id, st->name, st->id, lines, group_count, group_method, after, before);
+
+ time_t timestamp_in_data = rrdset2json_api_old(datasource_type, st, w->response.data, lines, group_count
+ , group_method, (unsigned long) after, (unsigned long) before
+ , nonzero);
+
+ if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+ if(timestamp_in_data > last_timestamp_in_data)
+ buffer_strcat(w->response.data, "});");
+
+ else {
+ // the client already has the latest data
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
+ google_responseHandler, google_version, google_reqId);
+ }
+ }
+
+ return 200;
+}
+
+inline int web_client_api_old_data_request_json(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_old_data_request(host, w, url, DATASOURCE_JSON);
+}
+
+inline int web_client_api_old_data_request_jsonp(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_old_data_request(host, w, url, DATASOURCE_DATATABLE_JSONP);
+}
+
+inline int web_client_api_old_graph_request(RRDHOST *host, struct web_client *w, char *url) {
+ // get the name of the data to show
+ char *tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+
+ // do we have such a data set?
+ RRDSET *st = rrdset_find_byname(host, tok);
+ if(!st) st = rrdset_find(host, tok);
+ if(!st) {
+ // we don't have it
+ // try to send a file with that name
+ buffer_flush(w->response.data);
+ return mysendfile(w, tok);
+ }
+ st->last_accessed_time = now_realtime_sec();
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+ rrd_graph2json_api_old(st, url, w->response.data);
+ return 200;
+ }
+
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Graph name?\r\n");
+ return 400;
+}
+
+inline int web_client_api_old_list_request(RRDHOST *host, struct web_client *w, char *url) {
+ (void)url;
+
+ buffer_flush(w->response.data);
+ RRDSET *st;
+
+ rrdhost_rdlock(host);
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st))
+ buffer_sprintf(w->response.data, "%s\n", st->name);
+ }
+ rrdhost_unlock(host);
+
+ return 200;
+}
+
+inline int web_client_api_old_all_json(RRDHOST *host, struct web_client *w, char *url) {
+ (void)url;
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+ rrd_all2json_api_old(host, w->response.data);
+ return 200;
+}
diff --git a/src/web_api_old.h b/src/web_api_old.h
new file mode 100644
index 000000000..dff48c2f3
--- /dev/null
+++ b/src/web_api_old.h
@@ -0,0 +1,13 @@
+#ifndef NETDATA_WEB_API_OLD_H
+#define NETDATA_WEB_API_OLD_H
+
+#include "common.h"
+
+extern int web_client_api_old_data_request(RRDHOST *host, struct web_client *w, char *url, int datasource_type);
+extern int web_client_api_old_data_request_json(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_data_request_jsonp(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_graph_request(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_list_request(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_all_json(RRDHOST *host, struct web_client *w, char *url);
+
+#endif //NETDATA_WEB_API_OLD_H
diff --git a/src/web_api_v1.c b/src/web_api_v1.c
new file mode 100644
index 000000000..0acc43acb
--- /dev/null
+++ b/src/web_api_v1.c
@@ -0,0 +1,903 @@
+#include "common.h"
+
+inline int web_client_api_request_v1_data_group(char *name, int def) {
+ if(!strcmp(name, "average"))
+ return GROUP_AVERAGE;
+
+ else if(!strcmp(name, "min"))
+ return GROUP_MIN;
+
+ else if(!strcmp(name, "max"))
+ return GROUP_MAX;
+
+ else if(!strcmp(name, "sum"))
+ return GROUP_SUM;
+
+ else if(!strcmp(name, "incremental-sum"))
+ return GROUP_INCREMENTAL_SUM;
+
+ return def;
+}
+
+inline uint32_t web_client_api_request_v1_data_options(char *o) {
+ uint32_t ret = 0x00000000;
+ char *tok;
+
+ while(o && *o && (tok = mystrsep(&o, ", |"))) {
+ if(!*tok) continue;
+
+ if(!strcmp(tok, "nonzero"))
+ ret |= RRDR_OPTION_NONZERO;
+ else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
+ ret |= RRDR_OPTION_REVERSED;
+ else if(!strcmp(tok, "jsonwrap"))
+ ret |= RRDR_OPTION_JSON_WRAP;
+ else if(!strcmp(tok, "min2max"))
+ ret |= RRDR_OPTION_MIN2MAX;
+ else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
+ ret |= RRDR_OPTION_MILLISECONDS;
+ else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
+ ret |= RRDR_OPTION_ABSOLUTE;
+ else if(!strcmp(tok, "seconds"))
+ ret |= RRDR_OPTION_SECONDS;
+ else if(!strcmp(tok, "null2zero"))
+ ret |= RRDR_OPTION_NULL2ZERO;
+ else if(!strcmp(tok, "objectrows"))
+ ret |= RRDR_OPTION_OBJECTSROWS;
+ else if(!strcmp(tok, "google_json"))
+ ret |= RRDR_OPTION_GOOGLE_JSON;
+ else if(!strcmp(tok, "percentage"))
+ ret |= RRDR_OPTION_PERCENTAGE;
+ else if(!strcmp(tok, "unaligned"))
+ ret |= RRDR_OPTION_NOT_ALIGNED;
+ }
+
+ return ret;
+}
+
+inline uint32_t web_client_api_request_v1_data_format(char *name) {
+ if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
+ return DATASOURCE_DATATABLE_JSON;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
+ return DATASOURCE_DATATABLE_JSONP;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
+ return DATASOURCE_JSON;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
+ return DATASOURCE_JSONP;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
+ return DATASOURCE_SSV;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
+ return DATASOURCE_CSV;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
+ return DATASOURCE_TSV;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
+ return DATASOURCE_HTML;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
+ return DATASOURCE_JS_ARRAY;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
+ return DATASOURCE_SSV_COMMA;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
+ return DATASOURCE_CSV_JSON_ARRAY;
+
+ return DATASOURCE_JSON;
+}
+
+inline uint32_t web_client_api_request_v1_data_google_format(char *name) {
+ if(!strcmp(name, "json"))
+ return DATASOURCE_DATATABLE_JSONP;
+
+ else if(!strcmp(name, "html"))
+ return DATASOURCE_HTML;
+
+ else if(!strcmp(name, "csv"))
+ return DATASOURCE_CSV;
+
+ else if(!strcmp(name, "tsv-excel"))
+ return DATASOURCE_TSV;
+
+ return DATASOURCE_JSON;
+}
+
+
+inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url) {
+ int all = 0;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ if(!strcmp(value, "all")) all = 1;
+ else if(!strcmp(value, "active")) all = 0;
+ }
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ health_alarms2json(host, w->response.data, all);
+ return 200;
+}
+
+inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) {
+ uint32_t after = 0;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ if(!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0);
+ }
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ health_alarm_log2json(host, w->response.data, after);
+ return 200;
+}
+
+inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf)) {
+ int ret = 400;
+ char *chart = NULL;
+
+ buffer_flush(w->response.data);
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ //else {
+ /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
+ // goto cleanup;
+ //}
+ }
+
+ if(!chart || !*chart) {
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, chart);
+ ret = 404;
+ goto cleanup;
+ }
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ st->last_accessed_time = now_realtime_sec();
+ callback(st, w->response.data);
+ return 200;
+
+ cleanup:
+ return ret;
+}
+
+inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
+}
+
+inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url) {
+ (void)url;
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ rrd_stats_api_v1_charts(host, w->response.data);
+ return 200;
+}
+
+inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url) {
+ int format = ALLMETRICS_SHELL;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ if(!strcmp(name, "format")) {
+ if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
+ format = ALLMETRICS_SHELL;
+ else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
+ format = ALLMETRICS_PROMETHEUS;
+ else if(!strcmp(value, ALLMETRICS_FORMAT_JSON))
+ format = ALLMETRICS_JSON;
+ else
+ format = 0;
+ }
+ }
+
+ buffer_flush(w->response.data);
+ buffer_no_cacheable(w->response.data);
+
+ switch(format) {
+ case ALLMETRICS_JSON:
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ rrd_stats_api_v1_charts_allmetrics_json(host, w->response.data);
+ return 200;
+
+ case ALLMETRICS_SHELL:
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ rrd_stats_api_v1_charts_allmetrics_shell(host, w->response.data);
+ return 200;
+
+ case ALLMETRICS_PROMETHEUS:
+ w->response.data->contenttype = CT_PROMETHEUS;
+ rrd_stats_api_v1_charts_allmetrics_prometheus(host, w->response.data);
+ return 200;
+
+ default:
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_strcat(w->response.data, "Which format? '" ALLMETRICS_FORMAT_SHELL "', '" ALLMETRICS_FORMAT_PROMETHEUS "' and '" ALLMETRICS_FORMAT_JSON "' are currently supported.");
+ return 400;
+ }
+}
+
+inline int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_request_single_chart(host, w, url, rrd_stats_api_v1_chart);
+}
+
+int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) {
+ int ret = 400;
+ buffer_flush(w->response.data);
+
+ BUFFER *dimensions = NULL;
+
+ const char *chart = NULL
+ , *before_str = NULL
+ , *after_str = NULL
+ , *points_str = NULL
+ , *multiply_str = NULL
+ , *divide_str = NULL
+ , *label = NULL
+ , *units = NULL
+ , *label_color = NULL
+ , *value_color = NULL
+ , *refresh_str = NULL
+ , *precision_str = NULL
+ , *alarm = NULL;
+
+ int group = GROUP_AVERAGE;
+ uint32_t options = 0x00000000;
+
+ while(url) {
+ char *value = mystrsep(&url, "/?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+ if(!dimensions)
+ dimensions = buffer_create(100);
+
+ buffer_strcat(dimensions, "|");
+ buffer_strcat(dimensions, value);
+ }
+ else if(!strcmp(name, "after")) after_str = value;
+ else if(!strcmp(name, "before")) before_str = value;
+ else if(!strcmp(name, "points")) points_str = value;
+ else if(!strcmp(name, "group")) {
+ group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
+ }
+ else if(!strcmp(name, "options")) {
+ options |= web_client_api_request_v1_data_options(value);
+ }
+ else if(!strcmp(name, "label")) label = value;
+ else if(!strcmp(name, "units")) units = value;
+ else if(!strcmp(name, "label_color")) label_color = value;
+ else if(!strcmp(name, "value_color")) value_color = value;
+ else if(!strcmp(name, "multiply")) multiply_str = value;
+ else if(!strcmp(name, "divide")) divide_str = value;
+ else if(!strcmp(name, "refresh")) refresh_str = value;
+ else if(!strcmp(name, "precision")) precision_str = value;
+ else if(!strcmp(name, "alarm")) alarm = value;
+ }
+
+ if(!chart || !*chart) {
+ buffer_no_cacheable(w->response.data);
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_no_cacheable(w->response.data);
+ buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
+ ret = 200;
+ goto cleanup;
+ }
+ st->last_accessed_time = now_realtime_sec();
+
+ RRDCALC *rc = NULL;
+ if(alarm) {
+ rc = rrdcalc_find(st, alarm);
+ if (!rc) {
+ buffer_no_cacheable(w->response.data);
+ buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
+ ret = 200;
+ goto cleanup;
+ }
+ }
+
+ long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1;
+ long long divide = (divide_str && *divide_str )?str2l(divide_str):1;
+ long long before = (before_str && *before_str )?str2l(before_str):0;
+ long long after = (after_str && *after_str )?str2l(after_str):-st->update_every;
+ int points = (points_str && *points_str )?str2i(points_str):1;
+ int precision = (precision_str && *precision_str)?str2i(precision_str):-1;
+
+ if(!multiply) multiply = 1;
+ if(!divide) divide = 1;
+
+ int refresh = 0;
+ if(refresh_str && *refresh_str) {
+ if(!strcmp(refresh_str, "auto")) {
+ if(rc) refresh = rc->update_every;
+ else if(options & RRDR_OPTION_NOT_ALIGNED)
+ refresh = st->update_every;
+ else {
+ refresh = (int)(before - after);
+ if(refresh < 0) refresh = -refresh;
+ }
+ }
+ else {
+ refresh = str2i(refresh_str);
+ if(refresh < 0) refresh = -refresh;
+ }
+ }
+
+ if(!label) {
+ if(alarm) {
+ char *s = (char *)alarm;
+ while(*s) {
+ if(*s == '_') *s = ' ';
+ s++;
+ }
+ label = alarm;
+ }
+ else if(dimensions) {
+ const char *dim = buffer_tostring(dimensions);
+ if(*dim == '|') dim++;
+ label = dim;
+ }
+ else
+ label = st->name;
+ }
+ if(!units) {
+ if(alarm) {
+ if(rc->units)
+ units = rc->units;
+ else
+ units = "";
+ }
+ else if(options & RRDR_OPTION_PERCENTAGE)
+ units = "%";
+ else
+ units = st->units;
+ }
+
+ debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
+ , w->id
+ , chart
+ , alarm?alarm:""
+ , (dimensions)?buffer_tostring(dimensions):""
+ , after
+ , before
+ , points
+ , group
+ , options
+ );
+
+ if(rc) {
+ if (refresh > 0) {
+ buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+ w->response.data->expires = now_realtime_sec() + refresh;
+ }
+ else buffer_no_cacheable(w->response.data);
+
+ if(!value_color) {
+ switch(rc->status) {
+ case RRDCALC_STATUS_CRITICAL:
+ value_color = "red";
+ break;
+
+ case RRDCALC_STATUS_WARNING:
+ value_color = "orange";
+ break;
+
+ case RRDCALC_STATUS_CLEAR:
+ value_color = "brightgreen";
+ break;
+
+ case RRDCALC_STATUS_UNDEFINED:
+ value_color = "lightgrey";
+ break;
+
+ case RRDCALC_STATUS_UNINITIALIZED:
+ value_color = "#000";
+ break;
+
+ default:
+ value_color = "grey";
+ break;
+ }
+ }
+
+ buffer_svg(w->response.data,
+ label,
+ (isnan(rc->value)||isinf(rc->value)) ? rc->value : rc->value * multiply / divide,
+ units,
+ label_color,
+ value_color,
+ precision);
+ ret = 200;
+ }
+ else {
+ time_t latest_timestamp = 0;
+ int value_is_null = 1;
+ calculated_number n = NAN;
+ ret = 500;
+
+ // if the collected value is too old, don't calculate its value
+ if (rrdset_last_entry_t(st) >= (now_realtime_sec() - (st->update_every * st->gap_when_lost_iterations_above)))
+ ret = rrdset2value_api_v1(st, w->response.data, &n, (dimensions) ? buffer_tostring(dimensions) : NULL
+ , points, after, before, group, options, NULL, &latest_timestamp, &value_is_null);
+
+ // if the value cannot be calculated, show empty badge
+ if (ret != 200) {
+ buffer_no_cacheable(w->response.data);
+ value_is_null = 1;
+ n = 0;
+ ret = 200;
+ }
+ else if (refresh > 0) {
+ buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+ w->response.data->expires = now_realtime_sec() + refresh;
+ }
+ else buffer_no_cacheable(w->response.data);
+
+ // render the badge
+ buffer_svg(w->response.data,
+ label,
+ (value_is_null)?NAN:(n * multiply / divide),
+ units,
+ label_color,
+ value_color,
+ precision);
+ }
+
+ cleanup:
+ buffer_free(dimensions);
+ return ret;
+}
+
+// returns the HTTP code
+inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
+ debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
+
+ int ret = 400;
+ BUFFER *dimensions = NULL;
+
+ buffer_flush(w->response.data);
+
+ char *google_version = "0.6",
+ *google_reqId = "0",
+ *google_sig = "0",
+ *google_out = "json",
+ *responseHandler = NULL,
+ *outFileName = NULL;
+
+ time_t last_timestamp_in_data = 0, google_timestamp = 0;
+
+ char *chart = NULL
+ , *before_str = NULL
+ , *after_str = NULL
+ , *points_str = NULL;
+
+ int group = GROUP_AVERAGE;
+ uint32_t format = DATASOURCE_JSON;
+ uint32_t options = 0x00000000;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+ if(!dimensions) dimensions = buffer_create(100);
+ buffer_strcat(dimensions, "|");
+ buffer_strcat(dimensions, value);
+ }
+ else if(!strcmp(name, "after")) after_str = value;
+ else if(!strcmp(name, "before")) before_str = value;
+ else if(!strcmp(name, "points")) points_str = value;
+ else if(!strcmp(name, "group")) {
+ group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
+ }
+ else if(!strcmp(name, "format")) {
+ format = web_client_api_request_v1_data_format(value);
+ }
+ else if(!strcmp(name, "options")) {
+ options |= web_client_api_request_v1_data_options(value);
+ }
+ else if(!strcmp(name, "callback")) {
+ responseHandler = value;
+ }
+ else if(!strcmp(name, "filename")) {
+ outFileName = value;
+ }
+ else if(!strcmp(name, "tqx")) {
+ // parse Google Visualization API options
+ // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
+ char *tqx_name, *tqx_value;
+
+ while(value) {
+ tqx_value = mystrsep(&value, ";");
+ if(!tqx_value || !*tqx_value) continue;
+
+ tqx_name = mystrsep(&tqx_value, ":");
+ if(!tqx_name || !*tqx_name) continue;
+ if(!tqx_value || !*tqx_value) continue;
+
+ if(!strcmp(tqx_name, "version"))
+ google_version = tqx_value;
+ else if(!strcmp(tqx_name, "reqId"))
+ google_reqId = tqx_value;
+ else if(!strcmp(tqx_name, "sig")) {
+ google_sig = tqx_value;
+ google_timestamp = strtoul(google_sig, NULL, 0);
+ }
+ else if(!strcmp(tqx_name, "out")) {
+ google_out = tqx_value;
+ format = web_client_api_request_v1_data_google_format(google_out);
+ }
+ else if(!strcmp(tqx_name, "responseHandler"))
+ responseHandler = tqx_value;
+ else if(!strcmp(tqx_name, "outFileName"))
+ outFileName = tqx_value;
+ }
+ }
+ }
+
+ if(!chart || !*chart) {
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, chart);
+ ret = 404;
+ goto cleanup;
+ }
+ st->last_accessed_time = now_realtime_sec();
+
+ long long before = (before_str && *before_str)?str2l(before_str):0;
+ long long after = (after_str && *after_str) ?str2l(after_str):0;
+ int points = (points_str && *points_str)?str2i(points_str):0;
+
+ debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
+ , w->id
+ , chart
+ , (dimensions)?buffer_tostring(dimensions):""
+ , after
+ , before
+ , points
+ , group
+ , format
+ , options
+ );
+
+ if(outFileName && *outFileName) {
+ buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
+ debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
+ }
+
+ if(format == DATASOURCE_DATATABLE_JSONP) {
+ if(responseHandler == NULL)
+ responseHandler = "google.visualization.Query.setResponse";
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
+ w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
+ );
+
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
+ responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
+ }
+ else if(format == DATASOURCE_JSONP) {
+ if(responseHandler == NULL)
+ responseHandler = "callback";
+
+ buffer_strcat(w->response.data, responseHandler);
+ buffer_strcat(w->response.data, "(");
+ }
+
+ ret = rrdset2anything_api_v1(st, w->response.data, dimensions, format, points, after, before, group, options
+ , &last_timestamp_in_data);
+
+ if(format == DATASOURCE_DATATABLE_JSONP) {
+ if(google_timestamp < last_timestamp_in_data)
+ buffer_strcat(w->response.data, "});");
+
+ else {
+ // the client already has the latest data
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
+ responseHandler, google_version, google_reqId);
+ }
+ }
+ else if(format == DATASOURCE_JSONP)
+ buffer_strcat(w->response.data, ");");
+
+ cleanup:
+ buffer_free(dimensions);
+ return ret;
+}
+
+inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
+ hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
+ hash_to = 0 /*, hash_redirects = 0 */;
+
+ if(unlikely(!hash_action)) {
+ hash_action = simple_hash("action");
+ hash_access = simple_hash("access");
+ hash_hello = simple_hash("hello");
+ hash_delete = simple_hash("delete");
+ hash_search = simple_hash("search");
+ hash_switch = simple_hash("switch");
+ hash_machine = simple_hash("machine");
+ hash_url = simple_hash("url");
+ hash_name = simple_hash("name");
+ hash_delete_url = simple_hash("delete_url");
+ hash_for = simple_hash("for");
+ hash_to = simple_hash("to");
+/*
+ hash_redirects = simple_hash("redirects");
+*/
+ }
+
+ char person_guid[GUID_LEN + 1] = "";
+
+ debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
+
+ // FIXME
+ // The browser may send multiple cookies with our id
+
+ char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
+ if(cookie)
+ strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
+
+ char action = '\0';
+ char *machine_guid = NULL,
+ *machine_url = NULL,
+ *url_name = NULL,
+ *search_machine_guid = NULL,
+ *delete_url = NULL,
+ *to_person_guid = NULL;
+/*
+ int redirects = 0;
+*/
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if (!name || !*name) continue;
+ if (!value || !*value) continue;
+
+ debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
+
+ uint32_t hash = simple_hash(name);
+
+ if(hash == hash_action && !strcmp(name, "action")) {
+ uint32_t vhash = simple_hash(value);
+
+ if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
+ else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
+ else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
+ else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
+ else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
+#ifdef NETDATA_INTERNAL_CHECKS
+ else error("unknown registry action '%s'", value);
+#endif /* NETDATA_INTERNAL_CHECKS */
+ }
+/*
+ else if(hash == hash_redirects && !strcmp(name, "redirects"))
+ redirects = atoi(value);
+*/
+ else if(hash == hash_machine && !strcmp(name, "machine"))
+ machine_guid = value;
+
+ else if(hash == hash_url && !strcmp(name, "url"))
+ machine_url = value;
+
+ else if(action == 'A') {
+ if(hash == hash_name && !strcmp(name, "name"))
+ url_name = value;
+ }
+ else if(action == 'D') {
+ if(hash == hash_delete_url && !strcmp(name, "delete_url"))
+ delete_url = value;
+ }
+ else if(action == 'S') {
+ if(hash == hash_for && !strcmp(name, "for"))
+ search_machine_guid = value;
+ }
+ else if(action == 'W') {
+ if(hash == hash_to && !strcmp(name, "to"))
+ to_person_guid = value;
+ }
+#ifdef NETDATA_INTERNAL_CHECKS
+ else error("unused registry URL parameter '%s' with value '%s'", name, value);
+#endif /* NETDATA_INTERNAL_CHECKS */
+ }
+
+ if(respect_web_browser_do_not_track_policy && w->donottrack) {
+ 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;
+ }
+
+ if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
+ error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Access request.");
+ return 400;
+ }
+ else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
+ error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Delete request.");
+ return 400;
+ }
+ else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
+ error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Search request.");
+ return 400;
+ }
+ else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
+ error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Switch request.");
+ return 400;
+ }
+
+ switch(action) {
+ case 'A':
+ w->tracking_required = 1;
+ return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
+
+ case 'D':
+ w->tracking_required = 1;
+ return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
+
+ case 'S':
+ w->tracking_required = 1;
+ 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;
+ return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
+
+ case 'H':
+ return registry_request_hello_json(host, w);
+
+ default:
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
+ return 400;
+ }
+}
+
+inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0, hash_raw = 0;
+
+ if(unlikely(hash_data == 0)) {
+ hash_data = simple_hash("data");
+ hash_chart = simple_hash("chart");
+ hash_charts = simple_hash("charts");
+ hash_registry = simple_hash("registry");
+ hash_badge = simple_hash("badge.svg");
+ hash_alarms = simple_hash("alarms");
+ hash_alarm_log = simple_hash("alarm_log");
+ hash_alarm_variables = simple_hash("alarm_variables");
+ hash_raw = simple_hash("allmetrics");
+ }
+
+ // get the command
+ char *tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
+ uint32_t hash = simple_hash(tok);
+
+ if(hash == hash_data && !strcmp(tok, "data"))
+ return web_client_api_request_v1_data(host, w, url);
+
+ else if(hash == hash_chart && !strcmp(tok, "chart"))
+ return web_client_api_request_v1_chart(host, w, url);
+
+ else if(hash == hash_charts && !strcmp(tok, "charts"))
+ return web_client_api_request_v1_charts(host, w, url);
+
+ else if(hash == hash_registry && !strcmp(tok, "registry"))
+ return web_client_api_request_v1_registry(host, w, url);
+
+ else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
+ return web_client_api_request_v1_badge(host, w, url);
+
+ else if(hash == hash_alarms && !strcmp(tok, "alarms"))
+ return web_client_api_request_v1_alarms(host, w, url);
+
+ else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
+ return web_client_api_request_v1_alarm_log(host, w, url);
+
+ else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
+ return web_client_api_request_v1_alarm_variables(host, w, url);
+
+ else if(hash == hash_raw && !strcmp(tok, "allmetrics"))
+ return web_client_api_request_v1_allmetrics(host, w, url);
+
+ else {
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Unsupported v1 API command: ");
+ buffer_strcat_htmlescape(w->response.data, tok);
+ return 404;
+ }
+ }
+ else {
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Which API v1 command?");
+ return 400;
+ }
+}
diff --git a/src/web_api_v1.h b/src/web_api_v1.h
new file mode 100644
index 000000000..e980edb1d
--- /dev/null
+++ b/src/web_api_v1.h
@@ -0,0 +1,21 @@
+#ifndef NETDATA_WEB_API_V1_H
+#define NETDATA_WEB_API_V1_H
+
+extern int web_client_api_request_v1_data_group(char *name, int def);
+extern uint32_t web_client_api_request_v1_data_options(char *o);
+extern uint32_t web_client_api_request_v1_data_format(char *name);
+extern uint32_t web_client_api_request_v1_data_google_format(char *name);
+
+extern int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf));
+extern int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url);
+
+#endif //NETDATA_WEB_API_V1_H
diff --git a/src/web_buffer.c b/src/web_buffer.c
index 6203db0f7..9f9ceda63 100644
--- a/src/web_buffer.c
+++ b/src/web_buffer.c
@@ -359,8 +359,9 @@ BUFFER *buffer_create(size_t size)
return(b);
}
-void buffer_free(BUFFER *b)
-{
+void buffer_free(BUFFER *b) {
+ if(unlikely(!b)) return;
+
buffer_overflow_check(b);
debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
diff --git a/src/web_buffer_svg.c b/src/web_buffer_svg.c
index cac365ab1..2591799d4 100644
--- a/src/web_buffer_svg.c
+++ b/src/web_buffer_svg.c
@@ -368,10 +368,226 @@ cleanup:
return len - i;
}
-static inline const char *fix_units(const char *units) {
- if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return "";
- if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%";
- return units;
+static inline char *format_value_with_precision_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
+ if(unlikely(isnan(value) || isinf(value)))
+ value = 0.0;
+
+ char *separator = "";
+ if(unlikely(isalnum(*units)))
+ separator = " ";
+
+ if(precision < 0) {
+ int len, lstop = 0, trim_zeros = 1;
+
+ calculated_number abs = value;
+ if(isless(value, 0)) {
+ lstop = 1;
+ abs = -value;
+ }
+
+ if(isgreaterequal(abs, 1000)) {
+ 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);
+
+ if(unlikely(trim_zeros)) {
+ int l;
+ // remove trailing zeros from the decimal part
+ for(l = len - 1; l > lstop; l--) {
+ if(likely(value_string[l] == '0')) {
+ value_string[l] = '\0';
+ len--;
+ }
+
+ else if(unlikely(value_string[l] == '.')) {
+ value_string[l] = '\0';
+ len--;
+ break;
+ }
+
+ else
+ break;
+ }
+ }
+
+ if(unlikely(len <= 0)) len = 1;
+ snprintfz(&value_string[len], value_string_len - len, "%s%s", separator, units);
+ }
+ else {
+ if(precision > 50) precision = 50;
+ snprintfz(value_string, value_string_len, "%0.*Lf%s%s", precision, (long double) value, separator, units);
+ }
+
+ return value_string;
+}
+
+inline char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
+ static uint32_t
+ hash_seconds = 0,
+ hash_seconds_ago = 0,
+ hash_minutes = 0,
+ hash_minutes_ago = 0,
+ hash_hours = 0,
+ hash_hours_ago = 0,
+ hash_onoff = 0,
+ hash_updown = 0,
+ hash_okerror = 0,
+ hash_okfailed = 0,
+ hash_empty = 0,
+ hash_null = 0,
+ hash_percentage = 0,
+ hash_percent = 0,
+ hash_pcent = 0;
+
+ if(unlikely(!hash_seconds)) {
+ hash_seconds = simple_hash("seconds");
+ hash_seconds_ago = simple_hash("seconds ago");
+ hash_minutes = simple_hash("minutes");
+ hash_minutes_ago = simple_hash("minutes ago");
+ hash_hours = simple_hash("hours");
+ hash_hours_ago = simple_hash("hours ago");
+ hash_onoff = simple_hash("on/off");
+ hash_updown = simple_hash("up/down");
+ hash_okerror = simple_hash("ok/error");
+ hash_okfailed = simple_hash("ok/failed");
+ hash_empty = simple_hash("empty");
+ hash_null = simple_hash("null");
+ hash_percentage = simple_hash("percentage");
+ hash_percent = simple_hash("percent");
+ hash_pcent = simple_hash("pcent");
+ }
+
+ if(unlikely(!units)) units = "";
+
+ uint32_t hash_units = simple_hash(units);
+
+ if(unlikely((hash_units == hash_seconds && !strcmp(units, "seconds")) || (hash_units == hash_seconds_ago && !strcmp(units, "seconds ago")))) {
+ if(value == 0.0) {
+ snprintfz(value_string, value_string_len, "%s", "now");
+ return value_string;
+ }
+ else if(isnan(value) || isinf(value)) {
+ snprintfz(value_string, value_string_len, "%s", "never");
+ return value_string;
+ }
+
+ const char *suffix = (hash_units == hash_seconds_ago)?" ago":"";
+
+ size_t s = (size_t)value;
+ size_t d = s / 86400;
+ s = s % 86400;
+
+ size_t h = s / 3600;
+ s = s % 3600;
+
+ size_t m = s / 60;
+ s = s % 60;
+
+ if(d)
+ snprintfz(value_string, value_string_len, "%zu %s %02zu:%02zu:%02zu%s", d, (d == 1)?"day":"days", h, m, s, suffix);
+ else
+ snprintfz(value_string, value_string_len, "%02zu:%02zu:%02zu%s", h, m, s, suffix);
+
+ return value_string;
+ }
+
+ else if(unlikely((hash_units == hash_minutes && !strcmp(units, "minutes")) || (hash_units == hash_minutes_ago && !strcmp(units, "minutes ago")))) {
+ if(value == 0.0) {
+ snprintfz(value_string, value_string_len, "%s", "now");
+ return value_string;
+ }
+ else if(isnan(value) || isinf(value)) {
+ snprintfz(value_string, value_string_len, "%s", "never");
+ return value_string;
+ }
+
+ const char *suffix = (hash_units == hash_minutes_ago)?" ago":"";
+
+ size_t m = (size_t)value;
+ size_t d = m / (60 * 24);
+ m = m % (60 * 24);
+
+ size_t h = m / 60;
+ m = m % 60;
+
+ if(d)
+ snprintfz(value_string, value_string_len, "%zud %02zuh %02zum%s", d, h, m, suffix);
+ else
+ snprintfz(value_string, value_string_len, "%zuh %zum%s", h, m, suffix);
+
+ return value_string;
+ }
+
+ else if(unlikely((hash_units == hash_hours && !strcmp(units, "hours")) || (hash_units == hash_hours_ago && !strcmp(units, "hours ago")))) {
+ if(value == 0.0) {
+ snprintfz(value_string, value_string_len, "%s", "now");
+ return value_string;
+ }
+ else if(isnan(value) || isinf(value)) {
+ snprintfz(value_string, value_string_len, "%s", "never");
+ return value_string;
+ }
+
+ const char *suffix = (hash_units == hash_hours_ago)?" ago":"";
+
+ size_t h = (size_t)value;
+ size_t d = h / 24;
+ h = h % 24;
+
+ if(d)
+ snprintfz(value_string, value_string_len, "%zud %zuh%s", d, h, suffix);
+ else
+ snprintfz(value_string, value_string_len, "%zuh%s", h, suffix);
+
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_onoff && !strcmp(units, "on/off"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"on":"off");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_updown && !strcmp(units, "up/down"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"up":"down");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_okerror && !strcmp(units, "ok/error"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"error");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_okfailed && !strcmp(units, "ok/failed"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"failed");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_empty && !strcmp(units, "empty")))
+ units = "";
+
+ else if(unlikely(hash_units == hash_null && !strcmp(units, "null")))
+ units = "";
+
+ else if(unlikely(hash_units == hash_percentage && !strcmp(units, "percentage")))
+ units = "%";
+
+ else if(unlikely(hash_units == hash_percent && !strcmp(units, "percent")))
+ units = "%";
+
+ else if(unlikely(hash_units == hash_pcent && !strcmp(units, "pcent")))
+ units = "%";
+
+
+ if(unlikely(isnan(value) || isinf(value))) {
+ strcpy(value_string, "-");
+ return value_string;
+ }
+
+ return format_value_with_precision_and_unit(value_string, value_string_len, value, units, precision);
}
static inline const char *color_map(const char *color) {
@@ -391,7 +607,13 @@ static inline const char *color_map(const char *color) {
return color;
}
-static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value, int value_is_null) {
+static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value) {
+ int value_is_null = 0;
+ if(isnan(value) || isinf(value)) {
+ value = 0.0;
+ value_is_null = 1;
+ }
+
char color_buffer[256 + 1] = "";
char value_buffer[256 + 1] = "";
char comparison = '>';
@@ -501,7 +723,7 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu
// colors
#define COLOR_STRING_SIZE 100
-void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision) {
+void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision) {
char label_buffer[LABEL_STRING_SIZE + 1]
, value_color_buffer[COLOR_STRING_SIZE + 1]
, value_string[VALUE_STRING_SIZE + 1]
@@ -516,102 +738,10 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch
label_color = "#555";
if(unlikely(!value_color || !*value_color))
- value_color = (value_is_null)?"#999":"#4c1";
-
- units = fix_units(units);
- calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value, value_is_null);
-
- char *separator = "";
- if(unlikely(isalnum(*units)))
- separator = " ";
-
- if(unlikely(!strcmp(units, "seconds"))) {
- size_t s = (size_t)value;
- size_t d = s / 86400;
- s = s % 86400;
-
- size_t h = s / 3600;
- s = s % 3600;
-
- size_t m = s / 60;
- s = s % 60;
-
- if(d)
- snprintfz(value_string, VALUE_STRING_SIZE, "%zu %s %02zu:%02zu:%02zu", d, (d == 1)?"day":"days", h, m, s);
- else
- snprintfz(value_string, VALUE_STRING_SIZE, "%02zu:%02zu:%02zu", h, m, s);
- }
-
- else if(unlikely(!strcmp(units, "minutes"))) {
- size_t m = (size_t)value;
- size_t d = m / (60 * 24);
- m = m % (60 * 24);
-
- size_t h = m / 60;
- m = m % 60;
+ value_color = (isnan(value) || isinf(value))?"#999":"#4c1";
- if(d)
- snprintfz(value_string, VALUE_STRING_SIZE, "%zud %02zuh %02zum", d, h, m);
- else
- snprintfz(value_string, VALUE_STRING_SIZE, "%zuh %zum", h, m);
- }
-
- else if(unlikely(!strcmp(units, "hours"))) {
- size_t h = (size_t)value;
- size_t d = h / 24;
- h = h % 24;
-
- if(d)
- snprintfz(value_string, VALUE_STRING_SIZE, "%zud %zuh", d, h);
- else
- snprintfz(value_string, VALUE_STRING_SIZE, "%zuh", h);
- }
-
- else if(unlikely(value_is_null))
- strcpy(value_string, "-");
-
- else if(precision < 0) {
- int len, lstop = 0, trim_zeros = 1;
-
- calculated_number abs = value;
- if(isless(value, 0)) {
- lstop = 1;
- abs = -value;
- }
-
- if(isgreaterequal(abs, 1000)) { len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.0Lf", (long double)value); trim_zeros = 0; }
- else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.1Lf", (long double)value);
- else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.2Lf", (long double)value);
- else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.3Lf", (long double)value);
- else len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.4Lf", (long double)value);
-
- if(unlikely(trim_zeros)) {
- int l;
- // remove trailing zeros from the decimal part
- for(l = len - 1; l > lstop ; l--) {
- if(likely(value_string[l] == '0')) {
- value_string[l] = '\0';
- len--;
- }
-
- else if(unlikely(value_string[l] == '.')) {
- value_string[l] = '\0';
- len--;
- break;
- }
-
- else
- break;
- }
- }
-
- if(len >= 0)
- snprintfz(&value_string[len], VALUE_STRING_SIZE - len, "%s%s", separator, units);
- }
- else {
- if(precision > 50) precision = 50;
- snprintfz(value_string, VALUE_STRING_SIZE, "%0.*Lf%s%s", precision, (long double)value, separator, units);
- }
+ calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value);
+ format_value_and_unit(value_string, VALUE_STRING_SIZE, value, units, precision);
// we need to copy the label, since verdana11_width may write to it
strncpyz(label_buffer, label, LABEL_STRING_SIZE);
diff --git a/src/web_buffer_svg.h b/src/web_buffer_svg.h
index 1281847eb..49f73e445 100644
--- a/src/web_buffer_svg.h
+++ b/src/web_buffer_svg.h
@@ -1,6 +1,7 @@
#ifndef NETDATA_WEB_BUFFER_SVG_H
#define NETDATA_WEB_BUFFER_SVG_H 1
-extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision);
+extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision);
+extern char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision);
#endif /* NETDATA_WEB_BUFFER_SVG_H */
diff --git a/src/web_client.c b/src/web_client.c
index 4b6ccf646..b5b25899f 100644
--- a/src/web_client.c
+++ b/src/web_client.c
@@ -5,7 +5,8 @@
#define TOO_BIG_REQUEST 16384
int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS;
-int web_donotrack_comply = 0;
+int respect_web_browser_do_not_track_policy = 0;
+char *web_x_frame_options = NULL;
#ifdef NETDATA_WITH_ZLIB
int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRATEGY;
@@ -24,6 +25,8 @@ static inline int web_client_crock_socket(struct web_client *w) {
return -1;
}
}
+#else
+ (void)w;
#endif /* TCP_CORK */
return 0;
@@ -39,13 +42,14 @@ static inline int web_client_uncrock_socket(struct web_client *w) {
return -1;
}
}
+#else
+ (void)w;
#endif /* TCP_CORK */
return 0;
}
-struct web_client *web_client_create(int listener)
-{
+struct web_client *web_client_create(int listener) {
struct web_client *w;
w = callocz(1, sizeof(struct web_client));
@@ -222,9 +226,9 @@ struct web_client *web_client_free(struct web_client *w) {
if(w->prev) w->prev->next = w->next;
if(w->next) w->next->prev = w->prev;
- if(w->response.header_output) buffer_free(w->response.header_output);
- if(w->response.header) buffer_free(w->response.header);
- if(w->response.data) buffer_free(w->response.data);
+ buffer_free(w->response.header_output);
+ buffer_free(w->response.header);
+ buffer_free(w->response.data);
if(w->ifd != -1) close(w->ifd);
if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
freez(w);
@@ -239,7 +243,7 @@ uid_t web_files_uid(void) {
static uid_t owner_uid = 0;
if(unlikely(!web_owner)) {
- web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
+ web_owner = config_get(CONFIG_SECTION_WEB, "web files owner", config_get(CONFIG_SECTION_GLOBAL, "run as user", ""));
if(!web_owner || !*web_owner)
owner_uid = geteuid();
else {
@@ -266,7 +270,7 @@ gid_t web_files_gid(void) {
static gid_t owner_gid = 0;
if(unlikely(!web_group)) {
- web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
+ web_group = config_get(CONFIG_SECTION_WEB, "web files group", config_get(CONFIG_SECTION_WEB, "web files owner", ""));
if(!web_group || !*web_group)
owner_gid = getegid();
else {
@@ -288,14 +292,8 @@ gid_t web_files_gid(void) {
return(owner_gid);
}
-int mysendfile(struct web_client *w, char *filename)
-{
- static char *web_dir = NULL;
-
- // initialize our static data
- if(unlikely(!web_dir)) web_dir = config_get("global", "web files directory", WEB_DIR);
-
- debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, web_dir, filename);
+int mysendfile(struct web_client *w, char *filename) {
+ debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, netdata_configured_web_dir, filename);
// skip leading slashes
while (*filename == '/') filename++;
@@ -308,6 +306,7 @@ int mysendfile(struct web_client *w, char *filename)
for(s = filename; *s ;s++) {
if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_sprintf(w->response.data, "Filename contains invalid characters: ");
buffer_strcat_htmlescape(w->response.data, filename);
return 400;
@@ -317,6 +316,7 @@ int mysendfile(struct web_client *w, char *filename)
// if the filename contains a .. refuse to serve it
if(strstr(filename, "..") != 0) {
debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Relative filenames are not supported: ");
buffer_strcat_htmlescape(w->response.data, filename);
return 400;
@@ -324,12 +324,13 @@ int mysendfile(struct web_client *w, char *filename)
// access the file
char webfilename[FILENAME_MAX + 1];
- snprintfz(webfilename, FILENAME_MAX, "%s/%s", web_dir, filename);
+ snprintfz(webfilename, FILENAME_MAX, "%s/%s", netdata_configured_web_dir, filename);
// check if the file exists
struct stat stat;
if(lstat(webfilename, &stat) != 0) {
debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "File does not exist, or is not accessible: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 404;
@@ -338,6 +339,7 @@ int mysendfile(struct web_client *w, char *filename)
// check if the file is owned by expected user
if(stat.st_uid != web_files_uid()) {
error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, stat.st_uid, web_files_uid());
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Access to file is not permitted: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 403;
@@ -346,6 +348,7 @@ int mysendfile(struct web_client *w, char *filename)
// check if the file is owned by expected group
if(stat.st_gid != web_files_gid()) {
error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, stat.st_gid, web_files_gid());
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Access to file is not permitted: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 403;
@@ -358,6 +361,7 @@ int mysendfile(struct web_client *w, char *filename)
if((stat.st_mode & S_IFMT) != S_IFREG) {
error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Access to file is not permitted: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 403;
@@ -370,6 +374,7 @@ int mysendfile(struct web_client *w, char *filename)
if(errno == EBUSY || errno == EAGAIN) {
error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
buffer_strcat(w->response.data, "File is currently busy, please try again later: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
@@ -377,6 +382,7 @@ int mysendfile(struct web_client *w, char *filename)
}
else {
error("%llu: Cannot open file '%s'.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Cannot open file: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 404;
@@ -536,98 +542,6 @@ void buffer_data_options2string(BUFFER *wb, uint32_t options) {
}
}
-uint32_t web_client_api_request_v1_data_options(char *o)
-{
- uint32_t ret = 0x00000000;
- char *tok;
-
- while(o && *o && (tok = mystrsep(&o, ", |"))) {
- if(!*tok) continue;
-
- if(!strcmp(tok, "nonzero"))
- ret |= RRDR_OPTION_NONZERO;
- else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
- ret |= RRDR_OPTION_REVERSED;
- else if(!strcmp(tok, "jsonwrap"))
- ret |= RRDR_OPTION_JSON_WRAP;
- else if(!strcmp(tok, "min2max"))
- ret |= RRDR_OPTION_MIN2MAX;
- else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
- ret |= RRDR_OPTION_MILLISECONDS;
- else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
- ret |= RRDR_OPTION_ABSOLUTE;
- else if(!strcmp(tok, "seconds"))
- ret |= RRDR_OPTION_SECONDS;
- else if(!strcmp(tok, "null2zero"))
- ret |= RRDR_OPTION_NULL2ZERO;
- else if(!strcmp(tok, "objectrows"))
- ret |= RRDR_OPTION_OBJECTSROWS;
- else if(!strcmp(tok, "google_json"))
- ret |= RRDR_OPTION_GOOGLE_JSON;
- else if(!strcmp(tok, "percentage"))
- ret |= RRDR_OPTION_PERCENTAGE;
- else if(!strcmp(tok, "unaligned"))
- ret |= RRDR_OPTION_NOT_ALIGNED;
- }
-
- return ret;
-}
-
-uint32_t web_client_api_request_v1_data_format(char *name)
-{
- if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
- return DATASOURCE_DATATABLE_JSON;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
- return DATASOURCE_DATATABLE_JSONP;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
- return DATASOURCE_JSON;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
- return DATASOURCE_JSONP;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
- return DATASOURCE_SSV;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
- return DATASOURCE_CSV;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
- return DATASOURCE_TSV;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
- return DATASOURCE_HTML;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
- return DATASOURCE_JS_ARRAY;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
- return DATASOURCE_SSV_COMMA;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
- return DATASOURCE_CSV_JSON_ARRAY;
-
- return DATASOURCE_JSON;
-}
-
-uint32_t web_client_api_request_v1_data_google_format(char *name)
-{
- if(!strcmp(name, "json"))
- return DATASOURCE_DATATABLE_JSONP;
-
- else if(!strcmp(name, "html"))
- return DATASOURCE_HTML;
-
- else if(!strcmp(name, "csv"))
- return DATASOURCE_CSV;
-
- else if(!strcmp(name, "tsv-excel"))
- return DATASOURCE_TSV;
-
- return DATASOURCE_JSON;
-}
-
const char *group_method2string(int group) {
switch(group) {
case GROUP_UNDEFINED:
@@ -653,844 +567,27 @@ const char *group_method2string(int group) {
}
}
-int web_client_api_request_v1_data_group(char *name, int def)
-{
- if(!strcmp(name, "average"))
- return GROUP_AVERAGE;
-
- else if(!strcmp(name, "min"))
- return GROUP_MIN;
-
- else if(!strcmp(name, "max"))
- return GROUP_MAX;
-
- else if(!strcmp(name, "sum"))
- return GROUP_SUM;
-
- else if(!strcmp(name, "incremental-sum"))
- return GROUP_INCREMENTAL_SUM;
-
- return def;
-}
-
-int web_client_api_request_v1_alarms(struct web_client *w, char *url)
-{
- int all = 0;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- if(!strcmp(value, "all")) all = 1;
- else if(!strcmp(value, "active")) all = 0;
- }
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- health_alarms2json(&localhost, w->response.data, all);
- return 200;
-}
-
-int web_client_api_request_v1_alarm_log(struct web_client *w, char *url)
-{
- uint32_t after = 0;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- if(!strcmp(name, "after")) after = strtoul(value, NULL, 0);
- }
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- health_alarm_log2json(&localhost, w->response.data, after);
- return 200;
-}
-
-int web_client_api_request_single_chart(struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf))
-{
- int ret = 400;
- char *chart = NULL;
-
- buffer_flush(w->response.data);
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if(!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- // name and value are now the parameters
- // they are not null and not empty
-
- if(!strcmp(name, "chart")) chart = value;
- //else {
- /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
- // goto cleanup;
- //}
- }
-
- if(!chart || !*chart) {
- buffer_sprintf(w->response.data, "No chart id is given at the request.");
- goto cleanup;
- }
-
- RRDSET *st = rrdset_find(chart);
- if(!st) st = rrdset_find_byname(chart);
- if(!st) {
- buffer_strcat(w->response.data, "Chart is not found: ");
- buffer_strcat_htmlescape(w->response.data, chart);
- ret = 404;
- goto cleanup;
- }
-
- w->response.data->contenttype = CT_APPLICATION_JSON;
- callback(st, w->response.data);
- return 200;
-
- cleanup:
- return ret;
-}
-
-int web_client_api_request_v1_alarm_variables(struct web_client *w, char *url)
-{
- return web_client_api_request_single_chart(w, url, health_api_v1_chart_variables2json);
-}
-
-int web_client_api_request_v1_charts(struct web_client *w, char *url)
-{
- (void)url;
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- rrd_stats_api_v1_charts(w->response.data);
- return 200;
-}
-
-int web_client_api_request_v1_allmetrics(struct web_client *w, char *url)
-{
- int format = ALLMETRICS_SHELL;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- if(!strcmp(name, "format")) {
- if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
- format = ALLMETRICS_SHELL;
- else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
- format = ALLMETRICS_PROMETHEUS;
- else
- format = 0;
- }
- }
-
- buffer_flush(w->response.data);
- buffer_no_cacheable(w->response.data);
-
- switch(format) {
- case ALLMETRICS_SHELL:
- w->response.data->contenttype = CT_TEXT_PLAIN;
- rrd_stats_api_v1_charts_allmetrics_shell(w->response.data);
- return 200;
-
- case ALLMETRICS_PROMETHEUS:
- w->response.data->contenttype = CT_PROMETHEUS;
- rrd_stats_api_v1_charts_allmetrics_prometheus(w->response.data);
- return 200;
-
- default:
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_strcat(w->response.data, "Which format? Only '" ALLMETRICS_FORMAT_SHELL "' and '" ALLMETRICS_FORMAT_PROMETHEUS "' is currently supported.");
- return 400;
- }
-}
-
-int web_client_api_request_v1_chart(struct web_client *w, char *url)
-{
- return web_client_api_request_single_chart(w, url, rrd_stats_api_v1_chart);
-}
-
-int web_client_api_request_v1_badge(struct web_client *w, char *url) {
- int ret = 400;
- buffer_flush(w->response.data);
-
- BUFFER *dimensions = NULL;
-
- const char *chart = NULL
- , *before_str = NULL
- , *after_str = NULL
- , *points_str = NULL
- , *multiply_str = NULL
- , *divide_str = NULL
- , *label = NULL
- , *units = NULL
- , *label_color = NULL
- , *value_color = NULL
- , *refresh_str = NULL
- , *precision_str = NULL
- , *alarm = NULL;
-
- int group = GROUP_AVERAGE;
- uint32_t options = 0x00000000;
-
- while(url) {
- char *value = mystrsep(&url, "/?&");
- if(!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
-
- // name and value are now the parameters
- // they are not null and not empty
-
- if(!strcmp(name, "chart")) chart = value;
- else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
- if(!dimensions)
- dimensions = buffer_create(100);
-
- buffer_strcat(dimensions, "|");
- buffer_strcat(dimensions, value);
- }
- else if(!strcmp(name, "after")) after_str = value;
- else if(!strcmp(name, "before")) before_str = value;
- else if(!strcmp(name, "points")) points_str = value;
- else if(!strcmp(name, "group")) {
- group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
- }
- else if(!strcmp(name, "options")) {
- options |= web_client_api_request_v1_data_options(value);
- }
- else if(!strcmp(name, "label")) label = value;
- else if(!strcmp(name, "units")) units = value;
- else if(!strcmp(name, "label_color")) label_color = value;
- else if(!strcmp(name, "value_color")) value_color = value;
- else if(!strcmp(name, "multiply")) multiply_str = value;
- else if(!strcmp(name, "divide")) divide_str = value;
- else if(!strcmp(name, "refresh")) refresh_str = value;
- else if(!strcmp(name, "precision")) precision_str = value;
- else if(!strcmp(name, "alarm")) alarm = value;
- }
-
- if(!chart || !*chart) {
- buffer_no_cacheable(w->response.data);
- buffer_sprintf(w->response.data, "No chart id is given at the request.");
- goto cleanup;
- }
-
- RRDSET *st = rrdset_find(chart);
- if(!st) st = rrdset_find_byname(chart);
- if(!st) {
- buffer_no_cacheable(w->response.data);
- buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
- ret = 200;
- goto cleanup;
- }
-
- RRDCALC *rc = NULL;
- if(alarm) {
- rc = rrdcalc_find(st, alarm);
- if (!rc) {
- buffer_no_cacheable(w->response.data);
- buffer_svg(w->response.data, "alarm not found", 0, "", NULL, NULL, 1, -1);
- ret = 200;
- goto cleanup;
- }
- }
-
- long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1;
- long long divide = (divide_str && *divide_str )?str2l(divide_str):1;
- long long before = (before_str && *before_str )?str2l(before_str):0;
- long long after = (after_str && *after_str )?str2l(after_str):-st->update_every;
- int points = (points_str && *points_str )?str2i(points_str):1;
- int precision = (precision_str && *precision_str)?str2i(precision_str):-1;
-
- if(!multiply) multiply = 1;
- if(!divide) divide = 1;
-
- int refresh = 0;
- if(refresh_str && *refresh_str) {
- if(!strcmp(refresh_str, "auto")) {
- if(rc) refresh = rc->update_every;
- else if(options & RRDR_OPTION_NOT_ALIGNED)
- refresh = st->update_every;
- else {
- refresh = (int)(before - after);
- if(refresh < 0) refresh = -refresh;
- }
- }
- else {
- refresh = str2i(refresh_str);
- if(refresh < 0) refresh = -refresh;
- }
- }
-
- if(!label) {
- if(alarm) {
- char *s = (char *)alarm;
- while(*s) {
- if(*s == '_') *s = ' ';
- s++;
- }
- label = alarm;
- }
- else if(dimensions) {
- const char *dim = buffer_tostring(dimensions);
- if(*dim == '|') dim++;
- label = dim;
- }
- else
- label = st->name;
- }
- if(!units) {
- if(alarm) {
- if(rc->units)
- units = rc->units;
- else
- units = "";
- }
- else if(options & RRDR_OPTION_PERCENTAGE)
- units = "%";
- else
- units = st->units;
- }
-
- debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
- , w->id
- , chart
- , alarm?alarm:""
- , (dimensions)?buffer_tostring(dimensions):""
- , after
- , before
- , points
- , group
- , options
- );
-
- if(rc) {
- calculated_number n = rc->value;
- if(isnan(n) || isinf(n)) n = 0;
-
- if (refresh > 0) {
- buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
- w->response.data->expires = now_realtime_sec() + refresh;
- }
- else buffer_no_cacheable(w->response.data);
-
- if(!value_color) {
- switch(rc->status) {
- case RRDCALC_STATUS_CRITICAL:
- value_color = "red";
- break;
-
- case RRDCALC_STATUS_WARNING:
- value_color = "orange";
- break;
-
- case RRDCALC_STATUS_CLEAR:
- value_color = "brightgreen";
- break;
-
- case RRDCALC_STATUS_UNDEFINED:
- value_color = "lightgrey";
- break;
-
- case RRDCALC_STATUS_UNINITIALIZED:
- value_color = "#000";
- break;
-
- default:
- value_color = "grey";
- break;
- }
- }
-
- buffer_svg(w->response.data,
- label,
- rc->value * multiply / divide,
- units,
- label_color,
- value_color,
- 0,
- precision);
- ret = 200;
- }
- else {
- time_t latest_timestamp = 0;
- int value_is_null = 1;
- calculated_number n = 0;
- ret = 500;
-
- // if the collected value is too old, don't calculate its value
- if (rrdset_last_entry_t(st) >= (now_realtime_sec() - (st->update_every * st->gap_when_lost_iterations_above)))
- ret = rrd2value(st,
- w->response.data,
- &n,
- (dimensions) ? buffer_tostring(dimensions) : NULL,
- points,
- after,
- before,
- group,
- options,
- NULL,
- &latest_timestamp,
- &value_is_null);
-
- // if the value cannot be calculated, show empty badge
- if (ret != 200) {
- buffer_no_cacheable(w->response.data);
- value_is_null = 1;
- n = 0;
- ret = 200;
- }
- else if (refresh > 0) {
- buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
- w->response.data->expires = now_realtime_sec() + refresh;
- }
- else buffer_no_cacheable(w->response.data);
-
- // render the badge
- buffer_svg(w->response.data,
- label,
- n * multiply / divide,
- units,
- label_color,
- value_color,
- value_is_null,
- precision);
- }
-
-cleanup:
- if(dimensions)
- buffer_free(dimensions);
- return ret;
-}
-
-// returns the HTTP code
-int web_client_api_request_v1_data(struct web_client *w, char *url)
-{
- debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
-
- int ret = 400;
- BUFFER *dimensions = NULL;
-
- buffer_flush(w->response.data);
-
- char *google_version = "0.6",
- *google_reqId = "0",
- *google_sig = "0",
- *google_out = "json",
- *responseHandler = NULL,
- *outFileName = NULL;
-
- time_t last_timestamp_in_data = 0, google_timestamp = 0;
-
- char *chart = NULL
- , *before_str = NULL
- , *after_str = NULL
- , *points_str = NULL;
-
- int group = GROUP_AVERAGE;
- uint32_t format = DATASOURCE_JSON;
- uint32_t options = 0x00000000;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if(!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
-
- // name and value are now the parameters
- // they are not null and not empty
-
- if(!strcmp(name, "chart")) chart = value;
- else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
- if(!dimensions) dimensions = buffer_create(100);
- buffer_strcat(dimensions, "|");
- buffer_strcat(dimensions, value);
- }
- else if(!strcmp(name, "after")) after_str = value;
- else if(!strcmp(name, "before")) before_str = value;
- else if(!strcmp(name, "points")) points_str = value;
- else if(!strcmp(name, "group")) {
- group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
- }
- else if(!strcmp(name, "format")) {
- format = web_client_api_request_v1_data_format(value);
- }
- else if(!strcmp(name, "options")) {
- options |= web_client_api_request_v1_data_options(value);
- }
- else if(!strcmp(name, "callback")) {
- responseHandler = value;
- }
- else if(!strcmp(name, "filename")) {
- outFileName = value;
- }
- else if(!strcmp(name, "tqx")) {
- // parse Google Visualization API options
- // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
- char *tqx_name, *tqx_value;
-
- while(value) {
- tqx_value = mystrsep(&value, ";");
- if(!tqx_value || !*tqx_value) continue;
-
- tqx_name = mystrsep(&tqx_value, ":");
- if(!tqx_name || !*tqx_name) continue;
- if(!tqx_value || !*tqx_value) continue;
-
- if(!strcmp(tqx_name, "version"))
- google_version = tqx_value;
- else if(!strcmp(tqx_name, "reqId"))
- google_reqId = tqx_value;
- else if(!strcmp(tqx_name, "sig")) {
- google_sig = tqx_value;
- google_timestamp = strtoul(google_sig, NULL, 0);
- }
- else if(!strcmp(tqx_name, "out")) {
- google_out = tqx_value;
- format = web_client_api_request_v1_data_google_format(google_out);
- }
- else if(!strcmp(tqx_name, "responseHandler"))
- responseHandler = tqx_value;
- else if(!strcmp(tqx_name, "outFileName"))
- outFileName = tqx_value;
- }
- }
- }
-
- if(!chart || !*chart) {
- buffer_sprintf(w->response.data, "No chart id is given at the request.");
- goto cleanup;
- }
-
- RRDSET *st = rrdset_find(chart);
- if(!st) st = rrdset_find_byname(chart);
- if(!st) {
- buffer_strcat(w->response.data, "Chart is not found: ");
- buffer_strcat_htmlescape(w->response.data, chart);
- ret = 404;
- goto cleanup;
- }
-
- long long before = (before_str && *before_str)?str2l(before_str):0;
- long long after = (after_str && *after_str) ?str2l(after_str):0;
- int points = (points_str && *points_str)?str2i(points_str):0;
-
- debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
- , w->id
- , chart
- , (dimensions)?buffer_tostring(dimensions):""
- , after
- , before
- , points
- , group
- , format
- , options
- );
-
- if(outFileName && *outFileName) {
- buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
- debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
- }
-
- if(format == DATASOURCE_DATATABLE_JSONP) {
- if(responseHandler == NULL)
- responseHandler = "google.visualization.Query.setResponse";
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
- w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
- );
-
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
- responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
- }
- else if(format == DATASOURCE_JSONP) {
- if(responseHandler == NULL)
- responseHandler = "callback";
-
- buffer_strcat(w->response.data, responseHandler);
- buffer_strcat(w->response.data, "(");
- }
-
- ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
-
- if(format == DATASOURCE_DATATABLE_JSONP) {
- if(google_timestamp < last_timestamp_in_data)
- buffer_strcat(w->response.data, "});");
-
- else {
- // the client already has the latest data
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
- responseHandler, google_version, google_reqId);
- }
- }
- else if(format == DATASOURCE_JSONP)
- buffer_strcat(w->response.data, ");");
-
-cleanup:
- if(dimensions) buffer_free(dimensions);
- return ret;
-}
-
-
-int web_client_api_request_v1_registry(struct web_client *w, char *url)
-{
- static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
- hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
- hash_to = 0 /*, hash_redirects = 0 */;
-
- if(unlikely(!hash_action)) {
- hash_action = simple_hash("action");
- hash_access = simple_hash("access");
- hash_hello = simple_hash("hello");
- hash_delete = simple_hash("delete");
- hash_search = simple_hash("search");
- hash_switch = simple_hash("switch");
- hash_machine = simple_hash("machine");
- hash_url = simple_hash("url");
- hash_name = simple_hash("name");
- hash_delete_url = simple_hash("delete_url");
- hash_for = simple_hash("for");
- hash_to = simple_hash("to");
-/*
- hash_redirects = simple_hash("redirects");
-*/
- }
-
- char person_guid[GUID_LEN + 1] = "";
-
- debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
-
- // FIXME
- // The browser may send multiple cookies with our id
-
- char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
- if(cookie)
- strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
-
- char action = '\0';
- char *machine_guid = NULL,
- *machine_url = NULL,
- *url_name = NULL,
- *search_machine_guid = NULL,
- *delete_url = NULL,
- *to_person_guid = NULL;
-/*
- int redirects = 0;
-*/
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if (!name || !*name) continue;
- if (!value || !*value) continue;
-
- debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
-
- uint32_t hash = simple_hash(name);
-
- if(hash == hash_action && !strcmp(name, "action")) {
- uint32_t vhash = simple_hash(value);
-
- if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
- else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
- else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
- else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
- else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
-#ifdef NETDATA_INTERNAL_CHECKS
- else error("unknown registry action '%s'", value);
-#endif /* NETDATA_INTERNAL_CHECKS */
- }
-/*
- else if(hash == hash_redirects && !strcmp(name, "redirects"))
- redirects = atoi(value);
-*/
- else if(hash == hash_machine && !strcmp(name, "machine"))
- machine_guid = value;
-
- else if(hash == hash_url && !strcmp(name, "url"))
- machine_url = value;
-
- else if(action == 'A') {
- if(hash == hash_name && !strcmp(name, "name"))
- url_name = value;
- }
- else if(action == 'D') {
- if(hash == hash_delete_url && !strcmp(name, "delete_url"))
- delete_url = value;
- }
- else if(action == 'S') {
- if(hash == hash_for && !strcmp(name, "for"))
- search_machine_guid = value;
- }
- else if(action == 'W') {
- if(hash == hash_to && !strcmp(name, "to"))
- to_person_guid = value;
- }
-#ifdef NETDATA_INTERNAL_CHECKS
- else error("unused registry URL parameter '%s' with value '%s'", name, value);
-#endif /* NETDATA_INTERNAL_CHECKS */
- }
-
- if(web_donotrack_comply && w->donottrack) {
+static inline int check_host_and_call(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) {
+ if(unlikely(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
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.");
+ buffer_strcat(w->response.data, "This host does not maintain a database");
return 400;
}
- if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
- error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Access request.");
- return 400;
- }
- else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
- error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Delete request.");
- return 400;
- }
- else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
- error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Search request.");
- return 400;
- }
- else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
- error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Switch request.");
- return 400;
- }
-
- switch(action) {
- case 'A':
- w->tracking_required = 1;
- return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
-
- case 'D':
- w->tracking_required = 1;
- return registry_request_delete_json(w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
-
- case 'S':
- w->tracking_required = 1;
- return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec());
-
- case 'W':
- w->tracking_required = 1;
- return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
-
- case 'H':
- return registry_request_hello_json(w);
-
- default:
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
- return 400;
- }
+ return func(host, w, url);
}
-int web_client_api_request_v1(struct web_client *w, char *url) {
- static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0, hash_raw = 0;
-
- if(unlikely(hash_data == 0)) {
- hash_data = simple_hash("data");
- hash_chart = simple_hash("chart");
- hash_charts = simple_hash("charts");
- hash_registry = simple_hash("registry");
- hash_badge = simple_hash("badge.svg");
- hash_alarms = simple_hash("alarms");
- hash_alarm_log = simple_hash("alarm_log");
- hash_alarm_variables = simple_hash("alarm_variables");
- hash_raw = simple_hash("allmetrics");
- }
-
- // get the command
- char *tok = mystrsep(&url, "/?&");
- if(tok && *tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
- uint32_t hash = simple_hash(tok);
-
- if(hash == hash_data && !strcmp(tok, "data"))
- return web_client_api_request_v1_data(w, url);
-
- else if(hash == hash_chart && !strcmp(tok, "chart"))
- return web_client_api_request_v1_chart(w, url);
-
- else if(hash == hash_charts && !strcmp(tok, "charts"))
- return web_client_api_request_v1_charts(w, url);
-
- else if(hash == hash_registry && !strcmp(tok, "registry"))
- return web_client_api_request_v1_registry(w, url);
-
- else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
- return web_client_api_request_v1_badge(w, url);
-
- else if(hash == hash_alarms && !strcmp(tok, "alarms"))
- return web_client_api_request_v1_alarms(w, url);
-
- else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
- return web_client_api_request_v1_alarm_log(w, url);
-
- else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
- return web_client_api_request_v1_alarm_variables(w, url);
-
- else if(hash == hash_raw && !strcmp(tok, "allmetrics"))
- return web_client_api_request_v1_allmetrics(w, url);
-
- else {
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Unsupported v1 API command: ");
- buffer_strcat_htmlescape(w->response.data, tok);
- return 404;
- }
- }
- else {
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Which API v1 command?");
- return 400;
- }
-}
-
-int web_client_api_request(struct web_client *w, char *url)
+int web_client_api_request(RRDHOST *host, struct web_client *w, char *url)
{
// get the api version
char *tok = mystrsep(&url, "/?&");
if(tok && *tok) {
debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
if(strcmp(tok, "v1") == 0)
- return web_client_api_request_v1(w, url);
+ return web_client_api_request_v1(host, w, url);
else {
buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Unsupported API version: ");
buffer_strcat_htmlescape(w->response.data, tok);
return 404;
@@ -1503,179 +600,6 @@ int web_client_api_request(struct web_client *w, char *url)
}
}
-int web_client_api_old_data_request(struct web_client *w, char *url, int datasource_type)
-{
- if(!url || !*url) {
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Incomplete request.");
- return 400;
- }
-
- RRDSET *st = NULL;
-
- char *args = strchr(url, '?');
- if(args) {
- *args='\0';
- args = &args[1];
- }
-
- // get the name of the data to show
- char *tok = mystrsep(&url, "/");
- if(!tok) tok = "";
-
- // do we have such a data set?
- if(*tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
- st = rrdset_find_byname(tok);
- if(!st) st = rrdset_find(tok);
- }
-
- if(!st) {
- // we don't have it
- // try to send a file with that name
- buffer_flush(w->response.data);
- return(mysendfile(w, tok));
- }
-
- // we have it
- debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
-
- // how many entries does the client want?
- int lines = rrd_default_history_entries;
- int group_count = 1;
- time_t after = 0, before = 0;
- int group_method = GROUP_AVERAGE;
- int nonzero = 0;
-
- if(url) {
- // parse the lines required
- tok = mystrsep(&url, "/");
- if(tok) lines = str2i(tok);
- if(lines < 1) lines = 1;
- }
- if(url) {
- // parse the group count required
- tok = mystrsep(&url, "/");
- if(tok && *tok) group_count = str2i(tok);
- if(group_count < 1) group_count = 1;
- //if(group_count > save_history / 20) group_count = save_history / 20;
- }
- if(url) {
- // parse the grouping method required
- tok = mystrsep(&url, "/");
- if(tok && *tok) {
- if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
- else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
- else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
- else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
- }
- }
- if(url) {
- // parse after time
- tok = mystrsep(&url, "/");
- if(tok && *tok) after = str2ul(tok);
- if(after < 0) after = 0;
- }
- if(url) {
- // parse before time
- tok = mystrsep(&url, "/");
- if(tok && *tok) before = str2ul(tok);
- if(before < 0) before = 0;
- }
- if(url) {
- // parse nonzero
- tok = mystrsep(&url, "/");
- if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
- }
-
- w->response.data->contenttype = CT_APPLICATION_JSON;
- buffer_flush(w->response.data);
-
- char *google_version = "0.6";
- char *google_reqId = "0";
- char *google_sig = "0";
- char *google_out = "json";
- char *google_responseHandler = "google.visualization.Query.setResponse";
- char *google_outFileName = NULL;
- time_t last_timestamp_in_data = 0;
- if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
-
- w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
-
- while(args) {
- tok = mystrsep(&args, "&");
- if(tok && *tok) {
- char *name = mystrsep(&tok, "=");
- if(name && *name && strcmp(name, "tqx") == 0) {
- char *key = mystrsep(&tok, ":");
- char *value = mystrsep(&tok, ";");
- if(key && value && *key && *value) {
- if(strcmp(key, "version") == 0)
- google_version = value;
-
- else if(strcmp(key, "reqId") == 0)
- google_reqId = value;
-
- else if(strcmp(key, "sig") == 0)
- google_sig = value;
-
- else if(strcmp(key, "out") == 0)
- google_out = value;
-
- else if(strcmp(key, "responseHandler") == 0)
- google_responseHandler = value;
-
- else if(strcmp(key, "outFileName") == 0)
- google_outFileName = value;
- }
- }
- }
- }
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
- w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
- );
-
- if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
- last_timestamp_in_data = strtoul(google_sig, NULL, 0);
-
- // check the client wants json
- if(strcmp(google_out, "json") != 0) {
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
- google_responseHandler, google_version, google_reqId, google_out);
- return 200;
- }
- }
- }
-
- if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
- google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
- }
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
- w->id, st->name, st->id, lines, group_count, group_method, after, before);
-
- time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, (unsigned long)after, (unsigned long)before, nonzero);
-
- if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
- if(timestamp_in_data > last_timestamp_in_data)
- buffer_strcat(w->response.data, "});");
-
- else {
- // the client already has the latest data
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
- google_responseHandler, google_version, google_reqId);
- }
- }
-
- return 200;
-}
-
const char *web_content_type_to_string(uint8_t contenttype) {
switch(contenttype) {
case CT_TEXT_HTML:
@@ -1834,7 +758,7 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
if(strcasestr(v, "keep-alive"))
w->keepalive = 1;
}
- else if(web_donotrack_comply && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
+ 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;
}
@@ -1862,7 +786,13 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
// > 0 : request is not supported
// < 0 : request is incomplete - wait for more data
-static inline int http_request_validate(struct web_client *w) {
+typedef enum http_validation {
+ HTTP_VALIDATION_OK,
+ HTTP_VALIDATION_NOT_SUPPORTED,
+ HTTP_VALIDATION_INCOMPLETE
+} HTTP_VALIDATION;
+
+static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
char *s = w->response.data->buffer, *encoded_url = NULL;
// is is a valid request?
@@ -1874,9 +804,13 @@ static inline int http_request_validate(struct web_client *w) {
encoded_url = s = &s[8];
w->mode = WEB_CLIENT_MODE_OPTIONS;
}
+ else if(!strncmp(s, "STREAM ", 7)) {
+ encoded_url = s = &s[7];
+ w->mode = WEB_CLIENT_MODE_STREAM;
+ }
else {
w->wait_receive = 0;
- return 1;
+ return HTTP_VALIDATION_NOT_SUPPORTED;
}
// find the SPACE + "HTTP/"
@@ -1892,7 +826,7 @@ static inline int http_request_validate(struct web_client *w) {
// incomplete requests
if(unlikely(!*s)) {
w->wait_receive = 1;
- return -2;
+ return HTTP_VALIDATION_INCOMPLETE;
}
// we have the end of encoded_url - remember it
@@ -1923,7 +857,7 @@ static inline int http_request_validate(struct web_client *w) {
strncpyz(w->last_url, w->decoded_url, URL_MAX);
w->wait_receive = 0;
- return 0;
+ return HTTP_VALIDATION_OK;
}
// another header line
@@ -1933,259 +867,26 @@ static inline int http_request_validate(struct web_client *w) {
// incomplete request
w->wait_receive = 1;
- return -3;
+ return HTTP_VALIDATION_INCOMPLETE;
}
-void web_client_process(struct web_client *w) {
- static uint32_t
- hash_api = 0,
- hash_netdata_conf = 0,
- hash_data = 0,
- hash_datasource = 0,
- hash_graph = 0,
- hash_list = 0,
- hash_all_json = 0;
-
-#ifdef NETDATA_INTERNAL_CHECKS
- static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
-#endif
-
- // start timing us
- now_realtime_timeval(&w->tv_in);
-
- if(unlikely(!hash_api)) {
- hash_api = simple_hash("api");
- hash_netdata_conf = simple_hash("netdata.conf");
- hash_data = simple_hash(WEB_PATH_DATA);
- hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
- hash_graph = simple_hash(WEB_PATH_GRAPH);
- hash_list = simple_hash("list");
- hash_all_json = simple_hash("all.json");
-#ifdef NETDATA_INTERNAL_CHECKS
- hash_exit = simple_hash("exit");
- hash_debug = simple_hash("debug");
- hash_mirror = simple_hash("mirror");
-#endif
- }
-
- int code = 500;
- ssize_t bytes;
-
- int what_to_do = http_request_validate(w);
-
- // wait for more data
- if(what_to_do < 0) {
- if(w->response.data->len > TOO_BIG_REQUEST) {
- strcpy(w->last_url, "too big request");
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
-
- code = 400;
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Received request is too big (%zu bytes).\r\n", w->response.data->len);
- }
- else {
- // wait for more data
- return;
- }
- }
- else if(what_to_do > 0) {
- // strcpy(w->last_url, "not a valid request");
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
-
- code = 500;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "I don't understand you...\r\n");
- }
- else { // what_to_do == 0
- if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
- code = 200;
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "OK");
- }
- else {
- char *url = w->decoded_url;
- char *tok = mystrsep(&url, "/?");
- if(tok && *tok) {
- uint32_t hash = simple_hash(tok);
- debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
-
- if(hash == hash_api && strcmp(tok, "api") == 0) {
- // the client is requesting api access
- code = web_client_api_request(w, url);
- }
- else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
-
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
- generate_config(w->response.data, 0);
- }
- else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
- // the client is requesting rrd data -- OLD API
- code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
- }
- else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
- // the client is requesting google datasource -- OLD API
- code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
- }
- else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
- // the client is requesting an rrd graph -- OLD API
-
- // get the name of the data to show
- tok = mystrsep(&url, "/?&");
- if(tok && *tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-
- // do we have such a data set?
- RRDSET *st = rrdset_find_byname(tok);
- if(!st) st = rrdset_find(tok);
- if(!st) {
- // we don't have it
- // try to send a file with that name
- buffer_flush(w->response.data);
- code = mysendfile(w, tok);
- }
- else {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- buffer_flush(w->response.data);
- rrd_stats_graph_json(st, url, w->response.data);
- }
- }
- else {
- code = 400;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Graph name?\r\n");
- }
- }
- else if(hash == hash_list && strcmp(tok, "list") == 0) {
- // OLD API
- code = 200;
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
-
- buffer_flush(w->response.data);
- RRDSET *st = localhost.rrdset_root;
-
- for ( ; st ; st = st->next )
- buffer_sprintf(w->response.data, "%s\n", st->name);
- }
- else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
- // OLD API
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
-
- w->response.data->contenttype = CT_APPLICATION_JSON;
- buffer_flush(w->response.data);
- rrd_stats_all_json(w->response.data);
- }
-#ifdef NETDATA_INTERNAL_CHECKS
- else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
- code = 200;
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
-
- if(!netdata_exit)
- buffer_strcat(w->response.data, "ok, will do...");
- else
- buffer_strcat(w->response.data, "I am doing it already");
-
- error("web request to exit received.");
- netdata_cleanup_and_exit(0);
- }
- else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
- buffer_flush(w->response.data);
-
- // get the name of the data to show
- tok = mystrsep(&url, "/?&");
- if(tok && *tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-
- // do we have such a data set?
- RRDSET *st = rrdset_find_byname(tok);
- if(!st) st = rrdset_find(tok);
- if(!st) {
- code = 404;
- buffer_strcat(w->response.data, "Chart is not found: ");
- buffer_strcat_htmlescape(w->response.data, tok);
- debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
- }
- else {
- code = 200;
- debug_flags |= D_RRD_STATS;
- st->debug = !st->debug;
- buffer_sprintf(w->response.data, "Chart has now debug %s: ", st->debug?"enabled":"disabled");
- buffer_strcat_htmlescape(w->response.data, tok);
- debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
- }
- }
- else {
- code = 500;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "debug which chart?\r\n");
- }
- }
- else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
- code = 200;
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
-
- // replace the zero bytes with spaces
- buffer_char_replace(w->response.data, '\0', ' ');
-
- // just leave the buffer as is
- // it will be copied back to the client
- }
-#endif /* NETDATA_INTERNAL_CHECKS */
- else {
- char filename[FILENAME_MAX+1];
- url = filename;
- strncpyz(filename, w->last_url, FILENAME_MAX);
- tok = mystrsep(&url, "?");
- buffer_flush(w->response.data);
- code = mysendfile(w, (tok && *tok)?tok:"/");
- }
- }
- else {
- char filename[FILENAME_MAX+1];
- url = filename;
- strncpyz(filename, w->last_url, FILENAME_MAX);
- tok = mystrsep(&url, "?");
- buffer_flush(w->response.data);
- code = mysendfile(w, (tok && *tok)?tok:"/");
- }
- }
- }
-
- now_realtime_timeval(&w->tv_ready);
- w->response.sent = 0;
- w->response.code = code;
-
- // set a proper last modified date
- if(unlikely(!w->response.data->date))
- w->response.data->date = w->tv_ready.tv_sec;
-
- if(unlikely(code != 200))
+static inline void web_client_send_http_header(struct web_client *w) {
+ if(unlikely(w->response.code != 200))
buffer_no_cacheable(w->response.data);
// set a proper expiration date, if not already set
if(unlikely(!w->response.data->expires)) {
if(w->response.data->options & WB_CONTENT_NO_CACHEABLE)
- w->response.data->expires = w->tv_ready.tv_sec + rrd_update_every;
+ w->response.data->expires = w->tv_ready.tv_sec + localhost->rrd_update_every;
else
w->response.data->expires = w->tv_ready.tv_sec + 86400;
}
// prepare the HTTP response header
- debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
+ debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, w->response.code);
const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
- const char *code_msg = web_response_code_to_string(code);
+ const char *code_msg = web_response_code_to_string(w->response.code);
// prepare the last modified and expiration dates
char date[32], edate[32];
@@ -2200,61 +901,64 @@ void web_client_process(struct web_client *w) {
}
buffer_sprintf(w->response.header_output,
- "HTTP/1.1 %d %s\r\n"
- "Connection: %s\r\n"
- "Server: NetData Embedded HTTP Server\r\n"
- "Access-Control-Allow-Origin: %s\r\n"
- "Access-Control-Allow-Credentials: true\r\n"
- "Content-Type: %s\r\n"
- "Date: %s\r\n"
- , code, code_msg
- , w->keepalive?"keep-alive":"close"
- , w->origin
- , content_type_string
- , date
- );
+ "HTTP/1.1 %d %s\r\n"
+ "Connection: %s\r\n"
+ "Server: NetData Embedded HTTP Server\r\n"
+ "Access-Control-Allow-Origin: %s\r\n"
+ "Access-Control-Allow-Credentials: true\r\n"
+ "Content-Type: %s\r\n"
+ "Date: %s\r\n"
+ , w->response.code, code_msg
+ , w->keepalive?"keep-alive":"close"
+ , w->origin
+ , content_type_string
+ , date
+ );
+
+ if(unlikely(web_x_frame_options))
+ buffer_sprintf(w->response.header_output, "X-Frame-Options: %s\r\n", web_x_frame_options);
if(w->cookie1[0] || w->cookie2[0]) {
if(w->cookie1[0]) {
buffer_sprintf(w->response.header_output,
- "Set-Cookie: %s\r\n",
- w->cookie1);
+ "Set-Cookie: %s\r\n",
+ w->cookie1);
}
if(w->cookie2[0]) {
buffer_sprintf(w->response.header_output,
- "Set-Cookie: %s\r\n",
- w->cookie2);
+ "Set-Cookie: %s\r\n",
+ w->cookie2);
}
- if(web_donotrack_comply)
+ if(respect_web_browser_do_not_track_policy)
buffer_sprintf(w->response.header_output,
- "Tk: T;cookies\r\n");
+ "Tk: T;cookies\r\n");
}
else {
- if(web_donotrack_comply) {
+ if(respect_web_browser_do_not_track_policy) {
if(w->tracking_required)
buffer_sprintf(w->response.header_output,
- "Tk: T;cookies\r\n");
+ "Tk: T;cookies\r\n");
else
buffer_sprintf(w->response.header_output,
- "Tk: N\r\n");
+ "Tk: N\r\n");
}
}
if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
buffer_strcat(w->response.header_output,
- "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
- "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control\r\n"
- "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
- );
+ "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
+ "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control\r\n"
+ "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
+ );
}
else {
buffer_sprintf(w->response.header_output,
- "Cache-Control: %s\r\n"
- "Expires: %s\r\n",
- (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache":"public",
- edate);
+ "Cache-Control: %s\r\n"
+ "Expires: %s\r\n",
+ (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache":"public",
+ edate);
}
// copy a possibly available custom header
@@ -2264,9 +968,9 @@ void web_client_process(struct web_client *w) {
// headers related to the transfer method
if(likely(w->response.zoutput)) {
buffer_strcat(w->response.header_output,
- "Content-Encoding: gzip\r\n"
- "Transfer-Encoding: chunked\r\n"
- );
+ "Content-Encoding: gzip\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ );
}
else {
if(likely((w->response.data->len || w->response.rlen))) {
@@ -2284,35 +988,284 @@ void web_client_process(struct web_client *w) {
// sent the HTTP header
debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
- , w->id
- , buffer_strlen(w->response.header_output)
- , buffer_tostring(w->response.header_output)
- );
+ , w->id
+ , buffer_strlen(w->response.header_output)
+ , buffer_tostring(w->response.header_output)
+ );
web_client_crock_socket(w);
- bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
+ ssize_t bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
if(bytes > 0)
w->stats_sent_bytes += bytes;
debug(D_WEB_CLIENT, "%llu: HTTP Header failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
- , w->id
- , buffer_strlen(w->response.header_output)
- , bytes);
+ , w->id
+ , buffer_strlen(w->response.header_output)
+ , bytes);
WEB_CLIENT_IS_DEAD(w);
return;
}
- else
+ else
w->stats_sent_bytes += bytes;
+}
+
+static inline int web_client_process_url(RRDHOST *host, struct web_client *w, char *url);
+
+static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t hash_localhost = 0;
+
+ if(unlikely(!hash_localhost)) {
+ hash_localhost = simple_hash("localhost");
+ }
+
+ if(host != localhost) {
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Nesting of hosts is not allowed.");
+ return 400;
+ }
+
+ char *tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for host with name '%s'.", w->id, tok);
+
+ // copy the URL, we need it to serve files
+ w->last_url[0] = '/';
+ if(url && *url) strncpyz(&w->last_url[1], url, URL_MAX - 1);
+ else w->last_url[1] = '\0';
+
+ uint32_t hash = simple_hash(tok);
+
+ host = rrdhost_find_by_hostname(tok, hash);
+ if(!host) host = rrdhost_find_by_guid(tok, hash);
+
+ if(host) return web_client_process_url(host, w, url);
+ }
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_TEXT_HTML;
+ buffer_strcat(w->response.data, "This netdata does not maintain a database for host: ");
+ buffer_strcat_htmlescape(w->response.data, tok?tok:"");
+ return 404;
+}
+
+static inline int web_client_process_url(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t
+ hash_api = 0,
+ hash_netdata_conf = 0,
+ hash_data = 0,
+ hash_datasource = 0,
+ hash_graph = 0,
+ hash_list = 0,
+ hash_all_json = 0,
+ hash_host = 0;
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
+#endif
+
+ if(unlikely(!hash_api)) {
+ hash_api = simple_hash("api");
+ hash_netdata_conf = simple_hash("netdata.conf");
+ hash_data = simple_hash(WEB_PATH_DATA);
+ hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
+ hash_graph = simple_hash(WEB_PATH_GRAPH);
+ hash_list = simple_hash("list");
+ hash_all_json = simple_hash("all.json");
+ hash_host = simple_hash("host");
+#ifdef NETDATA_INTERNAL_CHECKS
+ hash_exit = simple_hash("exit");
+ hash_debug = simple_hash("debug");
+ hash_mirror = simple_hash("mirror");
+#endif
+ }
+
+ char *tok = mystrsep(&url, "/?");
+ if(likely(tok && *tok)) {
+ uint32_t hash = simple_hash(tok);
+ debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
+
+ if(unlikely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
+ debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_request);
+ }
+ else if(unlikely(hash == hash_host && strcmp(tok, "host") == 0)) { // host switching
+ debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
+ return web_client_switch_host(host, w, url);
+ }
+ else if(unlikely(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0)) { // old API "data"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API data request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_data_request_json);
+ }
+ else if(unlikely(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0)) { // old API "datasource"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API datasource request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_data_request_jsonp);
+ }
+ else if(unlikely(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0)) { // old API "graph"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API graph request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_graph_request);
+ }
+ else if(unlikely(hash == hash_list && strcmp(tok, "list") == 0)) { // old API "list"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API list request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_list_request);
+ }
+ else if(unlikely(hash == hash_all_json && strcmp(tok, "all.json") == 0)) { // old API "all.json"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API all.json request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_all_json);
+ }
+ else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf
+ debug(D_WEB_CLIENT_ACCESS, "%llu: generating netdata.conf ...", w->id);
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+ config_generate(w->response.data, 0);
+ return 200;
+ }
+#ifdef NETDATA_INTERNAL_CHECKS
+ else if(unlikely(hash == hash_exit && strcmp(tok, "exit") == 0)) {
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+
+ if(!netdata_exit)
+ buffer_strcat(w->response.data, "ok, will do...");
+ else
+ buffer_strcat(w->response.data, "I am doing it already");
+
+ error("web request to exit received.");
+ netdata_cleanup_and_exit(0);
+ return 200;
+ }
+ else if(unlikely(hash == hash_debug && strcmp(tok, "debug") == 0)) {
+ buffer_flush(w->response.data);
+
+ // get the name of the data to show
+ tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+
+ // do we have such a data set?
+ RRDSET *st = rrdset_find_byname(host, tok);
+ if(!st) st = rrdset_find(host, tok);
+ if(!st) {
+ w->response.data->contenttype = CT_TEXT_HTML;
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, tok);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
+ return 404;
+ }
+
+ debug_flags |= D_RRD_STATS;
+
+ if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))
+ rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
+ else
+ rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
+
+ w->response.data->contenttype = CT_TEXT_HTML;
+ buffer_sprintf(w->response.data, "Chart has now debug %s: ", rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
+ buffer_strcat_htmlescape(w->response.data, tok);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
+ return 200;
+ }
+
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "debug which chart?\r\n");
+ return 400;
+ }
+ else if(unlikely(hash == hash_mirror && strcmp(tok, "mirror") == 0)) {
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
+
+ // replace the zero bytes with spaces
+ buffer_char_replace(w->response.data, '\0', ' ');
+
+ // just leave the buffer as is
+ // it will be copied back to the client
+
+ return 200;
+ }
+#endif /* NETDATA_INTERNAL_CHECKS */
+ }
+
+ char filename[FILENAME_MAX+1];
+ url = filename;
+ strncpyz(filename, w->last_url, FILENAME_MAX);
+ tok = mystrsep(&url, "?");
+ buffer_flush(w->response.data);
+ return mysendfile(w, (tok && *tok)?tok:"/");
+}
+
+void web_client_process_request(struct web_client *w) {
+
+ // start timing us
+ now_realtime_timeval(&w->tv_in);
+
+ switch(http_request_validate(w)) {
+ case HTTP_VALIDATION_OK:
+ switch(w->mode) {
+ case WEB_CLIENT_MODE_STREAM:
+ w->response.code = rrdpush_receiver_thread_spawn(localhost, w, w->decoded_url);
+ return;
+
+ case WEB_CLIENT_MODE_OPTIONS:
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "OK");
+ w->response.code = 200;
+ break;
+
+ case WEB_CLIENT_MODE_FILECOPY:
+ case WEB_CLIENT_MODE_NORMAL:
+ w->response.code = web_client_process_url(localhost, w, w->decoded_url);
+ break;
+ }
+ break;
+
+ case HTTP_VALIDATION_INCOMPLETE:
+ if(w->response.data->len > TOO_BIG_REQUEST) {
+ strcpy(w->last_url, "too big request");
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
+
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Received request is too big (%zu bytes).\r\n", w->response.data->len);
+ w->response.code = 400;
+ }
+ else {
+ // wait for more data
+ return;
+ }
+ break;
+
+ case HTTP_VALIDATION_NOT_SUPPORTED:
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
+
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "I don't understand you...\r\n");
+ w->response.code = 400;
+ break;
+ }
+
+ // keep track of the time we done processing
+ now_realtime_timeval(&w->tv_ready);
+
+ w->response.sent = 0;
+
+ // set a proper last modified date
+ if(unlikely(!w->response.data->date))
+ w->response.data->date = w->tv_ready.tv_sec;
+
+ 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;
- // pretty logging
switch(w->mode) {
+ case WEB_CLIENT_MODE_STREAM:
+ debug(D_WEB_CLIENT, "%llu: STREAM done.", w->id);
+ break;
+
case WEB_CLIENT_MODE_OPTIONS:
debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
break;
@@ -2344,7 +1297,7 @@ void web_client_process(struct web_client *w) {
break;
default:
- fatal("%llu: Unknown client mode %d.", w->id, w->mode);
+ fatal("%llu: Unknown client mode %u.", w->id, w->mode);
break;
}
}
@@ -2666,11 +1619,14 @@ void *web_client_main(void *ptr)
struct web_client *w = ptr;
struct pollfd fds[2], *ifd, *ofd;
- int retval, fdmax = 0, timeout;
+ int retval, timeout;
+ nfds_t fdmax = 0;
log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid());
for(;;) {
+ if(unlikely(netdata_exit)) break;
+
if(unlikely(w->dead)) {
debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
break;
@@ -2722,6 +1678,8 @@ void *web_client_main(void *ptr)
timeout = web_client_timeout * 1000;
retval = poll(fds, fdmax, timeout);
+ if(unlikely(netdata_exit)) break;
+
if(unlikely(retval == -1)) {
if(errno == EAGAIN || errno == EINTR) {
debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id);
@@ -2736,6 +1694,8 @@ void *web_client_main(void *ptr)
break;
}
+ if(unlikely(netdata_exit)) break;
+
int used = 0;
if(w->wait_send && ofd->revents & POLLOUT) {
used++;
@@ -2745,6 +1705,8 @@ void *web_client_main(void *ptr)
}
}
+ if(unlikely(netdata_exit)) break;
+
if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
used++;
if(web_client_receive(w) < 0) {
@@ -2754,7 +1716,12 @@ void *web_client_main(void *ptr)
if(w->mode == WEB_CLIENT_MODE_NORMAL) {
debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id);
- web_client_process(w);
+ web_client_process_request(w);
+
+ // if the sockets are closed, may have transferred this client
+ // to plugins.d
+ if(unlikely(w->mode == WEB_CLIENT_MODE_STREAM))
+ break;
}
}
diff --git a/src/web_client.h b/src/web_client.h
index 2555a0c24..70c5b1ff0 100644
--- a/src/web_client.h
+++ b/src/web_client.h
@@ -5,12 +5,20 @@
extern int web_client_timeout;
#ifdef NETDATA_WITH_ZLIB
-extern int web_enable_gzip, web_gzip_level, web_gzip_strategy, web_donotrack_comply;
+extern int web_enable_gzip,
+ web_gzip_level,
+ web_gzip_strategy;
#endif /* NETDATA_WITH_ZLIB */
-#define WEB_CLIENT_MODE_NORMAL 0
-#define WEB_CLIENT_MODE_FILECOPY 1
-#define WEB_CLIENT_MODE_OPTIONS 2
+extern int respect_web_browser_do_not_track_policy;
+extern char *web_x_frame_options;
+
+typedef enum web_client_mode {
+ WEB_CLIENT_MODE_NORMAL = 0,
+ WEB_CLIENT_MODE_FILECOPY = 1,
+ WEB_CLIENT_MODE_OPTIONS = 2,
+ WEB_CLIENT_MODE_STREAM = 3
+} WEB_CLIENT_MODE;
#define URL_MAX 8192
#define ZLIB_CHUNK 16384
@@ -50,14 +58,14 @@ struct web_client {
uint8_t keepalive:1; // if set to 1, the web client will be re-used
- uint8_t mode:3; // the operational mode of the client
-
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_MODE mode; // the operational mode of the client
+
int tcp_cork; // 1 = we have a cork on the socket
int ifd;
@@ -98,7 +106,7 @@ extern struct web_client *web_client_create(int listener);
extern struct web_client *web_client_free(struct web_client *w);
extern ssize_t web_client_send(struct web_client *w);
extern ssize_t web_client_receive(struct web_client *w);
-extern void web_client_process(struct web_client *w);
+extern void web_client_process_request(struct web_client *w);
extern void web_client_reset(struct web_client *w);
extern void *web_client_main(void *ptr);
@@ -107,4 +115,7 @@ extern int web_client_api_request_v1_data_group(char *name, int def);
extern const char *group_method2string(int group);
extern void buffer_data_options2string(BUFFER *wb, uint32_t options);
+
+extern int mysendfile(struct web_client *w, char *filename);
+
#endif
diff --git a/src/web_server.c b/src/web_server.c
index 8e942a59d..593a82a57 100644
--- a/src/web_server.c
+++ b/src/web_server.c
@@ -5,7 +5,8 @@ size_t listen_fds_count = 0;
int listen_fds[MAX_LISTEN_FDS] = { [0 ... 99] = -1 };
char *listen_fds_names[MAX_LISTEN_FDS] = { [0 ... 99] = NULL };
int listen_port = LISTEN_PORT;
-int web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
+
+WEB_SERVER_MODE web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
static int shown_server_socket_error = 0;
@@ -83,6 +84,29 @@ int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
}
#endif
+WEB_SERVER_MODE web_server_mode_id(const char *mode) {
+ if(!strcmp(mode, "none"))
+ return WEB_SERVER_MODE_NONE;
+ else if(!strcmp(mode, "single") || !strcmp(mode, "single-threaded"))
+ return WEB_SERVER_MODE_SINGLE_THREADED;
+ else // if(!strcmp(mode, "multi") || !strcmp(mode, "multi-threaded"))
+ return WEB_SERVER_MODE_MULTI_THREADED;
+}
+
+const char *web_server_mode_name(WEB_SERVER_MODE id) {
+ switch(id) {
+ case WEB_SERVER_MODE_NONE:
+ return "none";
+
+ case WEB_SERVER_MODE_SINGLE_THREADED:
+ return "single-threaded";
+
+ default:
+ case WEB_SERVER_MODE_MULTI_THREADED:
+ return "multi-threaded";
+ }
+}
+
int create_listen_socket4(const char *ip, int port, int listen_backlog) {
int sock;
int sockopt = 1;
@@ -316,22 +340,16 @@ static inline int bind_to_one(const char *definition, int default_port, int list
int create_listen_sockets(void) {
shown_server_socket_error = 0;
- listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
-
- if(config_exists("global", "bind socket to IP") && !config_exists("global", "bind to"))
- config_rename("global", "bind socket to IP", "bind to");
-
- if(config_exists("global", "port") && !config_exists("global", "default port"))
- config_rename("global", "port", "default port");
+ listen_backlog = (int) config_get_number(CONFIG_SECTION_WEB, "listen backlog", LISTEN_BACKLOG);
- listen_port = (int) config_get_number("global", "default port", LISTEN_PORT);
+ listen_port = (int) config_get_number(CONFIG_SECTION_WEB, "default port", LISTEN_PORT);
if(listen_port < 1 || listen_port > 65535) {
error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
- listen_port = (int) config_set_number("global", "default port", LISTEN_PORT);
+ listen_port = (int) config_set_number(CONFIG_SECTION_WEB, "default port", LISTEN_PORT);
}
debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
- char *s = config_get("global", "bind to", "*");
+ char *s = config_get(CONFIG_SECTION_WEB, "bind to", "*");
while(*s) {
char *e = s;
@@ -614,7 +632,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
- web_client_process(w);
+ web_client_process_request(w);
}
}
diff --git a/src/web_server.h b/src/web_server.h
index 93adc5b28..41dcfcf09 100644
--- a/src/web_server.h
+++ b/src/web_server.h
@@ -13,9 +13,17 @@
#define MAX_LISTEN_FDS 100
#endif
-#define WEB_SERVER_MODE_MULTI_THREADED 0
-#define WEB_SERVER_MODE_SINGLE_THREADED 1
-extern int web_server_mode;
+typedef enum web_server_mode {
+ WEB_SERVER_MODE_SINGLE_THREADED,
+ WEB_SERVER_MODE_MULTI_THREADED,
+ WEB_SERVER_MODE_NONE
+} WEB_SERVER_MODE;
+
+extern WEB_SERVER_MODE web_server_mode;
+
+extern WEB_SERVER_MODE web_server_mode_id(const char *mode);
+extern const char *web_server_mode_name(WEB_SERVER_MODE id);
+
extern void *socket_listen_main_multi_threaded(void *ptr);
extern void *socket_listen_main_single_threaded(void *ptr);