From 1e6c93250172946eeb38e94a92a1fd12c9d3011e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 7 Nov 2018 13:22:44 +0100 Subject: Merging upstream version 1.11.0+dfsg. Signed-off-by: Daniel Baumann --- src/.keep | 0 src/Makefile.am | 307 --- src/Makefile.in | 1238 ---------- src/adaptive_resortable_list.c | 269 -- src/adaptive_resortable_list.h | 171 -- src/appconfig.c | 606 ----- src/appconfig.h | 74 - src/apps_plugin.c | 3639 ---------------------------- src/avl.c | 403 --- src/avl.h | 86 - src/backend_prometheus.c | 479 ---- src/backend_prometheus.h | 11 - src/backends.c | 969 -------- src/backends.h | 30 - src/cgroup-network.c | 651 ----- src/clocks.c | 137 -- src/clocks.h | 124 - src/common.c | 1361 ----------- src/common.h | 360 --- src/daemon.c | 396 --- src/daemon.h | 12 - src/dictionary.c | 292 --- src/dictionary.h | 44 - src/eval.c | 1188 --------- src/eval.h | 72 - src/freebsd_devstat.c | 778 ------ src/freebsd_getifaddrs.c | 506 ---- src/freebsd_getmntinfo.c | 299 --- src/freebsd_ipfw.c | 370 --- src/freebsd_kstat_zfs.c | 298 --- src/freebsd_sysctl.c | 3171 ------------------------ src/freeipmi_plugin.c | 1680 ------------- src/global_statistics.c | 414 ---- src/global_statistics.h | 38 - src/health.c | 737 ------ src/health.h | 438 ---- src/health_config.c | 900 ------- src/health_json.c | 260 -- src/health_log.c | 463 ---- src/inlined.h | 291 --- src/ipc.c | 261 -- src/ipc.h | 7 - src/locks.c | 319 --- src/locks.h | 71 - src/log.c | 427 ---- src/log.h | 87 - src/macos_fw.c | 684 ------ src/macos_mach_smi.c | 238 -- src/macos_sysctl.c | 1504 ------------ src/main.c | 1071 -------- src/main.h | 41 - src/plugin_checks.c | 127 - src/plugin_checks.h | 8 - src/plugin_freebsd.c | 173 -- src/plugin_freebsd.h | 130 - src/plugin_idlejitter.c | 90 - src/plugin_idlejitter.h | 6 - src/plugin_macos.c | 67 - src/plugin_macos.h | 14 - src/plugin_nfacct.c | 819 ------- src/plugin_nfacct.h | 7 - src/plugin_proc.c | 201 -- src/plugin_proc.h | 42 - src/plugin_proc_diskspace.c | 460 ---- src/plugin_proc_diskspace.h | 6 - src/plugin_tc.c | 1164 --------- src/plugin_tc.h | 7 - src/plugins_d.c | 694 ------ src/plugins_d.h | 57 - src/popen.c | 204 -- src/popen.h | 11 - src/proc_diskstats.c | 1438 ----------- src/proc_interrupts.c | 253 -- src/proc_loadavg.c | 119 - src/proc_meminfo.c | 514 ---- src/proc_net_dev.c | 894 ------- src/proc_net_ip_vs_stats.c | 129 - src/proc_net_netstat.c | 761 ------ src/proc_net_rpc_nfs.c | 449 ---- src/proc_net_rpc_nfsd.c | 1002 -------- src/proc_net_snmp.c | 1020 -------- src/proc_net_snmp6.c | 1265 ---------- src/proc_net_sockstat.c | 514 ---- src/proc_net_sockstat6.c | 269 -- src/proc_net_softnet_stat.c | 147 -- src/proc_net_stat_conntrack.c | 348 --- src/proc_net_stat_synproxy.c | 181 -- src/proc_self_mountinfo.c | 401 --- src/proc_self_mountinfo.h | 55 - src/proc_softirqs.c | 249 -- src/proc_spl_kstat_zfs.c | 153 -- src/proc_stat.c | 557 ----- src/proc_sys_kernel_random_entropy_avail.c | 47 - src/proc_uptime.c | 103 - src/proc_vmstat.c | 255 -- src/procfile.c | 468 ---- src/procfile.h | 124 - src/registry.c | 414 ---- src/registry.h | 77 - src/registry_db.c | 343 --- src/registry_init.c | 143 -- src/registry_internals.c | 322 --- src/registry_internals.h | 86 - src/registry_log.c | 133 - src/registry_machine.c | 101 - src/registry_machine.h | 41 - src/registry_person.c | 264 -- src/registry_person.h | 60 - src/registry_url.c | 85 - src/registry_url.h | 33 - src/rrd.c | 148 -- src/rrd.h | 747 ------ src/rrd2json.c | 2059 ---------------- src/rrd2json.h | 82 - src/rrd2json_api_old.c | 487 ---- src/rrd2json_api_old.h | 14 - src/rrdcalc.c | 424 ---- src/rrdcalctemplate.c | 69 - src/rrddim.c | 387 --- src/rrddimvar.c | 212 -- src/rrdfamily.c | 59 - src/rrdhost.c | 735 ------ src/rrdpush.c | 1160 --------- src/rrdpush.h | 19 - src/rrdset.c | 1544 ------------ src/rrdsetvar.c | 183 -- src/rrdvar.c | 275 --- src/signals.c | 168 -- src/signals.h | 10 - src/simple_pattern.c | 260 -- src/simple_pattern.h | 28 - src/socket.c | 1518 ------------ src/socket.h | 162 -- src/statistical.c | 459 ---- src/statistical.h | 19 - src/statsd.c | 2499 ------------------- src/statsd.h | 9 - src/storage_number.c | 231 -- src/storage_number.h | 88 - src/sys_devices_system_edac_mc.c | 204 -- src/sys_devices_system_node.c | 161 -- src/sys_fs_btrfs.c | 714 ------ src/sys_fs_cgroup.c | 2765 --------------------- src/sys_kernel_mm_ksm.c | 197 -- src/threads.c | 181 -- src/threads.h | 33 - src/unit_test.c | 1368 ----------- src/unit_test.h | 10 - src/url.c | 77 - src/url.h | 24 - src/web_api_old.c | 237 -- src/web_api_old.h | 13 - src/web_api_v1.c | 1017 -------- src/web_api_v1.h | 23 - src/web_buffer.c | 400 --- src/web_buffer.h | 81 - src/web_buffer_svg.c | 832 ------- src/web_buffer_svg.h | 7 - src/web_client.c | 1706 ------------- src/web_client.h | 189 -- src/web_server.c | 1292 ---------- src/web_server.h | 46 - src/zfs_common.c | 713 ------ src/zfs_common.h | 111 - 164 files changed, 72832 deletions(-) delete mode 100644 src/.keep delete mode 100644 src/Makefile.am delete mode 100644 src/Makefile.in delete mode 100644 src/adaptive_resortable_list.c delete mode 100644 src/adaptive_resortable_list.h delete mode 100644 src/appconfig.c delete mode 100644 src/appconfig.h delete mode 100644 src/apps_plugin.c delete mode 100644 src/avl.c delete mode 100644 src/avl.h delete mode 100644 src/backend_prometheus.c delete mode 100644 src/backend_prometheus.h delete mode 100644 src/backends.c delete mode 100644 src/backends.h delete mode 100644 src/cgroup-network.c delete mode 100644 src/clocks.c delete mode 100644 src/clocks.h delete mode 100644 src/common.c delete mode 100644 src/common.h delete mode 100644 src/daemon.c delete mode 100644 src/daemon.h delete mode 100644 src/dictionary.c delete mode 100644 src/dictionary.h delete mode 100644 src/eval.c delete mode 100644 src/eval.h delete mode 100644 src/freebsd_devstat.c delete mode 100644 src/freebsd_getifaddrs.c delete mode 100644 src/freebsd_getmntinfo.c delete mode 100644 src/freebsd_ipfw.c delete mode 100644 src/freebsd_kstat_zfs.c delete mode 100644 src/freebsd_sysctl.c delete mode 100644 src/freeipmi_plugin.c delete mode 100644 src/global_statistics.c delete mode 100644 src/global_statistics.h delete mode 100644 src/health.c delete mode 100644 src/health.h delete mode 100644 src/health_config.c delete mode 100644 src/health_json.c delete mode 100644 src/health_log.c delete mode 100644 src/inlined.h delete mode 100644 src/ipc.c delete mode 100644 src/ipc.h delete mode 100644 src/locks.c delete mode 100644 src/locks.h delete mode 100644 src/log.c delete mode 100644 src/log.h delete mode 100644 src/macos_fw.c delete mode 100644 src/macos_mach_smi.c delete mode 100644 src/macos_sysctl.c delete mode 100644 src/main.c delete mode 100644 src/main.h delete mode 100644 src/plugin_checks.c delete mode 100644 src/plugin_checks.h delete mode 100644 src/plugin_freebsd.c delete mode 100644 src/plugin_freebsd.h delete mode 100644 src/plugin_idlejitter.c delete mode 100644 src/plugin_idlejitter.h delete mode 100644 src/plugin_macos.c delete mode 100644 src/plugin_macos.h delete mode 100644 src/plugin_nfacct.c delete mode 100644 src/plugin_nfacct.h delete mode 100644 src/plugin_proc.c delete mode 100644 src/plugin_proc.h delete mode 100644 src/plugin_proc_diskspace.c delete mode 100644 src/plugin_proc_diskspace.h delete mode 100644 src/plugin_tc.c delete mode 100644 src/plugin_tc.h delete mode 100644 src/plugins_d.c delete mode 100644 src/plugins_d.h delete mode 100644 src/popen.c delete mode 100644 src/popen.h delete mode 100644 src/proc_diskstats.c delete mode 100644 src/proc_interrupts.c delete mode 100644 src/proc_loadavg.c delete mode 100644 src/proc_meminfo.c delete mode 100644 src/proc_net_dev.c delete mode 100644 src/proc_net_ip_vs_stats.c delete mode 100644 src/proc_net_netstat.c delete mode 100644 src/proc_net_rpc_nfs.c delete mode 100644 src/proc_net_rpc_nfsd.c delete mode 100644 src/proc_net_snmp.c delete mode 100644 src/proc_net_snmp6.c delete mode 100644 src/proc_net_sockstat.c delete mode 100644 src/proc_net_sockstat6.c delete mode 100644 src/proc_net_softnet_stat.c delete mode 100644 src/proc_net_stat_conntrack.c delete mode 100644 src/proc_net_stat_synproxy.c delete mode 100644 src/proc_self_mountinfo.c delete mode 100644 src/proc_self_mountinfo.h delete mode 100644 src/proc_softirqs.c delete mode 100644 src/proc_spl_kstat_zfs.c delete mode 100644 src/proc_stat.c delete mode 100644 src/proc_sys_kernel_random_entropy_avail.c delete mode 100644 src/proc_uptime.c delete mode 100644 src/proc_vmstat.c delete mode 100644 src/procfile.c delete mode 100644 src/procfile.h delete mode 100644 src/registry.c delete mode 100644 src/registry.h delete mode 100644 src/registry_db.c delete mode 100644 src/registry_init.c delete mode 100644 src/registry_internals.c delete mode 100644 src/registry_internals.h delete mode 100644 src/registry_log.c delete mode 100644 src/registry_machine.c delete mode 100644 src/registry_machine.h delete mode 100644 src/registry_person.c delete mode 100644 src/registry_person.h delete mode 100644 src/registry_url.c delete mode 100644 src/registry_url.h delete mode 100644 src/rrd.c delete mode 100644 src/rrd.h delete mode 100644 src/rrd2json.c delete mode 100644 src/rrd2json.h delete mode 100644 src/rrd2json_api_old.c delete mode 100644 src/rrd2json_api_old.h delete mode 100644 src/rrdcalc.c delete mode 100644 src/rrdcalctemplate.c delete mode 100644 src/rrddim.c delete mode 100644 src/rrddimvar.c delete mode 100644 src/rrdfamily.c delete mode 100644 src/rrdhost.c delete mode 100644 src/rrdpush.c delete mode 100644 src/rrdpush.h delete mode 100644 src/rrdset.c delete mode 100644 src/rrdsetvar.c delete mode 100644 src/rrdvar.c delete mode 100644 src/signals.c delete mode 100644 src/signals.h delete mode 100644 src/simple_pattern.c delete mode 100644 src/simple_pattern.h delete mode 100644 src/socket.c delete mode 100644 src/socket.h delete mode 100644 src/statistical.c delete mode 100644 src/statistical.h delete mode 100644 src/statsd.c delete mode 100644 src/statsd.h delete mode 100644 src/storage_number.c delete mode 100644 src/storage_number.h delete mode 100644 src/sys_devices_system_edac_mc.c delete mode 100644 src/sys_devices_system_node.c delete mode 100644 src/sys_fs_btrfs.c delete mode 100644 src/sys_fs_cgroup.c delete mode 100644 src/sys_kernel_mm_ksm.c delete mode 100644 src/threads.c delete mode 100644 src/threads.h delete mode 100644 src/unit_test.c delete mode 100644 src/unit_test.h delete mode 100644 src/url.c delete mode 100644 src/url.h delete mode 100644 src/web_api_old.c delete mode 100644 src/web_api_old.h delete mode 100644 src/web_api_v1.c delete mode 100644 src/web_api_v1.h delete mode 100644 src/web_buffer.c delete mode 100644 src/web_buffer.h delete mode 100644 src/web_buffer_svg.c delete mode 100644 src/web_buffer_svg.h delete mode 100644 src/web_client.c delete mode 100644 src/web_client.h delete mode 100644 src/web_server.c delete mode 100644 src/web_server.h delete mode 100644 src/zfs_common.c delete mode 100644 src/zfs_common.h (limited to 'src') diff --git a/src/.keep b/src/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index df174cbd1..000000000 --- a/src/Makefile.am +++ /dev/null @@ -1,307 +0,0 @@ -# -# Copyright (C) 2015 Alon Bar-Lev -# -MAINTAINERCLEANFILES= $(srcdir)/Makefile.in - -AM_CPPFLAGS = \ - -DVARLIB_DIR="\"$(varlibdir)\"" \ - -DCACHE_DIR="\"$(cachedir)\"" \ - -DCONFIG_DIR="\"$(configdir)\"" \ - -DLOG_DIR="\"$(logdir)\"" \ - -DPLUGINS_DIR="\"$(pluginsdir)\"" \ - -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 -dist_cache_DATA = .keep -dist_varlib_DATA = .keep -dist_registry_DATA = .keep -dist_log_DATA = .keep -plugins_PROGRAMS = - -if ENABLE_PLUGIN_APPS -plugins_PROGRAMS += apps.plugin -endif - -if ENABLE_PLUGIN_FREEIPMI -plugins_PROGRAMS += freeipmi.plugin -endif - -if ENABLE_PLUGIN_CGROUP_NETWORK -plugins_PROGRAMS += cgroup-network -endif - -netdata_SOURCES = \ - adaptive_resortable_list.c \ - adaptive_resortable_list.h \ - appconfig.c \ - appconfig.h \ - avl.c \ - avl.h \ - backend_prometheus.c \ - backend_prometheus.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.c \ - locks.h \ - log.c \ - log.h \ - main.c \ - main.h \ - plugin_checks.c \ - plugin_checks.h \ - plugin_idlejitter.c \ - plugin_idlejitter.h \ - plugins_d.c \ - plugins_d.h \ - popen.c \ - popen.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 \ - signals.c \ - signals.h \ - simple_pattern.c \ - simple_pattern.h \ - socket.c \ - socket.h \ - statistical.c \ - statistical.h \ - statsd.c \ - statsd.h \ - storage_number.c \ - storage_number.h \ - threads.c \ - threads.h \ - 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) - -if FREEBSD -netdata_SOURCES += \ - plugin_freebsd.c \ - plugin_freebsd.h \ - freebsd_sysctl.c \ - freebsd_getmntinfo.c \ - freebsd_getifaddrs.c \ - freebsd_devstat.c \ - zfs_common.c \ - zfs_common.h \ - freebsd_kstat_zfs.c \ - freebsd_ipfw.c \ - $(NULL) -else -if MACOS -netdata_SOURCES += \ - plugin_macos.c \ - plugin_macos.h \ - macos_sysctl.c \ - macos_mach_smi.c \ - macos_fw.c \ - $(NULL) -else -netdata_SOURCES += \ - ipc.c \ - ipc.h \ - plugin_nfacct.c \ - plugin_nfacct.h \ - plugin_proc.c \ - plugin_proc.h \ - plugin_proc_diskspace.c \ - plugin_proc_diskspace.h \ - plugin_tc.c \ - plugin_tc.h \ - proc_diskstats.c \ - proc_interrupts.c \ - proc_softirqs.c \ - proc_loadavg.c \ - proc_meminfo.c \ - proc_net_dev.c \ - proc_net_ip_vs_stats.c \ - proc_net_netstat.c \ - proc_net_rpc_nfs.c \ - proc_net_rpc_nfsd.c \ - proc_net_snmp.c \ - proc_net_snmp6.c \ - proc_net_sockstat.c \ - proc_net_sockstat6.c \ - proc_net_softnet_stat.c \ - proc_net_stat_conntrack.c \ - proc_net_stat_synproxy.c \ - proc_self_mountinfo.c \ - proc_self_mountinfo.h \ - zfs_common.c \ - zfs_common.h \ - proc_spl_kstat_zfs.c \ - proc_stat.c \ - proc_sys_kernel_random_entropy_avail.c \ - proc_vmstat.c \ - proc_uptime.c \ - sys_kernel_mm_ksm.c \ - sys_devices_system_edac_mc.c \ - sys_devices_system_node.c \ - sys_fs_cgroup.c \ - sys_fs_btrfs.c \ - $(NULL) -endif -endif - -netdata_LDADD = \ - $(OPTIONAL_MATH_LIBS) \ - $(OPTIONAL_NFACCT_LIBS) \ - $(OPTIONAL_ZLIB_LIBS) \ - $(OPTIONAL_UUID_LIBS) \ - $(NULL) - -apps_plugin_SOURCES = \ - apps_plugin.c \ - avl.c \ - avl.h \ - clocks.c \ - clocks.h \ - common.c \ - common.h \ - inlined.h \ - locks.c \ - locks.h \ - log.c log.h \ - procfile.c \ - procfile.h \ - threads.c \ - threads.h \ - web_buffer.c \ - web_buffer.h \ - $(NULL) - -if FREEBSD -apps_plugin_SOURCES += \ - plugin_freebsd.h \ - $(NULL) -else -apps_plugin_SOURCES += \ - adaptive_resortable_list.c \ - adaptive_resortable_list.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 \ - locks.c \ - locks.h \ - log.c log.h \ - procfile.c \ - procfile.h \ - threads.c \ - threads.h \ - $(NULL) - -freeipmi_plugin_LDADD = \ - $(OPTIONAL_IPMIMONITORING_LIBS) \ - $(NULL) - -cgroup_network_SOURCES = \ - cgroup-network.c \ - clocks.c \ - clocks.h \ - common.c \ - common.h \ - inlined.h \ - locks.c \ - locks.h \ - log.c \ - log.h \ - procfile.c \ - procfile.h \ - popen.c \ - popen.h \ - signals.c \ - signals.h \ - threads.c \ - threads.h \ - $(NULL) - -cgroup_network_LDADD = \ - $(OPTIONAL_MATH_LIBS) \ - $(OPTIONAL_LIBCAP_LIBS) \ - $(NULL) diff --git a/src/Makefile.in b/src/Makefile.in deleted file mode 100644 index 75f85632e..000000000 --- a/src/Makefile.in +++ /dev/null @@ -1,1238 +0,0 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 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. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -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@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -sbin_PROGRAMS = netdata$(EXEEXT) -plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) -@ENABLE_PLUGIN_APPS_TRUE@am__append_1 = apps.plugin -@ENABLE_PLUGIN_FREEIPMI_TRUE@am__append_2 = freeipmi.plugin -@ENABLE_PLUGIN_CGROUP_NETWORK_TRUE@am__append_3 = cgroup-network -@FREEBSD_TRUE@am__append_4 = \ -@FREEBSD_TRUE@ plugin_freebsd.c \ -@FREEBSD_TRUE@ plugin_freebsd.h \ -@FREEBSD_TRUE@ freebsd_sysctl.c \ -@FREEBSD_TRUE@ freebsd_getmntinfo.c \ -@FREEBSD_TRUE@ freebsd_getifaddrs.c \ -@FREEBSD_TRUE@ freebsd_devstat.c \ -@FREEBSD_TRUE@ zfs_common.c \ -@FREEBSD_TRUE@ zfs_common.h \ -@FREEBSD_TRUE@ freebsd_kstat_zfs.c \ -@FREEBSD_TRUE@ freebsd_ipfw.c \ -@FREEBSD_TRUE@ $(NULL) - -@FREEBSD_FALSE@@MACOS_TRUE@am__append_5 = \ -@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.c \ -@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.h \ -@FREEBSD_FALSE@@MACOS_TRUE@ macos_sysctl.c \ -@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_6 = \ -@FREEBSD_FALSE@@MACOS_FALSE@ ipc.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ ipc.h \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_nfacct.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_nfacct.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@ plugin_tc.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_tc.h \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_diskstats.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_interrupts.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_softirqs.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_loadavg.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_meminfo.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_dev.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_ip_vs_stats.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_netstat.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_rpc_nfs.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_rpc_nfsd.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp6.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat6.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_softnet_stat.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_conntrack.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_synproxy.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_self_mountinfo.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_self_mountinfo.h \ -@FREEBSD_FALSE@@MACOS_FALSE@ zfs_common.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ zfs_common.h \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_spl_kstat_zfs.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_stat.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_sys_kernel_random_entropy_avail.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_vmstat.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_uptime.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_devices_system_edac_mc.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_devices_system_node.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_fs_cgroup.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_fs_btrfs.c \ -@FREEBSD_FALSE@@MACOS_FALSE@ $(NULL) - -@FREEBSD_TRUE@am__append_7 = \ -@FREEBSD_TRUE@ plugin_freebsd.h \ -@FREEBSD_TRUE@ $(NULL) - -@FREEBSD_FALSE@am__append_8 = \ -@FREEBSD_FALSE@ adaptive_resortable_list.c \ -@FREEBSD_FALSE@ adaptive_resortable_list.h \ -@FREEBSD_FALSE@ $(NULL) - -subdir = src -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp $(dist_cache_DATA) $(dist_log_DATA) \ - $(dist_registry_DATA) $(dist_varlib_DATA) -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_lto.m4 \ - $(top_srcdir)/m4/ax_c_mallinfo.m4 \ - $(top_srcdir)/m4/ax_c_mallopt.m4 \ - $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \ - $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \ - $(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -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) -@ENABLE_PLUGIN_CGROUP_NETWORK_TRUE@am__EXEEXT_3 = \ -@ENABLE_PLUGIN_CGROUP_NETWORK_TRUE@ cgroup-network$(EXEEXT) -am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" \ - "$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)" \ - "$(DESTDIR)$(registrydir)" "$(DESTDIR)$(varlibdir)" -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 locks.c locks.h log.c \ - log.h procfile.c procfile.h threads.c threads.h web_buffer.c \ - web_buffer.h plugin_freebsd.h adaptive_resortable_list.c \ - adaptive_resortable_list.h -am__objects_1 = -@FREEBSD_FALSE@am__objects_2 = adaptive_resortable_list.$(OBJEXT) -am_apps_plugin_OBJECTS = apps_plugin.$(OBJEXT) avl.$(OBJEXT) \ - clocks.$(OBJEXT) common.$(OBJEXT) locks.$(OBJEXT) \ - log.$(OBJEXT) procfile.$(OBJEXT) threads.$(OBJEXT) \ - web_buffer.$(OBJEXT) $(am__objects_1) $(am__objects_2) -apps_plugin_OBJECTS = $(am_apps_plugin_OBJECTS) -am__DEPENDENCIES_1 = -apps_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -am_cgroup_network_OBJECTS = cgroup-network.$(OBJEXT) clocks.$(OBJEXT) \ - common.$(OBJEXT) locks.$(OBJEXT) log.$(OBJEXT) \ - procfile.$(OBJEXT) popen.$(OBJEXT) signals.$(OBJEXT) \ - threads.$(OBJEXT) -cgroup_network_OBJECTS = $(am_cgroup_network_OBJECTS) -cgroup_network_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -am_freeipmi_plugin_OBJECTS = freeipmi_plugin.$(OBJEXT) \ - clocks.$(OBJEXT) common.$(OBJEXT) locks.$(OBJEXT) \ - log.$(OBJEXT) procfile.$(OBJEXT) threads.$(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 \ - backend_prometheus.c backend_prometheus.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.c \ - locks.h log.c log.h main.c main.h plugin_checks.c \ - plugin_checks.h plugin_idlejitter.c plugin_idlejitter.h \ - plugins_d.c plugins_d.h popen.c popen.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 \ - signals.c signals.h simple_pattern.c simple_pattern.h socket.c \ - socket.h statistical.c statistical.h statsd.c statsd.h \ - storage_number.c storage_number.h threads.c threads.h \ - unit_test.c unit_test.h url.c url.h web_api_old.c \ - web_api_old.h web_api_v1.c web_api_v1.h web_buffer.c \ - web_buffer.h web_buffer_svg.c web_buffer_svg.h web_client.c \ - web_client.h web_server.c web_server.h plugin_freebsd.c \ - plugin_freebsd.h freebsd_sysctl.c freebsd_getmntinfo.c \ - freebsd_getifaddrs.c freebsd_devstat.c zfs_common.c \ - zfs_common.h freebsd_kstat_zfs.c freebsd_ipfw.c plugin_macos.c \ - plugin_macos.h macos_sysctl.c macos_mach_smi.c macos_fw.c \ - ipc.c ipc.h plugin_nfacct.c plugin_nfacct.h plugin_proc.c \ - plugin_proc.h plugin_proc_diskspace.c plugin_proc_diskspace.h \ - plugin_tc.c plugin_tc.h proc_diskstats.c proc_interrupts.c \ - proc_softirqs.c proc_loadavg.c proc_meminfo.c proc_net_dev.c \ - proc_net_ip_vs_stats.c proc_net_netstat.c proc_net_rpc_nfs.c \ - proc_net_rpc_nfsd.c proc_net_snmp.c proc_net_snmp6.c \ - proc_net_sockstat.c proc_net_sockstat6.c \ - proc_net_softnet_stat.c proc_net_stat_conntrack.c \ - proc_net_stat_synproxy.c proc_self_mountinfo.c \ - proc_self_mountinfo.h proc_spl_kstat_zfs.c proc_stat.c \ - proc_sys_kernel_random_entropy_avail.c proc_vmstat.c \ - proc_uptime.c sys_kernel_mm_ksm.c sys_devices_system_edac_mc.c \ - sys_devices_system_node.c sys_fs_cgroup.c sys_fs_btrfs.c -@FREEBSD_TRUE@am__objects_3 = plugin_freebsd.$(OBJEXT) \ -@FREEBSD_TRUE@ freebsd_sysctl.$(OBJEXT) \ -@FREEBSD_TRUE@ freebsd_getmntinfo.$(OBJEXT) \ -@FREEBSD_TRUE@ freebsd_getifaddrs.$(OBJEXT) \ -@FREEBSD_TRUE@ freebsd_devstat.$(OBJEXT) zfs_common.$(OBJEXT) \ -@FREEBSD_TRUE@ freebsd_kstat_zfs.$(OBJEXT) \ -@FREEBSD_TRUE@ freebsd_ipfw.$(OBJEXT) -@FREEBSD_FALSE@@MACOS_TRUE@am__objects_4 = 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_5 = ipc.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_nfacct.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ plugin_tc.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_diskstats.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_interrupts.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_softirqs.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_loadavg.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_meminfo.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_dev.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_ip_vs_stats.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_netstat.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_rpc_nfs.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_rpc_nfsd.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp6.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat6.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_softnet_stat.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_conntrack.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_synproxy.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_self_mountinfo.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ zfs_common.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_spl_kstat_zfs.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_stat.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_sys_kernel_random_entropy_avail.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_vmstat.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ proc_uptime.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_devices_system_edac_mc.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_devices_system_node.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_fs_cgroup.$(OBJEXT) \ -@FREEBSD_FALSE@@MACOS_FALSE@ sys_fs_btrfs.$(OBJEXT) -am_netdata_OBJECTS = adaptive_resortable_list.$(OBJEXT) \ - appconfig.$(OBJEXT) avl.$(OBJEXT) backend_prometheus.$(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) locks.$(OBJEXT) log.$(OBJEXT) \ - main.$(OBJEXT) plugin_checks.$(OBJEXT) \ - plugin_idlejitter.$(OBJEXT) plugins_d.$(OBJEXT) \ - popen.$(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) \ - signals.$(OBJEXT) simple_pattern.$(OBJEXT) socket.$(OBJEXT) \ - statistical.$(OBJEXT) statsd.$(OBJEXT) \ - storage_number.$(OBJEXT) threads.$(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_3) \ - $(am__objects_4) $(am__objects_5) -netdata_OBJECTS = $(am_netdata_OBJECTS) -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) $(cgroup_network_SOURCES) \ - $(freeipmi_plugin_SOURCES) $(netdata_SOURCES) -DIST_SOURCES = $(am__apps_plugin_SOURCES_DIST) \ - $(cgroup_network_SOURCES) $(freeipmi_plugin_SOURCES) \ - $(am__netdata_SOURCES_DIST) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -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 -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -GREP = @GREP@ -INSTALL = @INSTALL@ -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@ -LIBS = @LIBS@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MATH_CFLAGS = @MATH_CFLAGS@ -MATH_LIBS = @MATH_LIBS@ -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@ -OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@ -OPTIONAL_UUID_CLFAGS = @OPTIONAL_UUID_CLFAGS@ -OPTIONAL_UUID_LIBS = @OPTIONAL_UUID_LIBS@ -OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@ -OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@ -PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREAD_CC = @PTHREAD_CC@ -PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ -PTHREAD_LIBS = @PTHREAD_LIBS@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SSE_CANDIDATE = @SSE_CANDIDATE@ -STRIP = @STRIP@ -UUID_CFLAGS = @UUID_CFLAGS@ -UUID_LIBS = @UUID_LIBS@ -VERSION = @VERSION@ -ZLIB_CFLAGS = @ZLIB_CFLAGS@ -ZLIB_LIBS = @ZLIB_LIBS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -ax_pthread_config = @ax_pthread_config@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -cachedir = @cachedir@ -chartsdir = @chartsdir@ -configdir = @configdir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -has_jemalloc = @has_jemalloc@ -has_tcmalloc = @has_tcmalloc@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -logdir = @logdir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -nodedir = @nodedir@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pluginsdir = @pluginsdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pythondir = @pythondir@ -registrydir = @registrydir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -varlibdir = @varlibdir@ -webdir = @webdir@ - -# -# Copyright (C) 2015 Alon Bar-Lev -# -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -AM_CPPFLAGS = \ - -DVARLIB_DIR="\"$(varlibdir)\"" \ - -DCACHE_DIR="\"$(cachedir)\"" \ - -DCONFIG_DIR="\"$(configdir)\"" \ - -DLOG_DIR="\"$(logdir)\"" \ - -DPLUGINS_DIR="\"$(pluginsdir)\"" \ - -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) - -dist_cache_DATA = .keep -dist_varlib_DATA = .keep -dist_registry_DATA = .keep -dist_log_DATA = .keep -netdata_SOURCES = adaptive_resortable_list.c \ - adaptive_resortable_list.h appconfig.c appconfig.h avl.c avl.h \ - backend_prometheus.c backend_prometheus.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.c \ - locks.h log.c log.h main.c main.h plugin_checks.c \ - plugin_checks.h plugin_idlejitter.c plugin_idlejitter.h \ - plugins_d.c plugins_d.h popen.c popen.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 \ - signals.c signals.h simple_pattern.c simple_pattern.h socket.c \ - socket.h statistical.c statistical.h statsd.c statsd.h \ - storage_number.c storage_number.h threads.c threads.h \ - unit_test.c unit_test.h url.c url.h web_api_old.c \ - web_api_old.h web_api_v1.c web_api_v1.h web_buffer.c \ - web_buffer.h web_buffer_svg.c web_buffer_svg.h web_client.c \ - web_client.h web_server.c web_server.h $(NULL) $(am__append_4) \ - $(am__append_5) $(am__append_6) -netdata_LDADD = \ - $(OPTIONAL_MATH_LIBS) \ - $(OPTIONAL_NFACCT_LIBS) \ - $(OPTIONAL_ZLIB_LIBS) \ - $(OPTIONAL_UUID_LIBS) \ - $(NULL) - -apps_plugin_SOURCES = apps_plugin.c avl.c avl.h clocks.c clocks.h \ - common.c common.h inlined.h locks.c locks.h log.c log.h \ - procfile.c procfile.h threads.c threads.h web_buffer.c \ - web_buffer.h $(NULL) $(am__append_7) $(am__append_8) -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 \ - locks.c \ - locks.h \ - log.c log.h \ - procfile.c \ - procfile.h \ - threads.c \ - threads.h \ - $(NULL) - -freeipmi_plugin_LDADD = \ - $(OPTIONAL_IPMIMONITORING_LIBS) \ - $(NULL) - -cgroup_network_SOURCES = \ - cgroup-network.c \ - clocks.c \ - clocks.h \ - common.c \ - common.h \ - inlined.h \ - locks.c \ - locks.h \ - log.c \ - log.h \ - procfile.c \ - procfile.h \ - popen.c \ - popen.h \ - signals.c \ - signals.h \ - threads.c \ - threads.h \ - $(NULL) - -cgroup_network_LDADD = \ - $(OPTIONAL_MATH_LIBS) \ - $(OPTIONAL_LIBCAP_LIBS) \ - $(NULL) - -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - 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*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-pluginsPROGRAMS: $(plugins_PROGRAMS) - @$(NORMAL_INSTALL) - @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; \ - done | \ - 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 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-pluginsPROGRAMS: - @$(NORMAL_UNINSTALL) - @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)/' \ - `; \ - test -n "$$list" || exit 0; \ - echo " ( cd '$(DESTDIR)$(pluginsdir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(pluginsdir)" && rm -f $$files - -clean-pluginsPROGRAMS: - -test -z "$(plugins_PROGRAMS)" || rm -f $(plugins_PROGRAMS) -install-sbinPROGRAMS: $(sbin_PROGRAMS) - @$(NORMAL_INSTALL) - @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; \ - done | \ - 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 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-sbinPROGRAMS: - @$(NORMAL_UNINSTALL) - @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)/' \ - `; \ - 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) - -cgroup-network$(EXEEXT): $(cgroup_network_OBJECTS) $(cgroup_network_DEPENDENCIES) $(EXTRA_cgroup_network_DEPENDENCIES) - @rm -f cgroup-network$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(cgroup_network_OBJECTS) $(cgroup_network_LDADD) $(LIBS) - -freeipmi.plugin$(EXEEXT): $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_DEPENDENCIES) $(EXTRA_freeipmi_plugin_DEPENDENCIES) - @rm -f freeipmi.plugin$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_LDADD) $(LIBS) - -netdata$(EXEEXT): $(netdata_OBJECTS) $(netdata_DEPENDENCIES) $(EXTRA_netdata_DEPENDENCIES) - @rm -f netdata$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(netdata_OBJECTS) $(netdata_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adaptive_resortable_list.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/appconfig.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apps_plugin.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_prometheus.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backends.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgroup-network.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clocks.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@ -@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_devstat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_getifaddrs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_getmntinfo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_ipfw.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_kstat_zfs.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)/locks.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@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macos_mach_smi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macos_sysctl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_checks.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_freebsd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_idlejitter.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_macos.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_nfacct.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_proc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_proc_diskspace.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_tc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugins_d.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/popen.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_diskstats.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_interrupts.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_loadavg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_meminfo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_dev.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_ip_vs_stats.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_netstat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_rpc_nfs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_rpc_nfsd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_snmp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_snmp6.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_sockstat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_sockstat6.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_softnet_stat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_stat_conntrack.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_stat_synproxy.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_self_mountinfo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_softirqs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_spl_kstat_zfs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_stat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_sys_kernel_random_entropy_avail.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_uptime.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_vmstat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/procfile.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_db.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_init.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_internals.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_log.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_machine.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_person.Po@am__quote@ -@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)/signals.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_pattern.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statistical.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statsd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_number.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_devices_system_edac_mc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_devices_system_node.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_fs_btrfs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_fs_cgroup.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_kernel_mm_ksm.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/threads.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@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zfs_common.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@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.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@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` -install-dist_cacheDATA: $(dist_cache_DATA) - @$(NORMAL_INSTALL) - @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"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(cachedir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(cachedir)" || exit $$?; \ - done - -uninstall-dist_cacheDATA: - @$(NORMAL_UNINSTALL) - @list='$(dist_cache_DATA)'; test -n "$(cachedir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(cachedir)'; $(am__uninstall_files_from_dir) -install-dist_logDATA: $(dist_log_DATA) - @$(NORMAL_INSTALL) - @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"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(logdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(logdir)" || exit $$?; \ - done - -uninstall-dist_logDATA: - @$(NORMAL_UNINSTALL) - @list='$(dist_log_DATA)'; test -n "$(logdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(logdir)'; $(am__uninstall_files_from_dir) -install-dist_registryDATA: $(dist_registry_DATA) - @$(NORMAL_INSTALL) - @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"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(registrydir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(registrydir)" || exit $$?; \ - done - -uninstall-dist_registryDATA: - @$(NORMAL_UNINSTALL) - @list='$(dist_registry_DATA)'; test -n "$(registrydir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(registrydir)'; $(am__uninstall_files_from_dir) -install-dist_varlibDATA: $(dist_varlib_DATA) - @$(NORMAL_INSTALL) - @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"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(varlibdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(varlibdir)" || exit $$?; \ - done - -uninstall-dist_varlibDATA: - @$(NORMAL_UNINSTALL) - @list='$(dist_varlib_DATA)'; test -n "$(varlibdir)" || list=; \ - 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) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -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 - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(PROGRAMS) $(DATA) -installdirs: - for dir in "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)" "$(DESTDIR)$(registrydir)" "$(DESTDIR)$(varlibdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) -clean: clean-am - -clean-am: clean-generic clean-pluginsPROGRAMS clean-sbinPROGRAMS \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-dist_cacheDATA install-dist_logDATA \ - install-dist_registryDATA install-dist_varlibDATA \ - install-pluginsPROGRAMS - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-sbinPROGRAMS - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-dist_cacheDATA uninstall-dist_logDATA \ - uninstall-dist_registryDATA uninstall-dist_varlibDATA \ - uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS - -.MAKE: install-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-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 \ - uninstall-am uninstall-dist_cacheDATA uninstall-dist_logDATA \ - uninstall-dist_registryDATA uninstall-dist_varlibDATA \ - uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS - - -# 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. -.NOEXPORT: diff --git a/src/adaptive_resortable_list.c b/src/adaptive_resortable_list.c deleted file mode 100644 index c564efff3..000000000 --- a/src/adaptive_resortable_list.c +++ /dev/null @@ -1,269 +0,0 @@ -#include "adaptive_resortable_list.h" - -// the default processor() of the ARL -// can be overwritten at arl_create() -inline void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; - (void)hash; - - register unsigned long long *d = dst; - *d = str2ull(value); - // fprintf(stderr, "name '%s' with hash %u and value '%s' is %llu\n", name, hash, value, *d); -} - -inline void arl_callback_str2kernel_uint_t(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; - (void)hash; - - register kernel_uint_t *d = dst; - *d = str2kernel_uint_t(value); - // fprintf(stderr, "name '%s' with hash %u and value '%s' is %llu\n", name, hash, value, (unsigned long long)*d); -} - -// create a new ARL -ARL_BASE *arl_create(const char *name, void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks) { - ARL_BASE *base = callocz(1, sizeof(ARL_BASE)); - - base->name = strdupz(name); - - if(!processor) - base->processor = arl_callback_str2ull; - else - base->processor = processor; - - base->rechecks = rechecks; - - return base; -} - -void arl_free(ARL_BASE *arl_base) { - if(unlikely(!arl_base)) - return; - - while(arl_base->head) { - ARL_ENTRY *e = arl_base->head; - arl_base->head = e->next; - - freez(e->name); -#ifdef NETDATA_INTERNAL_CHECKS - memset(e, 0, sizeof(ARL_ENTRY)); -#endif - freez(e); - } - - freez(arl_base->name); - -#ifdef NETDATA_INTERNAL_CHECKS - memset(arl_base, 0, sizeof(ARL_BASE)); -#endif - - freez(arl_base); -} - -void arl_begin(ARL_BASE *base) { - -#ifdef NETDATA_INTERNAL_CHECKS - if(likely(base->iteration > 10)) { - // do these checks after the ARL has been sorted - - if(unlikely(base->relinkings > (base->expected + base->allocated))) - info("ARL '%s' has %zu relinkings with %zu expected and %zu allocated entries. Is the source changing so fast?" - , base->name, base->relinkings, base->expected, base->allocated); - - if(unlikely(base->slow > base->fast)) - 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 - , base->iteration - , base->expected - , base->wanted - , base->allocated - , base->fred - , base->relinkings - , base->found - , base->added - , base->fast - , base->slow - ); - // for(e = base->head; e; e = e->next) fprintf(stderr, "%s ", e->name); - // fprintf(stderr, "\n"); - } - */ - } -#endif - - if(unlikely(base->iteration > 0 && (base->added || (base->iteration % base->rechecks) == 0))) { - int wanted_equals_expected = ((base->iteration % base->rechecks) == 0); - - // fprintf(stderr, "\n\narl_begin() rechecking, added %zu, iteration %zu, rechecks %zu, wanted_equals_expected %d\n\n\n", base->added, base->iteration, base->rechecks, wanted_equals_expected); - - base->added = 0; - base->wanted = (wanted_equals_expected)?base->expected:0; - - ARL_ENTRY *e = base->head; - while(e) { - if(e->flags & ARL_ENTRY_FLAG_FOUND) { - - // remove the found flag - e->flags &= ~ARL_ENTRY_FLAG_FOUND; - - // count it in wanted - if(!wanted_equals_expected && e->flags & ARL_ENTRY_FLAG_EXPECTED) - base->wanted++; - - } - 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 -// together with its destination ( i.e. the output of the processor() ) -ARL_ENTRY *arl_expect_custom(ARL_BASE *base, const char *keyword, void (*processor)(const char *name, uint32_t hash, const char *value, void *dst), void *dst) { - ARL_ENTRY *e = callocz(1, sizeof(ARL_ENTRY)); - e->name = strdupz(keyword); - e->hash = simple_hash(e->name); - e->processor = (processor)?processor:base->processor; - e->dst = dst; - e->flags = ARL_ENTRY_FLAG_EXPECTED; - e->prev = NULL; - e->next = base->head; - - if(base->head) base->head->prev = e; - else base->next_keyword = e; - - base->head = e; - base->expected++; - base->allocated++; - - base->wanted = base->expected; - - return e; -} - -int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *value) { - ARL_ENTRY *e; - - uint32_t hash = simple_hash(s); - - // find if it already exists in the data - for(e = base->head; e ; e = e->next) - if(e->hash == hash && !strcmp(e->name, s)) - break; - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(base->next_keyword && e == base->next_keyword)) - fatal("Internal Error: e == base->last"); -#endif - - if(e) { - // found it in the keywords - - base->relinkings++; - - // run the processor for it - if(unlikely(e->dst)) { - e->processor(e->name, hash, value, e->dst); - base->found++; - } - - // unlink it - we will relink it below - if(e->next) e->next->prev = e->prev; - if(e->prev) e->prev->next = e->next; - - // make sure the head is properly linked - if(base->head == e) - base->head = e->next; - } - else { - // not found - - // create it - e = callocz(1, sizeof(ARL_ENTRY)); - e->name = strdupz(s); - e->hash = hash; - e->flags = ARL_ENTRY_FLAG_DYNAMIC; - - base->allocated++; - base->added++; - } - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(base->iteration % 60 == 0 && e->flags & ARL_ENTRY_FLAG_FOUND)) - info("ARL '%s': entry '%s' is already found. Did you forget to call arl_begin()?", base->name, s); -#endif - - e->flags |= ARL_ENTRY_FLAG_FOUND; - - // link it here - e->next = base->next_keyword; - if(base->next_keyword) { - e->prev = base->next_keyword->prev; - base->next_keyword->prev = e; - - if(e->prev) - e->prev->next = e; - - if(base->head == base->next_keyword) - base->head = e; - } - 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; - - if(unlikely(base->found == base->wanted)) { - // fprintf(stderr, "FOUND ALL WANTED 1: found = %zu, wanted = %zu, expected %zu\n", base->found, base->wanted, base->expected); - return 1; - } - - return 0; -} diff --git a/src/adaptive_resortable_list.h b/src/adaptive_resortable_list.h deleted file mode 100644 index d05a8ede7..000000000 --- a/src/adaptive_resortable_list.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef NETDATA_ADAPTIVE_RESORTABLE_LIST_H -#define NETDATA_ADAPTIVE_RESORTABLE_LIST_H - -/* - * ADAPTIVE RE-SORTABLE LIST - * This structure allows netdata to read a file of NAME VALUE lines - * in the fastest possible way. - * - * It maintains a linked list of all NAME (keywords), sorted in the - * same order as found in the source data file. - * The linked list is kept sorted at all times - the source file - * may change at any time, the list will adapt. - * - * The caller: - * - * 1. calls arl_create() to create a list - * - * 2. calls arl_expect() to register the expected keyword - * - * Then: - * - * 3. calls arl_begin() to initiate a data collection iteration. - * This is to be called just ONCE every time the source is re-scanned. - * - * 4. calls arl_check() for each line read from the file. - * - * Finally: - * - * 5. calls arl_free() to destroy this and free all memory. - * - * The program will call the processor() function, given to - * arl_create(), for each expected keyword found. - * The default processor() expects dst to be an unsigned long long *. - * - * LIMITATIONS - * DO NOT USE THIS IF THE A NAME/KEYWORD MAY APPEAR MORE THAN - * ONCE IN THE SOURCE DATA SET. - */ - -#include "common.h" - -#define ARL_ENTRY_FLAG_FOUND 0x01 // the entry has been found in the source data -#define ARL_ENTRY_FLAG_EXPECTED 0x02 // the entry is expected by the program -#define ARL_ENTRY_FLAG_DYNAMIC 0x04 // the entry was dynamically allocated, from source data - -typedef struct arl_entry { - char *name; // the keywords - uint32_t hash; // the hash of the keyword - - void *dst; // the dst to pass to the processor - - uint8_t flags; // ARL_ENTRY_FLAG_* - - // the processor to do the job - void (*processor)(const char *name, uint32_t hash, const char *value, void *dst); - - // double linked list for fast re-linkings - struct arl_entry *prev, *next; -} ARL_ENTRY; - -typedef struct arl_base { - char *name; - - size_t iteration; // incremented on each iteration (arl_begin()) - size_t found; // the number of expected keywords found in this iteration - size_t expected; // the number of expected keywords - size_t wanted; // the number of wanted keywords - // i.e. the number of keywords found and expected - - size_t relinkings; // the number of relinkings we have made so far - - size_t allocated; // the number of keywords allocated - size_t fred; // the number of keywords cleaned up - - size_t rechecks; // the number of iterations between re-checks of the - // wanted number of keywords - // this is only needed in cases where the source - // is having less lines over time. - - size_t added; // it is non-zero if new keywords have been added - // this is only needed to detect new lines have - // been added to the file, over time. - -#ifdef NETDATA_INTERNAL_CHECKS - size_t fast; // the number of times we have taken the fast path - size_t slow; // the number of times we have taken the slow path -#endif - - // the processor to do the job - void (*processor)(const char *name, uint32_t hash, const char *value, void *dst); - - // the linked list of the keywords - ARL_ENTRY *head; - - // since we keep the list of keywords sorted (as found in the source data) - // this is next keyword that we expect to find in the source data. - ARL_ENTRY *next_keyword; -} ARL_BASE; - -// create a new ARL -extern ARL_BASE *arl_create(const char *name, void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks); - -// free an ARL -extern void arl_free(ARL_BASE *arl_base); - -// register an expected keyword to the ARL -// together with its destination ( i.e. the output of the processor() ) -extern ARL_ENTRY *arl_expect_custom(ARL_BASE *base, const char *keyword, void (*processor)(const char *name, uint32_t hash, const char *value, void *dst), void *dst); -#define arl_expect(base, keyword, dst) arl_expect_custom(base, keyword, NULL, dst) - -// an internal call to complete the check() call -extern int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *value); - -// begin an ARL iteration -extern void arl_begin(ARL_BASE *base); - -extern void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst); -extern void arl_callback_str2kernel_uint_t(const char *name, uint32_t hash, const char *value, void *dst); - -// check a keyword against the ARL -// this is to be called for each keyword read from source data -// s = the keyword, as collected -// src = the src data to be passed to the processor -// it is defined in the header file in order to be inlined -static inline int arl_check(ARL_BASE *base, const char *keyword, const char *value) { - ARL_ENTRY *e = base->next_keyword; - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely((base->fast + base->slow) % (base->expected + base->allocated) == 0 && (base->fast + base->slow) > (base->expected + base->allocated) * base->iteration)) - info("ARL '%s': Did you forget to call arl_begin()?", base->name); -#endif - - // it should be the first entry (pointed by base->next_keyword) - if(likely(!strcmp(keyword, e->name))) { - // it is - -#ifdef NETDATA_INTERNAL_CHECKS - base->fast++; -#endif - - e->flags |= ARL_ENTRY_FLAG_FOUND; - - // execute the processor - if(unlikely(e->dst)) { - e->processor(e->name, e->hash, value, e->dst); - base->found++; - } - - // be prepared for the next iteration - base->next_keyword = e->next; - if(unlikely(!base->next_keyword)) - base->next_keyword = base->head; - - // stop if we collected all the values for this iteration - if(unlikely(base->found == base->wanted)) { - // fprintf(stderr, "FOUND ALL WANTED 2: found = %zu, wanted = %zu, expected %zu\n", base->found, base->wanted, base->expected); - return 1; - } - - return 0; - } - -#ifdef NETDATA_INTERNAL_CHECKS - base->slow++; -#endif - - // we read from source, a not-expected keyword - return arl_find_or_create_and_relink(base, keyword, value); -} - -#endif //NETDATA_ADAPTIVE_RESORTABLE_LIST_H diff --git a/src/appconfig.c b/src/appconfig.c deleted file mode 100644 index 2424864b5..000000000 --- a/src/appconfig.c +++ /dev/null @@ -1,606 +0,0 @@ -#include "common.h" - -#define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2) - -// ---------------------------------------------------------------------------- -// definitions - -#define CONFIG_VALUE_LOADED 0x01 // has been loaded from the config -#define CONFIG_VALUE_USED 0x02 // has been accessed from the program -#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_option { - avl avl; // the index - this has to be first! - - uint8_t flags; - uint32_t hash; // a simple hash to speed up searching - // we first compare hashes, and only if the hashes are equal we do string comparisons - - char *name; - char *value; - - struct config_option *next; // config->mutex protects just this -}; - -struct section { - avl avl; - - uint32_t hash; // a simple hash to speed up searching - // we first compare hashes, and only if the hashes are equal we do string comparisons - - char *name; - - struct section *next; // gloabl config_mutex protects just this - - struct config_option *values; - avl_tree_lock values_index; - - netdata_mutex_t mutex; // this locks only the writers, to ensure atomic updates - // readers are protected using the rwlock in avl_tree_lock -}; - -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 appconfig_wrlock(struct config *root) { - netdata_mutex_lock(&root->mutex); -} - -static inline void appconfig_unlock(struct config *root) { - netdata_mutex_unlock(&root->mutex); -} - -static inline void config_section_wrlock(struct section *co) { - netdata_mutex_lock(&co->mutex); -} - -static inline void config_section_unlock(struct section *co) { - netdata_mutex_unlock(&co->mutex); -} - - -// ---------------------------------------------------------------------------- -// config name-value index - -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 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_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_option *)avl_search_lock(&(co->values_index), (avl *) &tmp); -} - - -// ---------------------------------------------------------------------------- -// config sections index - -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); -} - -#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 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 section *)avl_search_lock(&root->index, (avl *) &tmp); -} - - -// ---------------------------------------------------------------------------- -// config section methods - -static inline struct section *appconfig_section_find(struct config *root, const char *section) { - return appconfig_index_find(root, section, 0); -} - -static inline struct section *appconfig_section_create(struct config *root, const char *section) { - debug(D_CONFIG, "Creating section '%s'.", section); - - struct section *co = callocz(1, sizeof(struct section)); - co->name = strdupz(section); - co->hash = simple_hash(co->name); - netdata_mutex_init(&co->mutex); - - avl_init_lock(&co->values_index, appconfig_option_compare); - - if(unlikely(appconfig_index_add(root, co) != co)) - error("INTERNAL ERROR: indexing of section '%s', already exists.", co->name); - - appconfig_wrlock(root); - struct section *co2 = root->sections; - if(co2) { - while (co2->next) co2 = co2->next; - co2->next = co; - } - else root->sections = co; - appconfig_unlock(root); - - return co; -} - - -// ---------------------------------------------------------------------------- -// config name-value methods - -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_option *cv = callocz(1, sizeof(struct config_option)); - cv->name = strdupz(name); - cv->hash = simple_hash(cv->name); - cv->value = strdupz(value); - - 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_wrlock(co); - struct config_option *cv2 = co->values; - if(cv2) { - while (cv2->next) cv2 = cv2->next; - cv2->next = cv; - } - else co->values = cv; - config_section_unlock(co); - - return 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 section *co = appconfig_section_find(root, section); - if(!co) return 0; - - cv = appconfig_option_index_find(co, name, 0); - if(!cv) return 0; - - return 1; -} - -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', to section '%s', new name '%s'", section_old, name_old, section_new, name_new); - - struct section *co_old = appconfig_section_find(root, section_old); - if(!co_old) return ret; - - struct section *co_new = appconfig_section_find(root, section_new); - if(!co_new) co_new = appconfig_section_create(root, section_new); - - config_section_wrlock(co_old); - if(co_old != co_new) - config_section_wrlock(co_new); - - cv_old = appconfig_option_index_find(co_old, name_old, 0); - if(!cv_old) goto cleanup; - - cv_new = appconfig_option_index_find(co_new, name_new, 0); - if(cv_new) goto cleanup; - - 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); - - 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; - } - - 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: - if(co_old != co_new) - config_section_unlock(co_new); - config_section_unlock(co_old); - return ret; -} - -char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value) -{ - struct config_option *cv; - - debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value); - - struct section *co = appconfig_section_find(root, section); - if(!co) co = appconfig_section_create(root, section); - - cv = appconfig_option_index_find(co, name, 0); - if(!cv) { - cv = appconfig_value_create(co, name, default_value); - if(!cv) return NULL; - } - cv->flags |= CONFIG_VALUE_USED; - - if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) { - // this is a loaded value from the config file - // if it is different that the default, mark it - if(!(cv->flags & CONFIG_VALUE_CHECKED)) { - if(strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED; - cv->flags |= CONFIG_VALUE_CHECKED; - } - } - - return(cv->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 = appconfig_get(root, section, name, buffer); - if(!s) return value; - - return strtoll(s, NULL, 0); -} - -LONG_DOUBLE appconfig_get_float(struct config *root, const char *section, const char *name, LONG_DOUBLE value) -{ - char buffer[100], *s; - sprintf(buffer, "%0.5" LONG_DOUBLE_MODIFIER, value); - - s = appconfig_get(root, section, name, buffer); - if(!s) return value; - - return str2ld(s, NULL); -} - -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 = appconfig_get(root, section, name, s); - if(!s) return value; - - if(!strcasecmp(s, "yes") || !strcasecmp(s, "true") || !strcasecmp(s, "on") || !strcasecmp(s, "auto") || !strcasecmp(s, "on demand")) return 1; - return 0; -} - -int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value) -{ - char *s; - - if(value == CONFIG_BOOLEAN_AUTO) - s = "auto"; - - else if(value == CONFIG_BOOLEAN_NO) - s = "no"; - - else - s = "yes"; - - s = appconfig_get(root, section, name, s); - if(!s) return value; - - if(!strcmp(s, "yes")) - return CONFIG_BOOLEAN_YES; - else if(!strcmp(s, "no")) - return CONFIG_BOOLEAN_NO; - else if(!strcmp(s, "auto") || !strcmp(s, "on demand")) - return CONFIG_BOOLEAN_AUTO; - - return value; -} - -const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value) -{ - struct config_option *cv; - - debug(D_CONFIG, "request to set default config in section '%s', name '%s', value '%s'", section, name, value); - - struct section *co = appconfig_section_find(root, section); - if(!co) return appconfig_set(root, 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; - - if(cv->flags & CONFIG_VALUE_LOADED) - return cv->value; - - if(strcmp(cv->value, value) != 0) { - cv->flags |= CONFIG_VALUE_CHANGED; - - freez(cv->value); - cv->value = strdupz(value); - } - - return cv->value; -} - -const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value) -{ - struct config_option *cv; - - debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value); - - struct section *co = appconfig_section_find(root, section); - if(!co) co = appconfig_section_create(root, section); - - 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) { - cv->flags |= CONFIG_VALUE_CHANGED; - - freez(cv->value); - cv->value = strdupz(value); - } - - return 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); - - appconfig_set(root, section, name, buffer); - - return value; -} - -LONG_DOUBLE appconfig_set_float(struct config *root, const char *section, const char *name, LONG_DOUBLE value) -{ - char buffer[100]; - sprintf(buffer, "%0.5" LONG_DOUBLE_MODIFIER, value); - - appconfig_set(root, section, name, buffer); - - return 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"; - - appconfig_set(root, section, name, s); - - return value; -} - - -// ---------------------------------------------------------------------------- -// config load/save - -int appconfig_load(struct config *root, char *filename, int overwrite_used) -{ - int line = 0; - struct section *co = NULL; - - char buffer[CONFIG_FILE_LINE_MAX + 1], *s; - - if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME; - - debug(D_CONFIG, "CONFIG: opening config file '%s'", filename); - - FILE *fp = fopen(filename, "r"); - if(!fp) { - error("CONFIG: cannot open file '%s'", filename); - return 0; - } - - while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) { - buffer[CONFIG_FILE_LINE_MAX] = '\0'; - line++; - - s = trim(buffer); - if(!s || *s == '#') { - debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', it is empty.", line, filename); - continue; - } - - int len = (int) strlen(s); - if(*s == '[' && s[len - 1] == ']') { - // new section - s[len - 1] = '\0'; - s++; - - co = appconfig_section_find(root, s); - if(!co) co = appconfig_section_create(root, s); - - continue; - } - - if(!co) { - // line outside a section - error("CONFIG: ignoring line %d ('%s') of file '%s', it is outside all sections.", line, s, filename); - continue; - } - - char *name = s; - char *value = strchr(s, '='); - if(!value) { - error("CONFIG: ignoring line %d ('%s') of file '%s', there is no = in it.", line, s, filename); - continue; - } - *value = '\0'; - value++; - - name = trim(name); - value = trim(value); - - if(!name || *name == '#') { - error("CONFIG: ignoring line %d of file '%s', name is empty.", line, filename); - continue; - } - if(!value) { - debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', value is empty.", line, filename); - continue; - } - - struct config_option *cv = appconfig_option_index_find(co, name, 0); - - 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, "CONFIG: line %d of file '%s', overwriting '%s/%s'.", line, filename, co->name, cv->name); - freez(cv->value); - cv->value = strdupz(value); - } - else - debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', '%s/%s' is already present and used.", line, filename, co->name, cv->name); - } - cv->flags |= CONFIG_VALUE_LOADED; - } - - fclose(fp); - - return 1; -} - -void appconfig_generate(struct config *root, BUFFER *wb, int only_changed) -{ - int i, pri; - struct section *co; - struct config_option *cv; - - for(i = 0; i < 3 ;i++) { - switch(i) { - case 0: - buffer_strcat(wb, - "# netdata configuration\n" - "#\n" - "# You can download the latest version of this file, using:\n" - "#\n" - "# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf\n" - "# or\n" - "# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf\n" - "#\n" - "# You can uncomment and change any of the options below.\n" - "# The value shown in the commented settings, is the default value.\n" - "#\n" - "\n# global netdata configuration\n"); - break; - - case 1: - buffer_strcat(wb, "\n\n# per plugin configuration\n"); - break; - - case 2: - buffer_strcat(wb, "\n\n# per chart configuration\n"); - break; - } - - 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_STATSD) - || !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; - - if(i == pri) { - int loaded = 0; - int used = 0; - int changed = 0; - int count = 0; - - config_section_wrlock(co); - for(cv = co->values; cv ; cv = cv->next) { - used += (cv->flags & CONFIG_VALUE_USED)?1:0; - loaded += (cv->flags & CONFIG_VALUE_LOADED)?1:0; - changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0; - count++; - } - config_section_unlock(co); - - if(!count) continue; - if(only_changed && !changed && !loaded) continue; - - if(!used) { - buffer_sprintf(wb, "\n# section '%s' is not used.", co->name); - } - - buffer_sprintf(wb, "\n[%s]\n", co->name); - - config_section_wrlock(co); - for(cv = co->values; cv ; cv = cv->next) { - - if(used && !(cv->flags & CONFIG_VALUE_USED)) { - buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name); - } - buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_LOADED)) && (!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value); - } - config_section_unlock(co); - } - } - appconfig_unlock(root); - } -} diff --git a/src/appconfig.h b/src/appconfig.h deleted file mode 100644 index 7d056e6be..000000000 --- a/src/appconfig.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef NETDATA_CONFIG_H -#define NETDATA_CONFIG_H 1 - -#define CONFIG_FILENAME "netdata.conf" - -#define CONFIG_SECTION_GLOBAL "global" -#define CONFIG_SECTION_WEB "web" -#define CONFIG_SECTION_STATSD "statsd" -#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 - -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 LONG_DOUBLE appconfig_get_float(struct config *root, const char *section, const char *name, LONG_DOUBLE 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 LONG_DOUBLE appconfig_set_float(struct config *root, const char *section, const char *name, LONG_DOUBLE 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); - -// ---------------------------------------------------------------------------- -// shortcuts for the default netdata configuration - -#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_float(section, name, value) appconfig_get_float(&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) - -#define config_set(section, name, default_value) appconfig_set(&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_float(section, name, value) appconfig_set_float(&netdata_config, section, name, value) -#define config_set_boolean(section, name, value) appconfig_set_boolean(&netdata_config, section, name, value) - -#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) - -#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 deleted file mode 100644 index 8595da6c2..000000000 --- a/src/apps_plugin.c +++ /dev/null @@ -1,3639 +0,0 @@ - -/* - * netdata apps.plugin - * (C) Copyright 2016-2017 Costa Tsaousis - * Released under GPL v3+ - */ - -#include "common.h" - -#ifdef __FreeBSD__ -#include -#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 16384 - -// ---------------------------------------------------------------------------- -// 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 - - -// ---------------------------------------------------------------------------- -// 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; - - -// 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 - - -// ---------------------------------------------------------------------------- -// 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 -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) -static kernel_uint_t - global_utime = 0, - global_stime = 0, - global_gtime = 0; -#endif - -// 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 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]; - uint32_t comparehash; - size_t comparelen; - - char id[MAX_NAME + 1]; - uint32_t idhash; - - char name[MAX_NAME + 1]; - - uid_t uid; - gid_t gid; - - 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 status_vmsize; - kernel_uint_t status_vmrss; - kernel_uint_t status_vmshared; - kernel_uint_t status_rssfile; - kernel_uint_t status_rssshmem; - kernel_uint_t status_vmswap; - - 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; - - 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 - - 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 - - -// ---------------------------------------------------------------------------- -// 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; - - uint32_t log_thrown; - - // char state; - int32_t ppid; - // int32_t pgrp; - // int32_t session; - // int32_t tty_nr; - // int32_t tpgid; - // uint64_t flags; - - // 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 status_vmsize; - kernel_uint_t status_vmrss; - kernel_uint_t status_vmshared; - kernel_uint_t status_rssfile; - kernel_uint_t status_rssshmem; - kernel_uint_t status_vmswap; -#ifndef __FreeBSD__ - ARL_BASE *status_arl; -#endif - - 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 *status_filename; - char *io_filename; - char *cmdline_filename; - - struct pid_stat *parent; - struct pid_stat *prev; - struct pid_stat *next; -}; - -size_t pagesize; - -// log each problem once per process -// log flood protection flags (log_thrown) -#define PID_LOG_IO 0x00000001 -#define PID_LOG_STATUS 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; - - w = callocz(sizeof(struct target), 1); - snprintfz(w->compare, MAX_COMPARE_NAME, "%u", uid); - w->comparehash = simple_hash(w->compare); - w->comparelen = strlen(w->compare); - - snprintfz(w->id, MAX_NAME, "%u", uid); - w->idhash = simple_hash(w->id); - - struct passwd *pw = getpwuid(uid); - if(!pw || !pw->pw_name || !*pw->pw_name) - snprintfz(w->name, MAX_NAME, "%u", uid); - else - snprintfz(w->name, MAX_NAME, "%s", pw->pw_name); - - netdata_fix_chart_name(w->name); - - w->uid = uid; - - w->next = users_root_target; - users_root_target = w; - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: added uid %u ('%s') target\n", w->uid, w->name); - - return w; -} - -struct target *get_groups_target(gid_t gid) -{ - struct target *w; - for(w = groups_root_target ; w ; w = w->next) - if(w->gid == gid) return w; - - w = callocz(sizeof(struct target), 1); - snprintfz(w->compare, MAX_COMPARE_NAME, "%u", gid); - w->comparehash = simple_hash(w->compare); - w->comparelen = strlen(w->compare); - - snprintfz(w->id, MAX_NAME, "%u", gid); - w->idhash = simple_hash(w->id); - - struct group *gr = getgrgid(gid); - if(!gr || !gr->gr_name || !*gr->gr_name) - snprintfz(w->name, MAX_NAME, "%u", gid); - else - snprintfz(w->name, MAX_NAME, "%s", gr->gr_name); - - netdata_fix_chart_name(w->name); - - w->gid = gid; - - w->next = groups_root_target; - groups_root_target = w; - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: added gid %u ('%s') target\n", w->gid, w->name); - - return w; -} - -// find or create a new target -// there are targets that are just aggregated to other target (the second argument) -static struct target *get_apps_groups_target(const char *id, struct target *target, const char *name) { - int tdebug = 0, thidden = target?target->hidden:0, ends_with = 0; - const char *nid = id; - - // extract the options - while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') { - if(nid[0] == '-') thidden = 1; - if(nid[0] == '+') tdebug = 1; - if(nid[0] == '*') ends_with = 1; - nid++; - } - uint32_t hash = simple_hash(id); - - // find if it already exists - struct target *w, *last = apps_groups_root_target; - for(w = apps_groups_root_target ; w ; w = w->next) { - if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0) - return w; - - last = w; - } - - // find an existing target - if(unlikely(!target)) { - while(*name == '-') { - if(*name == '-') thidden = 1; - name++; - } - - 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); - else - fprintf(stderr, "apps.plugin: NEW TARGET NAME '%s' on ID '%s'\n", name, id); - } - } - - if(target && target->target) - fatal("Internal Error: request to link process '%s' to target '%s' which is linked to target '%s'", id, target->id, target->target->id); - - w = callocz(sizeof(struct target), 1); - strncpyz(w->id, nid, MAX_NAME); - w->idhash = simple_hash(w->id); - - if(unlikely(!target)) - // copy the name - strncpyz(w->name, name, MAX_NAME); - else - // copy the id - strncpyz(w->name, nid, MAX_NAME); - - strncpyz(w->compare, nid, MAX_COMPARE_NAME); - size_t len = strlen(w->compare); - if(w->compare[len - 1] == '*') { - w->compare[len - 1] = '\0'; - w->starts_with = 1; - } - w->ends_with = ends_with; - - if(w->starts_with && w->ends_with) - proc_pid_cmdline_is_needed = 1; - - w->comparehash = simple_hash(w->compare); - w->comparelen = strlen(w->compare); - - w->hidden = thidden; - w->debug = tdebug; - w->target = target; - - // append it, to maintain the order in apps_groups.conf - if(last) last->next = w; - else apps_groups_root_target = w; - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n" - , w->id - , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact")) - , w->target?w->target->name:w->name - , (w->hidden)?"hidden":"-" - , (w->debug)?"debug":"-" - ); - - return w; -} - -// read the apps_groups.conf file -static int read_apps_groups_conf(const char *file) -{ - char filename[FILENAME_MAX + 1]; - - snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, file); - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename); - - // ---------------------------------------- - - procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT); - if(!ff) return 1; - - procfile_set_quotes(ff, "'\""); - - ff = procfile_readall(ff); - if(!ff) - return 1; - - size_t line, lines = procfile_lines(ff); - - for(line = 0; line < lines ;line++) { - size_t word, words = procfile_linewords(ff, line); - if(!words) continue; - - char *name = procfile_lineword(ff, line, 0); - if(!name || !*name) continue; - - // find a possibly existing target - struct target *w = NULL; - - // loop through all words, skipping the first one (the name) - for(word = 0; word < words ;word++) { - char *s = procfile_lineword(ff, line, word); - if(!s || !*s) continue; - if(*s == '#') break; - - // is this the first word? skip it - if(s == name) continue; - - // add this target - struct target *n = get_apps_groups_target(s, w, name); - if(!n) { - error("Cannot create target '%s' (line %zu, word %zu)", s, line, word); - continue; - } - - // just some optimization - // to avoid searching for a target for each process - if(!w) w = n->target?n->target:n; - } - } - - procfile_close(ff); - - apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL, "other"); // match nothing - if(!apps_groups_default_target) - fatal("Cannot create default target"); - - // allow the user to override group 'other' - if(apps_groups_default_target->target) - apps_groups_default_target = apps_groups_default_target->target; - - return 0; -} - - -// ---------------------------------------------------------------------------- -// struct pid_stat management - -static inline struct pid_stat *get_pid_entry(pid_t pid) { - if(unlikely(all_pids[pid])) - return all_pids[pid]; - - struct pid_stat *p = callocz(sizeof(struct pid_stat), 1); - p->fds = callocz(sizeof(int), MAX_SPARE_FDS); - p->fds_size = MAX_SPARE_FDS; - - if(likely(root_of_pids)) - root_of_pids->prev = p; - - p->next = root_of_pids; - root_of_pids = p; - - p->pid = pid; - - all_pids[pid] = p; - all_pids_count++; - - return p; -} - -static inline void del_pid_entry(pid_t pid) { - struct pid_stat *p = all_pids[pid]; - - if(unlikely(!p)) { - error("attempted to free pid %d that is not allocated.", pid); - return; - } - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, p->comm); - - if(root_of_pids == p) - root_of_pids = p->next; - - if(p->next) p->next->prev = p->prev; - if(p->prev) p->prev->next = p->next; - - freez(p->fds); - freez(p->fds_dirname); - freez(p->stat_filename); - freez(p->status_filename); -#ifndef __FreeBSD__ - arl_free(p->status_arl); -#endif - freez(p->io_filename); - freez(p->cmdline_filename); - freez(p->cmdline); - freez(p); - - all_pids[pid] = NULL; - all_pids_count--; -} - -// ---------------------------------------------------------------------------- - -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: - #ifdef __FreeBSD__ - error("Cannot fetch process %d I/O info (command '%s')", p->pid, p->comm); - #else - error("Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_STATUS: - #ifdef __FreeBSD__ - error("Cannot fetch process %d status info (command '%s')", p->pid, p->comm); - #else - error("Cannot process %s/proc/%d/status (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_CMDLINE: - #ifdef __FreeBSD__ - error("Cannot fetch process %d command line (command '%s')", p->pid, p->comm); - #else - error("Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_FDS: - #ifdef __FreeBSD__ - error("Cannot fetch process %d files (command '%s')", p->pid, p->comm); - #else - error("Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - 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 void assign_target_to_pid(struct pid_stat *p) { - targets_assignment_counter++; - - 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(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 && p->cmdline && 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; - } - } -} - - -// ---------------------------------------------------------------------------- -// update pids from proc - -static inline int read_proc_pid_cmdline(struct pid_stat *p) { - static char cmdline[MAX_CMDLINE + 1]; - -#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, 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", netdata_configured_host_prefix, p->pid); - p->cmdline_filename = strdupz(filename); - } - - int fd = open(p->cmdline_filename, O_RDONLY, 0666); - if(unlikely(fd == -1)) goto cleanup; - - ssize_t i, bytes = read(fd, cmdline, MAX_CMDLINE); - close(fd); - - if(unlikely(bytes < 0)) goto cleanup; -#endif - - cmdline[bytes] = '\0'; - for(i = 0; i < bytes ; i++) - if(unlikely(!cmdline[i])) cmdline[i] = ' '; - - p->cmdline = strdupz(cmdline); - - if(unlikely(debug)) - fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline); - - return 1; - -cleanup: - // copy the command to the command line - p->cmdline = strdupz(p->comm); - return 0; -} - -// ---------------------------------------------------------------------------- -// 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) - - -// ---------------------------------------------------------------------------- - -#ifndef __FreeBSD__ -struct arl_callback_ptr { - struct pid_stat *p; - procfile *ff; - size_t line; -}; - -void arl_callback_status_uid(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 5)) return; - - //const char *real_uid = procfile_lineword(aptr->ff, aptr->line, 1); - const char *effective_uid = procfile_lineword(aptr->ff, aptr->line, 2); - //const char *saved_uid = procfile_lineword(aptr->ff, aptr->line, 3); - //const char *filesystem_uid = procfile_lineword(aptr->ff, aptr->line, 4); - - if(likely(effective_uid && *effective_uid)) - aptr->p->uid = (uid_t)str2l(effective_uid); -} - -void arl_callback_status_gid(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 5)) return; - - //const char *real_gid = procfile_lineword(aptr->ff, aptr->line, 1); - const char *effective_gid = procfile_lineword(aptr->ff, aptr->line, 2); - //const char *saved_gid = procfile_lineword(aptr->ff, aptr->line, 3); - //const char *filesystem_gid = procfile_lineword(aptr->ff, aptr->line, 4); - - if(likely(effective_gid && *effective_gid)) - aptr->p->gid = (uid_t)str2l(effective_gid); -} - -void arl_callback_status_vmsize(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; - - aptr->p->status_vmsize = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); -} - -void arl_callback_status_vmswap(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; - - aptr->p->status_vmswap = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); -} - -void arl_callback_status_vmrss(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; - - aptr->p->status_vmrss = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); -} - -void arl_callback_status_rssfile(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; - - aptr->p->status_rssfile = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); -} - -void arl_callback_status_rssshmem(const char *name, uint32_t hash, const char *value, void *dst) { - (void)name; (void)hash; (void)value; - struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; - if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; - - aptr->p->status_rssshmem = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); -} -#endif // !__FreeBSD__ - -static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) { - p->status_vmsize = 0; - p->status_vmrss = 0; - p->status_vmshared = 0; - p->status_rssfile = 0; - p->status_rssshmem = 0; - p->status_vmswap = 0; - -#ifdef __FreeBSD__ - struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr; - - p->uid = proc_info->ki_uid; - p->gid = proc_info->ki_groups[0]; - p->status_vmsize = proc_info->ki_size / 1024; // in kB - p->status_vmrss = proc_info->ki_rssize * pagesize / 1024; // in kB - // FIXME: what about shared and swap memory on FreeBSD? - return 1; -#else - (void)ptr; - - static struct arl_callback_ptr arl_ptr; - static procfile *ff = NULL; - - if(unlikely(!p->status_arl)) { - p->status_arl = arl_create("/proc/pid/status", NULL, 60); - arl_expect_custom(p->status_arl, "Uid", arl_callback_status_uid, &arl_ptr); - arl_expect_custom(p->status_arl, "Gid", arl_callback_status_gid, &arl_ptr); - arl_expect_custom(p->status_arl, "VmSize", arl_callback_status_vmsize, &arl_ptr); - arl_expect_custom(p->status_arl, "VmRSS", arl_callback_status_vmrss, &arl_ptr); - arl_expect_custom(p->status_arl, "RssFile", arl_callback_status_rssfile, &arl_ptr); - arl_expect_custom(p->status_arl, "RssShmem", arl_callback_status_rssshmem, &arl_ptr); - arl_expect_custom(p->status_arl, "VmSwap", arl_callback_status_vmswap, &arl_ptr); - } - - if(unlikely(!p->status_filename)) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/status", netdata_configured_host_prefix, p->pid); - p->status_filename = strdupz(filename); - } - - ff = procfile_reopen(ff, p->status_filename, (!ff)?" \t:,-()/":NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); - if(unlikely(!ff)) return 0; - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; - - calls_counter++; - - // let ARL use this pid - arl_ptr.p = p; - arl_ptr.ff = ff; - - size_t lines = procfile_lines(ff), l; - arl_begin(p->status_arl); - - for(l = 0; l < lines ;l++) { - // fprintf(stderr, "CHECK: line %zu of %zu, key '%s' = '%s'\n", l, lines, procfile_lineword(ff, l, 0), procfile_lineword(ff, l, 1)); - arl_ptr.line = l; - if(unlikely(arl_check(p->status_arl, - procfile_lineword(ff, l, 0), - procfile_lineword(ff, l, 1)))) break; - } - - p->status_vmshared = p->status_rssfile + p->status_rssshmem; - - // fprintf(stderr, "%s uid %d, gid %d, VmSize %zu, VmRSS %zu, RssFile %zu, RssShmem %zu, shared %zu\n", p->comm, (int)p->uid, (int)p->gid, p->status_vmsize, p->status_vmrss, p->status_rssfile, p->status_rssshmem, p->status_vmshared); - - return 1; -#endif -} - - -// ---------------------------------------------------------------------------- - -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", netdata_configured_host_prefix, p->pid); - p->stat_filename = strdupz(filename); - } - - int set_quotes = (!ff)?1:0; - - ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); - if(unlikely(!ff)) goto cleanup; - - // if(set_quotes) procfile_set_quotes(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_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 - - if(strcmp(p->comm, comm) != 0) { - 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, comm, MAX_COMPARE_NAME); - - // /proc//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_stime.tv_usec / 10000); - - p->num_threads = proc_info->ki_numthreads; - - if(enable_guest_charts) { - 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)); - - 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; - p->cutime -= (p->cutime >= p->cgtime) ? p->cgtime : p->cutime; - 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=" 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; - p->cminflt = 0; - p->majflt = 0; - p->cmajflt = 0; - p->utime = 0; - p->stime = 0; - p->gtime = 0; - p->cutime = 0; - p->cstime = 0; - p->cgtime = 0; - } - - return 1; - -cleanup: - p->minflt = 0; - p->cminflt = 0; - p->majflt = 0; - p->cmajflt = 0; - p->utime = 0; - p->stime = 0; - p->gtime = 0; - p->cutime = 0; - p->cstime = 0; - p->cgtime = 0; - p->num_threads = 0; - // p->rss = 0; - return 0; -} - -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", netdata_configured_host_prefix, p->pid); - p->io_filename = strdupz(filename); - } - - // open the file - ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); - if(unlikely(!ff)) goto cleanup; - - ff = procfile_readall(ff); - if(unlikely(!ff)) goto cleanup; -#endif - - calls_counter++; - - p->last_io_collected_usec = p->io_collected_usec; - p->io_collected_usec = now_monotonic_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; - p->io_logical_bytes_written = 0; - // p->io_read_calls = 0; - // p->io_write_calls = 0; - p->io_storage_bytes_read = 0; - p->io_storage_bytes_written = 0; - // p->io_cancelled_write_bytes = 0; - } - - return 1; - -#ifndef __FreeBSD__ -cleanup: - p->io_logical_bytes_read = 0; - p->io_logical_bytes_written = 0; - // p->io_read_calls = 0; - // p->io_write_calls = 0; - p->io_storage_bytes_read = 0; - p->io_storage_bytes_written = 0; - // p->io_cancelled_write_bytes = 0; - return 0; -#endif -} - -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) -static inline int read_proc_stat() { - static char filename[FILENAME_MAX + 1] = ""; - static procfile *ff = NULL; - static kernel_uint_t utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0; - static usec_t collected_usec = 0, last_collected_usec = 0; - - if(unlikely(!ff)) { - 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; - - last_collected_usec = collected_usec; - collected_usec = now_monotonic_usec(); - - calls_counter++; - - // temporary - it is added global_ntime; - kernel_uint_t global_ntime = 0; - - 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); - - global_utime += global_ntime; - - if(enable_guest_charts) { - // temporary - it is added global_ntime; - kernel_uint_t global_gntime = 0; - - // guest nice time, on guest time - 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; - } - - if(unlikely(global_iterations_counter == 1)) { - global_utime = 0; - global_stime = 0; - global_gtime = 0; - } - - return 1; - -cleanup: - global_utime = 0; - global_stime = 0; - global_gtime = 0; - return 0; -} -#else -static inline int read_proc_stat() { - return 0; -} -#endif - -// ---------------------------------------------------------------------------- - -int file_descriptor_compare(void* a, void* b) { -#ifdef NETDATA_INTERNAL_CHECKS - if(((struct file_descriptor *)a)->magic != 0x0BADCAFE || ((struct file_descriptor *)b)->magic != 0x0BADCAFE) - error("Corrupted index data detected. Please report this."); -#endif /* NETDATA_INTERNAL_CHECKS */ - - if(((struct file_descriptor *)a)->hash < ((struct file_descriptor *)b)->hash) - return -1; - - else if(((struct file_descriptor *)a)->hash > ((struct file_descriptor *)b)->hash) - return 1; - - else - return strcmp(((struct file_descriptor *)a)->name, ((struct file_descriptor *)b)->name); -} - -int file_descriptor_iterator(avl *a) { if(a) {}; return 0; } - -avl_tree all_files_index = { - NULL, - file_descriptor_compare -}; - -static struct file_descriptor *file_descriptor_find(const char *name, uint32_t hash) { - struct file_descriptor tmp; - tmp.hash = (hash)?hash:simple_hash(name); - tmp.name = name; - tmp.count = 0; - tmp.pos = 0; -#ifdef NETDATA_INTERNAL_CHECKS - tmp.magic = 0x0BADCAFE; -#endif /* NETDATA_INTERNAL_CHECKS */ - - return (struct file_descriptor *)avl_search(&all_files_index, (avl *) &tmp); -} - -#define file_descriptor_add(fd) avl_insert(&all_files_index, (avl *)(fd)) -#define file_descriptor_remove(fd) avl_remove(&all_files_index, (avl *)(fd)) - -// ---------------------------------------------------------------------------- - -static inline void file_descriptor_not_used(int id) -{ - if(id > 0 && id < all_files_size) { - -#ifdef NETDATA_INTERNAL_CHECKS - if(all_files[id].magic != 0x0BADCAFE) { - error("Ignoring request to remove empty file id %d.", id); - return; - } -#endif /* NETDATA_INTERNAL_CHECKS */ - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count); - - if(all_files[id].count > 0) { - all_files[id].count--; - - if(!all_files[id].count) { - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id); - - if(unlikely(file_descriptor_remove(&all_files[id]) != (void *)&all_files[id])) - error("INTERNAL ERROR: removal of unused fd from index, removed a different fd"); - -#ifdef NETDATA_INTERNAL_CHECKS - all_files[id].magic = 0x00000000; -#endif /* NETDATA_INTERNAL_CHECKS */ - all_files_len--; - } - } - else - error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name); - } - else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size); -} - -static inline void all_files_grow() { - void *old = all_files; - int i; - - // there is no empty slot - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); - - all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor)); - - // if the address changed, we have to rebuild the index - // since all pointers are now invalid - - if(unlikely(old && old != (void *)all_files)) { - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> re-indexing.\n"); - - all_files_index.root = NULL; - for(i = 0; i < all_files_size; i++) { - if(!all_files[i].count) continue; - if(unlikely(file_descriptor_add(&all_files[i]) != (void *)&all_files[i])) - error("INTERNAL ERROR: duplicate indexing of fd during realloc."); - } - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> re-indexing done.\n"); - } - - // initialize the newly added entries - - for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) { - all_files[i].count = 0; - all_files[i].name = NULL; -#ifdef NETDATA_INTERNAL_CHECKS - all_files[i].magic = 0x00000000; -#endif /* NETDATA_INTERNAL_CHECKS */ - all_files[i].pos = i; - } - - if(unlikely(!all_files_size)) all_files_len = 1; - all_files_size += FILE_DESCRIPTORS_INCREASE_STEP; -} - -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(); - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> searching for empty slot.\n"); - - // search for an empty slot - - static int last_pos = 0; - int i, c; - for(i = 0, c = last_pos ; i < all_files_size ; i++, c++) { - if(c >= all_files_size) c = 0; - if(c == 0) continue; - - if(!all_files[c].count) { - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c); - -#ifdef NETDATA_INTERNAL_CHECKS - if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash)) - error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name); -#endif /* NETDATA_INTERNAL_CHECKS */ - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name); - - freez((void *)all_files[c].name); - all_files[c].name = NULL; - last_pos = c; - break; - } - } - - all_files_len++; - - if(i == all_files_size) { - fatal("We should find an empty slot, but there isn't any"); - exit(1); - } - // else we have an empty slot in 'c' - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> updating slot %d.\n", c); - - all_files[c].name = strdupz(name); - all_files[c].hash = hash; - all_files[c].type = type; - all_files[c].pos = c; - all_files[c].count = 1; -#ifdef NETDATA_INTERNAL_CHECKS - all_files[c].magic = 0x0BADCAFE; -#endif /* NETDATA_INTERNAL_CHECKS */ - if(unlikely(file_descriptor_add(&all_files[c]) != (void *)&all_files[c])) - error("INTERNAL ERROR: duplicate indexing of fd."); - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name); - - return c; -} - -static inline int file_descriptor_find_or_add(const char *name) -{ - uint32_t hash = simple_hash(name); - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash); - - struct file_descriptor *fd = file_descriptor_find(name, hash); - if(fd) { - // found - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos); - - fd->count++; - return fd->pos; - } - // not found - - 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; - } - } - 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); - - type = FILETYPE_OTHER; - } - - return file_descriptor_set_on_empty_slot(name, hash, type); -} - -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++; - } -} - -static inline void cleanup_negative_pid_fds(struct pid_stat *p) { - int *fd = p->fds, *fdend = &p->fds[p->fds_size]; - - while(fd < fdend) { - if(unlikely(*fd < 0)) { - file_descriptor_not_used(-(*fd)); - *fd++ = 0; - } - else - fd++; - } -} - -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; -} - -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; - } - - bfdsbuf = fdsbuf; - efdsbuf = fdsbuf + size; - while (bfdsbuf < efdsbuf) { - fds = (struct kinfo_file *)(uintptr_t)bfdsbuf; - if (unlikely(fds->kf_structsize == 0)) - break; - - // 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; - } - - // get file descriptors array index - int fdid = fds->kf_fd; - - // 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; - } - - 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 */ -#if __FreeBSD_version < 1200031 - sprintf(fdsname, "socket: other: %d %s %s", fds->kf_sock_protocol, fds->kf_sa_local.__ss_pad1, fds->kf_sa_local.__ss_pad2); -#else - sprintf(fdsname, "socket: other: %d %s %s", fds->kf_sock_protocol, fds->kf_un.kf_sock.kf_sa_local.__ss_pad1, fds->kf_un.kf_sock.kf_sa_local.__ss_pad2); -#endif - } - 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: -#if __FreeBSD_version < 1200031 - sprintf(fdsname, "other: pts: %u", fds->kf_un.kf_pts.kf_pts_dev); -#else - sprintf(fdsname, "other: pts: %lu", fds->kf_un.kf_pts.kf_pts_dev); -#endif - 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]; - - 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; - } - - 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]; - } - - closedir(fds); -#endif - cleanup_negative_pid_fds(p); - - return 1; -} - -// ---------------------------------------------------------------------------- - -static inline int print_process_and_parents(struct pid_stat *p, usec_t time) { - char *prefix = "\\_ "; - int indent = 0; - - if(p->parent) - indent = print_process_and_parents(p->parent, p->stat_collected_usec); - else - prefix = " > "; - - char buffer[indent + 1]; - int i; - - for(i = 0; i < indent ;i++) buffer[i] = ' '; - buffer[i] = '\0'; - - fprintf(stderr, " %s %s%s (%d %s %llu" - , buffer - , prefix - , p->comm - , p->pid - , p->updated?"running":"exited" - , p->stat_collected_usec - time - ); - - 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; -} - -static inline void print_process_tree(struct pid_stat *p, char *msg) { - fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited"); - print_process_and_parents(p, p->stat_collected_usec); -} - -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; - - for(p = root_of_pids; p ; p = p->next) { - if(p == pe) continue; - - switch(type) { - case 1: - if(p->cminflt > lost) { - 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 " 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 " 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 " 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 " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm); - found++; - } - break; - } - } - - if(!found) { - switch(type) { - case 1: - 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 " 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 " 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 " 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 " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm); - break; - } - } -} - -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; - *field -= *pfield; - *pfield = 0; - } - else { - absorbed += *field; - *pfield -= *field; - *field = 0; - } - - return absorbed; -} - -static inline void process_exited_processes() { - struct pid_stat *p; - - for(p = root_of_pids; p ; p = p->next) { - if(p->updated || !p->stat_collected_usec) - continue; - - 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)) { - 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" - , utime - , stime - , gtime - , minflt - , majflt - ); - print_process_tree(p, "Searching parents"); - } - - struct pid_stat *pp; - for(pp = p->parent; pp ; pp = pp->parent) { - if(!pp->updated) continue; - - kernel_uint_t absorbed; - absorbed = remove_exited_child_from_parent(&utime, &pp->cutime); - if(unlikely(debug && absorbed)) - 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 " 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(>ime, &pp->cgtime); - if(unlikely(debug && absorbed)) - 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 " 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 " 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)) { - if(unlikely(debug)) { - if(utime) find_lost_child_debug(p, utime, 3); - if(stime) find_lost_child_debug(p, stime, 4); - if(gtime) find_lost_child_debug(p, gtime, 5); - if(minflt) find_lost_child_debug(p, minflt, 1); - if(majflt) find_lost_child_debug(p, majflt, 2); - } - - p->keep = 1; - - if(unlikely(debug)) - 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" - , utime - , stime - , gtime - , minflt - , majflt - ); - - for(pp = p->parent; pp ; pp = pp->parent) { - if(pp->updated) break; - pp->keep = 1; - - if(unlikely(debug)) - fprintf(stderr, " > - KEEP - parent for another loop: %s (%d %s)\n" - , pp->comm - , pp->pid - , pp->updated?"running":"exited" - ); - } - - p->utime_raw = utime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); - p->stime_raw = stime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); - p->gtime_raw = gtime * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); - p->minflt_raw = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); - p->majflt_raw = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (USEC_PER_SEC * RATES_DETAIL); - p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0; - - if(unlikely(debug)) - fprintf(stderr, "\n"); - } - else if(unlikely(debug)) { - fprintf(stderr, " > totally absorbed - DONE - %s (%d %s)\n" - , p->comm - , p->pid - , p->updated?"running":"exited" - ); - } - } -} - -static inline void link_all_processes_to_their_parents(void) { - struct pid_stat *p, *pp; - - // link all children to their parents - // and update children count on parents - for(p = root_of_pids; p ; p = p->next) { - // for each process found - - p->sortlist = 0; - p->parent = NULL; - - if(unlikely(!p->ppid)) { - p->parent = NULL; - continue; - } - - pp = all_pids[p->ppid]; - if(likely(pp)) { - p->parent = pp; - 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=" 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; - error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid); - } - } -} - -// ---------------------------------------------------------------------------- - -// 1. read all files in /proc -// 2. for each numeric directory: -// i. read /proc/pid/stat -// ii. read /proc/pid/status -// iii. read /proc/pid/io (requires root access) -// iii. read the entries in directory /proc/pid/fd (requires root access) -// for each entry: -// a. find or create a struct file_descriptor -// b. cleanup any old/unused file_descriptors - -// after all these, some pids may be linked to targets, while others may not - -// in case of errors, only 1 every 1000 errors is printed -// to avoid filling up all disk space -// if debug is enabled, all errors are printed - -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) -static int compar_pid(const void *pid1, const void *pid2) { - - struct pid_stat *p1 = all_pids[*((pid_t *)pid1)]; - struct pid_stat *p2 = all_pids[*((pid_t *)pid2)]; - - if(p1->sortlist > p2->sortlist) - return -1; - else - return 1; -} -#endif - -static inline int collect_data_for_pid(pid_t pid, void *ptr) { - if(unlikely(pid < 0 || pid > pid_max)) { - error("Invalid pid %d read (expected %d to %d). Ignoring process.", pid, 0, pid_max); - return 0; - } - - struct pid_stat *p = get_pid_entry(pid); - if(unlikely(!p || p->read)) return 0; - p->read = 1; - - // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist); - - // -------------------------------------------------------------------- - // /proc//stat - - 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; - - // check its parent pid - if(unlikely(p->ppid < 0 || p->ppid > pid_max)) { - error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid); - p->ppid = 0; - } - - // -------------------------------------------------------------------- - // /proc//io - - managed_log(p, PID_LOG_IO, read_proc_pid_io(p, ptr)); - - // -------------------------------------------------------------------- - // /proc//status - - if(unlikely(!managed_log(p, PID_LOG_STATUS, read_proc_pid_status(p, ptr)))) - // there is no reason to proceed if we cannot get its status - return 0; - - // -------------------------------------------------------------------- - // /proc//fd - - if(enable_file_charts) - managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p, ptr)); - - // -------------------------------------------------------------------- - // done! - - if(unlikely(debug && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read)) - fprintf(stderr, "Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read\n", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist); - - // mark it as updated - p->updated = 1; - p->keep = 0; - p->keeploops = 0; - - return 1; -} - -static int collect_data_for_all_processes(void) { - struct pid_stat *p = NULL; - -#ifdef __FreeBSD__ - int i, procnum; - - static size_t procbase_size = 0; - static struct kinfo_proc *procbase = NULL; - - size_t new_procbase_size; - - int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC }; - if (unlikely(sysctl(mib, 3, NULL, &new_procbase_size, NULL, 0))) { - error("sysctl error: Can't get processes data size"); - return 0; - } - - // give it some air for processes that may be started - // during this little time. - new_procbase_size += 100 * sizeof(struct kinfo_proc); - - // increase the buffer if needed - if(new_procbase_size > procbase_size) { - procbase_size = new_procbase_size; - procbase = reallocz(procbase, procbase_size); - } - - // sysctl() gets from new_procbase_size the buffer size - // and also returns to it the amount of data filled in - new_procbase_size = procbase_size; - - // get the processes from the system - if (unlikely(sysctl(mib, 3, procbase, &new_procbase_size, NULL, 0))) { - error("sysctl error: Can't get processes data"); - return 0; - } - - // based on the amount of data filled in - // calculate the number of processes we got - procnum = new_procbase_size / sizeof(struct kinfo_proc); - -#endif - - if(all_pids_count) { -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) - size_t slc = 0; -#endif - for(p = root_of_pids; p ; p = p->next) { - p->read = 0; // mark it as not read, so that collect_data_for_pid() will read it - p->updated = 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 %zu processes in my arrays, but it seems there are %zu.", all_pids_count, slc); - 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], NULL); - } -#endif - } - -#ifdef __FreeBSD__ - for (i = 0 ; i < procnum ; ++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", netdata_configured_host_prefix); - DIR *dir = opendir(dirname); - if(!dir) return 0; - - 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; - - pid_t pid = (pid_t) strtoul(de->d_name, &endptr, 10); - - // make sure we read a valid number - if(unlikely(endptr == de->d_name || *endptr != '\0')) - continue; - - 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 - process_exited_processes(); - - return 1; -} - -// ---------------------------------------------------------------------------- -// update statistics on the targets - -// 1. link all childs to their parents -// 2. go from bottom to top, marking as merged all childs to their parents -// this step links all parents without a target to the child target, if any -// 3. link all top level processes (the ones not merged) to the default target -// 4. go from top to bottom, linking all childs without a target, to their parent target -// after this step, all processes have a target -// [5. for each killed pid (updated = 0), remove its usage from its target] -// 6. zero all apps_groups_targets -// 7. concentrate all values on the apps_groups_targets -// 8. remove all killed processes -// 9. find the unique file count for each target -// check: update_apps_groups_statistics() - -static void cleanup_exited_pids(void) { - int c; - struct pid_stat *p = NULL; - - for(p = root_of_pids; p ;) { - if(!p->updated && (!p->keep || p->keeploops > 0)) { - 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; - } - - pid_t r = p->pid; - p = p->next; - del_pid_entry(r); - } - else { - if(unlikely(p->keep)) p->keeploops++; - p->keep = 0; - p = p->next; - } - } -} - -static void apply_apps_groups_targets_inheritance(void) { - struct pid_stat *p = NULL; - - // children that do not have a target - // inherit their target from their parent - int found = 1, loops = 0; - while(found) { - if(unlikely(debug)) loops++; - found = 0; - for(p = root_of_pids; p ; p = p->next) { - // if this process does not have a target - // and it has a parent - // and its parent has a target - // then, set the parent's target to this process - if(unlikely(!p->target && p->parent && p->parent->target)) { - p->target = p->parent->target; - found++; - - if(debug || (p->target && p->target->debug)) - fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm); - } - } - } - - // find all the procs with 0 childs and merge them to their parents - // repeat, until nothing more can be done. - int sortlist = 1; - found = 1; - while(found) { - if(unlikely(debug)) loops++; - found = 0; - - for(p = root_of_pids; p ; p = p->next) { - if(unlikely(!p->sortlist && !p->children_count)) - p->sortlist = sortlist++; - - if(unlikely( - !p->children_count // if this process does not have any children - && !p->merged // and is not already merged - && p->parent // and has a parent - && p->parent->children_count // and its parent has children - // and the target of this process and its parent is the same, - // or the parent does not have a target - && (p->target == p->parent->target || !p->parent->target) - && p->ppid != INIT_PID // and its parent is not init - )) { - // mark it as merged - p->parent->children_count--; - p->merged = 1; - - // the parent inherits the child's target, if it does not have a target itself - if(unlikely(p->target && !p->parent->target)) { - p->parent->target = p->target; - - if(debug || (p->target && p->target->debug)) - fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm); - } - - found++; - } - } - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found); - } - - // init goes always to default target - if(all_pids[INIT_PID]) - all_pids[INIT_PID]->target = apps_groups_default_target; - - // pid 0 goes always to default target - if(all_pids[0]) - all_pids[0]->target = apps_groups_default_target; - - // give a default target on all top level processes - if(unlikely(debug)) loops++; - for(p = root_of_pids; p ; p = p->next) { - // if the process is not merged itself - // then is is a top level process - if(unlikely(!p->merged && !p->target)) - p->target = apps_groups_default_target; - - // make sure all processes have a sortlist - if(unlikely(!p->sortlist)) - p->sortlist = sortlist++; - } - - if(all_pids[1]) - all_pids[1]->sortlist = sortlist++; - - // give a target to all merged child processes - found = 1; - while(found) { - if(unlikely(debug)) loops++; - found = 0; - for(p = root_of_pids; p ; p = p->next) { - if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) { - p->target = p->parent->target; - found++; - - if(debug || (p->target && p->target->debug)) - fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm); - } - } - } - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops); -} - -static size_t zero_all_targets(struct target *root) { - struct target *w; - size_t count = 0; - - for (w = root; w ; w = w->next) { - count++; - - w->minflt = 0; - w->majflt = 0; - w->utime = 0; - w->stime = 0; - w->gtime = 0; - w->cminflt = 0; - w->cmajflt = 0; - w->cutime = 0; - w->cstime = 0; - w->cgtime = 0; - w->num_threads = 0; - // w->rss = 0; - w->processes = 0; - - w->status_vmsize = 0; - w->status_vmrss = 0; - w->status_vmshared = 0; - w->status_rssfile = 0; - w->status_rssshmem = 0; - w->status_vmswap = 0; - - w->io_logical_bytes_read = 0; - w->io_logical_bytes_written = 0; - // w->io_read_calls = 0; - // w->io_write_calls = 0; - w->io_storage_bytes_read = 0; - w->io_storage_bytes_written = 0; - // w->io_cancelled_write_bytes = 0; - - // zero file counters - if(w->target_fds) { - memset(w->target_fds, 0, sizeof(int) * w->target_fds_size); - w->openfiles = 0; - w->openpipes = 0; - w->opensockets = 0; - w->openinotifies = 0; - w->openeventfds = 0; - w->opentimerfds = 0; - w->opensignalfds = 0; - w->openeventpolls = 0; - w->openother = 0; - } - } - - return count; -} - -static inline void reallocate_target_fds(struct target *w) { - if(unlikely(!w)) - return; - - if(unlikely(!w->target_fds || w->target_fds_size < all_files_size)) { - w->target_fds = reallocz(w->target_fds, sizeof(int) * all_files_size); - memset(&w->target_fds[w->target_fds_size], 0, sizeof(int) * (all_files_size - w->target_fds_size)); - w->target_fds_size = all_files_size; - } -} - -static inline void aggregate_fd_on_target(int fd, struct target *w) { - if(unlikely(!w)) - return; - - if(unlikely(w->target_fds[fd])) { - // it is already aggregated - // just increase its usage counter - w->target_fds[fd]++; - return; - } - - // increase its usage counter - // so that we will not add it again - w->target_fds[fd]++; - - switch(all_files[fd].type) { - case FILETYPE_FILE: - w->openfiles++; - break; - - case FILETYPE_PIPE: - w->openpipes++; - break; - - case FILETYPE_SOCKET: - w->opensockets++; - break; - - case FILETYPE_INOTIFY: - w->openinotifies++; - break; - - case FILETYPE_EVENTFD: - w->openeventfds++; - break; - - case FILETYPE_TIMERFD: - w->opentimerfds++; - break; - - case FILETYPE_SIGNALFD: - w->opensignalfds++; - break; - - case FILETYPE_EVENTPOLL: - w->openeventpolls++; - break; - - case FILETYPE_OTHER: - w->openother++; - break; - } -} - -static inline void aggregate_pid_fds_on_targets(struct pid_stat *p) { - - if(unlikely(!p->updated)) { - // the process is not running - return; - } - - struct target *w = p->target, *u = p->user_target, *g = p->group_target; - - reallocate_target_fds(w); - reallocate_target_fds(u); - reallocate_target_fds(g); - - int c, size = p->fds_size, *fds = p->fds; - for(c = 0; c < size ;c++) { - int fd = fds[c]; - - if(likely(fd <= 0 || fd >= all_files_size)) - continue; - - aggregate_fd_on_target(fd, w); - aggregate_fd_on_target(fd, u); - aggregate_fd_on_target(fd, g); - } -} - -static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) { - (void)o; - - if(unlikely(!p->updated)) { - // the process is not running - return; - } - - if(unlikely(!w)) { - error("pid %d %s was left without a target!", p->pid, p->comm); - return; - } - - w->cutime += p->cutime; - w->cstime += p->cstime; - w->cgtime += p->cgtime; - w->cminflt += p->cminflt; - w->cmajflt += p->cmajflt; - - w->utime += p->utime; - w->stime += p->stime; - w->gtime += p->gtime; - w->minflt += p->minflt; - w->majflt += p->majflt; - - // w->rss += p->rss; - - w->status_vmsize += p->status_vmsize; - w->status_vmrss += p->status_vmrss; - w->status_vmshared += p->status_vmshared; - w->status_rssfile += p->status_rssfile; - w->status_rssshmem += p->status_rssshmem; - w->status_vmswap += p->status_vmswap; - - w->io_logical_bytes_read += p->io_logical_bytes_read; - w->io_logical_bytes_written += p->io_logical_bytes_written; - // w->io_read_calls += p->io_read_calls; - // w->io_write_calls += p->io_write_calls; - w->io_storage_bytes_read += p->io_storage_bytes_read; - w->io_storage_bytes_written += p->io_storage_bytes_written; - // w->io_cancelled_write_bytes += p->io_cancelled_write_bytes; - - w->processes++; - w->num_threads += p->num_threads; - - if(unlikely(debug || w->debug)) - 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) { - - apply_apps_groups_targets_inheritance(); - - zero_all_targets(users_root_target); - zero_all_targets(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; - struct target *w = NULL, *o = NULL; - - // concentrate everything on the targets - for(p = root_of_pids; p ; p = p->next) { - - // -------------------------------------------------------------------- - // apps_groups target - - aggregate_pid_on_target(p->target, p, NULL); - - - // -------------------------------------------------------------------- - // user target - - o = p->user_target; - if(likely(p->user_target && p->user_target->uid == p->uid)) - w = p->user_target; - else { - if(unlikely(debug && p->user_target)) - fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %u (%s) to %u.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid); - - w = p->user_target = get_users_target(p->uid); - } - - aggregate_pid_on_target(w, p, o); - - - // -------------------------------------------------------------------- - // user group target - - o = p->group_target; - if(likely(p->group_target && p->group_target->gid == p->gid)) - w = p->group_target; - else { - if(unlikely(debug && p->group_target)) - fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %u (%s) to %u.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid); - - w = p->group_target = get_groups_target(p->gid); - } - - aggregate_pid_on_target(w, p, o); - - - // -------------------------------------------------------------------- - // aggregate all file descriptors - - if(enable_file_charts) - aggregate_pid_fds_on_targets(p); - } - - cleanup_exited_pids(); -} - -// ---------------------------------------------------------------------------- -// update chart dimensions - -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, usec_t usec) { - fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec); -} - -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"); -} - -void send_resource_usage_to_netdata(usec_t dt) { - static struct timeval last = { 0, 0 }; - static struct rusage me_last; - - struct timeval now; - struct rusage me; - - usec_t cpuuser; - usec_t cpusyst; - - if(!last.tv_sec) { - now_monotonic_timeval(&last); - getrusage(RUSAGE_SELF, &me_last); - - cpuuser = 0; - cpusyst = 0; - } - else { - now_monotonic_timeval(&now); - getrusage(RUSAGE_SELF, &me); - - cpuuser = me.ru_utime.tv_sec * USEC_PER_SEC + me.ru_utime.tv_usec; - cpusyst = me.ru_stime.tv_sec * USEC_PER_SEC + me.ru_stime.tv_usec; - - memmove(&last, &now, sizeof(struct timeval)); - 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" - , update_every - ); - -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) - fprintf(stdout, - "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 - ); -#endif - - } - - fprintf(stdout, - "BEGIN netdata.apps_cpu %llu\n" - "SET user = %llu\n" - "SET system = %llu\n" - "END\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 = %zu\n" - "SET new_pids = %zu\n" - "END\n" - , dt - , cpuuser - , cpusyst - , dt - , calls_counter - , file_counter - , all_pids_count - , all_files_len - , apps_groups_targets_count - , targets_assignment_counter - ); - -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) - fprintf(stdout, - "BEGIN netdata.apps_fix %llu\n" - "SET utime = %u\n" - "SET stime = %u\n" - "SET gtime = %u\n" - "SET minflt = %u\n" - "SET majflt = %u\n" - "END\n" - , dt - , (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 = %u\n" - "SET cstime = %u\n" - "SET cgtime = %u\n" - "SET cminflt = %u\n" - "SET cmajflt = %u\n" - "END\n" - , dt - , (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) - ); -#endif -} - -#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) -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. - - 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_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; - - utime += w->utime; - stime += w->stime; - gtime += w->gtime; - cutime += w->cutime; - cstime += w->cstime; - cgtime += w->cgtime; - - minflt += w->minflt; - majflt += w->majflt; - cminflt += w->cminflt; - cmajflt += w->cmajflt; - } - - if((global_utime || global_stime || global_gtime) && (utime || stime || gtime)) { - if(global_utime + global_stime + global_gtime > utime + cutime + stime + cstime + gtime + cgtime) { - // everything we collected fits - utime_fix_ratio = - stime_fix_ratio = - gtime_fix_ratio = - cutime_fix_ratio = - cstime_fix_ratio = - cgtime_fix_ratio = 1.0; //(double)(global_utime + global_stime) / (double)(utime + cutime + stime + cstime); - } - else if(global_utime + global_stime > utime + stime) { - // childrens resources are too high - // lower only the children resources - utime_fix_ratio = - stime_fix_ratio = - gtime_fix_ratio = 1.0; - cutime_fix_ratio = - cstime_fix_ratio = - cgtime_fix_ratio = (double)((global_utime + global_stime) - (utime + stime)) / (double)(cutime + cstime); - } - else { - // even running processes are unrealistic - // zero the children resources - // lower the running processes resources - utime_fix_ratio = - stime_fix_ratio = - gtime_fix_ratio = (double)(global_utime + global_stime) / (double)(utime + stime); - cutime_fix_ratio = - cstime_fix_ratio = - cgtime_fix_ratio = 0.0; - } - } - else { - utime_fix_ratio = - stime_fix_ratio = - gtime_fix_ratio = - cutime_fix_ratio = - cstime_fix_ratio = - cgtime_fix_ratio = 0.0; - } - - if(utime_fix_ratio > 1.0) utime_fix_ratio = 1.0; - if(cutime_fix_ratio > 1.0) cutime_fix_ratio = 1.0; - if(stime_fix_ratio > 1.0) stime_fix_ratio = 1.0; - if(cstime_fix_ratio > 1.0) cstime_fix_ratio = 1.0; - if(gtime_fix_ratio > 1.0) gtime_fix_ratio = 1.0; - if(cgtime_fix_ratio > 1.0) cgtime_fix_ratio = 1.0; - - // if(utime_fix_ratio < 0.0) utime_fix_ratio = 0.0; - // if(cutime_fix_ratio < 0.0) cutime_fix_ratio = 0.0; - // if(stime_fix_ratio < 0.0) stime_fix_ratio = 0.0; - // if(cstime_fix_ratio < 0.0) cstime_fix_ratio = 0.0; - // if(gtime_fix_ratio < 0.0) gtime_fix_ratio = 0.0; - // if(cgtime_fix_ratio < 0.0) cgtime_fix_ratio = 0.0; - - // FIXME - // we use cpu time to normalize page faults - // the problem is that to find the proper max values - // for page faults we have to parse /proc/vmstat - // which is quite big to do it again (netdata does it already) - // - // a better solution could be to somehow have netdata - // do this normalization for us - - if(utime || stime || gtime) - majflt_fix_ratio = - minflt_fix_ratio = (double)(utime * utime_fix_ratio + stime * stime_fix_ratio + gtime * gtime_fix_ratio) / (double)(utime + stime + gtime); - else - minflt_fix_ratio = - majflt_fix_ratio = 1.0; - - if(cutime || cstime || cgtime) - cmajflt_fix_ratio = - cminflt_fix_ratio = (double)(cutime * cutime_fix_ratio + cstime * cstime_fix_ratio + cgtime * cgtime_fix_ratio) / (double)(cutime + cstime + cgtime); - else - cminflt_fix_ratio = - cmajflt_fix_ratio = 1.0; - - // the report - - if(unlikely(debug)) { - fprintf(stderr, - "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=" 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 - , global_gtime - , utime - , stime - , gtime - , cutime - , cstime - , cgtime - , 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 - , (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) - ); - } -} -#else // ALL_PIDS_ARE_READ_INSTANTLY == 1 -static void normalize_utilization(struct target *root) { - (void)root; -} -#endif // ALL_PIDS_ARE_READ_INSTANTLY - -static void send_collected_data_to_netdata(struct target *root, const char *type, usec_t dt) { - struct target *w; - - send_BEGIN(type, "cpu", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - 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", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - 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", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - 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(); - - if(show_guest_time) { - send_BEGIN(type, "cpu_guest", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - 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(); - } - - send_BEGIN(type, "threads", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->num_threads); - } - send_END(); - - send_BEGIN(type, "processes", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->processes); - } - send_END(); - - send_BEGIN(type, "mem", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, (w->status_vmrss > w->status_vmshared)?(w->status_vmrss - w->status_vmshared):0ULL); - } - send_END(); - - send_BEGIN(type, "vmem", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->status_vmsize); - } - send_END(); - -#ifndef __FreeBSD__ - send_BEGIN(type, "swap", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->status_vmswap); - } - send_END(); -#endif - - send_BEGIN(type, "minor_faults", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - 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", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - 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", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->io_logical_bytes_read); - } - send_END(); - - send_BEGIN(type, "lwrites", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->io_logical_bytes_written); - } - send_END(); -#endif - - send_BEGIN(type, "preads", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->io_storage_bytes_read); - } - send_END(); - - send_BEGIN(type, "pwrites", dt); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - send_SET(w->name, w->io_storage_bytes_written); - } - send_END(); - - if(enable_file_charts) { - send_BEGIN(type, "files", dt); - for (w = root; w; w = w->next) { - if (unlikely(w->exposed)) - send_SET(w->name, w->openfiles); - } - send_END(); - - send_BEGIN(type, "sockets", dt); - for (w = root; w; w = w->next) { - if (unlikely(w->exposed)) - send_SET(w->name, w->opensockets); - } - send_END(); - - send_BEGIN(type, "pipes", dt); - for (w = root; w; w = w->next) { - if (unlikely(w->exposed)) - send_SET(w->name, w->openpipes); - } - send_END(); - } -} - - -// ---------------------------------------------------------------------------- -// generate the charts - -static void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title) -{ - struct target *w; - int newly_added = 0; - - for(w = root ; w ; w = w->next) { - if (w->target) continue; - - if (!w->exposed && w->processes) { - newly_added++; - w->exposed = 1; - if (debug || w->debug) fprintf(stderr, "apps.plugin: %s just added - regenerating charts.\n", w->name); - } - } - - // nothing more to show - if(!newly_added && show_guest_time == show_guest_time_old) return; - - // we have something new to show - // update the charts - fprintf(stdout, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : ""); - } - - fprintf(stdout, "CHART %s.mem '' '%s Real Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute %ld %ld\n", w->name, 1L, 1024L); - } - - fprintf(stdout, "CHART %s.vmem '' '%s Virtual Memory Size' 'MB' mem %s.vmem stacked 20005 %d\n", type, title, type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute %ld %ld\n", w->name, 1L, 1024L); - } - - fprintf(stdout, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20006 %d\n", type, title, type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name); - } - - fprintf(stdout, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20007 %d\n", type, title, type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name); - } - - fprintf(stdout, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU); - } - - fprintf(stdout, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU); - } - - if(show_guest_time) { - fprintf(stdout, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every); - for (w = root; w; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU); - } - } - -#ifndef __FreeBSD__ - fprintf(stdout, "CHART %s.swap '' '%s Swap Memory' 'MB' swap %s.swap stacked 20011 %d\n", type, title, type, update_every); - for (w = root; w ; w = w->next) { - if(unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute %ld %ld\n", w->name, 1L, 1024L); - } -#endif - - fprintf(stdout, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20012 %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.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %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); - } - -#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.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.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.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, - title, type, update_every); - for (w = root; w; w = w->next) { - if (unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name); - } - - fprintf(stdout, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", - type, title, type, update_every); - for (w = root; w; w = w->next) { - if (unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name); - } - - fprintf(stdout, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, - title, type, update_every); - for (w = root; w; w = w->next) { - if (unlikely(w->exposed)) - fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name); - } - } -} - - -// ---------------------------------------------------------------------------- -// 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; - char *name = NULL; - - for(i = 1; i < argc; i++) { - if(!freq) { - int n = (int)str2l(argv[i]); - if(n > 0) { - freq = n; - continue; - } - } - - if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) { - printf("apps.plugin %s\n", VERSION); - exit(0); - } - - 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; - continue; - } - - if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) { - include_exited_childs = 0; - continue; - } - - if(strcmp("with-childs", argv[i]) == 0) { - include_exited_childs = 1; - continue; - } - - if(strcmp("with-guest", argv[i]) == 0) { - enable_guest_charts = 1; - continue; - } - - if(strcmp("no-guest", argv[i]) == 0 || strcmp("without-guest", argv[i]) == 0) { - enable_guest_charts = 0; - continue; - } - - if(strcmp("with-files", argv[i]) == 0) { - enable_file_charts = 1; - continue; - } - - if(strcmp("no-files", argv[i]) == 0 || strcmp("without-files", argv[i]) == 0) { - enable_file_charts = 0; - continue; - } - - if(strcmp("no-users", argv[i]) == 0 || strcmp("without-users", argv[i]) == 0) { - enable_users_charts = 0; - continue; - } - - if(strcmp("no-groups", argv[i]) == 0 || strcmp("without-groups", argv[i]) == 0) { - enable_groups_charts = 0; - continue; - } - - if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) { - fprintf(stderr, - "\n" - " netdata apps.plugin %s\n" - " Copyright (C) 2016-2017 Costa Tsaousis \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 set the data collection frequency\n" - "\n" - " debug enable debugging (lot of output)\n" - "\n" - " with-childs\n" - " without-childs enable / disable aggregating exited\n" - " children resources into parents\n" - " (default is enabled)\n" - "\n" - " with-guest\n" - " without-guest enable / disable reporting guest charts\n" - " (default is disabled)\n" - "\n" - " with-files\n" - " without-files enable / disable reporting files, sockets, pipes\n" - " (default is enabled)\n" - "\n" - " NAME read apps_NAME.conf instead of\n" - " apps_groups.conf\n" - " (default NAME=groups)\n" - "\n" - " version or -v or -V print program version and exit\n" - "\n" - , VERSION - ); - exit(1); - } - - if(!name) { - name = argv[i]; - continue; - } - - error("Cannot understand option %s", argv[i]); - exit(1); - } - - if(freq > 0) update_every = freq; - if(!name) name = "groups"; - - if(read_apps_groups_conf(name)) { - error("Cannot read process groups '%s/apps_%s.conf'. There are no internal defaults. Failing.", config_dir, name); - exit(1); - } -} - -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; - - pagesize = (size_t)sysconf(_SC_PAGESIZE); - - // set the name for logging - program_name = "apps.plugin"; - - // disable syslog for apps.plugin - error_log_syslog = 0; - - // set errors flood protection to 100 logs per hour - error_log_errors_per_period = 100; - error_log_throttle_period = 3600; - - netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX"); - if(netdata_configured_host_prefix == NULL) { - // info("NETDATA_HOST_PREFIX is not passed from netdata"); - netdata_configured_host_prefix = ""; - } - // else info("Found NETDATA_HOST_PREFIX='%s'", netdata_configured_host_prefix); - - config_dir = getenv("NETDATA_CONFIG_DIR"); - if(config_dir == NULL) { - // info("NETDATA_CONFIG_DIR is not passed from netdata"); - config_dir = CONFIG_DIR; - } - // else info("Found NETDATA_CONFIG_DIR='%s'", config_dir); - -#ifdef NETDATA_INTERNAL_CHECKS - if(debug_flags != 0) { - 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_monotonic_sec(); - get_system_HZ(); - get_system_pid_max(); - get_system_cpus(); - - parse_args(argc, argv); - - 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 - } - - 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++) { - -#ifdef NETDATA_PROFILING -#warning "compiling for profiling" - static int profiling_count=0; - profiling_count++; - if(unlikely(profiling_count > 2000)) exit(0); - usec_t dt = update_every * USEC_PER_SEC; -#else - usec_t dt = heartbeat_next(&hb, step); -#endif - - 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_utilization(apps_groups_root_target); - - send_resource_usage_to_netdata(dt); - - // this is smart enough to show only newly added apps, when needed - send_charts_updates_to_netdata(apps_groups_root_target, "apps", "Apps"); - - if(likely(enable_users_charts)) - send_charts_updates_to_netdata(users_root_target, "users", "Users"); - - if(likely(enable_groups_charts)) - send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups"); - - send_collected_data_to_netdata(apps_groups_root_target, "apps", dt); - - if(likely(enable_users_charts)) - send_collected_data_to_netdata(users_root_target, "users", dt); - - if(likely(enable_groups_charts)) - send_collected_data_to_netdata(groups_root_target, "groups", dt); - - fflush(stdout); - - show_guest_time_old = show_guest_time; - - if(unlikely(debug)) - fprintf(stderr, "apps.plugin: done Loop No %zu\n", global_iterations_counter); - - // restart check (14400 seconds) - if(now_monotonic_sec() - started_t > 14400) exit(0); - } -} diff --git a/src/avl.c b/src/avl.c deleted file mode 100644 index a2c6911e7..000000000 --- a/src/avl.c +++ /dev/null @@ -1,403 +0,0 @@ -#include "common.h" - -/* ------------------------------------------------------------------------- */ -/* - * avl_insert(), avl_remove() and avl_search() - * are adaptations (by Costa Tsaousis) of the AVL algorithm found in libavl - * v2.0.3, so that they do not use any memory allocations and their memory - * footprint is optimized (by eliminating non-necessary data members). - * - * libavl - library for manipulation of binary trees. - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software - * Foundation, Inc. - * GNU Lesser General Public License -*/ - - -/* Search |tree| for an item matching |item|, and return it if found. - Otherwise return |NULL|. */ -avl *avl_search(avl_tree *tree, avl *item) { - avl *p; - - // assert (tree != NULL && item != NULL); - - for (p = tree->root; p != NULL; ) { - int cmp = tree->compar(item, p); - - if (cmp < 0) - p = p->avl_link[0]; - else if (cmp > 0) - p = p->avl_link[1]; - else /* |cmp == 0| */ - return p; - } - - return NULL; -} - -/* Inserts |item| into |tree| and returns a pointer to |item|'s address. - If a duplicate item is found in the tree, - returns a pointer to the duplicate without inserting |item|. - */ -avl *avl_insert(avl_tree *tree, avl *item) { - avl *y, *z; /* Top node to update balance factor, and parent. */ - avl *p, *q; /* Iterator, and parent. */ - avl *n; /* Newly inserted node. */ - avl *w; /* New root of rebalanced subtree. */ - int dir; /* Direction to descend. */ - - unsigned char da[AVL_MAX_HEIGHT]; /* Cached comparison results. */ - int k = 0; /* Number of cached results. */ - - // assert(tree != NULL && item != NULL); - - z = (avl *) &tree->root; - y = tree->root; - dir = 0; - for (q = z, p = y; p != NULL; q = p, p = p->avl_link[dir]) { - int cmp = tree->compar(item, p); - if (cmp == 0) - return p; - - if (p->avl_balance != 0) - z = q, y = p, k = 0; - da[k++] = dir = (cmp > 0); - } - - n = q->avl_link[dir] = item; - - // tree->avl_count++; - n->avl_link[0] = n->avl_link[1] = NULL; - n->avl_balance = 0; - if (y == NULL) return n; - - for (p = y, k = 0; p != n; p = p->avl_link[da[k]], k++) - if (da[k] == 0) - p->avl_balance--; - else - p->avl_balance++; - - if (y->avl_balance == -2) { - avl *x = y->avl_link[0]; - if (x->avl_balance == -1) { - w = x; - y->avl_link[0] = x->avl_link[1]; - x->avl_link[1] = y; - x->avl_balance = y->avl_balance = 0; - } - else { - // assert (x->avl_balance == +1); - w = x->avl_link[1]; - x->avl_link[1] = w->avl_link[0]; - w->avl_link[0] = x; - y->avl_link[0] = w->avl_link[1]; - w->avl_link[1] = y; - if (w->avl_balance == -1) - x->avl_balance = 0, y->avl_balance = +1; - else if (w->avl_balance == 0) - x->avl_balance = y->avl_balance = 0; - else /* |w->avl_balance == +1| */ - x->avl_balance = -1, y->avl_balance = 0; - w->avl_balance = 0; - } - } - else if (y->avl_balance == +2) { - avl *x = y->avl_link[1]; - if (x->avl_balance == +1) { - w = x; - y->avl_link[1] = x->avl_link[0]; - x->avl_link[0] = y; - x->avl_balance = y->avl_balance = 0; - } - else { - // assert (x->avl_balance == -1); - w = x->avl_link[0]; - x->avl_link[0] = w->avl_link[1]; - w->avl_link[1] = x; - y->avl_link[1] = w->avl_link[0]; - w->avl_link[0] = y; - if (w->avl_balance == +1) - x->avl_balance = 0, y->avl_balance = -1; - else if (w->avl_balance == 0) - x->avl_balance = y->avl_balance = 0; - else /* |w->avl_balance == -1| */ - x->avl_balance = +1, y->avl_balance = 0; - w->avl_balance = 0; - } - } - else return n; - - z->avl_link[y != z->avl_link[0]] = w; - - // tree->avl_generation++; - return n; -} - -/* Deletes from |tree| and returns an item matching |item|. - Returns a null pointer if no matching item found. */ -avl *avl_remove(avl_tree *tree, avl *item) { - /* Stack of nodes. */ - avl *pa[AVL_MAX_HEIGHT]; /* Nodes. */ - unsigned char da[AVL_MAX_HEIGHT]; /* |avl_link[]| indexes. */ - int k; /* Stack pointer. */ - - avl *p; /* Traverses tree to find node to delete. */ - int cmp; /* Result of comparison between |item| and |p|. */ - - // assert (tree != NULL && item != NULL); - - k = 0; - p = (avl *) &tree->root; - for(cmp = -1; cmp != 0; cmp = tree->compar(item, p)) { - int dir = (cmp > 0); - - pa[k] = p; - da[k++] = dir; - - p = p->avl_link[dir]; - if(p == NULL) return NULL; - } - - item = p; - - if (p->avl_link[1] == NULL) - pa[k - 1]->avl_link[da[k - 1]] = p->avl_link[0]; - else { - avl *r = p->avl_link[1]; - if (r->avl_link[0] == NULL) { - r->avl_link[0] = p->avl_link[0]; - r->avl_balance = p->avl_balance; - pa[k - 1]->avl_link[da[k - 1]] = r; - da[k] = 1; - pa[k++] = r; - } - else { - avl *s; - int j = k++; - - for (;;) { - da[k] = 0; - pa[k++] = r; - s = r->avl_link[0]; - if (s->avl_link[0] == NULL) break; - - r = s; - } - - s->avl_link[0] = p->avl_link[0]; - r->avl_link[0] = s->avl_link[1]; - s->avl_link[1] = p->avl_link[1]; - s->avl_balance = p->avl_balance; - - pa[j - 1]->avl_link[da[j - 1]] = s; - da[j] = 1; - pa[j] = s; - } - } - - // assert (k > 0); - while (--k > 0) { - avl *y = pa[k]; - - if (da[k] == 0) { - y->avl_balance++; - if (y->avl_balance == +1) break; - else if (y->avl_balance == +2) { - avl *x = y->avl_link[1]; - if (x->avl_balance == -1) { - avl *w; - // assert (x->avl_balance == -1); - w = x->avl_link[0]; - x->avl_link[0] = w->avl_link[1]; - w->avl_link[1] = x; - y->avl_link[1] = w->avl_link[0]; - w->avl_link[0] = y; - if (w->avl_balance == +1) - x->avl_balance = 0, y->avl_balance = -1; - else if (w->avl_balance == 0) - x->avl_balance = y->avl_balance = 0; - else /* |w->avl_balance == -1| */ - x->avl_balance = +1, y->avl_balance = 0; - w->avl_balance = 0; - pa[k - 1]->avl_link[da[k - 1]] = w; - } - else { - y->avl_link[1] = x->avl_link[0]; - x->avl_link[0] = y; - pa[k - 1]->avl_link[da[k - 1]] = x; - if (x->avl_balance == 0) { - x->avl_balance = -1; - y->avl_balance = +1; - break; - } - else x->avl_balance = y->avl_balance = 0; - } - } - } - else - { - y->avl_balance--; - if (y->avl_balance == -1) break; - else if (y->avl_balance == -2) { - avl *x = y->avl_link[0]; - if (x->avl_balance == +1) { - avl *w; - // assert (x->avl_balance == +1); - w = x->avl_link[1]; - x->avl_link[1] = w->avl_link[0]; - w->avl_link[0] = x; - y->avl_link[0] = w->avl_link[1]; - w->avl_link[1] = y; - if (w->avl_balance == -1) - x->avl_balance = 0, y->avl_balance = +1; - else if (w->avl_balance == 0) - x->avl_balance = y->avl_balance = 0; - else /* |w->avl_balance == +1| */ - x->avl_balance = -1, y->avl_balance = 0; - w->avl_balance = 0; - pa[k - 1]->avl_link[da[k - 1]] = w; - } - else { - y->avl_link[0] = x->avl_link[1]; - x->avl_link[1] = y; - pa[k - 1]->avl_link[da[k - 1]] = x; - if (x->avl_balance == 0) { - x->avl_balance = +1; - y->avl_balance = -1; - break; - } - else x->avl_balance = y->avl_balance = 0; - } - } - } - } - - // tree->avl_count--; - // tree->avl_generation++; - return item; -} - -/* ------------------------------------------------------------------------- */ -// below are functions by (C) Costa Tsaousis - -// --------------------------- -// traversing - -int avl_walker(avl *node, int (*callback)(void *entry, void *data), void *data) { - int total = 0, ret = 0; - - if(node->avl_link[0]) { - ret = avl_walker(node->avl_link[0], callback, data); - if(ret < 0) return ret; - total += ret; - } - - ret = callback(node, data); - if(ret < 0) return ret; - total += ret; - - if(node->avl_link[1]) { - ret = avl_walker(node->avl_link[1], callback, data); - if (ret < 0) return ret; - total += ret; - } - - return total; -} - -int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data) { - if(t->root) - return avl_walker(t->root, callback, data); - else - return 0; -} - -// --------------------------- -// locks - -void avl_read_lock(avl_tree_lock *t) { -#ifndef AVL_WITHOUT_PTHREADS -#ifdef AVL_LOCK_WITH_MUTEX - netdata_mutex_lock(&t->mutex); -#else - netdata_rwlock_rdlock(&t->rwlock); -#endif -#endif /* AVL_WITHOUT_PTHREADS */ -} - -void avl_write_lock(avl_tree_lock *t) { -#ifndef AVL_WITHOUT_PTHREADS -#ifdef AVL_LOCK_WITH_MUTEX - netdata_mutex_lock(&t->mutex); -#else - netdata_rwlock_wrlock(&t->rwlock); -#endif -#endif /* AVL_WITHOUT_PTHREADS */ -} - -void avl_unlock(avl_tree_lock *t) { -#ifndef AVL_WITHOUT_PTHREADS -#ifdef AVL_LOCK_WITH_MUTEX - netdata_mutex_unlock(&t->mutex); -#else - netdata_rwlock_unlock(&t->rwlock); -#endif -#endif /* AVL_WITHOUT_PTHREADS */ -} - -// --------------------------- -// operations with locking - -void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) { - avl_init(&t->avl_tree, compar); - -#ifndef AVL_WITHOUT_PTHREADS - int lock; - -#ifdef AVL_LOCK_WITH_MUTEX - lock = netdata_mutex_init(&t->mutex, NULL); -#else - lock = netdata_rwlock_init(&t->rwlock); -#endif - - if(lock != 0) - fatal("Failed to initialize AVL mutex/rwlock, error: %d", lock); - -#endif /* AVL_WITHOUT_PTHREADS */ -} - -avl *avl_search_lock(avl_tree_lock *t, avl *a) { - avl_read_lock(t); - avl *ret = avl_search(&t->avl_tree, a); - avl_unlock(t); - return ret; -} - -avl * avl_remove_lock(avl_tree_lock *t, avl *a) { - avl_write_lock(t); - avl *ret = avl_remove(&t->avl_tree, a); - avl_unlock(t); - return ret; -} - -avl *avl_insert_lock(avl_tree_lock *t, avl *a) { - avl_write_lock(t); - avl * ret = avl_insert(&t->avl_tree, a); - avl_unlock(t); - return ret; -} - -int avl_traverse_lock(avl_tree_lock *t, int (*callback)(void *entry, void *data), void *data) { - int ret; - avl_read_lock(t); - ret = avl_traverse(&t->avl_tree, callback, data); - avl_unlock(t); - return ret; -} - -void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) { - t->root = NULL; - t->compar = compar; -} - -// ------------------ \ No newline at end of file diff --git a/src/avl.h b/src/avl.h deleted file mode 100644 index 19648cd1d..000000000 --- a/src/avl.h +++ /dev/null @@ -1,86 +0,0 @@ - -#ifndef _AVL_H -#define _AVL_H 1 - -/* Maximum AVL tree height. */ -#ifndef AVL_MAX_HEIGHT -#define AVL_MAX_HEIGHT 92 -#endif - -#ifndef AVL_WITHOUT_PTHREADS -#include - -// #define AVL_LOCK_WITH_MUTEX 1 - -#ifdef AVL_LOCK_WITH_MUTEX -#define AVL_LOCK_INITIALIZER NETDATA_MUTEX_INITIALIZER -#else /* AVL_LOCK_WITH_MUTEX */ -#define AVL_LOCK_INITIALIZER NETDATA_RWLOCK_INITIALIZER -#endif /* AVL_LOCK_WITH_MUTEX */ - -#else /* AVL_WITHOUT_PTHREADS */ -#define AVL_LOCK_INITIALIZER -#endif /* AVL_WITHOUT_PTHREADS */ - -/* Data structures */ - -/* One element of the AVL tree */ -typedef struct avl { - struct avl *avl_link[2]; /* Subtrees. */ - signed char avl_balance; /* Balance factor. */ -} avl; - -/* An AVL tree */ -typedef struct avl_tree { - avl *root; - int (*compar)(void *a, void *b); -} avl_tree; - -typedef struct avl_tree_lock { - avl_tree avl_tree; - -#ifndef AVL_WITHOUT_PTHREADS -#ifdef AVL_LOCK_WITH_MUTEX - netdata_mutex_t mutex; -#else /* AVL_LOCK_WITH_MUTEX */ - netdata_rwlock_t rwlock; -#endif /* AVL_LOCK_WITH_MUTEX */ -#endif /* AVL_WITHOUT_PTHREADS */ -} avl_tree_lock; - -/* Public methods */ - -/* Insert element a into the AVL tree t - * returns the added element a, or a pointer the - * element that is equal to a (as returned by t->compar()) - * a is linked directly to the tree, so it has to - * be properly allocated by the caller. - */ -avl *avl_insert_lock(avl_tree_lock *t, avl *a) NEVERNULL WARNUNUSED; -avl *avl_insert(avl_tree *t, avl *a) NEVERNULL WARNUNUSED; - -/* Remove an element a from the AVL tree t - * returns a pointer to the removed element - * or NULL if an element equal to a is not found - * (equal as returned by t->compar()) - */ -avl *avl_remove_lock(avl_tree_lock *t, avl *a) WARNUNUSED; -avl *avl_remove(avl_tree *t, avl *a) WARNUNUSED; - -/* Find the element into the tree that equal to a - * (equal as returned by t->compar()) - * returns NULL is no element is equal to a - */ -avl *avl_search_lock(avl_tree_lock *t, avl *a); -avl *avl_search(avl_tree *t, avl *a); - -/* Initialize the avl_tree_lock - */ -void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)); -void avl_init(avl_tree *t, int (*compar)(void *a, void *b)); - - -int avl_traverse_lock(avl_tree_lock *t, int (*callback)(void *entry, void *data), void *data); -int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data); - -#endif /* avl.h */ diff --git a/src/backend_prometheus.c b/src/backend_prometheus.c deleted file mode 100644 index bfcda9297..000000000 --- a/src/backend_prometheus.c +++ /dev/null @@ -1,479 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// PROMETHEUS -// /api/v1/allmetrics?format=prometheus and /api/v1/allmetrics?format=prometheus_all_hosts - -static struct prometheus_server { - const char *server; - uint32_t hash; - RRDHOST *host; - time_t last_access; - struct prometheus_server *next; -} *prometheus_server_root = NULL; - -static inline time_t prometheus_server_last_access(const char *server, RRDHOST *host, time_t now) { - static netdata_mutex_t prometheus_server_root_mutex = NETDATA_MUTEX_INITIALIZER; - - uint32_t hash = simple_hash(server); - - netdata_mutex_lock(&prometheus_server_root_mutex); - - struct prometheus_server *ps; - for(ps = prometheus_server_root; ps ;ps = ps->next) { - if (host == ps->host && hash == ps->hash && !strcmp(server, ps->server)) { - time_t last = ps->last_access; - ps->last_access = now; - netdata_mutex_unlock(&prometheus_server_root_mutex); - return last; - } - } - - ps = callocz(1, sizeof(struct prometheus_server)); - ps->server = strdupz(server); - ps->hash = hash; - ps->host = host; - ps->last_access = now; - ps->next = prometheus_server_root; - prometheus_server_root = ps; - - netdata_mutex_unlock(&prometheus_server_root_mutex); - return 0; -} - -static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable) { - size_t n; - - for(n = 0; *s && n < usable ; d++, s++, n++) { - register char c = *s; - - if(!isalnum(c)) *d = '_'; - else *d = c; - } - *d = '\0'; - - return n; -} - -static inline size_t prometheus_label_copy(char *d, const char *s, size_t usable) { - size_t n; - - // make sure we can escape one character without overflowing the buffer - usable--; - - for(n = 0; *s && n < usable ; d++, s++, n++) { - register char c = *s; - - if(unlikely(c == '"' || c == '\\' || c == '\n')) { - *d++ = '\\'; - n++; - } - *d = c; - } - *d = '\0'; - - return n; -} - -static inline char *prometheus_units_copy(char *d, const char *s, size_t usable) { - const char *sorig = s; - char *ret = d; - size_t n; - - *d++ = '_'; - for(n = 1; *s && n < usable ; d++, s++, n++) { - register char c = *s; - - if(!isalnum(c)) *d = '_'; - else *d = c; - } - - if(n == 2 && sorig[0] == '%') { - n = 0; - d = ret; - s = "_percent"; - for( ; *s && n < usable ; n++) *d++ = *s++; - } - else if(n > 3 && sorig[n-3] == '/' && sorig[n-2] == 's') { - n = n - 2; - d -= 2; - s = "_persec"; - for( ; *s && n < usable ; n++) *d++ = *s++; - } - - *d = '\0'; - - return ret; -} - - -#define PROMETHEUS_ELEMENT_MAX 256 -#define PROMETHEUS_LABELS_MAX 1024 - -static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb, const char *prefix, uint32_t options, time_t after, time_t before, int allhosts, int help, int types, int names, int timestamps) { - rrdhost_rdlock(host); - - char hostname[PROMETHEUS_ELEMENT_MAX + 1]; - prometheus_label_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX); - - char labels[PROMETHEUS_LABELS_MAX + 1] = ""; - if(allhosts) { - if(timestamps) - buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS); - else - buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n", hostname, host->program_name, host->program_version); - - if(host->tags && *(host->tags)) { - if(timestamps) { - buffer_sprintf(wb, "netdata_host_tags_info{instance=\"%s\",%s} 1 %llu\n", hostname, host->tags, now_realtime_usec() / USEC_PER_MS); - - // deprecated, exists only for compatibility with older queries - buffer_sprintf(wb, "netdata_host_tags{instance=\"%s\",%s} 1 %llu\n", hostname, host->tags, now_realtime_usec() / USEC_PER_MS); - } - else { - buffer_sprintf(wb, "netdata_host_tags_info{instance=\"%s\",%s} 1\n", hostname, host->tags); - - // deprecated, exists only for compatibility with older queries - buffer_sprintf(wb, "netdata_host_tags{instance=\"%s\",%s} 1\n", hostname, host->tags); - } - - } - - snprintfz(labels, PROMETHEUS_LABELS_MAX, ",instance=\"%s\"", hostname); - } - else { - if(timestamps) - buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS); - else - buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n", hostname, host->program_name, host->program_version); - - if(host->tags && *(host->tags)) { - if(timestamps) { - buffer_sprintf(wb, "netdata_host_tags_info{%s} 1 %llu\n", host->tags, now_realtime_usec() / USEC_PER_MS); - - // deprecated, exists only for compatibility with older queries - buffer_sprintf(wb, "netdata_host_tags{%s} 1 %llu\n", host->tags, now_realtime_usec() / USEC_PER_MS); - } - else { - buffer_sprintf(wb, "netdata_host_tags_info{%s} 1\n", host->tags); - - // deprecated, exists only for compatibility with older queries - buffer_sprintf(wb, "netdata_host_tags{%s} 1\n", host->tags); - } - } - } - - // for each chart - RRDSET *st; - rrdset_foreach_read(st, host) { - char chart[PROMETHEUS_ELEMENT_MAX + 1]; - char context[PROMETHEUS_ELEMENT_MAX + 1]; - char family[PROMETHEUS_ELEMENT_MAX + 1]; - char units[PROMETHEUS_ELEMENT_MAX + 1] = ""; - - prometheus_label_copy(chart, (names && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX); - prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX); - prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX); - - if(likely(backends_can_send_rrdset(options, st))) { - rrdset_rdlock(st); - - int as_collected = ((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AS_COLLECTED); - int homogeneus = 1; - if(as_collected) { - if(rrdset_flag_check(st, RRDSET_FLAG_HOMEGENEOUS_CHECK)) - rrdset_update_heterogeneous_flag(st); - - if(rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS)) - homogeneus = 0; - } - else { - if((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AVERAGE) - prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX); - } - - if(unlikely(help)) - buffer_sprintf(wb, "\n# COMMENT %s chart \"%s\", context \"%s\", family \"%s\", units \"%s\"\n" - , (homogeneus)?"homogeneus":"heterogeneous" - , (names && st->name) ? st->name : st->id - , st->context - , st->family - , st->units - ); - - // for each dimension - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - if(rd->collections_counter) { - char dimension[PROMETHEUS_ELEMENT_MAX + 1]; - char *suffix = ""; - - if (as_collected) { - // we need as-collected / raw data - - const char *t = "gauge", *h = "gives"; - if(rd->algorithm == RRD_ALGORITHM_INCREMENTAL || - rd->algorithm == RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL) { - t = "counter"; - h = "delta gives"; - suffix = "_total"; - } - - if(homogeneus) { - // all the dimensions of the chart, has the same algorithm, multiplier and divisor - // we add all dimensions as labels - - prometheus_label_copy(dimension, (names && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX); - - if(unlikely(help)) - buffer_sprintf(wb - , "# COMMENT %s_%s%s: chart \"%s\", context \"%s\", family \"%s\", dimension \"%s\", value * " COLLECTED_NUMBER_FORMAT " / " COLLECTED_NUMBER_FORMAT " %s %s (%s)\n" - , prefix - , context - , suffix - , (names && st->name) ? st->name : st->id - , st->context - , st->family - , (names && rd->name) ? rd->name : rd->id - , rd->multiplier - , rd->divisor - , h - , st->units - , t - ); - - if(unlikely(types)) - buffer_sprintf(wb, "# COMMENT TYPE %s_%s%s %s\n" - , prefix - , context - , suffix - , t - ); - - if(timestamps) - buffer_sprintf(wb - , "%s_%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " COLLECTED_NUMBER_FORMAT " %llu\n" - , prefix - , context - , suffix - , chart - , family - , dimension - , labels - , rd->last_collected_value - , timeval_msec(&rd->last_collected_time) - ); - else - buffer_sprintf(wb - , "%s_%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " COLLECTED_NUMBER_FORMAT "\n" - , prefix - , context - , suffix - , chart - , family - , dimension - , labels - , rd->last_collected_value - ); - } - else { - // the dimensions of the chart, do not have the same algorithm, multiplier or divisor - // we create a metric per dimension - - prometheus_name_copy(dimension, (names && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX); - - if(unlikely(help)) - buffer_sprintf(wb - , "# COMMENT %s_%s_%s%s: chart \"%s\", context \"%s\", family \"%s\", dimension \"%s\", value * " COLLECTED_NUMBER_FORMAT " / " COLLECTED_NUMBER_FORMAT " %s %s (%s)\n" - , prefix - , context - , dimension - , suffix - , (names && st->name) ? st->name : st->id - , st->context - , st->family - , (names && rd->name) ? rd->name : rd->id - , rd->multiplier - , rd->divisor - , h - , st->units - , t - ); - - if(unlikely(types)) - buffer_sprintf(wb, "# COMMENT TYPE %s_%s_%s%s %s\n" - , prefix - , context - , dimension - , suffix - , t - ); - - if(timestamps) - buffer_sprintf(wb - , "%s_%s_%s%s{chart=\"%s\",family=\"%s\"%s} " COLLECTED_NUMBER_FORMAT " %llu\n" - , prefix - , context - , dimension - , suffix - , chart - , family - , labels - , rd->last_collected_value - , timeval_msec(&rd->last_collected_time) - ); - else - buffer_sprintf(wb - , "%s_%s_%s%s{chart=\"%s\",family=\"%s\"%s} " COLLECTED_NUMBER_FORMAT "\n" - , prefix - , context - , dimension - , suffix - , chart - , family - , labels - , rd->last_collected_value - ); - } - } - else { - // we need average or sum of the data - - time_t first_t = after, last_t = before; - calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options, &first_t, &last_t); - - if(!isnan(value) && !isinf(value)) { - - if((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AVERAGE) - suffix = "_average"; - else if((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_SUM) - suffix = "_sum"; - - prometheus_label_copy(dimension, (names && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX); - - if (unlikely(help)) - buffer_sprintf(wb, "# COMMENT %s_%s%s%s: dimension \"%s\", value is %s, gauge, dt %llu to %llu inclusive\n" - , prefix - , context - , units - , suffix - , (names && rd->name) ? rd->name : rd->id - , st->units - , (unsigned long long)first_t - , (unsigned long long)last_t - ); - - if (unlikely(types)) - buffer_sprintf(wb, "# COMMENT TYPE %s_%s%s%s gauge\n" - , prefix - , context - , units - , suffix - ); - - if(timestamps) - buffer_sprintf(wb, "%s_%s%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " CALCULATED_NUMBER_FORMAT " %llu\n" - , prefix - , context - , units - , suffix - , chart - , family - , dimension - , labels - , value - , last_t * MSEC_PER_SEC - ); - else - buffer_sprintf(wb, "%s_%s%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " CALCULATED_NUMBER_FORMAT "\n" - , prefix - , context - , units - , suffix - , chart - , family - , dimension - , labels - , value - ); - } - } - } - } - - rrdset_unlock(st); - } - } - - rrdhost_unlock(host); -} - -static inline time_t prometheus_preparation(RRDHOST *host, BUFFER *wb, uint32_t options, const char *server, time_t now, int help) { - if(!server || !*server) server = "default"; - - time_t after = prometheus_server_last_access(server, host, now); - - int first_seen = 0; - if(!after) { - after = now - backend_update_every; - first_seen = 1; - } - - if(after > now) { - // oops! this should never happen - after = now - backend_update_every; - } - - if(help) { - int show_range = 1; - char *mode; - if((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AS_COLLECTED) { - mode = "as collected"; - show_range = 0; - } - else if((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AVERAGE) - mode = "average"; - else if((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_SUM) - mode = "sum"; - else - mode = "unknown"; - - buffer_sprintf(wb, "# COMMENT netdata \"%s\" to %sprometheus \"%s\", source \"%s\", last seen %lu %s" - , host->hostname - , (first_seen)?"FIRST SEEN ":"" - , server - , mode - , (unsigned long)((first_seen)?0:(now - after)) - , (first_seen)?"never":"seconds ago" - ); - - if(show_range) - buffer_sprintf(wb, ", time range %lu to %lu", (unsigned long)after, (unsigned long)now); - - buffer_strcat(wb, "\n\n"); - } - - return after; -} - -void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, uint32_t options, int help, int types, int names, int timestamps) { - time_t before = now_realtime_sec(); - - // we start at the point we had stopped before - time_t after = prometheus_preparation(host, wb, options, server, before, help); - - rrd_stats_api_v1_charts_allmetrics_prometheus(host, wb, prefix, options, after, before, 0, help, types, names, timestamps); -} - -void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, uint32_t options, int help, int types, int names, int timestamps) { - time_t before = now_realtime_sec(); - - // we start at the point we had stopped before - time_t after = prometheus_preparation(host, wb, options, server, before, help); - - rrd_rdlock(); - rrdhost_foreach_read(host) { - rrd_stats_api_v1_charts_allmetrics_prometheus(host, wb, prefix, options, after, before, 1, help, types, names, timestamps); - } - rrd_unlock(); -} diff --git a/src/backend_prometheus.h b/src/backend_prometheus.h deleted file mode 100644 index b1a021baa..000000000 --- a/src/backend_prometheus.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by costa on 09/07/17. -// - -#ifndef NETDATA_BACKEND_PROMETHEUS_H -#define NETDATA_BACKEND_PROMETHEUS_H - -extern void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, uint32_t options, int help, int types, int names, int timestamps); -extern void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, uint32_t options, int help, int types, int names, int timestamps); - -#endif //NETDATA_BACKEND_PROMETHEUS_H diff --git a/src/backends.c b/src/backends.c deleted file mode 100644 index 1360638f2..000000000 --- a/src/backends.c +++ /dev/null @@ -1,969 +0,0 @@ -#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. -// - -const char *backend_prefix = "netdata"; -int backend_send_names = 1; -int backend_update_every = 10; -uint32_t backend_options = BACKEND_SOURCE_DATA_AVERAGE; - -// ---------------------------------------------------------------------------- -// helper functions for backends - -static inline size_t backend_name_copy(char *d, const char *s, size_t usable) { - size_t n; - - for(n = 0; *s && n < usable ; d++, s++, n++) { - char c = *s; - - if(c != '.' && !isalnum(c)) *d = '_'; - else *d = c; - } - *d = '\0'; - - return n; -} - -// 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 - -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 - , time_t *first_timestamp // the first point of the database used in this response - , time_t *last_timestamp // the timestamp that should be reported to backend -) { - RRDHOST *host = st->rrdhost; - - // 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 update_every = st->update_every; - - // step back a little, to make sure we have complete data collection - // for all metrics - after -= update_every * 2; - before -= update_every * 2; - - // align the time-frame - after = after - (after % update_every); - before = before - (before % update_every); - - // for before, loose another iteration - // the latest point will be reported the next time - before -= update_every; - - if(unlikely(after > before)) - // this can happen when update_every > before - after - after = before; - - if(unlikely(after < first_t)) - after = first_t; - - if(unlikely(before > last_t)) - before = last_t; - - if(unlikely(before < first_t || after > last_t)) { - // the chart has not been updated in the wanted timeframe - debug(D_BACKEND, "BACKEND: %s.%s.%s: aligned timeframe %lu to %lu is outside the chart's database range %lu to %lu", - host->hostname, st->id, rd->id, - (unsigned long)after, (unsigned long)before, - (unsigned long)first_t, (unsigned long)last_t - ); - return NAN; - } - - *first_timestamp = after; - *last_timestamp = before; - - size_t counter = 0; - calculated_number sum = 0; - - long start_at_slot = rrdset_time2slot(st, before), - stop_at_slot = rrdset_time2slot(st, after), - 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))) { - // not collected - continue; - } - - calculated_number value = unpack_storage_number(n); - sum += value; - - counter++; - } - - if(unlikely(!counter)) { - debug(D_BACKEND, "BACKEND: %s.%s.%s: no values stored in database for range %lu to %lu", - host->hostname, st->id, rd->id, - (unsigned long)after, (unsigned long)before - ); - return NAN; - } - - if(unlikely((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_SUM)) - return sum; - - return sum / (calculated_number)counter; -} - - -// 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("BACKEND: 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; - - char chart_name[RRD_ID_LENGTH_MAX + 1]; - char dimension_name[RRD_ID_LENGTH_MAX + 1]; - backend_name_copy(chart_name, (backend_send_names && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX); - backend_name_copy(dimension_name, (backend_send_names && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX); - - buffer_sprintf( - b - , "%s.%s.%s.%s " COLLECTED_NUMBER_FORMAT " %u\n" - , prefix - , hostname - , chart_name - , dimension_name - , rd->last_collected_value - , (uint32_t)rd->last_collected_time.tv_sec - ); - - return 1; -} - -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; - - char chart_name[RRD_ID_LENGTH_MAX + 1]; - char dimension_name[RRD_ID_LENGTH_MAX + 1]; - backend_name_copy(chart_name, (backend_send_names && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX); - backend_name_copy(dimension_name, (backend_send_names && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX); - - time_t first_t = after, last_t = before; - calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options, &first_t, &last_t); - - if(!isnan(value)) { - - buffer_sprintf( - b - , "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n" - , prefix - , hostname - , chart_name - , dimension_name - , value - , (uint32_t) last_t - ); - - return 1; - } - return 0; -} - -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; - - char chart_name[RRD_ID_LENGTH_MAX + 1]; - char dimension_name[RRD_ID_LENGTH_MAX + 1]; - backend_name_copy(chart_name, (backend_send_names && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX); - backend_name_copy(dimension_name, (backend_send_names && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX); - - buffer_sprintf( - b - , "put %s.%s.%s %u " COLLECTED_NUMBER_FORMAT " host=%s%s%s\n" - , prefix - , chart_name - , dimension_name - , (uint32_t)rd->last_collected_time.tv_sec - , rd->last_collected_value - , hostname - , (host->tags)?" ":"" - , (host->tags)?host->tags:"" - ); - - return 1; -} - -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; - - time_t first_t = after, last_t = before; - calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options, &first_t, &last_t); - - char chart_name[RRD_ID_LENGTH_MAX + 1]; - char dimension_name[RRD_ID_LENGTH_MAX + 1]; - backend_name_copy(chart_name, (backend_send_names && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX); - backend_name_copy(dimension_name, (backend_send_names && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX); - - if(!isnan(value)) { - - buffer_sprintf( - b - , "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s%s%s\n" - , prefix - , chart_name - , dimension_name - , (uint32_t) last_t - , value - , hostname - , (host->tags)?" ":"" - , (host->tags)?host->tags:"" - ); - - return 1; - } - return 0; -} - -static inline int process_opentsdb_response(BUFFER *b) { - return discard_response(b, "opentsdb"); -} - - -// ---------------------------------------------------------------------------- -// 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; - - const char *tags_pre = "", *tags_post = "", *tags = host->tags; - if(!tags) tags = ""; - - if(*tags) { - if(*tags == '{' || *tags == '[' || *tags == '"') { - tags_pre = "\"host_tags\":"; - tags_post = ","; - } - else { - tags_pre = "\"host_tags\":\""; - tags_post = "\","; - } - } - - buffer_sprintf(b, "{" - "\"prefix\":\"%s\"," - "\"hostname\":\"%s\"," - "%s%s%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, - tags_pre, tags, tags_post, - - 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 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; - - time_t first_t = after, last_t = before; - calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options, &first_t, &last_t); - - if(!isnan(value)) { - const char *tags_pre = "", *tags_post = "", *tags = host->tags; - if(!tags) tags = ""; - - if(*tags) { - if(*tags == '{' || *tags == '[' || *tags == '"') { - tags_pre = "\"host_tags\":"; - tags_post = ","; - } - else { - tags_pre = "\"host_tags\":\""; - tags_post = "\","; - } - } - - buffer_sprintf(b, "{" - "\"prefix\":\"%s\"," - "\"hostname\":\"%s\"," - "%s%s%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, - tags_pre, tags, tags_post, - - st->id, - st->name, - st->family, - st->context, - st->type, - st->units, - - rd->id, - rd->name, - value, - - (uint32_t) last_t - ); - - return 1; - } - return 0; -} - -static inline int process_json_response(BUFFER *b) { - return discard_response(b, "json"); -} - - -// ---------------------------------------------------------------------------- -// the backend thread - -static SIMPLE_PATTERN *charts_pattern = NULL; -static SIMPLE_PATTERN *hosts_pattern = NULL; - -inline int backends_can_send_rrdset(uint32_t options, RRDSET *st) { - RRDHOST *host = st->rrdhost; - - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_BACKEND_IGNORE))) - return 0; - - if(unlikely(!rrdset_flag_check(st, RRDSET_FLAG_BACKEND_SEND))) { - // we have not checked this chart - if(simple_pattern_matches(charts_pattern, st->id) || simple_pattern_matches(charts_pattern, st->name)) - rrdset_flag_set(st, RRDSET_FLAG_BACKEND_SEND); - else { - rrdset_flag_set(st, RRDSET_FLAG_BACKEND_IGNORE); - debug(D_BACKEND, "BACKEND: not sending chart '%s' of host '%s', because it is disabled for backends.", st->id, host->hostname); - return 0; - } - } - - if(unlikely(!rrdset_is_available_for_backends(st))) { - debug(D_BACKEND, "BACKEND: not sending chart '%s' of host '%s', because it is not available for backends.", st->id, host->hostname); - return 0; - } - - if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE && !((options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AS_COLLECTED))) { - debug(D_BACKEND, "BACKEND: not sending chart '%s' of host '%s' because its memory mode is '%s' and the backend requires database access.", st->id, host->hostname, rrd_memory_mode_name(host->rrd_memory_mode)); - return 0; - } - - return 1; -} - -inline uint32_t backend_parse_data_source(const char *source, uint32_t mode) { - if(!strcmp(source, "raw") || !strcmp(source, "as collected") || !strcmp(source, "as-collected") || !strcmp(source, "as_collected") || !strcmp(source, "ascollected")) { - mode |= BACKEND_SOURCE_DATA_AS_COLLECTED; - mode &= ~(BACKEND_SOURCE_BITS ^ BACKEND_SOURCE_DATA_AS_COLLECTED); - } - else if(!strcmp(source, "average")) { - mode |= BACKEND_SOURCE_DATA_AVERAGE; - mode &= ~(BACKEND_SOURCE_BITS ^ BACKEND_SOURCE_DATA_AVERAGE); - } - else if(!strcmp(source, "sum") || !strcmp(source, "volume")) { - mode |= BACKEND_SOURCE_DATA_SUM; - mode &= ~(BACKEND_SOURCE_BITS ^ BACKEND_SOURCE_DATA_SUM); - } - else { - error("BACKEND: invalid data source method '%s'.", source); - } - - return mode; -} - -static void backends_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *backends_main(void *ptr) { - netdata_thread_cleanup_push(backends_main_cleanup, ptr); - - int default_port = 0; - int sock = -1; - BUFFER *b = buffer_create(1), *response = buffer_create(1); - 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; - - // ------------------------------------------------------------------------ - // collect configuration options - - struct timeval timeout = { - .tv_sec = 0, - .tv_usec = 0 - }; - 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"); - backend_prefix = config_get(CONFIG_SECTION_BACKEND, "prefix", "netdata"); - const char *hostname = config_get(CONFIG_SECTION_BACKEND, "hostname", localhost->hostname); - backend_update_every = (int)config_get_number(CONFIG_SECTION_BACKEND, "update every", backend_update_every); - 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", backend_update_every * 2 * 1000); - backend_send_names = config_get_boolean(CONFIG_SECTION_BACKEND, "send names instead of ids", backend_send_names); - - charts_pattern = simple_pattern_create(config_get(CONFIG_SECTION_BACKEND, "send charts matching", "*"), NULL, SIMPLE_PATTERN_EXACT); - hosts_pattern = simple_pattern_create(config_get(CONFIG_SECTION_BACKEND, "send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT); - - - // ------------------------------------------------------------------------ - // validate configuration options - // and prepare for sending data to our backend - - backend_options = backend_parse_data_source(source, backend_options); - - if(timeoutms < 1) { - error("BACKEND: invalid timeout %ld ms given. Assuming %d ms.", timeoutms, backend_update_every * 2 * 1000); - timeoutms = backend_update_every * 2 * 1000; - } - timeout.tv_sec = (timeoutms * 1000) / 1000000; - timeout.tv_usec = (timeoutms * 1000) % 1000000; - - if(!enabled || backend_update_every < 1) - goto cleanup; - - // ------------------------------------------------------------------------ - // select the backend type - - if(!strcmp(type, "graphite") || !strcmp(type, "graphite:plaintext")) { - - default_port = 2003; - backend_response_checker = process_graphite_response; - - if((backend_options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AS_COLLECTED) - backend_request_formatter = format_dimension_collected_graphite_plaintext; - else - backend_request_formatter = format_dimension_stored_graphite_plaintext; - - } - else if(!strcmp(type, "opentsdb") || !strcmp(type, "opentsdb:telnet")) { - - default_port = 4242; - backend_response_checker = process_opentsdb_response; - - if((backend_options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AS_COLLECTED) - backend_request_formatter = format_dimension_collected_opentsdb_telnet; - else - backend_request_formatter = format_dimension_stored_opentsdb_telnet; - - } - else if (!strcmp(type, "json") || !strcmp(type, "json:plaintext")) { - - default_port = 5448; - backend_response_checker = process_json_response; - - if ((backend_options & BACKEND_SOURCE_BITS) == BACKEND_SOURCE_DATA_AS_COLLECTED) - backend_request_formatter = format_dimension_collected_json_plaintext; - else - backend_request_formatter = format_dimension_stored_json_plaintext; - - } - else { - error("BACKEND: Unknown backend type '%s'", type); - goto cleanup; - } - - if(backend_request_formatter == NULL || backend_response_checker == NULL) { - error("BACKEND: backend is misconfigured - disabling it."); - goto cleanup; - } - - - // ------------------------------------------------------------------------ - // prepare the charts for monitoring the backend operation - - struct rusage thread; - - collected_number - chart_buffered_metrics = 0, - chart_lost_metrics = 0, - chart_sent_metrics = 0, - chart_buffered_bytes = 0, - chart_received_bytes = 0, - chart_sent_bytes = 0, - chart_receptions = 0, - chart_transmission_successes = 0, - chart_transmission_failures = 0, - chart_data_lost_events = 0, - chart_lost_bytes = 0, - chart_backend_reconnects = 0, - chart_backend_latency = 0; - - RRDSET *chart_metrics = rrdset_create_localhost("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", "backends", NULL, 130600, backend_update_every, 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_create_localhost("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", "backends", NULL, 130610, backend_update_every, 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_create_localhost("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", "backends", NULL, 130630, backend_update_every, 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 - * this time is not related to the time required for the data to travel to - * the backend database and the time that server needed to process them - * - * issue #1432 and https://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html - * - RRDSET *chart_latency = rrdset_create_localhost("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", "backends", NULL, 130620, backend_update_every, RRDSET_TYPE_AREA); - rrddim_add(chart_latency, "latency", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - */ - - RRDSET *chart_rusage = rrdset_create_localhost("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", "backends", NULL, 130630, backend_update_every, 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 - - info("BACKEND: configured ('%s' on '%s' sending '%s' data, every %d seconds, as host '%s', with prefix '%s')", type, destination, source, backend_update_every, hostname, backend_prefix); - - usec_t step_ut = backend_update_every * USEC_PER_SEC; - time_t after = now_realtime_sec(); - int failures = 0; - heartbeat_t hb; - heartbeat_init(&hb); - - while(!netdata_exit) { - - // ------------------------------------------------------------------------ - // Wait for the next iteration point. - - heartbeat_next(&hb, step_ut); - time_t before = now_realtime_sec(); - debug(D_BACKEND, "BACKEND: preparing buffer for timeframe %lu to %lu", (unsigned long)after, (unsigned long)before); - - // ------------------------------------------------------------------------ - // add to the buffer the data we need to send to the backend - - netdata_thread_disable_cancelability(); - - size_t count_hosts = 0; - size_t count_charts_total = 0; - size_t count_dims_total = 0; - - rrd_rdlock(); - RRDHOST *host; - rrdhost_foreach_read(host) { - if(unlikely(!rrdhost_flag_check(host, RRDHOST_FLAG_BACKEND_SEND|RRDHOST_FLAG_BACKEND_DONT_SEND))) { - char *name = (host == localhost)?"localhost":host->hostname; - if (!hosts_pattern || simple_pattern_matches(hosts_pattern, name)) { - rrdhost_flag_set(host, RRDHOST_FLAG_BACKEND_SEND); - info("enabled backend for host '%s'", name); - } - else { - rrdhost_flag_set(host, RRDHOST_FLAG_BACKEND_DONT_SEND); - info("disabled backend for host '%s'", name); - } - } - - if(unlikely(!rrdhost_flag_check(host, RRDHOST_FLAG_BACKEND_SEND))) - continue; - - rrdhost_rdlock(host); - - count_hosts++; - size_t count_charts = 0; - size_t count_dims = 0; - size_t count_dims_skipped = 0; - - const char *__hostname = (host == localhost)?hostname:host->hostname; - - RRDSET *st; - rrdset_foreach_read(st, host) { - if(likely(backends_can_send_rrdset(backend_options, st))) { - rrdset_rdlock(st); - - count_charts++; - - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - if (likely(rd->last_collected_time.tv_sec >= after)) { - chart_buffered_metrics += backend_request_formatter(b, backend_prefix, host, __hostname, st, rd, after, before, backend_options); - count_dims++; - } - else { - debug(D_BACKEND, "BACKEND: not sending dimension '%s' of chart '%s' from host '%s', its last data collection (%lu) is not within our timeframe (%lu to %lu)", rd->id, st->id, __hostname, (unsigned long)rd->last_collected_time.tv_sec, (unsigned long)after, (unsigned long)before); - count_dims_skipped++; - } - } - - rrdset_unlock(st); - } - } - - debug(D_BACKEND, "BACKEND: sending host '%s', metrics of %zu dimensions, of %zu charts. Skipped %zu dimensions.", __hostname, count_dims, count_charts, count_dims_skipped); - count_charts_total += count_charts; - count_dims_total += count_dims; - - rrdhost_unlock(host); - } - rrd_unlock(); - - netdata_thread_enable_cancelability(); - - debug(D_BACKEND, "BACKEND: buffer has %zu bytes, added metrics for %zu dimensions, of %zu charts, from %zu hosts", buffer_strlen(b), count_dims_total, count_charts_total, count_hosts); - - // ------------------------------------------------------------------------ - - chart_buffered_bytes = (collected_number)buffer_strlen(b); - - // reset the monitoring chart counters - chart_received_bytes = - chart_sent_bytes = - chart_sent_metrics = - chart_lost_metrics = - chart_transmission_successes = - chart_transmission_failures = - chart_data_lost_events = - chart_lost_bytes = - chart_backend_reconnects = - chart_backend_latency = 0; - - if(unlikely(netdata_exit)) break; - - //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 - - if(likely(sock != -1)) { - errno = 0; - - // loop through to collect all data - while(sock != -1 && errno != EWOULDBLOCK) { - buffer_need_bytes(response, 4096); - - ssize_t r = recv(sock, &response->buffer[response->len], response->size - response->len, MSG_DONTWAIT); - if(likely(r > 0)) { - // we received some data - response->len += r; - chart_received_bytes += r; - chart_receptions++; - } - else if(r == 0) { - error("BACKEND: '%s' closed the socket", destination); - close(sock); - sock = -1; - } - else { - // failed to receive data - if(errno != EAGAIN && errno != EWOULDBLOCK) { - error("BACKEND: cannot receive data from backend '%s'.", destination); - } - } - } - - // if we received data, process them - if(buffer_strlen(response)) - backend_response_checker(response); - } - - // ------------------------------------------------------------------------ - // if we are not connected, connect to a backend server - - if(unlikely(sock == -1)) { - 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; - - // ------------------------------------------------------------------------ - // if we are connected, send our buffer to the backend server - - if(likely(sock != -1)) { - size_t len = buffer_strlen(b); - 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_monotonic_usec() - start_ut; - if(written != -1 && (size_t)written == len) { - // we sent the data successfully - chart_transmission_successes++; - chart_sent_bytes += written; - chart_sent_metrics = chart_buffered_metrics; - - // reset the failures count - failures = 0; - - // empty the buffer - buffer_flush(b); - } - else { - // oops! we couldn't send (all or some of the) data - error("BACKEND: failed to write data to database backend '%s'. Willing to write %zu bytes, wrote %zd bytes. Will re-connect.", destination, len, written); - chart_transmission_failures++; - - if(written != -1) - chart_sent_bytes += written; - - // increment the counter we check for data loss - failures++; - - // close the socket - we will re-open it next time - close(sock); - sock = -1; - } - } - else { - error("BACKEND: failed to update database backend '%s'", destination); - chart_transmission_failures++; - - // increment the counter we check for data loss - failures++; - } - - if(failures > buffer_on_failures) { - // too bad! we are going to lose data - chart_lost_bytes += buffer_strlen(b); - error("BACKEND: reached %d backend failures. Flushing buffers to protect this host - this results in data loss on back-end server '%s'", failures, destination); - buffer_flush(b); - failures = 0; - chart_data_lost_events++; - chart_lost_metrics = chart_buffered_metrics; - } - - if(unlikely(netdata_exit)) break; - - // ------------------------------------------------------------------------ - // update the monitoring charts - - 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); - rrddim_set(chart_ops, "failure", chart_transmission_failures); - rrddim_set(chart_ops, "reconnect", chart_backend_reconnects); - rrdset_done(chart_ops); - - 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(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); - rrddim_set(chart_bytes, "received", chart_received_bytes); - rrdset_done(chart_bytes); - - /* - 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(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); - - if(likely(buffer_strlen(b) == 0)) - chart_buffered_metrics = 0; - - if(unlikely(netdata_exit)) break; - } - -cleanup: - if(sock != -1) - close(sock); - - buffer_free(b); - buffer_free(response); - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/backends.h b/src/backends.h deleted file mode 100644 index e882f3db1..000000000 --- a/src/backends.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef NETDATA_BACKENDS_H -#define NETDATA_BACKENDS_H 1 - -#define BACKEND_SOURCE_DATA_AS_COLLECTED 0x00000001 -#define BACKEND_SOURCE_DATA_AVERAGE 0x00000002 -#define BACKEND_SOURCE_DATA_SUM 0x00000004 - -#define BACKEND_SOURCE_BITS (BACKEND_SOURCE_DATA_AS_COLLECTED|BACKEND_SOURCE_DATA_AVERAGE|BACKEND_SOURCE_DATA_SUM) - -extern int backend_send_names; -extern int backend_update_every; -extern uint32_t backend_options; -extern const char *backend_prefix; - -extern void *backends_main(void *ptr); - -extern int backends_can_send_rrdset(uint32_t options, RRDSET *st); -extern uint32_t backend_parse_data_source(const char *source, uint32_t mode); - -extern 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 - , time_t *first_timestamp // the timestamp of the first point used in this response - , time_t *last_timestamp // the timestamp that should be reported to backend -); - -#endif /* NETDATA_BACKENDS_H */ diff --git a/src/cgroup-network.c b/src/cgroup-network.c deleted file mode 100644 index 0e2d5163a..000000000 --- a/src/cgroup-network.c +++ /dev/null @@ -1,651 +0,0 @@ -#include "common.h" -#include - -#ifdef HAVE_SETNS -#ifndef _GNU_SOURCE -#define _GNU_SOURCE /* See feature_test_macros(7) */ -#endif -#include -#endif - -char *host_prefix = ""; - -char environment_variable2[FILENAME_MAX + 50] = ""; -char *environment[] = { - "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", - environment_variable2, - NULL -}; - - -// ---------------------------------------------------------------------------- -// callback required by fatal() - -void netdata_cleanup_and_exit(int ret) { - exit(ret); -} -void health_reload(void) {}; -void rrdhost_save_all(void) {}; - - -// ---------------------------------------------------------------------------- - -struct iface { - const char *device; - uint32_t hash; - - unsigned int ifindex; - unsigned int iflink; - - struct iface *next; -}; - -unsigned int read_iface_iflink(const char *prefix, const char *iface) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix?prefix:"", iface); - - unsigned long long iflink = 0; - int ret = read_single_number_file(filename, &iflink); - if(ret) error("Cannot read '%s'.", filename); - - return (unsigned int)iflink; -} - -unsigned int read_iface_ifindex(const char *prefix, const char *iface) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix?prefix:"", iface); - - unsigned long long ifindex = 0; - int ret = read_single_number_file(filename, &ifindex); - if(ret) error("Cannot read '%s'.", filename); - - return (unsigned int)ifindex; -} - -struct iface *read_proc_net_dev(const char *prefix) { - procfile *ff = NULL; - char filename[FILENAME_MAX + 1]; - - snprintfz(filename, FILENAME_MAX, "%s%s", prefix?prefix:"", "/proc/net/dev"); - ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) { - error("Cannot open file '%s'", filename); - return NULL; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) { - error("Cannot read file '%s'", filename); - return NULL; - } - - size_t lines = procfile_lines(ff), l; - struct iface *root = NULL; - for(l = 2; l < lines ;l++) { - if (unlikely(procfile_linewords(ff, l) < 1)) continue; - - struct iface *t = callocz(1, sizeof(struct iface)); - t->device = strdupz(procfile_lineword(ff, l, 0)); - t->hash = simple_hash(t->device); - t->ifindex = read_iface_ifindex(prefix, t->device); - t->iflink = read_iface_iflink(prefix, t->device); - t->next = root; - root = t; - } - - procfile_close(ff); - - return root; -} - -void free_iface(struct iface *iface) { - freez((void *)iface->device); - freez(iface); -} - -void free_host_ifaces(struct iface *iface) { - while(iface) { - struct iface *t = iface->next; - free_iface(iface); - iface = t; - } -} - -int iface_is_eligible(struct iface *iface) { - if(iface->iflink != iface->ifindex) - return 1; - - return 0; -} - -int eligible_ifaces(struct iface *root) { - int eligible = 0; - - struct iface *t; - for(t = root; t ; t = t->next) - if(iface_is_eligible(t)) - eligible++; - - return eligible; -} - -static void continue_as_child(void) { - pid_t child = fork(); - int status; - pid_t ret; - - if (child < 0) - error("fork() failed"); - - /* Only the child returns */ - if (child == 0) - return; - - for (;;) { - ret = waitpid(child, &status, WUNTRACED); - if ((ret == child) && (WIFSTOPPED(status))) { - /* The child suspended so suspend us as well */ - kill(getpid(), SIGSTOP); - kill(child, SIGCONT); - } else { - break; - } - } - - /* Return the child's exit code if possible */ - if (WIFEXITED(status)) { - exit(WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - kill(getpid(), WTERMSIG(status)); - } - - exit(EXIT_FAILURE); -} - -int proc_pid_fd(const char *prefix, const char *ns, pid_t pid) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix?prefix:"", (int)pid, ns); - int fd = open(filename, O_RDONLY); - - if(fd == -1) - error("Cannot open file '%s'", filename); - - return fd; -} - -static struct ns { - int nstype; - int fd; - int status; - const char *name; - const char *path; -} all_ns[] = { - // { .nstype = CLONE_NEWUSER, .fd = -1, .status = -1, .name = "user", .path = "ns/user" }, - // { .nstype = CLONE_NEWCGROUP, .fd = -1, .status = -1, .name = "cgroup", .path = "ns/cgroup" }, - // { .nstype = CLONE_NEWIPC, .fd = -1, .status = -1, .name = "ipc", .path = "ns/ipc" }, - // { .nstype = CLONE_NEWUTS, .fd = -1, .status = -1, .name = "uts", .path = "ns/uts" }, - { .nstype = CLONE_NEWNET, .fd = -1, .status = -1, .name = "network", .path = "ns/net" }, - { .nstype = CLONE_NEWPID, .fd = -1, .status = -1, .name = "pid", .path = "ns/pid" }, - { .nstype = CLONE_NEWNS, .fd = -1, .status = -1, .name = "mount", .path = "ns/mnt" }, - - // terminator - { .nstype = 0, .fd = -1, .status = -1, .name = NULL, .path = NULL } -}; - -int switch_namespace(const char *prefix, pid_t pid) { -#ifdef HAVE_SETNS - - int i; - for(i = 0; all_ns[i].name ; i++) - all_ns[i].fd = proc_pid_fd(prefix, all_ns[i].path, pid); - - int root_fd = proc_pid_fd(prefix, "root", pid); - int cwd_fd = proc_pid_fd(prefix, "cwd", pid); - - setgroups(0, NULL); - - // 2 passes - found it at nsenter source code - // this is related CLONE_NEWUSER functionality - - // FIXME: this code cannot switch user namespace - // Fortunately, we don't need it. - - int pass, errors = 0; - for(pass = 0; pass < 2 ;pass++) { - for(i = 0; all_ns[i].name ; i++) { - if (all_ns[i].fd != -1 && all_ns[i].status == -1) { - if(setns(all_ns[i].fd, all_ns[i].nstype) == -1) { - if(pass == 1) { - all_ns[i].status = 0; - error("Cannot switch to %s namespace of pid %d", all_ns[i].name, (int) pid); - errors++; - } - } - else - all_ns[i].status = 1; - } - } - } - - setgroups(0, NULL); - - if(root_fd != -1) { - if(fchdir(root_fd) < 0) - error("Cannot fchdir() to pid %d root directory", (int)pid); - - if(chroot(".") < 0) - error("Cannot chroot() to pid %d root directory", (int)pid); - - close(root_fd); - } - - if(cwd_fd != -1) { - if(fchdir(cwd_fd) < 0) - error("Cannot fchdir() to pid %d current working directory", (int)pid); - - close(cwd_fd); - } - - int do_fork = 0; - for(i = 0; all_ns[i].name ; i++) - if(all_ns[i].fd != -1) { - - // CLONE_NEWPID requires a fork() to become effective - if(all_ns[i].nstype == CLONE_NEWPID && all_ns[i].status) - do_fork = 1; - - close(all_ns[i].fd); - } - - if(do_fork) - continue_as_child(); - - return 0; - -#else - - errno = ENOSYS; - error("setns() is missing on this system."); - return 1; - -#endif -} - -pid_t read_pid_from_cgroup_file(const char *filename) { - FILE *fp = fopen(filename, "r"); - if(!fp) { - error("Cannot read file '%s'.", filename); - return 0; - } - - char buffer[100 + 1]; - pid_t pid = 0; - char *s; - while((s = fgets(buffer, 100, fp))) { - buffer[100] = '\0'; - pid = atoi(s); - if(pid > 0) break; - } - - fclose(fp); - return pid; -} - -pid_t read_pid_from_cgroup_files(const char *path) { - char filename[FILENAME_MAX + 1]; - - snprintfz(filename, FILENAME_MAX, "%s/cgroup.procs", path); - pid_t pid = read_pid_from_cgroup_file(filename); - if(pid > 0) return pid; - - snprintfz(filename, FILENAME_MAX, "%s/tasks", path); - return read_pid_from_cgroup_file(filename); -} - -pid_t read_pid_from_cgroup(const char *path) { - pid_t pid = read_pid_from_cgroup_files(path); - if (pid > 0) return pid; - - DIR *dir = opendir(path); - if (!dir) { - error("cannot read directory '%s'", path); - return 0; - } - - struct dirent *de = NULL; - while ((de = readdir(dir))) { - 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') - )) - continue; - - if (de->d_type == DT_DIR) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/%s", path, de->d_name); - pid = read_pid_from_cgroup(filename); - if(pid > 0) break; - } - } - closedir(dir); - return pid; -} - -// ---------------------------------------------------------------------------- -// send the result to netdata - -struct found_device { - const char *host_device; - const char *guest_device; - - uint32_t host_device_hash; - - struct found_device *next; -} *detected_devices = NULL; - -void add_device(const char *host, const char *guest) { - uint32_t hash = simple_hash(host); - - if(guest && (!*guest || strcmp(host, guest) == 0)) - guest = NULL; - - struct found_device *f; - for(f = detected_devices; f ; f = f->next) { - if(f->host_device_hash == hash && strcmp(host, f->host_device) == 0) { - - if(guest && !f->guest_device) - f->guest_device = strdupz(guest); - - return; - } - } - - f = mallocz(sizeof(struct found_device)); - f->host_device = strdupz(host); - f->host_device_hash = hash; - f->guest_device = (guest)?strdupz(guest):NULL; - f->next = detected_devices; - detected_devices = f; -} - -int send_devices(void) { - int found = 0; - - struct found_device *f; - for(f = detected_devices; f ; f = f->next) { - found++; - printf("%s %s\n", f->host_device, (f->guest_device)?f->guest_device:f->host_device); - } - - return found; -} - -// ---------------------------------------------------------------------------- -// this function should be called only **ONCE** -// also it has to be the **LAST** to be called -// since it switches namespaces, so after this call, everything is different! - -void detect_veth_interfaces(pid_t pid) { - struct iface *host, *cgroup, *h, *c; - const char *prefix = getenv("NETDATA_HOST_PREFIX"); - - host = read_proc_net_dev(prefix); - if(!host) { - errno = 0; - error("cannot read host interface list."); - return; - } - - if(!eligible_ifaces(host)) { - errno = 0; - error("there are no double-linked host interfaces available."); - goto cleanup; - } - - if(switch_namespace(prefix, pid)) { - errno = 0; - error("cannot switch to the namespace of pid %u", (unsigned int) pid); - goto cleanup; - } - - cgroup = read_proc_net_dev(NULL); - if(!cgroup) { - errno = 0; - error("cannot read cgroup interface list."); - goto cleanup; - } - - if(!eligible_ifaces(cgroup)) { - errno = 0; - error("there are not double-linked cgroup interfaces available."); - goto cleanup; - } - - for(h = host; h ; h = h->next) { - if(iface_is_eligible(h)) { - for (c = cgroup; c; c = c->next) { - if(iface_is_eligible(c) && h->ifindex == c->iflink && h->iflink == c->ifindex) { - add_device(h->device, c->device); - } - } - } - } - -cleanup: - free_host_ifaces(host); -} - -// ---------------------------------------------------------------------------- -// call the external helper - -#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048 -void call_the_helper(pid_t pid, const char *cgroup) { - if(setresuid(0, 0, 0) == -1) - error("setresuid(0, 0, 0) failed."); - - char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; - if(cgroup) - snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup); - else - snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid); - - info("running: %s", buffer); - - pid_t cgroup_pid; - FILE *fp = mypopene(buffer, &cgroup_pid, environment); - if(fp) { - char *s; - while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) { - trim(s); - - if(*s && *s != '\n') { - char *t = s; - while(*t && *t != ' ') t++; - if(*t == ' ') { - *t = '\0'; - t++; - } - - if(!*s || !*t) continue; - add_device(s, t); - } - } - - mypclose(fp, cgroup_pid); - } - else - error("cannot execute cgroup-network helper script: %s", buffer); -} - -int is_valid_path_symbol(char c) { - switch(c) { - case '/': // path separators - case '\\': // needed for virsh domains \x2d1\x2dname - case ' ': // space - case '-': // hyphen - case '_': // underscore - case '.': // dot - case ',': // comma - return 1; - - default: - return 0; - } -} - -// we will pass this path a shell script running as root -// so, we need to make sure the path will be valid -// and will not include anything that could allow -// the caller use shell expansion for gaining escalated -// privileges. -int verify_path(const char *path) { - struct stat sb; - - char c; - const char *s = path; - while((c = *s++)) { - if(!( isalnum(c) || is_valid_path_symbol(c) )) { - error("invalid character in path '%s'", path); - return -1; - } - } - - if(strstr(path, "\\") && !strstr(path, "\\x")) { - error("invalid escape sequence in path '%s'", path); - return 1; - } - - if(strstr(path, "/../")) { - error("invalid parent path sequence detected in '%s'", path); - return 1; - } - - if(path[0] != '/') { - error("only absolute path names are supported - invalid path '%s'", path); - return -1; - } - - if (stat(path, &sb) == -1) { - error("cannot stat() path '%s'", path); - return -1; - } - - if((sb.st_mode & S_IFMT) != S_IFDIR) { - error("path '%s' is not a directory", path); - return -1; - } - - return 0; -} - -/* -char *fix_path_variable(void) { - const char *path = getenv("PATH"); - if(!path || !*path) return 0; - - char *p = strdupz(path); - char *safe_path = callocz(1, strlen(p) + strlen("PATH=") + 1); - strcpy(safe_path, "PATH="); - - int added = 0; - char *ptr = p; - while(ptr && *ptr) { - char *s = strsep(&ptr, ":"); - if(s && *s) { - if(verify_path(s) == -1) { - error("the PATH variable includes an invalid path '%s' - removed it.", s); - } - else { - info("the PATH variable includes a valid path '%s'.", s); - if(added) strcat(safe_path, ":"); - strcat(safe_path, s); - added++; - } - } - } - - info("unsafe PATH: '%s'.", path); - info(" safe PATH: '%s'.", safe_path); - - freez(p); - return safe_path; -} -*/ - -// ---------------------------------------------------------------------------- -// main - -void usage(void) { - fprintf(stderr, "%s [ -p PID | --pid PID | --cgroup /path/to/cgroup ]\n", program_name); - exit(1); -} - -int main(int argc, char **argv) { - pid_t pid = 0; - - program_name = argv[0]; - program_version = VERSION; - error_log_syslog = 0; - - - // ------------------------------------------------------------------------ - // make sure NETDATA_HOST_PREFIX is safe - - host_prefix = getenv("NETDATA_HOST_PREFIX"); - if(!host_prefix || !*host_prefix) - host_prefix = ""; - - if(host_prefix[0] != '\0' && verify_path(host_prefix) == -1) - fatal("invalid NETDATA_HOST_PREFIX '%s'", host_prefix); - - // ------------------------------------------------------------------------ - // build a safe environment for our script - - // the first environment variable is a fixed PATH= - snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", host_prefix); - - // ------------------------------------------------------------------------ - - if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) { - fprintf(stderr, "cgroup-network %s\n", VERSION); - exit(0); - } - - if(argc != 3) - usage(); - - if(!strcmp(argv[1], "-p") || !strcmp(argv[1], "--pid")) { - pid = atoi(argv[2]); - - if(pid <= 0) { - errno = 0; - error("Invalid pid %d given", (int) pid); - return 2; - } - - call_the_helper(pid, NULL); - } - else if(!strcmp(argv[1], "--cgroup")) { - char *cgroup = argv[2]; - if(verify_path(cgroup) == -1) - fatal("cgroup '%s' does not exist or is not valid.", cgroup); - - pid = read_pid_from_cgroup(cgroup); - call_the_helper(pid, cgroup); - - if(pid <= 0 && !detected_devices) { - errno = 0; - error("Cannot find a cgroup PID from cgroup '%s'", cgroup); - } - } - else - usage(); - - if(pid > 0) - detect_veth_interfaces(pid); - - int found = send_devices(); - if(found <= 0) return 1; - return 0; -} diff --git a/src/clocks.c b/src/clocks.c deleted file mode 100644 index 2b1c36e3f..000000000 --- a/src/clocks.c +++ /dev/null @@ -1,137 +0,0 @@ -#include "common.h" - -#ifndef HAVE_CLOCK_GETTIME -inline int clock_gettime(clockid_t clk_id, struct timespec *ts) { - struct timeval tv; - if(unlikely(gettimeofday(&tv, NULL) == -1)) - return -1; - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC; - return 0; -} -#endif - -static inline time_t now_sec(clockid_t clk_id) { - struct timespec ts; - if(unlikely(clock_gettime(clk_id, &ts) == -1)) - return 0; - return ts.tv_sec; -} - -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(clk_id, &ts) == -1)) { - tv->tv_sec = 0; - tv->tv_usec = 0; - return -1; - } - - tv->tv_sec = ts.tv_sec; - 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) { - 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) { - return now_sec(CLOCK_MONOTONIC); -} - -inline usec_t now_monotonic_usec(void) { - 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) { - return now_sec(CLOCK_BOOTTIME); -} - -inline usec_t now_boottime_usec(void) { - 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 % 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) { - usec_t ts1 = timeval_usec(now); - 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 + tick / 2)) { - errno = 0; - error("heartbeat missed %llu microseconds", dt - tick); - } - - 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 deleted file mode 100644 index ca5715254..000000000 --- a/src/clocks.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef NETDATA_CLOCKS_H -#define NETDATA_CLOCKS_H 1 - -#ifndef HAVE_STRUCT_TIMESPEC -struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; -#endif - -#ifndef HAVE_CLOCKID_T -typedef int clockid_t; -#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 -#define CLOCK_REALTIME 0 -#endif - -#ifndef CLOCK_MONOTONIC -/* fallback to CLOCK_REALTIME if not available */ -#define CLOCK_MONOTONIC CLOCK_REALTIME -#endif - -#ifndef CLOCK_BOOTTIME - -#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 -#endif // CLOCK_UPTIME - -#else // CLOCK_BOOTTIME - -#ifdef HAVE_CLOCK_GETTIME -#define CLOCK_BOOTTIME_IS_AVAILABLE 1 // required for /proc/uptime -#endif // HAVE_CLOCK_GETTIME - -#endif // CLOCK_BOOTTIME - -#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 - -#define USEC_PER_MS 1000ULL - -#ifndef HAVE_CLOCK_GETTIME -/* Fallback function for POSIX.1-2001 clock_gettime() function. - * - * We use a realtime clock from gettimeofday(), this will - * make systems without clock_gettime() support sensitive - * to time jumps or hibernation/suspend side effects. - */ -extern int clock_gettime(clockid_t clk_id, struct timespec *ts); -#endif - -/* - * 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); -extern time_t now_realtime_sec(void); -extern usec_t now_realtime_usec(void); - -extern int now_monotonic_timeval(struct timeval *tv); -extern time_t now_monotonic_sec(void); -extern usec_t now_monotonic_usec(void); - -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 deleted file mode 100644 index 94fd5e429..000000000 --- a/src/common.c +++ /dev/null @@ -1,1361 +0,0 @@ -#include "common.h" - -#ifdef __APPLE__ -#define INHERIT_NONE 0 -#endif /* __APPLE__ */ -#if defined(__FreeBSD__) || defined(__APPLE__) -# define O_NOATIME 0 -# define MADV_DONTFORK INHERIT_NONE -#endif /* __FreeBSD__ || __APPLE__*/ - -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; -char *netdata_configured_timezone = NULL; - -struct rlimit rlimit_nofile = { .rlim_cur = 1024, .rlim_max = 1024 }; -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 - -// although netdata does not use memory allocations too often (netdata tries to -// maintain its memory footprint stable during runtime, i.e. all buffers are -// allocated during initialization and are adapted to current use throughout -// its lifetime), these can be used to override the default system allocation -// routines. - -#ifdef NETDATA_LOG_ALLOCATIONS -static struct memory_statistics { - volatile size_t malloc_calls_made; - volatile size_t calloc_calls_made; - volatile size_t realloc_calls_made; - volatile size_t strdup_calls_made; - volatile size_t free_calls_made; - volatile size_t memory_calls_made; - volatile size_t allocated_memory; - volatile size_t mmapped_memory; -} memory_statistics; - -static inline void print_allocations(const char *file, const char *function, const unsigned long line) { - static struct memory_statistics old = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - //if(unlikely(!(memory_statistics.memory_calls_made % 5))) { - fprintf(stderr, "(%04lu@%-10.10s:%-15.15s): Allocated %zu KB (+%zu B), mmapped %zu KB (+%zu B): malloc %zu (+%zu), calloc %zu (+%zu), realloc %zu (+%zu), strdup %zu (+%zu), free %zu (+%zu)\n", - line, file, function, - (memory_statistics.allocated_memory + 512) / 1024, memory_statistics.allocated_memory - old.allocated_memory, - (memory_statistics.mmapped_memory + 512) / 1024, memory_statistics.mmapped_memory - old.mmapped_memory, - memory_statistics.malloc_calls_made, memory_statistics.malloc_calls_made - old.malloc_calls_made, - memory_statistics.calloc_calls_made, memory_statistics.calloc_calls_made - old.calloc_calls_made, - memory_statistics.realloc_calls_made, memory_statistics.realloc_calls_made - old.realloc_calls_made, - memory_statistics.strdup_calls_made, memory_statistics.strdup_calls_made - old.strdup_calls_made, - memory_statistics.free_calls_made, memory_statistics.free_calls_made - old.free_calls_made - ); - - memcpy(&old, &memory_statistics, sizeof(struct memory_statistics)); - //} -} - -static inline void malloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); -#else - // this is for debugging - we don't care locking it - memory_statistics.memory_calls_made++; - memory_statistics.malloc_calls_made++; - memory_statistics.allocated_memory += size; -#endif - print_allocations(file, function, line); -} - -static inline void mmap_accounting(size_t size) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.mmapped_memory, size, __ATOMIC_SEQ_CST); -#else - // this is for debugging - we don't care locking it - memory_statistics.memory_calls_made++; - memory_statistics.mmapped_memory += size; -#endif -} - -static inline void calloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.calloc_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); -#else - // this is for debugging - we don't care locking it - memory_statistics.memory_calls_made++; - memory_statistics.calloc_calls_made++; - memory_statistics.allocated_memory += size; -#endif - print_allocations(file, function, line); -} - -static inline void realloc_accounting(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) { - (void)ptr; - -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.realloc_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); -#else - // this is for debugging - we don't care locking it - memory_statistics.memory_calls_made++; - memory_statistics.realloc_calls_made++; - memory_statistics.allocated_memory += size; -#endif - print_allocations(file, function, line); -} - -static inline void strdup_accounting(const char *file, const char *function, const unsigned long line, const char *s) { - size_t size = strlen(s) + 1; - -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.strdup_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); -#else - // this is for debugging - we don't care locking it - memory_statistics.memory_calls_made++; - memory_statistics.strdup_calls_made++; - memory_statistics.allocated_memory += size; -#endif - print_allocations(file, function, line); -} - -static inline void free_accounting(const char *file, const char *function, const unsigned long line, void *ptr) { - (void)file; - (void)function; - (void)line; - - if(likely(ptr)) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&memory_statistics.free_calls_made, 1, __ATOMIC_SEQ_CST); -#else - // this is for debugging - we don't care locking it - memory_statistics.memory_calls_made++; - memory_statistics.free_calls_made++; -#endif - } -} -#endif - -#ifdef NETDATA_LOG_ALLOCATIONS -char *strdupz_int(const char *file, const char *function, const unsigned long line, const char *s) { - strdup_accounting(file, function, line, s); -#else -char *strdupz(const char *s) { -#endif - - char *t = strdup(s); - if (unlikely(!t)) fatal("Cannot strdup() string '%s'", s); - return t; -} - -#ifdef NETDATA_LOG_ALLOCATIONS -void *mallocz_int(const char *file, const char *function, const unsigned long line, size_t size) { - malloc_accounting(file, function, line, size); -#else -void *mallocz(size_t size) { -#endif - - void *p = malloc(size); - if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size); - return p; -} - -#ifdef NETDATA_LOG_ALLOCATIONS -void *callocz_int(const char *file, const char *function, const unsigned long line, size_t nmemb, size_t size) { - calloc_accounting(file, function, line, nmemb * size); -#else -void *callocz(size_t nmemb, size_t size) { -#endif - - void *p = calloc(nmemb, size); - if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size); - return p; -} - -#ifdef NETDATA_LOG_ALLOCATIONS -void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) { - realloc_accounting(file, function, line, ptr, size); -#else -void *reallocz(void *ptr, size_t size) { -#endif - - void *p = realloc(ptr, size); - if (unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size); - return p; -} - -#ifdef NETDATA_LOG_ALLOCATIONS -void freez_int(const char *file, const char *function, const unsigned long line, void *ptr) { - free_accounting(file, function, line, ptr); -#else -void freez(void *ptr) { -#endif - - free(ptr); -} - -void json_escape_string(char *dst, const char *src, size_t size) { - const char *t; - char *d = dst, *e = &dst[size - 1]; - - for(t = src; *t && d < e ;t++) { - if(unlikely(*t == '\\' || *t == '"')) { - if(unlikely(d + 1 >= e)) break; - *d++ = '\\'; - } - *d++ = *t; - } - - *d = '\0'; -} - -void json_fix_string(char *s) { - unsigned char c; - while((c = (unsigned char)*s)) { - if(unlikely(c == '\\')) - *s++ = '/'; - else if(unlikely(c == '"')) - *s++ = '\''; - else if(unlikely(isspace(c) || iscntrl(c))) - *s++ = ' '; - else if(unlikely(!isprint(c) || c > 127)) - *s++ = '_'; - else - s++; - } -} - -int sleep_usec(usec_t usec) { - -#ifndef NETDATA_WITH_USLEEP - // we expect microseconds (1.000.000 per second) - // but timespec is nanoseconds (1.000.000.000 per second) - struct timespec rem, req = { - .tv_sec = (time_t) (usec / 1000000), - .tv_nsec = (suseconds_t) ((usec % 1000000) * 1000) - }; - - while (nanosleep(&req, &rem) == -1) { - if (likely(errno == EINTR)) { - debug(D_SYSTEM, "nanosleep() interrupted (while sleeping for %llu microseconds).", usec); - req.tv_sec = rem.tv_sec; - req.tv_nsec = rem.tv_nsec; - } else { - error("Cannot nanosleep() for %llu microseconds.", usec); - break; - } - } - - return 0; -#else - int ret = usleep(usec); - if(unlikely(ret == -1 && errno == EINVAL)) { - // on certain systems, usec has to be up to 999999 - if(usec > 999999) { - int counter = usec / 999999; - while(counter--) - usleep(999999); - - usleep(usec % 999999); - } - else { - error("Cannot usleep() for %llu microseconds.", usec); - return ret; - } - } - - if(ret != 0) - error("usleep() failed for %llu microseconds.", usec); - - return ret; -#endif -} - -unsigned char netdata_map_chart_names[256] = { - [0] = '\0', // - [1] = '_', // - [2] = '_', // - [3] = '_', // - [4] = '_', // - [5] = '_', // - [6] = '_', // - [7] = '_', // - [8] = '_', // - [9] = '_', // - [10] = '_', // - [11] = '_', // - [12] = '_', // - [13] = '_', // - [14] = '_', // - [15] = '_', // - [16] = '_', // - [17] = '_', // - [18] = '_', // - [19] = '_', // - [20] = '_', // - [21] = '_', // - [22] = '_', // - [23] = '_', // - [24] = '_', // - [25] = '_', // - [26] = '_', // - [27] = '_', // - [28] = '_', // - [29] = '_', // - [30] = '_', // - [31] = '_', // - [32] = '_', // - [33] = '_', // ! - [34] = '_', // " - [35] = '_', // # - [36] = '_', // $ - [37] = '_', // % - [38] = '_', // & - [39] = '_', // ' - [40] = '_', // ( - [41] = '_', // ) - [42] = '_', // * - [43] = '_', // + - [44] = '.', // , - [45] = '-', // - - [46] = '.', // . - [47] = '/', // / - [48] = '0', // 0 - [49] = '1', // 1 - [50] = '2', // 2 - [51] = '3', // 3 - [52] = '4', // 4 - [53] = '5', // 5 - [54] = '6', // 6 - [55] = '7', // 7 - [56] = '8', // 8 - [57] = '9', // 9 - [58] = '_', // : - [59] = '_', // ; - [60] = '_', // < - [61] = '_', // = - [62] = '_', // > - [63] = '_', // ? - [64] = '_', // @ - [65] = 'a', // A - [66] = 'b', // B - [67] = 'c', // C - [68] = 'd', // D - [69] = 'e', // E - [70] = 'f', // F - [71] = 'g', // G - [72] = 'h', // H - [73] = 'i', // I - [74] = 'j', // J - [75] = 'k', // K - [76] = 'l', // L - [77] = 'm', // M - [78] = 'n', // N - [79] = 'o', // O - [80] = 'p', // P - [81] = 'q', // Q - [82] = 'r', // R - [83] = 's', // S - [84] = 't', // T - [85] = 'u', // U - [86] = 'v', // V - [87] = 'w', // W - [88] = 'x', // X - [89] = 'y', // Y - [90] = 'z', // Z - [91] = '_', // [ - [92] = '/', // backslash - [93] = '_', // ] - [94] = '_', // ^ - [95] = '_', // _ - [96] = '_', // ` - [97] = 'a', // a - [98] = 'b', // b - [99] = 'c', // c - [100] = 'd', // d - [101] = 'e', // e - [102] = 'f', // f - [103] = 'g', // g - [104] = 'h', // h - [105] = 'i', // i - [106] = 'j', // j - [107] = 'k', // k - [108] = 'l', // l - [109] = 'm', // m - [110] = 'n', // n - [111] = 'o', // o - [112] = 'p', // p - [113] = 'q', // q - [114] = 'r', // r - [115] = 's', // s - [116] = 't', // t - [117] = 'u', // u - [118] = 'v', // v - [119] = 'w', // w - [120] = 'x', // x - [121] = 'y', // y - [122] = 'z', // z - [123] = '_', // { - [124] = '_', // | - [125] = '_', // } - [126] = '_', // ~ - [127] = '_', // - [128] = '_', // - [129] = '_', // - [130] = '_', // - [131] = '_', // - [132] = '_', // - [133] = '_', // - [134] = '_', // - [135] = '_', // - [136] = '_', // - [137] = '_', // - [138] = '_', // - [139] = '_', // - [140] = '_', // - [141] = '_', // - [142] = '_', // - [143] = '_', // - [144] = '_', // - [145] = '_', // - [146] = '_', // - [147] = '_', // - [148] = '_', // - [149] = '_', // - [150] = '_', // - [151] = '_', // - [152] = '_', // - [153] = '_', // - [154] = '_', // - [155] = '_', // - [156] = '_', // - [157] = '_', // - [158] = '_', // - [159] = '_', // - [160] = '_', // - [161] = '_', // - [162] = '_', // - [163] = '_', // - [164] = '_', // - [165] = '_', // - [166] = '_', // - [167] = '_', // - [168] = '_', // - [169] = '_', // - [170] = '_', // - [171] = '_', // - [172] = '_', // - [173] = '_', // - [174] = '_', // - [175] = '_', // - [176] = '_', // - [177] = '_', // - [178] = '_', // - [179] = '_', // - [180] = '_', // - [181] = '_', // - [182] = '_', // - [183] = '_', // - [184] = '_', // - [185] = '_', // - [186] = '_', // - [187] = '_', // - [188] = '_', // - [189] = '_', // - [190] = '_', // - [191] = '_', // - [192] = '_', // - [193] = '_', // - [194] = '_', // - [195] = '_', // - [196] = '_', // - [197] = '_', // - [198] = '_', // - [199] = '_', // - [200] = '_', // - [201] = '_', // - [202] = '_', // - [203] = '_', // - [204] = '_', // - [205] = '_', // - [206] = '_', // - [207] = '_', // - [208] = '_', // - [209] = '_', // - [210] = '_', // - [211] = '_', // - [212] = '_', // - [213] = '_', // - [214] = '_', // - [215] = '_', // - [216] = '_', // - [217] = '_', // - [218] = '_', // - [219] = '_', // - [220] = '_', // - [221] = '_', // - [222] = '_', // - [223] = '_', // - [224] = '_', // - [225] = '_', // - [226] = '_', // - [227] = '_', // - [228] = '_', // - [229] = '_', // - [230] = '_', // - [231] = '_', // - [232] = '_', // - [233] = '_', // - [234] = '_', // - [235] = '_', // - [236] = '_', // - [237] = '_', // - [238] = '_', // - [239] = '_', // - [240] = '_', // - [241] = '_', // - [242] = '_', // - [243] = '_', // - [244] = '_', // - [245] = '_', // - [246] = '_', // - [247] = '_', // - [248] = '_', // - [249] = '_', // - [250] = '_', // - [251] = '_', // - [252] = '_', // - [253] = '_', // - [254] = '_', // - [255] = '_' // -}; - -// make sure the supplied string -// is good for a netdata chart/dimension ID/NAME -void netdata_fix_chart_name(char *s) { - while ((*s = netdata_map_chart_names[(unsigned char) *s])) s++; -} - -unsigned char netdata_map_chart_ids[256] = { - [0] = '\0', // - [1] = '_', // - [2] = '_', // - [3] = '_', // - [4] = '_', // - [5] = '_', // - [6] = '_', // - [7] = '_', // - [8] = '_', // - [9] = '_', // - [10] = '_', // - [11] = '_', // - [12] = '_', // - [13] = '_', // - [14] = '_', // - [15] = '_', // - [16] = '_', // - [17] = '_', // - [18] = '_', // - [19] = '_', // - [20] = '_', // - [21] = '_', // - [22] = '_', // - [23] = '_', // - [24] = '_', // - [25] = '_', // - [26] = '_', // - [27] = '_', // - [28] = '_', // - [29] = '_', // - [30] = '_', // - [31] = '_', // - [32] = '_', // - [33] = '_', // ! - [34] = '_', // " - [35] = '_', // # - [36] = '_', // $ - [37] = '_', // % - [38] = '_', // & - [39] = '_', // ' - [40] = '_', // ( - [41] = '_', // ) - [42] = '_', // * - [43] = '_', // + - [44] = '.', // , - [45] = '-', // - - [46] = '.', // . - [47] = '_', // / - [48] = '0', // 0 - [49] = '1', // 1 - [50] = '2', // 2 - [51] = '3', // 3 - [52] = '4', // 4 - [53] = '5', // 5 - [54] = '6', // 6 - [55] = '7', // 7 - [56] = '8', // 8 - [57] = '9', // 9 - [58] = '_', // : - [59] = '_', // ; - [60] = '_', // < - [61] = '_', // = - [62] = '_', // > - [63] = '_', // ? - [64] = '_', // @ - [65] = 'a', // A - [66] = 'b', // B - [67] = 'c', // C - [68] = 'd', // D - [69] = 'e', // E - [70] = 'f', // F - [71] = 'g', // G - [72] = 'h', // H - [73] = 'i', // I - [74] = 'j', // J - [75] = 'k', // K - [76] = 'l', // L - [77] = 'm', // M - [78] = 'n', // N - [79] = 'o', // O - [80] = 'p', // P - [81] = 'q', // Q - [82] = 'r', // R - [83] = 's', // S - [84] = 't', // T - [85] = 'u', // U - [86] = 'v', // V - [87] = 'w', // W - [88] = 'x', // X - [89] = 'y', // Y - [90] = 'z', // Z - [91] = '_', // [ - [92] = '/', // backslash - [93] = '_', // ] - [94] = '_', // ^ - [95] = '_', // _ - [96] = '_', // ` - [97] = 'a', // a - [98] = 'b', // b - [99] = 'c', // c - [100] = 'd', // d - [101] = 'e', // e - [102] = 'f', // f - [103] = 'g', // g - [104] = 'h', // h - [105] = 'i', // i - [106] = 'j', // j - [107] = 'k', // k - [108] = 'l', // l - [109] = 'm', // m - [110] = 'n', // n - [111] = 'o', // o - [112] = 'p', // p - [113] = 'q', // q - [114] = 'r', // r - [115] = 's', // s - [116] = 't', // t - [117] = 'u', // u - [118] = 'v', // v - [119] = 'w', // w - [120] = 'x', // x - [121] = 'y', // y - [122] = 'z', // z - [123] = '_', // { - [124] = '_', // | - [125] = '_', // } - [126] = '_', // ~ - [127] = '_', // - [128] = '_', // - [129] = '_', // - [130] = '_', // - [131] = '_', // - [132] = '_', // - [133] = '_', // - [134] = '_', // - [135] = '_', // - [136] = '_', // - [137] = '_', // - [138] = '_', // - [139] = '_', // - [140] = '_', // - [141] = '_', // - [142] = '_', // - [143] = '_', // - [144] = '_', // - [145] = '_', // - [146] = '_', // - [147] = '_', // - [148] = '_', // - [149] = '_', // - [150] = '_', // - [151] = '_', // - [152] = '_', // - [153] = '_', // - [154] = '_', // - [155] = '_', // - [156] = '_', // - [157] = '_', // - [158] = '_', // - [159] = '_', // - [160] = '_', // - [161] = '_', // - [162] = '_', // - [163] = '_', // - [164] = '_', // - [165] = '_', // - [166] = '_', // - [167] = '_', // - [168] = '_', // - [169] = '_', // - [170] = '_', // - [171] = '_', // - [172] = '_', // - [173] = '_', // - [174] = '_', // - [175] = '_', // - [176] = '_', // - [177] = '_', // - [178] = '_', // - [179] = '_', // - [180] = '_', // - [181] = '_', // - [182] = '_', // - [183] = '_', // - [184] = '_', // - [185] = '_', // - [186] = '_', // - [187] = '_', // - [188] = '_', // - [189] = '_', // - [190] = '_', // - [191] = '_', // - [192] = '_', // - [193] = '_', // - [194] = '_', // - [195] = '_', // - [196] = '_', // - [197] = '_', // - [198] = '_', // - [199] = '_', // - [200] = '_', // - [201] = '_', // - [202] = '_', // - [203] = '_', // - [204] = '_', // - [205] = '_', // - [206] = '_', // - [207] = '_', // - [208] = '_', // - [209] = '_', // - [210] = '_', // - [211] = '_', // - [212] = '_', // - [213] = '_', // - [214] = '_', // - [215] = '_', // - [216] = '_', // - [217] = '_', // - [218] = '_', // - [219] = '_', // - [220] = '_', // - [221] = '_', // - [222] = '_', // - [223] = '_', // - [224] = '_', // - [225] = '_', // - [226] = '_', // - [227] = '_', // - [228] = '_', // - [229] = '_', // - [230] = '_', // - [231] = '_', // - [232] = '_', // - [233] = '_', // - [234] = '_', // - [235] = '_', // - [236] = '_', // - [237] = '_', // - [238] = '_', // - [239] = '_', // - [240] = '_', // - [241] = '_', // - [242] = '_', // - [243] = '_', // - [244] = '_', // - [245] = '_', // - [246] = '_', // - [247] = '_', // - [248] = '_', // - [249] = '_', // - [250] = '_', // - [251] = '_', // - [252] = '_', // - [253] = '_', // - [254] = '_', // - [255] = '_' // -}; - -// make sure the supplied string -// is good for a netdata chart/dimension ID/NAME -void netdata_fix_chart_id(char *s) { - while ((*s = netdata_map_chart_ids[(unsigned char) *s])) s++; -} - -/* -// http://stackoverflow.com/questions/7666509/hash-function-for-string -uint32_t simple_hash(const char *name) -{ - const char *s = name; - uint32_t hash = 5381; - int i; - - while((i = *s++)) hash = ((hash << 5) + hash) + i; - - // fprintf(stderr, "HASH: %lu %s\n", hash, name); - - return hash; -} -*/ - -/* -// http://isthe.com/chongo/tech/comp/fnv/#FNV-1a -uint32_t simple_hash(const char *name) { - unsigned char *s = (unsigned char *) name; - uint32_t hval = 0x811c9dc5; - - // FNV-1a algorithm - while (*s) { - // multiply by the 32 bit FNV magic prime mod 2^32 - // NOTE: No need to optimize with left shifts. - // GCC will use imul instruction anyway. - // Tested with 'gcc -O3 -S' - //hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); - hval *= 16777619; - - // xor the bottom with the current octet - hval ^= (uint32_t) *s++; - } - - // fprintf(stderr, "HASH: %u = %s\n", hval, name); - return hval; -} - -uint32_t simple_uhash(const char *name) { - unsigned char *s = (unsigned char *) name; - uint32_t hval = 0x811c9dc5, c; - - // FNV-1a algorithm - while ((c = *s++)) { - if (unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A'; - hval *= 16777619; - hval ^= c; - } - return hval; -} -*/ - -/* -// http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx -// one at a time hash -uint32_t simple_hash(const char *name) { - unsigned char *s = (unsigned char *)name; - uint32_t h = 0; - - while(*s) { - h += *s++; - h += (h << 10); - h ^= (h >> 6); - } - - h += (h << 3); - h ^= (h >> 11); - h += (h << 15); - - // fprintf(stderr, "HASH: %u = %s\n", h, name); - - return h; -} -*/ - -void strreverse(char *begin, char *end) { - while (end > begin) { - // clearer code. - char aux = *end; - *end-- = *begin; - *begin++ = aux; - } -} - -char *strsep_on_1char(char **ptr, char c) { - if(unlikely(!ptr || !*ptr)) - return NULL; - - // remember the position we started - char *s = *ptr; - - // skip separators in front - while(*s == c) s++; - char *ret = s; - - // find the next separator - while(*s++) { - if(unlikely(*s == c)) { - *s++ = '\0'; - *ptr = s; - return ret; - } - } - - *ptr = NULL; - return ret; -} - -char *mystrsep(char **ptr, char *s) { - char *p = ""; - while (p && !p[0] && *ptr) p = strsep(ptr, s); - return (p); -} - -char *trim(char *s) { - // skip leading spaces - while (*s && isspace(*s)) s++; - if (!*s) return NULL; - - // skip tailing spaces - // this way is way faster. Writes only one NUL char. - ssize_t l = strlen(s); - if (--l >= 0) { - char *p = s + l; - while (p > s && isspace(*p)) p--; - *++p = '\0'; - } - - if (!*s) return NULL; - - return s; -} - -inline char *trim_all(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 int memory_file_open(const char *filename, size_t size) { - // info("memory_file_open('%s', %zu", filename, size); - - int fd = open(filename, O_RDWR | O_CREAT | O_NOATIME, 0664); - if (fd != -1) { - if (lseek(fd, size, SEEK_SET) == (off_t) size) { - if (write(fd, "", 1) == 1) { - if (ftruncate(fd, size)) - error("Cannot truncate file '%s' to size %zu. Will use the larger file.", filename, size); - } - else error("Cannot write to file '%s' at position %zu.", filename, size); - } - else error("Cannot seek file '%s' to size %zu.", filename, size); - } - else error("Cannot create/open file '%s'.", filename); - - return fd; -} - -// mmap_shared is used for memory mode = map -static void *memory_file_mmap(const char *filename, size_t size, int flags) { - // info("memory_file_mmap('%s', %zu", filename, size); - static int log_madvise = 1; - - int fd = -1; - if(filename) { - fd = memory_file_open(filename, size); - if(fd == -1) return MAP_FAILED; - } - - void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0); - if (mem != MAP_FAILED) { -#ifdef NETDATA_LOG_ALLOCATIONS - mmap_accounting(size); -#endif - int advise = MADV_SEQUENTIAL | MADV_DONTFORK; - if (flags & MAP_SHARED) advise |= MADV_WILLNEED; - - if (madvise(mem, size, advise) != 0 && log_madvise) { - error("Cannot advise the kernel about shared memory usage."); - log_madvise--; - } - } - - if(fd != -1) - close(fd); - - return mem; -} - -#ifdef MADV_MERGEABLE -static void *memory_file_mmap_ksm(const char *filename, size_t size, int flags) { - // info("memory_file_mmap_ksm('%s', %zu", filename, size); - static int log_madvise_2 = 1, log_madvise_3 = 1; - - int fd = -1; - if(filename) { - fd = memory_file_open(filename, size); - if(fd == -1) return MAP_FAILED; - } - - void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0); - if (mem != MAP_FAILED) { -#ifdef NETDATA_LOG_ALLOCATIONS - mmap_accounting(size); -#endif - if(fd != -1) { - if (lseek(fd, 0, SEEK_SET) == 0) { - if (read(fd, mem, size) != (ssize_t) size) - error("Cannot read from file '%s'", filename); - } - else error("Cannot seek to beginning of file '%s'.", filename); - } - - // don't use MADV_SEQUENTIAL|MADV_DONTFORK, they disable MADV_MERGEABLE - if (madvise(mem, size, MADV_SEQUENTIAL | MADV_DONTFORK) != 0 && log_madvise_2) { - error("Cannot advise the kernel about the memory usage (MADV_SEQUENTIAL|MADV_DONTFORK) of file '%s'.", filename); - log_madvise_2--; - } - - if (madvise(mem, size, MADV_MERGEABLE) != 0 && log_madvise_3) { - error("Cannot advise the kernel about the memory usage (MADV_MERGEABLE) of file '%s'.", filename); - log_madvise_3--; - } - } - - if(fd != -1) - close(fd); - - return mem; -} -#else -static void *memory_file_mmap_ksm(const char *filename, size_t size, int flags) { - // info("memory_file_mmap_ksm FALLBACK ('%s', %zu", filename, size); - - if(filename) - return memory_file_mmap(filename, size, flags); - - // when KSM is not available and no filename is given (memory mode = ram), - // we just report failure - return MAP_FAILED; -} -#endif - -void *mymmap(const char *filename, size_t size, int flags, int ksm) { - void *mem = NULL; - - if (filename && (flags & MAP_SHARED || !enable_ksm || !ksm)) - // memory mode = map | save - // when KSM is not enabled - // MAP_SHARED is used for memory mode = map (no KSM possible) - mem = memory_file_mmap(filename, size, flags); - - else - // memory mode = save | ram - // when KSM is enabled - // for memory mode = ram, the filename is NULL - mem = memory_file_mmap_ksm(filename, size, flags); - - if(mem == MAP_FAILED) return NULL; - - errno = 0; - return mem; -} - -int memory_file_save(const char *filename, void *mem, size_t size) { - char tmpfilename[FILENAME_MAX + 1]; - - snprintfz(tmpfilename, FILENAME_MAX, "%s.%ld.tmp", filename, (long) getpid()); - - int fd = open(tmpfilename, O_RDWR | O_CREAT | O_NOATIME, 0664); - if (fd < 0) { - error("Cannot create/open file '%s'.", filename); - return -1; - } - - if (write(fd, mem, size) != (ssize_t) size) { - error("Cannot write to file '%s' %ld bytes.", filename, (long) size); - close(fd); - return -1; - } - - close(fd); - - if (rename(tmpfilename, filename)) { - error("Cannot rename '%s' to '%s'", tmpfilename, filename); - return -1; - } - - return 0; -} - -int fd_is_valid(int fd) { - return fcntl(fd, F_GETFD) != -1 || errno != EBADF; -} - -char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) { - char *s = fgets(buf, (int)buf_size, fp); - if (!s) return NULL; - - char *t = s; - if (*t != '\0') { - // find the string end - while (*++t != '\0'); - - // trim trailing spaces/newlines/tabs - while (--t > s && *t == '\n') - *t = '\0'; - } - - if (len) - *len = t - s + 1; - - return s; -} - -int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) { - int size = vsnprintf(dst, n, fmt, args); - - if (unlikely((size_t) size > n)) { - // truncated - size = (int)n; - } - - dst[size] = '\0'; - return size; -} - -int snprintfz(char *dst, size_t n, const char *fmt, ...) { - va_list args; - - va_start(args, fmt); - int ret = vsnprintfz(dst, n, fmt, args); - va_end(args); - - return ret; -} - -// ---------------------------------------------------------------------------- -// system functions -// to retrieve settings of the system - -int processors = 1; -long get_system_cpus(void) { - processors = 1; - - #ifdef __APPLE__ - int32_t 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; - } - - return processors; - #else - - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix); - - procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT); - if(!ff) { - error("Cannot open file '%s'. Assuming system has %d processors.", filename, processors); - return processors; - } - - ff = procfile_readall(ff); - if(!ff) { - error("Cannot open file '%s'. Assuming system has %d processors.", filename, processors); - return processors; - } - - processors = 0; - unsigned int i; - for(i = 0; i < procfile_lines(ff); i++) { - if(!procfile_linewords(ff, i)) continue; - - if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++; - } - processors--; - if(processors < 1) processors = 1; - - procfile_close(ff); - - debug(D_SYSTEM, "System has %d processors.", processors); - return processors; - - #endif /* __APPLE__, __FreeBSD__ */ -} - -pid_t pid_max = 32768; -pid_t get_system_pid_max(void) { - #ifdef __APPLE__ - // As we currently do not know a solution to query pid_max from the os - // 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", netdata_configured_host_prefix); - - 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; - } - - if(!max) { - error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max); - return pid_max; - } - - pid_max = (pid_t) max; - return pid_max; - - #endif /* __APPLE__, __FreeBSD__ */ -} - -unsigned int hz; -void get_system_HZ(void) { - long ticks; - - if ((ticks = sysconf(_SC_CLK_TCK)) == -1) { - error("Cannot get system clock ticks"); - } - - hz = (unsigned int) ticks; -} - -/* -// poor man cycle counting -static unsigned long tsc; -void begin_tsc(void) { - unsigned long a, d; - asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx"); - tsc = ((unsigned long)d << 32) | (unsigned long)a; -} -unsigned long end_tsc(void) { - unsigned long a, d; - asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx"); - return (((unsigned long)d << 32) | (unsigned long)a) - tsc; -} -*/ - -int recursively_delete_dir(const char *path, const char *reason) { - DIR *dir = opendir(path); - if(!dir) { - error("Cannot read %s directory to be deleted '%s'", reason?reason:"", path); - return -1; - } - - int ret = 0; - struct dirent *de = NULL; - while((de = readdir(dir))) { - 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') - )) - continue; - - char fullpath[FILENAME_MAX + 1]; - snprintfz(fullpath, FILENAME_MAX, "%s/%s", path, de->d_name); - - if(de->d_type == DT_DIR) { - int r = recursively_delete_dir(fullpath, reason); - if(r > 0) ret += r; - continue; - } - - info("Deleting %s file '%s'", reason?reason:"", fullpath); - if(unlikely(unlink(fullpath) == -1)) - error("Cannot delete %s file '%s'", reason?reason:"", fullpath); - else - ret++; - } - - info("Deleting empty directory '%s'", path); - if(unlikely(rmdir(path) == -1)) - error("Cannot delete empty directory '%s'", path); - else - ret++; - - closedir(dir); - - return ret; -} diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 15fc50a6a..000000000 --- a/src/common.h +++ /dev/null @@ -1,360 +0,0 @@ -#ifndef NETDATA_COMMON_H -#define NETDATA_COMMON_H 1 - -#ifdef HAVE_CONFIG_H -#include -#endif - - -// ---------------------------------------------------------------------------- -// system include files for all netdata C programs - -/* select the memory allocator, based on autoconf findings */ -#if defined(ENABLE_JEMALLOC) - -#if defined(HAVE_JEMALLOC_JEMALLOC_H) -#include -#else -#include -#endif - -#elif defined(ENABLE_TCMALLOC) - -#include - -#else /* !defined(ENABLE_JEMALLOC) && !defined(ENABLE_TCMALLOC) */ - -#if !(defined(__FreeBSD__) || defined(__APPLE__)) -#include -#endif /* __FreeBSD__ || __APPLE__ */ - -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#ifdef HAVE_RESOLV_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETDB_H -#include -#endif - -#include - -#include -#include -#include -#include - -#ifdef HAVE_SYS_PRCTL_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// #1408 -#ifdef MAJOR_IN_MKDEV -#include -#endif -#ifdef MAJOR_IN_SYSMACROS -#include -#endif - -/* -#include -*/ - -#ifdef STORAGE_WITH_MATH -#include -#include -#endif - -#if defined(HAVE_INTTYPES_H) -#include -#elif defined(HAVE_STDINT_H) -#include -#endif - -#ifdef NETDATA_WITH_ZLIB -#include -#endif - -#ifdef HAVE_CAPABILITY -#include -#endif - -// ---------------------------------------------------------------------------- -// netdata chart priorities - -// This is a work in progress - to scope is to collect here all chart priorities. -// These should be based on the CONTEXT of the charts + the chart id when needed -// - for each SECTION +1000 (or +X000 for big sections) -// - for each FAMILY +100 -// - for each CHART +10 - -// Memory Section - 1xxx -#define NETDATA_CHART_PRIO_MEM_SYSTEM 1000 -#define NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE 1010 -#define NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED 1020 -#define NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS 1030 -#define NETDATA_CHART_PRIO_MEM_KERNEL 1100 -#define NETDATA_CHART_PRIO_MEM_SLAB 1200 -#define NETDATA_CHART_PRIO_MEM_HUGEPAGES 1250 -#define NETDATA_CHART_PRIO_MEM_KSM 1300 -#define NETDATA_CHART_PRIO_MEM_NUMA 1400 -#define NETDATA_CHART_PRIO_MEM_HW 1500 - - -// ---------------------------------------------------------------------------- -// netdata common definitions - -#if (SIZEOF_VOID_P == 8) -#define ENVIRONMENT64 -#elif (SIZEOF_VOID_P == 4) -#define ENVIRONMENT32 -#else -#error "Cannot detect if this is a 32 or 64 bit CPU" -#endif - -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#endif // __GNUC__ - -#ifdef HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL -#define NEVERNULL __attribute__((returns_nonnull)) -#else -#define NEVERNULL -#endif - -#ifdef HAVE_FUNC_ATTRIBUTE_NOINLINE -#define NOINLINE __attribute__((noinline)) -#else -#define NOINLINE -#endif - -#ifdef HAVE_FUNC_ATTRIBUTE_MALLOC -#define MALLOCLIKE __attribute__((malloc)) -#else -#define MALLOCLIKE -#endif - -#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT -#define PRINTFLIKE(f, a) __attribute__ ((format(__printf__, f, a))) -#else -#define PRINTFLIKE(f, a) -#endif - -#ifdef HAVE_FUNC_ATTRIBUTE_NORETURN -#define NORETURN __attribute__ ((noreturn)) -#else -#define NORETURN -#endif - -#ifdef HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT -#define WARNUNUSED __attribute__ ((warn_unused_result)) -#else -#define WARNUNUSED -#endif - -#ifdef abs -#undef abs -#endif -#define abs(x) (((x) < 0)? (-(x)) : (x)) - -#define GUID_LEN 36 - -// ---------------------------------------------------------------------------- -// netdata include files - -#include "clocks.h" -#include "log.h" -#include "threads.h" -#include "locks.h" -#include "simple_pattern.h" -#include "avl.h" -#include "global_statistics.h" -#include "storage_number.h" -#include "web_buffer.h" -#include "web_buffer_svg.h" -#include "url.h" -#include "popen.h" - -#include "procfile.h" -#include "appconfig.h" -#include "dictionary.h" -#include "proc_self_mountinfo.h" -#include "plugin_checks.h" -#include "plugin_idlejitter.h" -#include "plugin_nfacct.h" - -#if defined(__FreeBSD__) -#include -#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__*/ - -typedef enum rrdcalc_status { - RRDCALC_STATUS_REMOVED = -2, - RRDCALC_STATUS_UNDEFINED = -1, - RRDCALC_STATUS_UNINITIALIZED = 0, - RRDCALC_STATUS_CLEAR = 1, - RRDCALC_STATUS_RAISED = 2, - RRDCALC_STATUS_WARNING = 3, - RRDCALC_STATUS_CRITICAL = 4 -} RRDCALC_STATUS; - -#include "eval.h" -#include "health.h" - -#include "statistical.h" -#include "socket.h" -#include "rrd.h" -#include "plugin_tc.h" -#include "plugins_d.h" -#include "statsd.h" -#include "rrd2json.h" -#include "rrd2json_api_old.h" -#include "web_client.h" -#include "web_server.h" -#include "registry.h" -#include "signals.h" -#include "daemon.h" -#include "main.h" -#include "unit_test.h" -#include "ipc.h" -#include "backends.h" -#include "backend_prometheus.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_base; -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 char *netdata_configured_timezone; - -extern void netdata_fix_chart_id(char *s); -extern void netdata_fix_chart_name(char *s); - -extern void strreverse(char* begin, char* end); -extern char *mystrsep(char **ptr, char *s); -extern char *trim(char *s); // remove leading and trailing spaces; may return NULL -extern char *trim_all(char *buffer); // like trim(), but also remove duplicate spaces inside the string; may return NULL - -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); - -// memory allocation functions that handle failures -#ifdef NETDATA_LOG_ALLOCATIONS -#define strdupz(s) strdupz_int(__FILE__, __FUNCTION__, __LINE__, s) -#define callocz(nmemb, size) callocz_int(__FILE__, __FUNCTION__, __LINE__, nmemb, size) -#define mallocz(size) mallocz_int(__FILE__, __FUNCTION__, __LINE__, size) -#define reallocz(ptr, size) reallocz_int(__FILE__, __FUNCTION__, __LINE__, ptr, size) -#define freez(ptr) freez_int(__FILE__, __FUNCTION__, __LINE__, ptr) - -extern char *strdupz_int(const char *file, const char *function, const unsigned long line, const char *s); -extern void *callocz_int(const char *file, const char *function, const unsigned long line, size_t nmemb, size_t size); -extern void *mallocz_int(const char *file, const char *function, const unsigned long line, size_t size); -extern void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size); -extern void freez_int(const char *file, const char *function, const unsigned long line, void *ptr); -#else -extern char *strdupz(const char *s) MALLOCLIKE NEVERNULL; -extern void *callocz(size_t nmemb, size_t size) MALLOCLIKE NEVERNULL; -extern void *mallocz(size_t size) MALLOCLIKE NEVERNULL; -extern void *reallocz(void *ptr, size_t size) MALLOCLIKE NEVERNULL; -extern void freez(void *ptr); -#endif - -extern void json_escape_string(char *dst, const char *src, size_t size); -extern void json_fix_string(char *s); - -extern void *mymmap(const char *filename, size_t size, int flags, int ksm); -extern int memory_file_save(const char *filename, void *mem, size_t size); - -extern int fd_is_valid(int fd); - -extern struct rlimit rlimit_nofile; - -extern int enable_ksm; - -extern int sleep_usec(usec_t usec); - -extern char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len); - -extern int processors; -extern long get_system_cpus(void); - -extern pid_t pid_max; -extern pid_t get_system_pid_max(void); - -/* Number of ticks per second */ -extern unsigned int hz; -extern void get_system_HZ(void); - -extern int recursively_delete_dir(const char *path, const char *reason); - -extern volatile sig_atomic_t netdata_exit; -extern const char *os_type; - -extern const char *program_version; - -/* fix for alpine linux */ -#ifndef RUSAGE_THREAD -#ifdef RUSAGE_CHILDREN -#define RUSAGE_THREAD RUSAGE_CHILDREN -#endif -#endif - -#define BITS_IN_A_KILOBIT 1000 - -#endif /* NETDATA_COMMON_H */ diff --git a/src/daemon.c b/src/daemon.c deleted file mode 100644 index 471c62c6e..000000000 --- a/src/daemon.c +++ /dev/null @@ -1,396 +0,0 @@ -#include "common.h" -#include - -char pidfile[FILENAME_MAX + 1] = ""; - -static void chown_open_file(int fd, uid_t uid, gid_t gid) { - if(fd == -1) return; - - struct stat buf; - - if(fstat(fd, &buf) == -1) { - error("Cannot fstat() fd %d", fd); - return; - } - - if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) { - if(fchown(fd, uid, gid) == -1) - error("Cannot fchown() fd %d.", fd); - } -} - -void create_needed_dir(const char *dir, uid_t uid, gid_t gid) -{ - // attempt to create the directory - if(mkdir(dir, 0755) == 0) { - // we created it - - // chown it to match the required user - if(chown(dir, uid, gid) == -1) - error("Cannot chown directory '%s' to %u:%u", dir, (unsigned int)uid, (unsigned int)gid); - } - else if(errno != EEXIST) - // log an error only if the directory does not exist - error("Cannot create directory '%s'", dir); -} - -int become_user(const char *username, int pid_fd) { - int am_i_root = (getuid() == 0)?1:0; - - struct passwd *pw = getpwnam(username); - if(!pw) { - error("User %s is not present.", username); - return -1; - } - - uid_t uid = pw->pw_uid; - gid_t gid = pw->pw_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) - error("Cannot chown '%s' to %u:%u", pidfile, (unsigned int)uid, (unsigned int)gid); - } - - int ngroups = (int)sysconf(_SC_NGROUPS_MAX); - gid_t *supplementary_groups = NULL; - if(ngroups > 0) { - supplementary_groups = mallocz(sizeof(gid_t) * ngroups); - if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) { - if(am_i_root) - error("Cannot get supplementary groups of user '%s'.", username); - - ngroups = 0; - } - } - - chown_open_file(STDOUT_FILENO, uid, gid); - chown_open_file(STDERR_FILENO, uid, gid); - chown_open_file(stdaccess_fd, uid, gid); - chown_open_file(pid_fd, uid, gid); - - if(supplementary_groups && ngroups > 0) { - if(setgroups((size_t)ngroups, supplementary_groups) == -1) { - if(am_i_root) - error("Cannot set supplementary groups for user '%s'", username); - } - ngroups = 0; - } - - if(supplementary_groups) - freez(supplementary_groups); - -#ifdef __APPLE__ - if(setregid(gid, gid) != 0) { -#else - if(setresgid(gid, gid, gid) != 0) { -#endif /* __APPLE__ */ - error("Cannot switch to user's %s group (gid: %u).", username, gid); - return -1; - } - -#ifdef __APPLE__ - if(setreuid(uid, uid) != 0) { -#else - if(setresuid(uid, uid, uid) != 0) { -#endif /* __APPLE__ */ - error("Cannot switch to user %s (uid: %u).", username, uid); - return -1; - } - - if(setgid(gid) != 0) { - error("Cannot switch to user's %s group (gid: %u).", username, gid); - return -1; - } - if(setegid(gid) != 0) { - error("Cannot effectively switch to user's %s group (gid: %u).", username, gid); - return -1; - } - if(setuid(uid) != 0) { - error("Cannot switch to user %s (uid: %u).", username, uid); - return -1; - } - if(seteuid(uid) != 0) { - error("Cannot effectively switch to user %s (uid: %u).", username, uid); - return -1; - } - - return(0); -} - -#ifndef OOM_SCORE_ADJ_MAX -#define OOM_SCORE_ADJ_MAX (1000) -#endif -#ifndef OOM_SCORE_ADJ_MIN -#define OOM_SCORE_ADJ_MIN (-1000) -#endif - -static void oom_score_adj(void) { - char buf[30 + 1]; - long long int old_score, wanted_score = OOM_SCORE_ADJ_MAX, final_score = 0; - - // read the existing score - if(read_single_signed_number_file("/proc/self/oom_score_adj", &old_score)) { - error("Out-Of-Memory (OOM) score setting is not supported on this system."); - return; - } - - if(old_score != 0) - wanted_score = old_score; - - // check the environment - char *s = getenv("OOMScoreAdjust"); - if(!s || !*s) { - snprintfz(buf, 30, "%d", (int)wanted_score); - s = buf; - } - - // check netdata.conf configuration - s = config_get(CONFIG_SECTION_GLOBAL, "OOM score", s); - if(s && *s && (isdigit(*s) || *s == '-' || *s == '+')) - wanted_score = atoll(s); - else { - info("Out-Of-Memory (OOM) score not changed due to non-numeric setting: '%s' (running with %d)", s, (int)old_score); - return; - } - - if(wanted_score < OOM_SCORE_ADJ_MIN) { - error("Wanted Out-Of-Memory (OOM) score %d is too small. Using %d", (int)wanted_score, (int)OOM_SCORE_ADJ_MIN); - wanted_score = OOM_SCORE_ADJ_MIN; - } - - if(wanted_score > OOM_SCORE_ADJ_MAX) { - error("Wanted Out-Of-Memory (OOM) score %d is too big. Using %d", (int)wanted_score, (int)OOM_SCORE_ADJ_MAX); - wanted_score = OOM_SCORE_ADJ_MAX; - } - - if(old_score == wanted_score) { - info("Out-Of-Memory (OOM) score is already set to the wanted value %d", (int)old_score); - return; - } - - int written = 0; - int fd = open("/proc/self/oom_score_adj", O_WRONLY); - if(fd != -1) { - snprintfz(buf, 30, "%d", (int)wanted_score); - ssize_t len = strlen(buf); - if(len > 0 && write(fd, buf, (size_t)len) == len) written = 1; - close(fd); - - if(written) { - if(read_single_signed_number_file("/proc/self/oom_score_adj", &final_score)) - error("Adjusted my Out-Of-Memory (OOM) score to %d, but cannot verify it.", (int)wanted_score); - else if(final_score == wanted_score) - info("Adjusted my Out-Of-Memory (OOM) score from %d to %d.", (int)old_score, (int)final_score); - else - error("Adjusted my Out-Of-Memory (OOM) score from %d to %d, but it has been set to %d.", (int)old_score, (int)wanted_score, (int)final_score); - } - else - error("Failed to adjust my Out-Of-Memory (OOM) score to %d. Running with %d. (systemd systems may change it via netdata.service)", (int)wanted_score, (int)old_score); - } - else - error("Failed to adjust my Out-Of-Memory (OOM) score. Cannot open /proc/self/oom_score_adj for writing."); -} - -static void process_nice_level(void) { -#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 - { "idle", SCHED_IDLE, 0, SCHED_FLAG_NONE }, -#endif - -#ifdef SCHED_OTHER - { "nice", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE }, - { "other", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE }, -#endif - -#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; - policy = scheduler_defaults[i].policy; - 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 - errno = 0; - if(priority < sched_get_priority_min(policy)) { - error("scheduler %s (%d) priority %d is below the minimum %d. Using the minimum.", name, policy, priority, sched_get_priority_min(policy)); - priority = sched_get_priority_min(policy); - } -#endif -#ifdef HAVE_SCHED_GET_PRIORITY_MAX - errno = 0; - if(priority > sched_get_priority_max(policy)) { - error("scheduler %s (%d) priority %d is above the maximum %d. Using the maximum.", name, policy, 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 - }; - - errno = 0; - i = sched_setscheduler(0, policy, ¶m); - if(i != 0) { - error("Cannot adjust netdata scheduling policy to %s (%d), with priority %d. Falling back to nice.", name, policy, priority); - } - else { - info("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) -{ - if(!dont_fork) { - int i = fork(); - if(i == -1) { - perror("cannot fork"); - exit(1); - } - if(i != 0) { - exit(0); // the parent - } - - // become session leader - if (setsid() < 0) { - perror("Cannot become session leader."); - exit(2); - } - - // fork() again - i = fork(); - if(i == -1) { - perror("cannot fork"); - exit(1); - } - if(i != 0) { - exit(0); // the parent - } - } - - // generate our pid file - int pidfd = -1; - if(pidfile[0]) { - pidfd = open(pidfile, O_WRONLY | O_CREAT, 0644); - if(pidfd >= 0) { - if(ftruncate(pidfd, 0) != 0) - error("Cannot truncate pidfile '%s'.", pidfile); - - char b[100]; - sprintf(b, "%d\n", getpid()); - ssize_t i = write(pidfd, b, strlen(b)); - if(i <= 0) - error("Cannot write pidfile '%s'.", pidfile); - } - else error("Failed to open pidfile '%s'.", pidfile); - } - - // Set new file permissions - umask(0007); - - // adjust my Out-Of-Memory score - oom_score_adj(); - - // never become a problem - sched_setscheduler_set(); - - if(user && *user) { - if(become_user(user, pidfd) != 0) { - error("Cannot become user '%s'. Continuing as we are.", user); - } - else debug(D_SYSTEM, "Successfully became user '%s'.", user); - } - else { - create_needed_dir(netdata_configured_cache_dir, getuid(), getgid()); - create_needed_dir(netdata_configured_varlib_dir, getuid(), getgid()); - } - - if(pidfd != -1) - close(pidfd); - - return(0); -} diff --git a/src/daemon.h b/src/daemon.h deleted file mode 100644 index 150d74e3a..000000000 --- a/src/daemon.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef NETDATA_DAEMON_H -#define NETDATA_DAEMON_H 1 - -extern int become_user(const char *username, int pid_fd); - -extern int become_daemon(int dont_fork, const char *user); - -extern void netdata_cleanup_and_exit(int i); - -extern char pidfile[]; - -#endif /* NETDATA_DAEMON_H */ diff --git a/src/dictionary.c b/src/dictionary.c deleted file mode 100644 index 512b4bbe6..000000000 --- a/src/dictionary.c +++ /dev/null @@ -1,292 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// dictionary statistics - -static inline void NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->inserts++; -} -static inline void NETDATA_DICTIONARY_STATS_DELETES_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->deletes++; -} -static inline void NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->searches++; -} -static inline void NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->entries++; -} -static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->entries--; -} - - -// ---------------------------------------------------------------------------- -// dictionary locks - -static inline void dictionary_read_lock(DICTIONARY *dict) { - if(likely(dict->rwlock)) { - // debug(D_DICTIONARY, "Dictionary READ lock"); - netdata_rwlock_rdlock(dict->rwlock); - } -} - -static inline void dictionary_write_lock(DICTIONARY *dict) { - if(likely(dict->rwlock)) { - // debug(D_DICTIONARY, "Dictionary WRITE lock"); - netdata_rwlock_wrlock(dict->rwlock); - } -} - -static inline void dictionary_unlock(DICTIONARY *dict) { - if(likely(dict->rwlock)) { - // debug(D_DICTIONARY, "Dictionary UNLOCK lock"); - netdata_rwlock_unlock(dict->rwlock); - } -} - - -// ---------------------------------------------------------------------------- -// avl index - -static int name_value_compare(void* a, void* b) { - if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1; - else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1; - else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name); -} - -static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) { - NAME_VALUE tmp; - tmp.hash = (hash)?hash:simple_hash(name); - tmp.name = (char *)name; - - NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict); - return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp); -} - -// ---------------------------------------------------------------------------- -// internal methods - -static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) { - debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name); - - NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE)); - - if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE) - nv->name = (char *)name; - else { - nv->name = strdupz(name); - } - - nv->hash = (hash)?hash:simple_hash(nv->name); - - if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) - nv->value = value; - else { - nv->value = mallocz(value_len); - memcpy(nv->value, value, value_len); - } - - // index it - NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict); - if(unlikely(avl_insert(&((dict)->values_index), (avl *)(nv)) != (avl *)nv)) - error("dictionary: INTERNAL ERROR: duplicate insertion to dictionary."); - - NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict); - - return nv; -} - -static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) { - debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name); - - NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict); - if(unlikely(avl_remove(&(dict->values_index), (avl *)(nv)) != (avl *)nv)) - error("dictionary: INTERNAL ERROR: dictionary invalid removal of node."); - - NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict); - - if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) { - debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name); - freez(nv->value); - } - - if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) { - debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name); - freez(nv->name); - } - - freez(nv); -} - -// ---------------------------------------------------------------------------- -// API - basic methods - -DICTIONARY *dictionary_create(uint8_t flags) { - debug(D_DICTIONARY, "Creating dictionary."); - - DICTIONARY *dict = callocz(1, sizeof(DICTIONARY)); - - if(flags & DICTIONARY_FLAG_WITH_STATISTICS) - dict->stats = callocz(1, sizeof(struct dictionary_stats)); - - if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) { - dict->rwlock = callocz(1, sizeof(netdata_rwlock_t)); - netdata_rwlock_init(dict->rwlock); - } - - avl_init(&dict->values_index, name_value_compare); - dict->flags = flags; - - return dict; -} - -void dictionary_destroy(DICTIONARY *dict) { - debug(D_DICTIONARY, "Destroying dictionary."); - - dictionary_write_lock(dict); - - while(dict->values_index.root) - dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root); - - dictionary_unlock(dict); - - if(dict->stats) - freez(dict->stats); - - if(dict->rwlock) { - netdata_rwlock_destroy(dict->rwlock); - freez(dict->rwlock); - } - - freez(dict); -} - -// ---------------------------------------------------------------------------- - -void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) { - debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name); - - uint32_t hash = simple_hash(name); - - dictionary_write_lock(dict); - - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash); - if(unlikely(!nv)) { - debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name); - - nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash); - if(unlikely(!nv)) - fatal("Cannot create name_value."); - } - else { - debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name); - - if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) { - debug(D_REGISTRY, "Dictionary: linking value to '%s'", name); - nv->value = value; - } - else { - debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name); - - // copy the new value without breaking - // any other thread accessing the same entry - void *new = mallocz(value_len), - *old = nv->value; - - memcpy(new, value, value_len); - nv->value = new; - - debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name); - freez(old); - } - } - - dictionary_unlock(dict); - - return nv->value; -} - -void *dictionary_get(DICTIONARY *dict, const char *name) { - debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name); - - dictionary_read_lock(dict); - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0); - dictionary_unlock(dict); - - if(unlikely(!nv)) { - debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name); - return NULL; - } - - debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name); - return nv->value; -} - -int dictionary_del(DICTIONARY *dict, const char *name) { - int ret; - - debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name); - - dictionary_write_lock(dict); - - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0); - if(unlikely(!nv)) { - debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name); - ret = -1; - } - else { - debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name); - dictionary_name_value_destroy_nolock(dict, nv); - ret = 0; - } - - dictionary_unlock(dict); - - return ret; -} - - -// ---------------------------------------------------------------------------- -// API - walk through the dictionary -// the dictionary is locked for reading while this happens -// do not user other dictionary calls while walking the dictionary - deadlock! - -static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) { - int total = 0, ret = 0; - - if(a->avl_link[0]) { - ret = dictionary_walker(a->avl_link[0], callback, data); - if(ret < 0) return ret; - total += ret; - } - - ret = callback(((NAME_VALUE *)a)->value, data); - if(ret < 0) return ret; - total += ret; - - if(a->avl_link[1]) { - ret = dictionary_walker(a->avl_link[1], callback, data); - if (ret < 0) return ret; - total += ret; - } - - return total; -} - -int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) { - int ret = 0; - - dictionary_read_lock(dict); - - if(likely(dict->values_index.root)) - ret = dictionary_walker(dict->values_index.root, callback, data); - - dictionary_unlock(dict); - - return ret; -} diff --git a/src/dictionary.h b/src/dictionary.h deleted file mode 100644 index f028dbb30..000000000 --- a/src/dictionary.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef NETDATA_DICTIONARY_H -#define NETDATA_DICTIONARY_H 1 - -struct dictionary_stats { - unsigned long long inserts; - unsigned long long deletes; - unsigned long long searches; - unsigned long long entries; -}; - -typedef struct name_value { - avl avl; // the index - this has to be first! - - uint32_t hash; // a simple hash to speed up searching - // we first compare hashes, and only if the hashes are equal we do string comparisons - - char *name; - void *value; -} NAME_VALUE; - -typedef struct dictionary { - avl_tree values_index; - - uint8_t flags; - - struct dictionary_stats *stats; - netdata_rwlock_t *rwlock; -} DICTIONARY; - -#define DICTIONARY_FLAG_DEFAULT 0x00000000 -#define DICTIONARY_FLAG_SINGLE_THREADED 0x00000001 -#define DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE 0x00000002 -#define DICTIONARY_FLAG_NAME_LINK_DONT_CLONE 0x00000004 -#define DICTIONARY_FLAG_WITH_STATISTICS 0x00000008 - -extern DICTIONARY *dictionary_create(uint8_t flags); -extern void dictionary_destroy(DICTIONARY *dict); -extern void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len); -extern void *dictionary_get(DICTIONARY *dict, const char *name); -extern int dictionary_del(DICTIONARY *dict, const char *name); - -extern int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *d), void *data); - -#endif /* NETDATA_DICTIONARY_H */ diff --git a/src/eval.c b/src/eval.c deleted file mode 100644 index 84369f6d4..000000000 --- a/src/eval.c +++ /dev/null @@ -1,1188 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// data structures for storing the parsed expression in memory - -typedef struct eval_value { - int type; - - union { - calculated_number number; - EVAL_VARIABLE *variable; - struct eval_node *expression; - }; -} EVAL_VALUE; - -typedef struct eval_node { - int id; - unsigned char operator; - int precedence; - - int count; - EVAL_VALUE ops[]; -} EVAL_NODE; - -// these are used for EVAL_NODE.operator -// they are used as internal IDs to identify an operator -// THEY ARE NOT USED FOR PARSING OPERATORS LIKE THAT -#define EVAL_OPERATOR_NOP '\0' -#define EVAL_OPERATOR_EXPRESSION_OPEN '(' -#define EVAL_OPERATOR_EXPRESSION_CLOSE ')' -#define EVAL_OPERATOR_NOT '!' -#define EVAL_OPERATOR_PLUS '+' -#define EVAL_OPERATOR_MINUS '-' -#define EVAL_OPERATOR_AND '&' -#define EVAL_OPERATOR_OR '|' -#define EVAL_OPERATOR_GREATER_THAN_OR_EQUAL 'G' -#define EVAL_OPERATOR_LESS_THAN_OR_EQUAL 'L' -#define EVAL_OPERATOR_NOT_EQUAL '~' -#define EVAL_OPERATOR_EQUAL '=' -#define EVAL_OPERATOR_LESS '<' -#define EVAL_OPERATOR_GREATER '>' -#define EVAL_OPERATOR_MULTIPLY '*' -#define EVAL_OPERATOR_DIVIDE '/' -#define EVAL_OPERATOR_SIGN_PLUS 'P' -#define EVAL_OPERATOR_SIGN_MINUS 'M' -#define EVAL_OPERATOR_ABS 'A' -#define EVAL_OPERATOR_IF_THEN_ELSE '?' - -// ---------------------------------------------------------------------------- -// forward function definitions - -static inline void eval_node_free(EVAL_NODE *op); -static inline EVAL_NODE *parse_full_expression(const char **string, int *error); -static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error); -static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error); -static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error); -static inline void print_parsed_as_constant(BUFFER *out, calculated_number n); - -// ---------------------------------------------------------------------------- -// evaluation of expressions - -static inline calculated_number eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *v, int *error) { - static uint32_t this_hash = 0, now_hash = 0, after_hash = 0, before_hash = 0, status_hash = 0, removed_hash = 0, uninitialized_hash = 0, undefined_hash = 0, clear_hash = 0, warning_hash = 0, critical_hash = 0; - calculated_number n; - - if(unlikely(this_hash == 0)) { - this_hash = simple_hash("this"); - now_hash = simple_hash("now"); - after_hash = simple_hash("after"); - before_hash = simple_hash("before"); - status_hash = simple_hash("status"); - removed_hash = simple_hash("REMOVED"); - uninitialized_hash = simple_hash("UNINITIALIZED"); - undefined_hash = simple_hash("UNDEFINED"); - clear_hash = simple_hash("CLEAR"); - warning_hash = simple_hash("WARNING"); - critical_hash = simple_hash("CRITICAL"); - } - - if(unlikely(v->hash == this_hash && !strcmp(v->name, "this"))) { - n = (exp->this)?*exp->this:NAN; - buffer_strcat(exp->error_msg, "[ $this = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == after_hash && !strcmp(v->name, "after"))) { - n = (exp->after && *exp->after)?*exp->after:NAN; - buffer_strcat(exp->error_msg, "[ $after = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == before_hash && !strcmp(v->name, "before"))) { - n = (exp->before && *exp->before)?*exp->before:NAN; - buffer_strcat(exp->error_msg, "[ $before = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == now_hash && !strcmp(v->name, "now"))) { - n = now_realtime_sec(); - buffer_strcat(exp->error_msg, "[ $now = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == status_hash && !strcmp(v->name, "status"))) { - n = (exp->status)?*exp->status:RRDCALC_STATUS_UNINITIALIZED; - buffer_strcat(exp->error_msg, "[ $status = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == removed_hash && !strcmp(v->name, "REMOVED"))) { - n = RRDCALC_STATUS_REMOVED; - buffer_strcat(exp->error_msg, "[ $REMOVED = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == uninitialized_hash && !strcmp(v->name, "UNINITIALIZED"))) { - n = RRDCALC_STATUS_UNINITIALIZED; - buffer_strcat(exp->error_msg, "[ $UNINITIALIZED = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == undefined_hash && !strcmp(v->name, "UNDEFINED"))) { - n = RRDCALC_STATUS_UNDEFINED; - buffer_strcat(exp->error_msg, "[ $UNDEFINED = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == clear_hash && !strcmp(v->name, "CLEAR"))) { - n = RRDCALC_STATUS_CLEAR; - buffer_strcat(exp->error_msg, "[ $CLEAR = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == warning_hash && !strcmp(v->name, "WARNING"))) { - n = RRDCALC_STATUS_WARNING; - buffer_strcat(exp->error_msg, "[ $WARNING = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(unlikely(v->hash == critical_hash && !strcmp(v->name, "CRITICAL"))) { - n = RRDCALC_STATUS_CRITICAL; - buffer_strcat(exp->error_msg, "[ $CRITICAL = "); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - if(exp->rrdcalc && health_variable_lookup(v->name, v->hash, exp->rrdcalc, &n)) { - buffer_sprintf(exp->error_msg, "[ ${%s} = ", v->name); - print_parsed_as_constant(exp->error_msg, n); - buffer_strcat(exp->error_msg, " ] "); - return n; - } - - *error = EVAL_ERROR_UNKNOWN_VARIABLE; - buffer_sprintf(exp->error_msg, "[ undefined variable '%s' ] ", v->name); - return 0; -} - -static inline calculated_number eval_value(EVAL_EXPRESSION *exp, EVAL_VALUE *v, int *error) { - calculated_number n; - - switch(v->type) { - case EVAL_VALUE_EXPRESSION: - n = eval_node(exp, v->expression, error); - break; - - case EVAL_VALUE_NUMBER: - n = v->number; - break; - - case EVAL_VALUE_VARIABLE: - n = eval_variable(exp, v->variable, error); - break; - - default: - *error = EVAL_ERROR_INVALID_VALUE; - n = 0; - break; - } - - return n; -} - -static inline int is_true(calculated_number n) { - if(isnan(n)) return 0; - if(isinf(n)) return 1; - if(n == 0) return 0; - return 1; -} - -calculated_number eval_and(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - return is_true(eval_value(exp, &op->ops[0], error)) && is_true(eval_value(exp, &op->ops[1], error)); -} -calculated_number eval_or(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - return is_true(eval_value(exp, &op->ops[0], error)) || is_true(eval_value(exp, &op->ops[1], error)); -} -calculated_number eval_greater_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - return isgreaterequal(n1, n2); -} -calculated_number eval_less_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - return islessequal(n1, n2); -} -calculated_number eval_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - if(isnan(n1) && isnan(n2)) return 1; - if(isinf(n1) && isinf(n2)) return 1; - if(isnan(n1) || isnan(n2)) return 0; - if(isinf(n1) || isinf(n2)) return 0; - return calculated_number_equal(n1, n2); -} -calculated_number eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - return !eval_equal(exp, op, error); -} -calculated_number eval_less(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - return isless(n1, n2); -} -calculated_number eval_greater(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - return isgreater(n1, n2); -} -calculated_number eval_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - if(isnan(n1) || isnan(n2)) return NAN; - if(isinf(n1) || isinf(n2)) return INFINITY; - return n1 + n2; -} -calculated_number eval_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - if(isnan(n1) || isnan(n2)) return NAN; - if(isinf(n1) || isinf(n2)) return INFINITY; - return n1 - n2; -} -calculated_number eval_multiply(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - if(isnan(n1) || isnan(n2)) return NAN; - if(isinf(n1) || isinf(n2)) return INFINITY; - return n1 * n2; -} -calculated_number eval_divide(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - calculated_number n2 = eval_value(exp, &op->ops[1], error); - if(isnan(n1) || isnan(n2)) return NAN; - if(isinf(n1) || isinf(n2)) return INFINITY; - return n1 / n2; -} -calculated_number eval_nop(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - return eval_value(exp, &op->ops[0], error); -} -calculated_number eval_not(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - return !is_true(eval_value(exp, &op->ops[0], error)); -} -calculated_number eval_sign_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - return eval_value(exp, &op->ops[0], error); -} -calculated_number eval_sign_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - if(isnan(n1)) return NAN; - if(isinf(n1)) return INFINITY; - return -n1; -} -calculated_number eval_abs(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - calculated_number n1 = eval_value(exp, &op->ops[0], error); - if(isnan(n1)) return NAN; - if(isinf(n1)) return INFINITY; - return abs(n1); -} -calculated_number eval_if_then_else(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - if(is_true(eval_value(exp, &op->ops[0], error))) - return eval_value(exp, &op->ops[1], error); - else - return eval_value(exp, &op->ops[2], error); -} - -static struct operator { - const char *print_as; - char precedence; - char parameters; - char isfunction; - calculated_number (*eval)(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error); -} operators[256] = { - // this is a random access array - // we always access it with a known EVAL_OPERATOR_X - - [EVAL_OPERATOR_AND] = { "&&", 2, 2, 0, eval_and }, - [EVAL_OPERATOR_OR] = { "||", 2, 2, 0, eval_or }, - [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, 2, 0, eval_greater_than_or_equal }, - [EVAL_OPERATOR_LESS_THAN_OR_EQUAL] = { "<=", 3, 2, 0, eval_less_than_or_equal }, - [EVAL_OPERATOR_NOT_EQUAL] = { "!=", 3, 2, 0, eval_not_equal }, - [EVAL_OPERATOR_EQUAL] = { "==", 3, 2, 0, eval_equal }, - [EVAL_OPERATOR_LESS] = { "<", 3, 2, 0, eval_less }, - [EVAL_OPERATOR_GREATER] = { ">", 3, 2, 0, eval_greater }, - [EVAL_OPERATOR_PLUS] = { "+", 4, 2, 0, eval_plus }, - [EVAL_OPERATOR_MINUS] = { "-", 4, 2, 0, eval_minus }, - [EVAL_OPERATOR_MULTIPLY] = { "*", 5, 2, 0, eval_multiply }, - [EVAL_OPERATOR_DIVIDE] = { "/", 5, 2, 0, eval_divide }, - [EVAL_OPERATOR_NOT] = { "!", 6, 1, 0, eval_not }, - [EVAL_OPERATOR_SIGN_PLUS] = { "+", 6, 1, 0, eval_sign_plus }, - [EVAL_OPERATOR_SIGN_MINUS] = { "-", 6, 1, 0, eval_sign_minus }, - [EVAL_OPERATOR_ABS] = { "abs(",6,1, 1, eval_abs }, - [EVAL_OPERATOR_IF_THEN_ELSE] = { "?", 7, 3, 0, eval_if_then_else }, - [EVAL_OPERATOR_NOP] = { NULL, 8, 1, 0, eval_nop }, - [EVAL_OPERATOR_EXPRESSION_OPEN] = { NULL, 8, 1, 0, eval_nop }, - - // this should exist in our evaluation list - [EVAL_OPERATOR_EXPRESSION_CLOSE] = { NULL, 99, 1, 0, eval_nop } -}; - -#define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence) - -static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { - if(unlikely(op->count != operators[op->operator].parameters)) { - *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS; - return 0; - } - - calculated_number n = operators[op->operator].eval(exp, op, error); - - return n; -} - -// ---------------------------------------------------------------------------- -// parsed-as generation - -static inline void print_parsed_as_variable(BUFFER *out, EVAL_VARIABLE *v, int *error) { - (void)error; - buffer_sprintf(out, "${%s}", v->name); -} - -static inline void print_parsed_as_constant(BUFFER *out, calculated_number n) { - if(unlikely(isnan(n))) { - buffer_strcat(out, "nan"); - return; - } - - if(unlikely(isinf(n))) { - buffer_strcat(out, "inf"); - return; - } - - char b[100+1], *s; - snprintfz(b, 100, CALCULATED_NUMBER_FORMAT, n); - - s = &b[strlen(b) - 1]; - while(s > b && *s == '0') { - *s ='\0'; - s--; - } - - if(s > b && *s == '.') - *s = '\0'; - - buffer_strcat(out, b); -} - -static inline void print_parsed_as_value(BUFFER *out, EVAL_VALUE *v, int *error) { - switch(v->type) { - case EVAL_VALUE_EXPRESSION: - print_parsed_as_node(out, v->expression, error); - break; - - case EVAL_VALUE_NUMBER: - print_parsed_as_constant(out, v->number); - break; - - case EVAL_VALUE_VARIABLE: - print_parsed_as_variable(out, v->variable, error); - break; - - default: - *error = EVAL_ERROR_INVALID_VALUE; - break; - } -} - -static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error) { - if(unlikely(op->count != operators[op->operator].parameters)) { - *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS; - return; - } - - if(operators[op->operator].parameters == 1) { - - if(operators[op->operator].print_as) - buffer_sprintf(out, "%s", operators[op->operator].print_as); - - //if(op->operator == EVAL_OPERATOR_EXPRESSION_OPEN) - // buffer_strcat(out, "("); - - print_parsed_as_value(out, &op->ops[0], error); - - //if(op->operator == EVAL_OPERATOR_EXPRESSION_OPEN) - // buffer_strcat(out, ")"); - } - - else if(operators[op->operator].parameters == 2) { - buffer_strcat(out, "("); - print_parsed_as_value(out, &op->ops[0], error); - - if(operators[op->operator].print_as) - buffer_sprintf(out, " %s ", operators[op->operator].print_as); - - print_parsed_as_value(out, &op->ops[1], error); - buffer_strcat(out, ")"); - } - else if(op->operator == EVAL_OPERATOR_IF_THEN_ELSE && operators[op->operator].parameters == 3) { - buffer_strcat(out, "("); - print_parsed_as_value(out, &op->ops[0], error); - - if(operators[op->operator].print_as) - buffer_sprintf(out, " %s ", operators[op->operator].print_as); - - print_parsed_as_value(out, &op->ops[1], error); - buffer_strcat(out, " : "); - print_parsed_as_value(out, &op->ops[2], error); - buffer_strcat(out, ")"); - } - - if(operators[op->operator].isfunction) - buffer_strcat(out, ")"); -} - -// ---------------------------------------------------------------------------- -// parsing expressions - -// skip spaces -static inline void skip_spaces(const char **string) { - const char *s = *string; - while(isspace(*s)) s++; - *string = s; -} - -// what character can appear just after an operator keyword -// like NOT AND OR ? -static inline int isoperatorterm_word(const char s) { - if(isspace(s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit(s) || !s) - return 1; - - return 0; -} - -// what character can appear just after an operator symbol? -static inline int isoperatorterm_symbol(const char s) { - if(isoperatorterm_word(s) || isalpha(s)) - return 1; - - return 0; -} - -// return 1 if the character should never appear in a variable -static inline int isvariableterm(const char s) { - if(isalnum(s) || s == '.' || s == '_') - return 0; - - return 1; -} - -// ---------------------------------------------------------------------------- -// parse operators - -static inline int parse_and(const char **string) { - const char *s = *string; - - // AND - if((s[0] == 'A' || s[0] == 'a') && (s[1] == 'N' || s[1] == 'n') && (s[2] == 'D' || s[2] == 'd') && isoperatorterm_word(s[3])) { - *string = &s[4]; - return 1; - } - - // && - if(s[0] == '&' && s[1] == '&' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - return 1; - } - - return 0; -} - -static inline int parse_or(const char **string) { - const char *s = *string; - - // OR - if((s[0] == 'O' || s[0] == 'o') && (s[1] == 'R' || s[1] == 'r') && isoperatorterm_word(s[2])) { - *string = &s[3]; - return 1; - } - - // || - if(s[0] == '|' && s[1] == '|' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - return 1; - } - - return 0; -} - -static inline int parse_greater_than_or_equal(const char **string) { - const char *s = *string; - - // >= - if(s[0] == '>' && s[1] == '=' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - return 1; - } - - return 0; -} - -static inline int parse_less_than_or_equal(const char **string) { - const char *s = *string; - - // <= - if (s[0] == '<' && s[1] == '=' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - return 1; - } - - return 0; -} - -static inline int parse_greater(const char **string) { - const char *s = *string; - - // > - if(s[0] == '>' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_less(const char **string) { - const char *s = *string; - - // < - if(s[0] == '<' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_equal(const char **string) { - const char *s = *string; - - // == - if(s[0] == '=' && s[1] == '=' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - return 1; - } - - // = - if(s[0] == '=' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_not_equal(const char **string) { - const char *s = *string; - - // != - if(s[0] == '!' && s[1] == '=' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - return 1; - } - - // <> - if(s[0] == '<' && s[1] == '>' && isoperatorterm_symbol(s[2])) { - *string = &s[2]; - } - - return 0; -} - -static inline int parse_not(const char **string) { - const char *s = *string; - - // NOT - if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') && isoperatorterm_word(s[3])) { - *string = &s[3]; - return 1; - } - - if(s[0] == '!') { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_multiply(const char **string) { - const char *s = *string; - - // * - if(s[0] == '*' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_divide(const char **string) { - const char *s = *string; - - // / - if(s[0] == '/' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_minus(const char **string) { - const char *s = *string; - - // - - if(s[0] == '-' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_plus(const char **string) { - const char *s = *string; - - // + - if(s[0] == '+' && isoperatorterm_symbol(s[1])) { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_open_subexpression(const char **string) { - const char *s = *string; - - // ( - if(s[0] == '(') { - *string = &s[1]; - return 1; - } - - return 0; -} - -#define parse_close_function(x) parse_close_subexpression(x) - -static inline int parse_close_subexpression(const char **string) { - const char *s = *string; - - // ) - if(s[0] == ')') { - *string = &s[1]; - return 1; - } - - return 0; -} - -static inline int parse_variable(const char **string, char *buffer, size_t len) { - const char *s = *string; - - // $ - if(*s == '$') { - size_t i = 0; - s++; - - if(*s == '{') { - // ${variable_name} - - s++; - while (*s && *s != '}' && i < len) - buffer[i++] = *s++; - - if(*s == '}') - s++; - } - else { - // $variable_name - - while (*s && !isvariableterm(*s) && i < len) - buffer[i++] = *s++; - } - - buffer[i] = '\0'; - - if (buffer[0]) { - *string = s; - return 1; - } - } - - return 0; -} - -static inline int parse_constant(const char **string, calculated_number *number) { - char *end = NULL; - calculated_number n = str2ld(*string, &end); - if(unlikely(!end || *string == end)) { - *number = 0; - return 0; - } - *number = n; - *string = end; - return 1; -} - -static inline int parse_abs(const char **string) { - const char *s = *string; - - // ABS - if((s[0] == 'A' || s[0] == 'a') && (s[1] == 'B' || s[1] == 'b') && (s[2] == 'S' || s[2] == 's') && s[3] == '(') { - *string = &s[3]; - return 1; - } - - return 0; -} - -static inline int parse_if_then_else(const char **string) { - const char *s = *string; - - // ? - if(s[0] == '?') { - *string = &s[1]; - return 1; - } - - return 0; -} - -static struct operator_parser { - unsigned char id; - int (*parse)(const char **); -} operator_parsers[] = { - // the order in this list is important! - // the first matching will be used - // so place the longer of overlapping ones - // at the top - - { EVAL_OPERATOR_AND, parse_and }, - { EVAL_OPERATOR_OR, parse_or }, - { EVAL_OPERATOR_GREATER_THAN_OR_EQUAL, parse_greater_than_or_equal }, - { EVAL_OPERATOR_LESS_THAN_OR_EQUAL, parse_less_than_or_equal }, - { EVAL_OPERATOR_NOT_EQUAL, parse_not_equal }, - { EVAL_OPERATOR_EQUAL, parse_equal }, - { EVAL_OPERATOR_LESS, parse_less }, - { EVAL_OPERATOR_GREATER, parse_greater }, - { EVAL_OPERATOR_PLUS, parse_plus }, - { EVAL_OPERATOR_MINUS, parse_minus }, - { EVAL_OPERATOR_MULTIPLY, parse_multiply }, - { EVAL_OPERATOR_DIVIDE, parse_divide }, - { EVAL_OPERATOR_IF_THEN_ELSE, parse_if_then_else }, - - /* we should not put in this list the following: - * - * - NOT - * - ( - * - ) - * - * these are handled in code - */ - - // termination - { EVAL_OPERATOR_NOP, NULL } -}; - -static inline unsigned char parse_operator(const char **string, int *precedence) { - skip_spaces(string); - - int i; - for(i = 0 ; operator_parsers[i].parse != NULL ; i++) - if(operator_parsers[i].parse(string)) { - if(precedence) *precedence = eval_precedence(operator_parsers[i].id); - return operator_parsers[i].id; - } - - return EVAL_OPERATOR_NOP; -} - -// ---------------------------------------------------------------------------- -// memory management - -static inline EVAL_NODE *eval_node_alloc(int count) { - static int id = 1; - - EVAL_NODE *op = callocz(1, sizeof(EVAL_NODE) + (sizeof(EVAL_VALUE) * count)); - - op->id = id++; - op->operator = EVAL_OPERATOR_NOP; - op->precedence = eval_precedence(EVAL_OPERATOR_NOP); - op->count = count; - return op; -} - -static inline void eval_node_set_value_to_node(EVAL_NODE *op, int pos, EVAL_NODE *value) { - if(pos >= op->count) - fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1); - - op->ops[pos].type = EVAL_VALUE_EXPRESSION; - op->ops[pos].expression = value; -} - -static inline void eval_node_set_value_to_constant(EVAL_NODE *op, int pos, calculated_number value) { - if(pos >= op->count) - fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1); - - op->ops[pos].type = EVAL_VALUE_NUMBER; - op->ops[pos].number = value; -} - -static inline void eval_node_set_value_to_variable(EVAL_NODE *op, int pos, const char *variable) { - if(pos >= op->count) - fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1); - - op->ops[pos].type = EVAL_VALUE_VARIABLE; - op->ops[pos].variable = callocz(1, sizeof(EVAL_VARIABLE)); - op->ops[pos].variable->name = strdupz(variable); - op->ops[pos].variable->hash = simple_hash(op->ops[pos].variable->name); -} - -static inline void eval_variable_free(EVAL_VARIABLE *v) { - freez(v->name); - freez(v); -} - -static inline void eval_value_free(EVAL_VALUE *v) { - switch(v->type) { - case EVAL_VALUE_EXPRESSION: - eval_node_free(v->expression); - break; - - case EVAL_VALUE_VARIABLE: - eval_variable_free(v->variable); - break; - - default: - break; - } -} - -static inline void eval_node_free(EVAL_NODE *op) { - if(op->count) { - int i; - for(i = op->count - 1; i >= 0 ;i--) - eval_value_free(&op->ops[i]); - } - - freez(op); -} - -// ---------------------------------------------------------------------------- -// the parsing logic - -// helper function to avoid allocations all over the place -static inline EVAL_NODE *parse_next_operand_given_its_operator(const char **string, unsigned char operator_type, int *error) { - EVAL_NODE *sub = parse_one_full_operand(string, error); - if(!sub) return NULL; - - EVAL_NODE *op = eval_node_alloc(1); - op->operator = operator_type; - eval_node_set_value_to_node(op, 0, sub); - return op; -} - -// parse a full operand, including its sign or other associative operator (e.g. NOT) -static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error) { - char variable_buffer[EVAL_MAX_VARIABLE_NAME_LENGTH + 1]; - EVAL_NODE *op1 = NULL; - calculated_number number; - - *error = EVAL_ERROR_OK; - - skip_spaces(string); - if(!(**string)) { - *error = EVAL_ERROR_MISSING_OPERAND; - return NULL; - } - - if(parse_not(string)) { - op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_NOT, error); - op1->precedence = eval_precedence(EVAL_OPERATOR_NOT); - } - else if(parse_plus(string)) { - op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_SIGN_PLUS, error); - op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_PLUS); - } - else if(parse_minus(string)) { - op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_SIGN_MINUS, error); - op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_MINUS); - } - else if(parse_abs(string)) { - op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_ABS, error); - op1->precedence = eval_precedence(EVAL_OPERATOR_ABS); - } - else if(parse_open_subexpression(string)) { - EVAL_NODE *sub = parse_full_expression(string, error); - if(sub) { - op1 = eval_node_alloc(1); - op1->operator = EVAL_OPERATOR_EXPRESSION_OPEN; - op1->precedence = eval_precedence(EVAL_OPERATOR_EXPRESSION_OPEN); - eval_node_set_value_to_node(op1, 0, sub); - if(!parse_close_subexpression(string)) { - *error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION; - eval_node_free(op1); - return NULL; - } - } - } - else if(parse_variable(string, variable_buffer, EVAL_MAX_VARIABLE_NAME_LENGTH)) { - op1 = eval_node_alloc(1); - op1->operator = EVAL_OPERATOR_NOP; - eval_node_set_value_to_variable(op1, 0, variable_buffer); - } - else if(parse_constant(string, &number)) { - op1 = eval_node_alloc(1); - op1->operator = EVAL_OPERATOR_NOP; - eval_node_set_value_to_constant(op1, 0, number); - } - else if(**string) - *error = EVAL_ERROR_UNKNOWN_OPERAND; - else - *error = EVAL_ERROR_MISSING_OPERAND; - - return op1; -} - -// parse an operator and the rest of the expression -// precedence processing is handled here -static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *error, EVAL_NODE *op1) { - EVAL_NODE *op2 = NULL; - unsigned char operator; - int precedence; - - operator = parse_operator(string, &precedence); - skip_spaces(string); - - if(operator != EVAL_OPERATOR_NOP) { - op2 = parse_one_full_operand(string, error); - if(!op2) { - // error is already reported - eval_node_free(op1); - return NULL; - } - - EVAL_NODE *op = eval_node_alloc(operators[operator].parameters); - op->operator = operator; - op->precedence = precedence; - - if(operator == EVAL_OPERATOR_IF_THEN_ELSE && op->count == 3) { - skip_spaces(string); - - if(**string != ':') { - eval_node_free(op); - eval_node_free(op1); - eval_node_free(op2); - *error = EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE; - return NULL; - } - (*string)++; - - skip_spaces(string); - - EVAL_NODE *op3 = parse_one_full_operand(string, error); - if(!op3) { - eval_node_free(op); - eval_node_free(op1); - eval_node_free(op2); - // error is already reported - return NULL; - } - - eval_node_set_value_to_node(op, 2, op3); - } - - eval_node_set_value_to_node(op, 1, op2); - - // precedence processing - // if this operator has a higher precedence compared to its next - // put the next operator on top of us (top = evaluated later) - // function recursion does the rest... - if(op->precedence > op1->precedence && op1->count == 2 && op1->operator != '(' && op1->ops[1].type == EVAL_VALUE_EXPRESSION) { - eval_node_set_value_to_node(op, 0, op1->ops[1].expression); - op1->ops[1].expression = op; - op = op1; - } - else - eval_node_set_value_to_node(op, 0, op1); - - return parse_rest_of_expression(string, error, op); - } - else if(**string == ')') { - ; - } - else if(**string) { - eval_node_free(op1); - op1 = NULL; - *error = EVAL_ERROR_MISSING_OPERATOR; - } - - return op1; -} - -// high level function to parse an expression or a sub-expression -static inline EVAL_NODE *parse_full_expression(const char **string, int *error) { - EVAL_NODE *op1 = parse_one_full_operand(string, error); - if(!op1) { - *error = EVAL_ERROR_MISSING_OPERAND; - return NULL; - } - - return parse_rest_of_expression(string, error, op1); -} - -// ---------------------------------------------------------------------------- -// public API - -int expression_evaluate(EVAL_EXPRESSION *exp) { - exp->error = EVAL_ERROR_OK; - - buffer_reset(exp->error_msg); - exp->result = eval_node(exp, (EVAL_NODE *)exp->nodes, &exp->error); - - if(unlikely(isnan(exp->result))) { - if(exp->error == EVAL_ERROR_OK) - exp->error = EVAL_ERROR_VALUE_IS_NAN; - } - else if(unlikely(isinf(exp->result))) { - if(exp->error == EVAL_ERROR_OK) - exp->error = EVAL_ERROR_VALUE_IS_INFINITE; - } - else if(unlikely(exp->error == EVAL_ERROR_UNKNOWN_VARIABLE)) { - // although there is an unknown variable - // the expression was evaluated successfully - exp->error = EVAL_ERROR_OK; - } - - if(exp->error != EVAL_ERROR_OK) { - exp->result = NAN; - - if(buffer_strlen(exp->error_msg)) - buffer_strcat(exp->error_msg, "; "); - - buffer_sprintf(exp->error_msg, "failed to evaluate expression with error %d (%s)", exp->error, expression_strerror(exp->error)); - return 0; - } - - return 1; -} - -EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error) { - const char *s = string; - int err = EVAL_ERROR_OK; - - EVAL_NODE *op = parse_full_expression(&s, &err); - - if(*s) { - if(op) { - eval_node_free(op); - op = NULL; - } - err = EVAL_ERROR_REMAINING_GARBAGE; - } - - if (failed_at) *failed_at = s; - if (error) *error = err; - - if(!op) { - unsigned long pos = s - string + 1; - error("failed to parse expression '%s': %s at character %lu (i.e.: '%s').", string, expression_strerror(err), pos, s); - return NULL; - } - - BUFFER *out = buffer_create(1024); - print_parsed_as_node(out, op, &err); - if(err != EVAL_ERROR_OK) { - error("failed to re-generate expression '%s' with reason: %s", string, expression_strerror(err)); - eval_node_free(op); - buffer_free(out); - return NULL; - } - - EVAL_EXPRESSION *exp = callocz(1, sizeof(EVAL_EXPRESSION)); - - exp->source = strdupz(string); - exp->parsed_as = strdupz(buffer_tostring(out)); - buffer_free(out); - - exp->error_msg = buffer_create(100); - exp->nodes = (void *)op; - - return exp; -} - -void expression_free(EVAL_EXPRESSION *exp) { - if(!exp) return; - - if(exp->nodes) eval_node_free((EVAL_NODE *)exp->nodes); - freez((void *)exp->source); - freez((void *)exp->parsed_as); - buffer_free(exp->error_msg); - freez(exp); -} - -const char *expression_strerror(int error) { - switch(error) { - case EVAL_ERROR_OK: - return "success"; - - case EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION: - return "missing closing parenthesis"; - - case EVAL_ERROR_UNKNOWN_OPERAND: - return "unknown operand"; - - case EVAL_ERROR_MISSING_OPERAND: - return "expected operand"; - - case EVAL_ERROR_MISSING_OPERATOR: - return "expected operator"; - - case EVAL_ERROR_REMAINING_GARBAGE: - return "remaining characters after expression"; - - case EVAL_ERROR_INVALID_VALUE: - return "invalid value structure - internal error"; - - case EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS: - return "wrong number of operands for operation - internal error"; - - case EVAL_ERROR_VALUE_IS_NAN: - return "value is unset"; - - case EVAL_ERROR_VALUE_IS_INFINITE: - return "computed value is infinite"; - - case EVAL_ERROR_UNKNOWN_VARIABLE: - return "undefined variable"; - - case EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE: - return "missing second sub-expression of inline conditional"; - - default: - return "unknown error"; - } -} diff --git a/src/eval.h b/src/eval.h deleted file mode 100644 index 6a5562fd4..000000000 --- a/src/eval.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef NETDATA_EVAL_H -#define NETDATA_EVAL_H - -#define EVAL_MAX_VARIABLE_NAME_LENGTH 300 - -typedef struct eval_variable { - char *name; - uint32_t hash; - struct eval_variable *next; -} EVAL_VARIABLE; - -typedef struct eval_expression { - const char *source; - const char *parsed_as; - - RRDCALC_STATUS *status; - calculated_number *this; - time_t *after; - time_t *before; - - calculated_number result; - - int error; - BUFFER *error_msg; - - // hidden EVAL_NODE * - void *nodes; - - // custom data to be used for looking up variables - struct rrdcalc *rrdcalc; -} EVAL_EXPRESSION; - -#define EVAL_VALUE_INVALID 0 -#define EVAL_VALUE_NUMBER 1 -#define EVAL_VALUE_VARIABLE 2 -#define EVAL_VALUE_EXPRESSION 3 - -// parsing and evaluation -#define EVAL_ERROR_OK 0 - -// parsing errors -#define EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION 1 -#define EVAL_ERROR_UNKNOWN_OPERAND 2 -#define EVAL_ERROR_MISSING_OPERAND 3 -#define EVAL_ERROR_MISSING_OPERATOR 4 -#define EVAL_ERROR_REMAINING_GARBAGE 5 -#define EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE 6 - -// evaluation errors -#define EVAL_ERROR_INVALID_VALUE 101 -#define EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS 102 -#define EVAL_ERROR_VALUE_IS_NAN 103 -#define EVAL_ERROR_VALUE_IS_INFINITE 104 -#define EVAL_ERROR_UNKNOWN_VARIABLE 105 - -// parse the given string as an expression and return: -// a pointer to an expression if it parsed OK -// NULL in which case the pointer to error has the error code -extern EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error); - -// free all resources allocated for an expression -extern void expression_free(EVAL_EXPRESSION *op); - -// convert an error code to a message -extern const char *expression_strerror(int error); - -// evaluate an expression and return -// 1 = OK, the result is in: expression->result -// 2 = FAILED, the error message is in: buffer_tostring(expression->error_msg) -extern int expression_evaluate(EVAL_EXPRESSION *expression); - -#endif //NETDATA_EVAL_H diff --git a/src/freebsd_devstat.c b/src/freebsd_devstat.c deleted file mode 100644 index ed7466ead..000000000 --- a/src/freebsd_devstat.c +++ /dev/null @@ -1,778 +0,0 @@ -#include "common.h" - -#include - -struct disk { - char *name; - uint32_t hash; - size_t len; - - // flags - int configured; - int enabled; - int updated; - - 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 bytes_free; - collected_number operations_read; - collected_number operations_write; - collected_number operations_other; - collected_number operations_free; - collected_number duration_read_ms; - collected_number duration_write_ms; - collected_number duration_other_ms; - collected_number duration_free_ms; - collected_number busy_time_ms; - } prev_dstat; - - // charts and dimensions - - RRDSET *st_io; - RRDDIM *rd_io_in; - RRDDIM *rd_io_out; - RRDDIM *rd_io_free; - - RRDSET *st_ops; - RRDDIM *rd_ops_in; - RRDDIM *rd_ops_out; - RRDDIM *rd_ops_other; - RRDDIM *rd_ops_free; - - RRDSET *st_qops; - RRDDIM *rd_qops; - - RRDSET *st_util; - RRDDIM *rd_util; - - RRDSET *st_iotime; - RRDDIM *rd_iotime_in; - RRDDIM *rd_iotime_out; - RRDDIM *rd_iotime_other; - RRDDIM *rd_iotime_free; - - RRDSET *st_await; - RRDDIM *rd_await_in; - RRDDIM *rd_await_out; - RRDDIM *rd_await_other; - RRDDIM *rd_await_free; - - RRDSET *st_avagsz; - RRDDIM *rd_avagsz_in; - RRDDIM *rd_avagsz_out; - RRDDIM *rd_avagsz_free; - - RRDSET *st_svctm; - RRDDIM *rd_svctm; - - struct disk *next; -}; - -static struct disk *disks_root = NULL, *disks_last_used = NULL; - -static size_t disks_added = 0, disks_found = 0; - -static void disk_free(struct disk *dm) { - if (likely(dm->st_io)) - rrdset_is_obsolete(dm->st_io); - if (likely(dm->st_ops)) - rrdset_is_obsolete(dm->st_ops); - if (likely(dm->st_qops)) - rrdset_is_obsolete(dm->st_qops); - if (likely(dm->st_util)) - rrdset_is_obsolete(dm->st_util); - if (likely(dm->st_iotime)) - rrdset_is_obsolete(dm->st_iotime); - if (likely(dm->st_await)) - rrdset_is_obsolete(dm->st_await); - if (likely(dm->st_avagsz)) - rrdset_is_obsolete(dm->st_avagsz); - if (likely(dm->st_svctm)) - rrdset_is_obsolete(dm->st_svctm); - - disks_added--; - freez(dm->name); - freez(dm); -} - -static void disks_cleanup() { - if (likely(disks_found == disks_added)) return; - - struct disk *dm = disks_root, *last = NULL; - while(dm) { - if (unlikely(!dm->updated)) { - // info("Removing disk '%s', linked after '%s'", dm->name, last?last->name:"ROOT"); - - if (disks_last_used == dm) - disks_last_used = last; - - struct disk *t = dm; - - if (dm == disks_root || !last) - disks_root = dm = dm->next; - - else - last->next = dm = dm->next; - - t->next = NULL; - disk_free(t); - } - else { - last = dm; - dm->updated = 0; - dm = dm->next; - } - } -} - -static struct disk *get_disk(const char *name) { - struct disk *dm; - - uint32_t hash = simple_hash(name); - - // search it, from the last position to the end - for(dm = disks_last_used ; dm ; dm = dm->next) { - if (unlikely(hash == dm->hash && !strcmp(name, dm->name))) { - disks_last_used = dm->next; - return dm; - } - } - - // search it from the beginning to the last position we used - for(dm = disks_root ; dm != disks_last_used ; dm = dm->next) { - if (unlikely(hash == dm->hash && !strcmp(name, dm->name))) { - disks_last_used = dm->next; - return dm; - } - } - - // create a new one - dm = callocz(1, sizeof(struct disk)); - dm->name = strdupz(name); - dm->hash = simple_hash(dm->name); - dm->len = strlen(dm->name); - disks_added++; - - // link it to the end - if (disks_root) { - struct disk *e; - for(e = disks_root; e->next ; e = e->next) ; - e->next = dm; - } - else - disks_root = dm; - - return dm; -} - -// -------------------------------------------------------------------------------------------------------------------- -// 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_new_disks = -1; - 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; - static SIMPLE_PATTERN *excluded_disks = NULL; - - if (unlikely(enable_new_disks == -1)) { - enable_new_disks = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, - "enable new disks detected at runtime", CONFIG_BOOLEAN_AUTO); - - 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); - - excluded_disks = simple_pattern_create( - config_get(CONFIG_SECTION_KERN_DEVSTAT, "disable by default disks matching", DELAULT_EXLUDED_DISKS) - , NULL - , SIMPLE_PATTERN_EXACT - ); - } - - 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; - static int old_numdevs = 0; - - if (unlikely(numdevs != old_numdevs)) { - devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * - numdevs); // there is generation number before devstat structures - old_numdevs = numdevs; - } - 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; - - disks_found = 0; - - 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]; - struct cur_dstat { - collected_number duration_read_ms; - collected_number duration_write_ms; - collected_number duration_other_ms; - collected_number duration_free_ms; - collected_number busy_time_ms; - } cur_dstat; - - sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number); - - struct disk *dm = get_disk(disk); - dm->updated = 1; - disks_found++; - - if(unlikely(!dm->configured)) { - char var_name[4096 + 1]; - - // this is the first time we see this disk - - // remember we configured it - dm->configured = 1; - - dm->enabled = enable_new_disks; - - if (likely(dm->enabled)) - dm->enabled = !simple_pattern_matches(excluded_disks, disk); - - snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_KERN_DEVSTAT, disk); - dm->enabled = config_get_boolean_ondemand(var_name, "enabled", dm->enabled); - - dm->do_io = config_get_boolean_ondemand(var_name, "bandwidth", do_io); - dm->do_ops = config_get_boolean_ondemand(var_name, "operations", do_ops); - dm->do_qops = config_get_boolean_ondemand(var_name, "queued operations", do_qops); - dm->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", do_util); - dm->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", do_iotime); - dm->do_await = config_get_boolean_ondemand(var_name, "average completed i/o time", - do_await); - dm->do_avagsz = config_get_boolean_ondemand(var_name, "average completed i/o bandwidth", - do_avagsz); - dm->do_svctm = config_get_boolean_ondemand(var_name, "average service time", do_svctm); - - // initialise data for differential charts - - dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ]; - dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE]; - dm->prev_dstat.bytes_free = dstat[i].bytes[DEVSTAT_FREE]; - dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ]; - dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE]; - dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA]; - dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE]; - dm->prev_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 - + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE; - dm->prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 - + dstat[i].duration[DEVSTAT_WRITE].frac * BINTIME_SCALE; - dm->prev_dstat.duration_other_ms = dstat[i].duration[DEVSTAT_NO_DATA].sec * 1000 - + dstat[i].duration[DEVSTAT_NO_DATA].frac * BINTIME_SCALE; - dm->prev_dstat.duration_free_ms = dstat[i].duration[DEVSTAT_FREE].sec * 1000 - + dstat[i].duration[DEVSTAT_FREE].frac * BINTIME_SCALE; - dm->prev_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 - + dstat[i].busy_time.frac * BINTIME_SCALE; - } - - 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_WRITE].frac * BINTIME_SCALE; - cur_dstat.duration_other_ms = dstat[i].duration[DEVSTAT_NO_DATA].sec * 1000 - + dstat[i].duration[DEVSTAT_NO_DATA].frac * BINTIME_SCALE; - cur_dstat.duration_free_ms = dstat[i].duration[DEVSTAT_FREE].sec * 1000 - + dstat[i].duration[DEVSTAT_FREE].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] || - dstat[i].bytes[DEVSTAT_FREE]))) { - if (unlikely(!dm->st_io)) { - dm->st_io = rrdset_create_localhost("disk", - disk, - NULL, - disk, - "disk.io", - "Disk I/O Bandwidth", - "kilobytes/s", - "freebsd", - "devstat", - 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); - dm->rd_io_free = rrddim_add(dm->st_io, "frees", 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]); - rrddim_set_by_pointer(dm->st_io, dm->rd_io_free, dstat[i].bytes[DEVSTAT_FREE]); - 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] || - dstat[i].operations[DEVSTAT_NO_DATA] || - dstat[i].operations[DEVSTAT_FREE]))) { - 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", - "freebsd", - "devstat", - 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); - dm->rd_ops_other = rrddim_add(dm->st_ops, "other", NULL, 1, 1, - RRD_ALGORITHM_INCREMENTAL); - dm->rd_ops_free = rrddim_add(dm->st_ops, "frees", 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]); - rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_other, dstat[i].operations[DEVSTAT_NO_DATA]); - rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_free, dstat[i].operations[DEVSTAT_FREE]); - 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", - "freebsd", - "devstat", - 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", - "freebsd", - "devstat", - 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 || - cur_dstat.duration_other_ms || - cur_dstat.duration_free_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", - "freebsd", - "devstat", - 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); - dm->rd_iotime_other = rrddim_add(dm->st_iotime, "other", NULL, 1, 1, - RRD_ALGORITHM_INCREMENTAL); - dm->rd_iotime_free = rrddim_add(dm->st_iotime, "frees", 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); - rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_other, cur_dstat.duration_other_ms); - rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_free, cur_dstat.duration_free_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] || - dstat[i].operations[DEVSTAT_NO_DATA] || - dstat[i].operations[DEVSTAT_FREE]))) { - 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", - "freebsd", - "devstat", - 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); - dm->rd_await_other = rrddim_add(dm->st_await, "other", NULL, 1, 1, - RRD_ALGORITHM_ABSOLUTE); - dm->rd_await_free = rrddim_add(dm->st_await, "frees", 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); - rrddim_set_by_pointer(dm->st_await, dm->rd_await_other, - (dstat[i].operations[DEVSTAT_NO_DATA] - - dm->prev_dstat.operations_other) ? - (cur_dstat.duration_other_ms - dm->prev_dstat.duration_other_ms) / - (dstat[i].operations[DEVSTAT_NO_DATA] - - dm->prev_dstat.operations_other) : - 0); - rrddim_set_by_pointer(dm->st_await, dm->rd_await_free, - (dstat[i].operations[DEVSTAT_FREE] - - dm->prev_dstat.operations_free) ? - (cur_dstat.duration_free_ms - dm->prev_dstat.duration_free_ms) / - (dstat[i].operations[DEVSTAT_FREE] - - dm->prev_dstat.operations_free) : - 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] || - dstat[i].operations[DEVSTAT_FREE]))) { - 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", - "freebsd", - "devstat", - 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); - dm->rd_avagsz_free = rrddim_add(dm->st_avagsz, "frees", 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); - rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_free, - (dstat[i].operations[DEVSTAT_FREE] - - dm->prev_dstat.operations_free) ? - (dstat[i].bytes[DEVSTAT_FREE] - dm->prev_dstat.bytes_free) / - (dstat[i].operations[DEVSTAT_FREE] - - dm->prev_dstat.operations_free) : - 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] || - dstat[i].operations[DEVSTAT_NO_DATA] || - dstat[i].operations[DEVSTAT_FREE]))) { - if (unlikely(!dm->st_svctm)) { - dm->st_svctm = rrdset_create_localhost("disk_svctm", - disk, - NULL, - disk, - "disk.svctm", - "Average Service Time", - "ms per operation", - "freebsd", - "devstat", - 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) + - (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) + - (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) ? - (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) + - (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) + - (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) : - 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.bytes_free = dstat[i].bytes[DEVSTAT_FREE]; - dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ]; - dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE]; - dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA]; - dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE]; - 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.duration_other_ms = cur_dstat.duration_other_ms; - dm->prev_dstat.duration_free_ms = cur_dstat.duration_free_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", - "freebsd", - "devstat", - 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; - } - - disks_cleanup(); - - return 0; -} diff --git a/src/freebsd_getifaddrs.c b/src/freebsd_getifaddrs.c deleted file mode 100644 index 73f8f1824..000000000 --- a/src/freebsd_getifaddrs.c +++ /dev/null @@ -1,506 +0,0 @@ -#include "common.h" - -#include - -struct cgroup_network_interface { - char *name; - uint32_t hash; - size_t len; - - // flags - int configured; - int enabled; - int updated; - - 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; - - struct cgroup_network_interface *next; -}; - -static struct cgroup_network_interface *network_interfaces_root = NULL, *network_interfaces_last_used = NULL; - -static size_t network_interfaces_added = 0, network_interfaces_found = 0; - -static void network_interface_free(struct cgroup_network_interface *ifm) { - if (likely(ifm->st_bandwidth)) - rrdset_is_obsolete(ifm->st_bandwidth); - if (likely(ifm->st_packets)) - rrdset_is_obsolete(ifm->st_packets); - if (likely(ifm->st_errors)) - rrdset_is_obsolete(ifm->st_errors); - if (likely(ifm->st_drops)) - rrdset_is_obsolete(ifm->st_drops); - if (likely(ifm->st_events)) - rrdset_is_obsolete(ifm->st_events); - - network_interfaces_added--; - freez(ifm->name); - freez(ifm); -} - -static void network_interfaces_cleanup() { - if (likely(network_interfaces_found == network_interfaces_added)) return; - - struct cgroup_network_interface *ifm = network_interfaces_root, *last = NULL; - while(ifm) { - if (unlikely(!ifm->updated)) { - // info("Removing network interface '%s', linked after '%s'", ifm->name, last?last->name:"ROOT"); - - if (network_interfaces_last_used == ifm) - network_interfaces_last_used = last; - - struct cgroup_network_interface *t = ifm; - - if (ifm == network_interfaces_root || !last) - network_interfaces_root = ifm = ifm->next; - - else - last->next = ifm = ifm->next; - - t->next = NULL; - network_interface_free(t); - } - else { - last = ifm; - ifm->updated = 0; - ifm = ifm->next; - } - } -} - -static struct cgroup_network_interface *get_network_interface(const char *name) { - struct cgroup_network_interface *ifm; - - uint32_t hash = simple_hash(name); - - // search it, from the last position to the end - for(ifm = network_interfaces_last_used ; ifm ; ifm = ifm->next) { - if (unlikely(hash == ifm->hash && !strcmp(name, ifm->name))) { - network_interfaces_last_used = ifm->next; - return ifm; - } - } - - // search it from the beginning to the last position we used - for(ifm = network_interfaces_root ; ifm != network_interfaces_last_used ; ifm = ifm->next) { - if (unlikely(hash == ifm->hash && !strcmp(name, ifm->name))) { - network_interfaces_last_used = ifm->next; - return ifm; - } - } - - // create a new one - ifm = callocz(1, sizeof(struct cgroup_network_interface)); - ifm->name = strdupz(name); - ifm->hash = simple_hash(ifm->name); - ifm->len = strlen(ifm->name); - network_interfaces_added++; - - // link it to the end - if (network_interfaces_root) { - struct cgroup_network_interface *e; - for(e = network_interfaces_root; e->next ; e = e->next) ; - e->next = ifm; - } - else - network_interfaces_root = ifm; - - return ifm; -} - -// -------------------------------------------------------------------------------------------------------------------- -// getifaddrs - -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 enable_new_interfaces = -1; - 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; - static SIMPLE_PATTERN *excluded_interfaces = NULL; - - if (unlikely(enable_new_interfaces == -1)) { - enable_new_interfaces = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, - "enable new interfaces detected at runtime", - CONFIG_BOOLEAN_AUTO); - - 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); - - excluded_interfaces = simple_pattern_create( - config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching", DELAULT_EXLUDED_INTERFACES) - , NULL - , SIMPLE_PATTERN_EXACT - ); - } - - 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 { -#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 (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", - "freebsd", - "getifaddrs", - 500, - update_every, - RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } else - rrdset_next(st); - - rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes); - rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes); - 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", - "freebsd", - "getifaddrs", - 500, - update_every, - RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } else - rrdset_next(st); - - rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes); - rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - network_interfaces_found = 0; - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - - struct cgroup_network_interface *ifm = get_network_interface(ifa->ifa_name); - ifm->updated = 1; - network_interfaces_found++; - - if (unlikely(!ifm->configured)) { - char var_name[4096 + 1]; - - // this is the first time we see this network interface - - // remember we configured it - ifm->configured = 1; - - ifm->enabled = enable_new_interfaces; - - if (likely(ifm->enabled)) - ifm->enabled = !simple_pattern_matches(excluded_interfaces, ifa->ifa_name); - - snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETIFADDRS, ifa->ifa_name); - ifm->enabled = config_get_boolean_ondemand(var_name, "enabled", ifm->enabled); - - if (unlikely(ifm->enabled == CONFIG_BOOLEAN_NO)) - continue; - - ifm->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth); - ifm->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets); - ifm->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors); - ifm->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops); - ifm->do_events = config_get_boolean_ondemand(var_name, "events", do_events); - } - - if (unlikely(!ifm->enabled)) - continue; - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "getifaddrs", - 7000, - update_every, - RRDSET_TYPE_AREA - ); - - ifm->rd_bandwidth_in = rrddim_add(ifm->st_bandwidth, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - ifm->rd_bandwidth_out = rrddim_add(ifm->st_bandwidth, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } else - rrdset_next(ifm->st_bandwidth); - - 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", - "freebsd", - "getifaddrs", - 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", - "freebsd", - "getifaddrs", - 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) - #if __FreeBSD__ >= 11 - || IFA_DATA(oqdrops) -#endif - ))) { - 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", - "freebsd", - "getifaddrs", - 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", - "freebsd", - "getifaddrs", - 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; - } - - network_interfaces_cleanup(); - - return 0; -} diff --git a/src/freebsd_getmntinfo.c b/src/freebsd_getmntinfo.c deleted file mode 100644 index ea82b9fd1..000000000 --- a/src/freebsd_getmntinfo.c +++ /dev/null @@ -1,299 +0,0 @@ -#include "common.h" - -#include - -struct mount_point { - char *name; - uint32_t hash; - size_t len; - - // flags - int configured; - int enabled; - int updated; - - 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; - - struct mount_point *next; -}; - -static struct mount_point *mount_points_root = NULL, *mount_points_last_used = NULL; - -static size_t mount_points_added = 0, mount_points_found = 0; - -static void mount_point_free(struct mount_point *m) { - if (likely(m->st_space)) - rrdset_is_obsolete(m->st_space); - if (likely(m->st_inodes)) - rrdset_is_obsolete(m->st_inodes); - - mount_points_added--; - freez(m->name); - freez(m); -} - -static void mount_points_cleanup() { - if (likely(mount_points_found == mount_points_added)) return; - - struct mount_point *m = mount_points_root, *last = NULL; - while(m) { - if (unlikely(!m->updated)) { - // info("Removing mount point '%s', linked after '%s'", m->name, last?last->name:"ROOT"); - - if (mount_points_last_used == m) - mount_points_last_used = last; - - struct mount_point *t = m; - - if (m == mount_points_root || !last) - mount_points_root = m = m->next; - - else - last->next = m = m->next; - - t->next = NULL; - mount_point_free(t); - } - else { - last = m; - m->updated = 0; - m = m->next; - } - } -} - -static struct mount_point *get_mount_point(const char *name) { - struct mount_point *m; - - uint32_t hash = simple_hash(name); - - // search it, from the last position to the end - for(m = mount_points_last_used ; m ; m = m->next) { - if (unlikely(hash == m->hash && !strcmp(name, m->name))) { - mount_points_last_used = m->next; - return m; - } - } - - // search it from the beginning to the last position we used - for(m = mount_points_root ; m != mount_points_last_used ; m = m->next) { - if (unlikely(hash == m->hash && !strcmp(name, m->name))) { - mount_points_last_used = m->next; - return m; - } - } - - // create a new one - m = callocz(1, sizeof(struct mount_point)); - m->name = strdupz(name); - m->hash = simple_hash(m->name); - m->len = strlen(m->name); - mount_points_added++; - - // link it to the end - if (mount_points_root) { - struct mount_point *e; - for(e = mount_points_root; e->next ; e = e->next) ; - e->next = m; - } - else - mount_points_root = m; - - return m; -} - -// -------------------------------------------------------------------------------------------------------------------- -// getmntinfo - -int do_getmntinfo(int update_every, usec_t dt) { - (void)dt; - -#define DELAULT_EXCLUDED_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 enable_new_mount_points = -1; - static int do_space = -1, do_inodes = -1; - static SIMPLE_PATTERN *excluded_mountpoints = NULL; - static SIMPLE_PATTERN *excluded_filesystems = NULL; - - if (unlikely(enable_new_mount_points == -1)) { - enable_new_mount_points = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, - "enable new mount points detected at runtime", - CONFIG_BOOLEAN_AUTO); - - 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); - - excluded_mountpoints = simple_pattern_create( - config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths", - DELAULT_EXCLUDED_PATHS) - , NULL - , SIMPLE_PATTERN_EXACT - ); - - excluded_filesystems = simple_pattern_create( - config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems", - DEFAULT_EXCLUDED_FILESYSTEMS) - , NULL - , SIMPLE_PATTERN_EXACT - ); - } - - 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.* charts"); - do_inodes = 0; - error("DISABLED: disk_inodes.* charts"); - error("DISABLED: getmntinfo module"); - return 1; - } else { - int i; - - mount_points_found = 0; - - for (i = 0; i < mntsize; i++) { - char title[4096 + 1]; - - struct mount_point *m = get_mount_point(mntbuf[i].f_mntonname); - m->updated = 1; - mount_points_found++; - - if (unlikely(!m->configured)) { - char var_name[4096 + 1]; - - // this is the first time we see this filesystem - - // remember we configured it - m->configured = 1; - - m->enabled = enable_new_mount_points; - - if (likely(m->enabled)) - m->enabled = !(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname) - || simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename)); - - snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname); - m->enabled = config_get_boolean_ondemand(var_name, "enabled", m->enabled); - - if (unlikely(m->enabled == CONFIG_BOOLEAN_NO)) - continue; - - m->do_space = config_get_boolean_ondemand(var_name, "space usage", do_space); - m->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", do_inodes); - } - - if (unlikely(!m->enabled)) - continue; - - if (unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected)) - continue; - - // -------------------------------------------------------------------------- - - 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", - "freebsd", - "getmntinfo", - 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(m->st_space); - - 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 (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", - "freebsd", - "getmntinfo", - 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(m->st_inodes); - - 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; - } - - mount_points_cleanup(); - - return 0; -} diff --git a/src/freebsd_ipfw.c b/src/freebsd_ipfw.c deleted file mode 100644 index 81264b3f3..000000000 --- a/src/freebsd_ipfw.c +++ /dev/null @@ -1,370 +0,0 @@ -#include "common.h" - -#include - -#define FREE_MEM_THRESHOLD 10000 // number of unused chunks that trigger memory freeing - -#define COMMON_IPFW_ERROR() error("DISABLED: ipfw.packets chart"); \ - error("DISABLED: ipfw.bytes chart"); \ - error("DISABLED: ipfw.dyn_active chart"); \ - error("DISABLED: ipfw.dyn_expired chart"); \ - error("DISABLED: ipfw.mem chart"); - -// -------------------------------------------------------------------------------------------------------------------- -// ipfw - -int do_ipfw(int update_every, usec_t dt) { - (void)dt; -#if __FreeBSD__ >= 11 - - static int do_static = -1, do_dynamic = -1, do_mem = -1; - - if (unlikely(do_static == -1)) { - do_static = config_get_boolean("plugin:freebsd:ipfw", "counters for static rules", 1); - do_dynamic = config_get_boolean("plugin:freebsd:ipfw", "number of dynamic rules", 1); - do_mem = config_get_boolean("plugin:freebsd:ipfw", "allocated memory", 1); - } - - // variables for getting ipfw configuration - - int error; - static int ipfw_socket = -1; - static ipfw_cfg_lheader *cfg = NULL; - ip_fw3_opheader *op3 = NULL; - static socklen_t *optlen = NULL, cfg_size = 0; - - // variables for static rules handling - - ipfw_obj_ctlv *ctlv = NULL; - ipfw_obj_tlv *rbase = NULL; - int rcnt = 0; - - int n, seen; - struct ip_fw_rule *rule; - struct ip_fw_bcounter *cntr; - int c = 0; - - char rule_num_str[12]; - - // variables for dynamic rules handling - - caddr_t dynbase = NULL; - size_t dynsz = 0; - size_t readsz = sizeof(*cfg);; - int ttype = 0; - ipfw_obj_tlv *tlv; - ipfw_dyn_rule *dyn_rule; - uint16_t rulenum, prev_rulenum = IPFW_DEFAULT_RULE; - unsigned srn, static_rules_num = 0; - static size_t dyn_rules_num_size = 0; - - static struct dyn_rule_num { - uint16_t rule_num; - uint32_t active_rules; - uint32_t expired_rules; - } *dyn_rules_num = NULL; - - uint32_t *dyn_rules_counter; - - if (likely(do_static | do_dynamic | do_mem)) { - - // initialize the smallest ipfw_cfg_lheader possible - - if (unlikely((optlen == NULL) || (cfg == NULL))) { - optlen = reallocz(optlen, sizeof(socklen_t)); - *optlen = cfg_size = 32; - cfg = reallocz(cfg, *optlen); - } - - // get socket descriptor and initialize ipfw_cfg_lheader structure - - if (unlikely(ipfw_socket == -1)) - ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (unlikely(ipfw_socket == -1)) { - error("FREEBSD: can't get socket for ipfw configuration"); - error("FREEBSD: run netdata as root to get access to ipfw data"); - COMMON_IPFW_ERROR(); - return 1; - } - - bzero(cfg, 32); - cfg->flags = IPFW_CFG_GET_STATIC | IPFW_CFG_GET_COUNTERS | IPFW_CFG_GET_STATES; - op3 = &cfg->opheader; - op3->opcode = IP_FW_XGET; - - // get ifpw configuration size than get configuration - - *optlen = cfg_size; - error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen); - if (error) - if (errno != ENOMEM) { - error("FREEBSD: ipfw socket reading error"); - COMMON_IPFW_ERROR(); - return 1; - } - if ((cfg->size > cfg_size) || ((cfg_size - cfg->size) > sizeof(struct dyn_rule_num) * FREE_MEM_THRESHOLD)) { - *optlen = cfg_size = cfg->size; - cfg = reallocz(cfg, *optlen); - bzero(cfg, 32); - cfg->flags = IPFW_CFG_GET_STATIC | IPFW_CFG_GET_COUNTERS | IPFW_CFG_GET_STATES; - op3 = &cfg->opheader; - op3->opcode = IP_FW_XGET; - error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen); - if (error) { - error("FREEBSD: ipfw socket reading error"); - COMMON_IPFW_ERROR(); - return 1; - } - } - - // go through static rules configuration structures - - ctlv = (ipfw_obj_ctlv *) (cfg + 1); - - if (cfg->flags & IPFW_CFG_GET_STATIC) { - /* We've requested static rules */ - if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { - readsz += ctlv->head.length; - ctlv = (ipfw_obj_ctlv *) ((caddr_t) ctlv + - ctlv->head.length); - } - - if (ctlv->head.type == IPFW_TLV_RULE_LIST) { - rbase = (ipfw_obj_tlv *) (ctlv + 1); - rcnt = ctlv->count; - readsz += ctlv->head.length; - ctlv = (ipfw_obj_ctlv *) ((caddr_t) ctlv + ctlv->head.length); - } - } - - if ((cfg->flags & IPFW_CFG_GET_STATES) && (readsz != *optlen)) { - /* We may have some dynamic states */ - dynsz = *optlen - readsz; - /* Skip empty header */ - if (dynsz != sizeof(ipfw_obj_ctlv)) - dynbase = (caddr_t) ctlv; - else - dynsz = 0; - } - - // -------------------------------------------------------------------- - - if (likely(do_mem)) { - static RRDSET *st_mem = NULL; - static RRDDIM *rd_dyn_mem = NULL; - static RRDDIM *rd_stat_mem = NULL; - - if (unlikely(!st_mem)) { - st_mem = rrdset_create_localhost("ipfw", - "mem", - NULL, - "memory allocated", - NULL, - "Memory allocated by rules", - "bytes", - "freebsd", - "ipfw", - 3005, - update_every, - RRDSET_TYPE_STACKED - ); - rrdset_flag_set(st_mem, RRDSET_FLAG_DETAIL); - - rd_dyn_mem = rrddim_add(st_mem, "dynamic", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_stat_mem = rrddim_add(st_mem, "static", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } else - rrdset_next(st_mem); - - rrddim_set_by_pointer(st_mem, rd_dyn_mem, dynsz); - rrddim_set_by_pointer(st_mem, rd_stat_mem, *optlen - dynsz); - rrdset_done(st_mem); - } - - // -------------------------------------------------------------------- - - static RRDSET *st_packets = NULL, *st_bytes = NULL; - RRDDIM *rd_packets = NULL, *rd_bytes = NULL; - - if (likely(do_static || do_dynamic)) { - if (likely(do_static)) { - if (unlikely(!st_packets)) - st_packets = rrdset_create_localhost("ipfw", - "packets", - NULL, - "static rules", - NULL, - "Packets", - "packets/s", - "freebsd", - "ipfw", - 3001, - update_every, - RRDSET_TYPE_STACKED - ); - else - rrdset_next(st_packets); - - if (unlikely(!st_bytes)) - st_bytes = rrdset_create_localhost("ipfw", - "bytes", - NULL, - "static rules", - NULL, - "Bytes", - "bytes/s", - "freebsd", - "ipfw", - 3002, - update_every, - RRDSET_TYPE_STACKED - ); - else - rrdset_next(st_bytes); - } - - for (n = seen = 0; n < rcnt; n++, rbase = (ipfw_obj_tlv *) ((caddr_t) rbase + rbase->length)) { - cntr = (struct ip_fw_bcounter *) (rbase + 1); - rule = (struct ip_fw_rule *) ((caddr_t) cntr + cntr->size); - if (rule->rulenum != prev_rulenum) - static_rules_num++; - if (rule->rulenum > IPFW_DEFAULT_RULE) - break; - - if (likely(do_static)) { - sprintf(rule_num_str, "%d_%d", rule->rulenum, rule->id); - - rd_packets = rrddim_find(st_packets, rule_num_str); - if (unlikely(!rd_packets)) - rd_packets = rrddim_add(st_packets, rule_num_str, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_set_by_pointer(st_packets, rd_packets, cntr->pcnt); - - rd_bytes = rrddim_find(st_bytes, rule_num_str); - if (unlikely(!rd_bytes)) - rd_bytes = rrddim_add(st_bytes, rule_num_str, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_set_by_pointer(st_bytes, rd_bytes, cntr->bcnt); - } - - c += rbase->length; - seen++; - } - - if (likely(do_static)) { - rrdset_done(st_packets); - rrdset_done(st_bytes); - } - } - - // -------------------------------------------------------------------- - - // go through dynamic rules configuration structures - - if (likely(do_dynamic && (dynsz > 0))) { - if ((dyn_rules_num_size < sizeof(struct dyn_rule_num) * static_rules_num) || - ((dyn_rules_num_size - sizeof(struct dyn_rule_num) * static_rules_num) > - sizeof(struct dyn_rule_num) * FREE_MEM_THRESHOLD)) { - dyn_rules_num_size = sizeof(struct dyn_rule_num) * static_rules_num; - dyn_rules_num = reallocz(dyn_rules_num, dyn_rules_num_size); - } - bzero(dyn_rules_num, sizeof(struct dyn_rule_num) * static_rules_num); - dyn_rules_num->rule_num = IPFW_DEFAULT_RULE; - - if (dynsz > 0 && ctlv->head.type == IPFW_TLV_DYNSTATE_LIST) { - dynbase += sizeof(*ctlv); - dynsz -= sizeof(*ctlv); - ttype = IPFW_TLV_DYN_ENT; - } - - while (dynsz > 0) { - tlv = (ipfw_obj_tlv *) dynbase; - if (tlv->type != ttype) - break; - - dyn_rule = (ipfw_dyn_rule *) (tlv + 1); - bcopy(&dyn_rule->rule, &rulenum, sizeof(rulenum)); - - for (srn = 0; srn < (static_rules_num - 1); srn++) { - if (dyn_rule->expire > 0) - dyn_rules_counter = &dyn_rules_num[srn].active_rules; - else - dyn_rules_counter = &dyn_rules_num[srn].expired_rules; - if (dyn_rules_num[srn].rule_num == rulenum) { - (*dyn_rules_counter)++; - break; - } - if (dyn_rules_num[srn].rule_num == IPFW_DEFAULT_RULE) { - dyn_rules_num[srn].rule_num = rulenum; - dyn_rules_num[srn + 1].rule_num = IPFW_DEFAULT_RULE; - (*dyn_rules_counter)++; - break; - } - } - - dynsz -= tlv->length; - dynbase += tlv->length; - } - - // -------------------------------------------------------------------- - - static RRDSET *st_active = NULL, *st_expired = NULL; - RRDDIM *rd_active = NULL, *rd_expired = NULL; - - if (unlikely(!st_active)) - st_active = rrdset_create_localhost("ipfw", - "active", - NULL, - "dynamic_rules", - NULL, - "Active rules", - "rules", - "freebsd", - "ipfw", - 3003, - update_every, - RRDSET_TYPE_STACKED - ); - else - rrdset_next(st_active); - - if (unlikely(!st_expired)) - st_expired = rrdset_create_localhost("ipfw", - "expired", - NULL, - "dynamic_rules", - NULL, - "Expired rules", - "rules", - "freebsd", - "ipfw", - 3004, - update_every, - RRDSET_TYPE_STACKED - ); - else - rrdset_next(st_expired); - - for (srn = 0; (srn < (static_rules_num - 1)) && (dyn_rules_num[srn].rule_num != IPFW_DEFAULT_RULE); srn++) { - sprintf(rule_num_str, "%d", dyn_rules_num[srn].rule_num); - - rd_active = rrddim_find(st_active, rule_num_str); - if (unlikely(!rd_active)) - rd_active = rrddim_add(st_active, rule_num_str, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rrddim_set_by_pointer(st_active, rd_active, dyn_rules_num[srn].active_rules); - - rd_expired = rrddim_find(st_expired, rule_num_str); - if (unlikely(!rd_expired)) - rd_expired = rrddim_add(st_expired, rule_num_str, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rrddim_set_by_pointer(st_expired, rd_expired, dyn_rules_num[srn].expired_rules); - } - - rrdset_done(st_active); - rrdset_done(st_expired); - } - } - - return 0; -#else - error("FREEBSD: ipfw charts supported for FreeBSD 11.0 and newer releases only"); - COMMON_IPFW_ERROR(); - return 1; -#endif -} diff --git a/src/freebsd_kstat_zfs.c b/src/freebsd_kstat_zfs.c deleted file mode 100644 index 1bd48d4bf..000000000 --- a/src/freebsd_kstat_zfs.c +++ /dev/null @@ -1,298 +0,0 @@ -#include "common.h" -#include "zfs_common.h" - -extern struct arcstats arcstats; - -// -------------------------------------------------------------------------------------------------------------------- -// kstat.zfs.misc.arcstats - -int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt) { - (void)dt; - - unsigned long long l2_size; - size_t uint64_t_size = sizeof(uint64_t); - static struct mibs { - int hits[5]; - int misses[5]; - int demand_data_hits[5]; - int demand_data_misses[5]; - int demand_metadata_hits[5]; - int demand_metadata_misses[5]; - int prefetch_data_hits[5]; - int prefetch_data_misses[5]; - int prefetch_metadata_hits[5]; - int prefetch_metadata_misses[5]; - int mru_hits[5]; - int mru_ghost_hits[5]; - int mfu_hits[5]; - int mfu_ghost_hits[5]; - int deleted[5]; - int mutex_miss[5]; - int evict_skip[5]; - int evict_not_enough[5]; - int evict_l2_cached[5]; - int evict_l2_eligible[5]; - int evict_l2_ineligible[5]; - int evict_l2_skip[5]; - int hash_elements[5]; - int hash_elements_max[5]; - int hash_collisions[5]; - int hash_chains[5]; - int hash_chain_max[5]; - int p[5]; - int c[5]; - int c_min[5]; - int c_max[5]; - int size[5]; - int hdr_size[5]; - int data_size[5]; - int metadata_size[5]; - int other_size[5]; - int anon_size[5]; - int anon_evictable_data[5]; - int anon_evictable_metadata[5]; - int mru_size[5]; - int mru_evictable_data[5]; - int mru_evictable_metadata[5]; - int mru_ghost_size[5]; - int mru_ghost_evictable_data[5]; - int mru_ghost_evictable_metadata[5]; - int mfu_size[5]; - int mfu_evictable_data[5]; - int mfu_evictable_metadata[5]; - int mfu_ghost_size[5]; - int mfu_ghost_evictable_data[5]; - int mfu_ghost_evictable_metadata[5]; - int l2_hits[5]; - int l2_misses[5]; - int l2_feeds[5]; - int l2_rw_clash[5]; - int l2_read_bytes[5]; - int l2_write_bytes[5]; - int l2_writes_sent[5]; - int l2_writes_done[5]; - int l2_writes_error[5]; - int l2_writes_lock_retry[5]; - int l2_evict_lock_retry[5]; - int l2_evict_reading[5]; - int l2_evict_l1cached[5]; - int l2_free_on_write[5]; - int l2_cdata_free_on_write[5]; - int l2_abort_lowmem[5]; - int l2_cksum_bad[5]; - int l2_io_error[5]; - int l2_size[5]; - int l2_asize[5]; - int l2_hdr_size[5]; - int l2_compress_successes[5]; - int l2_compress_zeros[5]; - int l2_compress_failures[5]; - int memory_throttle_count[5]; - int duplicate_buffers[5]; - int duplicate_buffers_size[5]; - int duplicate_reads[5]; - int memory_direct_count[5]; - int memory_indirect_count[5]; - int arc_no_grow[5]; - int arc_tempreserve[5]; - int arc_loaned_bytes[5]; - int arc_prune[5]; - int arc_meta_used[5]; - int arc_meta_limit[5]; - int arc_meta_max[5]; - int arc_meta_min[5]; - int arc_need_free[5]; - int arc_sys_free[5]; - } mibs; - - arcstats.l2exist = -1; - - if(unlikely(sysctlbyname("kstat.zfs.misc.arcstats.l2_size", &l2_size, &uint64_t_size, NULL, 0))) - return 0; - - if(likely(l2_size)) - arcstats.l2exist = 1; - else - arcstats.l2exist = 0; - - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hits", mibs.hits, arcstats.hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.misses", mibs.misses, arcstats.misses); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.demand_data_hits", mibs.demand_data_hits, arcstats.demand_data_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.demand_data_misses", mibs.demand_data_misses, arcstats.demand_data_misses); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.demand_metadata_hits", mibs.demand_metadata_hits, arcstats.demand_metadata_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.demand_metadata_misses", mibs.demand_metadata_misses, arcstats.demand_metadata_misses); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.prefetch_data_hits", mibs.prefetch_data_hits, arcstats.prefetch_data_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.prefetch_data_misses", mibs.prefetch_data_misses, arcstats.prefetch_data_misses); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.prefetch_metadata_hits", mibs.prefetch_metadata_hits, arcstats.prefetch_metadata_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.prefetch_metadata_misses", mibs.prefetch_metadata_misses, arcstats.prefetch_metadata_misses); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_hits", mibs.mru_hits, arcstats.mru_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_ghost_hits", mibs.mru_ghost_hits, arcstats.mru_ghost_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_hits", mibs.mfu_hits, arcstats.mfu_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_ghost_hits", mibs.mfu_ghost_hits, arcstats.mfu_ghost_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.deleted", mibs.deleted, arcstats.deleted); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mutex_miss", mibs.mutex_miss, arcstats.mutex_miss); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.evict_skip", mibs.evict_skip, arcstats.evict_skip); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.evict_not_enough", mibs.evict_not_enough, arcstats.evict_not_enough); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.evict_l2_cached", mibs.evict_l2_cached, arcstats.evict_l2_cached); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.evict_l2_eligible", mibs.evict_l2_eligible, arcstats.evict_l2_eligible); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.evict_l2_ineligible", mibs.evict_l2_ineligible, arcstats.evict_l2_ineligible); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.evict_l2_skip", mibs.evict_l2_skip, arcstats.evict_l2_skip); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hash_elements", mibs.hash_elements, arcstats.hash_elements); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hash_elements_max", mibs.hash_elements_max, arcstats.hash_elements_max); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hash_collisions", mibs.hash_collisions, arcstats.hash_collisions); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hash_chains", mibs.hash_chains, arcstats.hash_chains); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hash_chain_max", mibs.hash_chain_max, arcstats.hash_chain_max); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.p", mibs.p, arcstats.p); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.c", mibs.c, arcstats.c); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.c_min", mibs.c_min, arcstats.c_min); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.c_max", mibs.c_max, arcstats.c_max); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.size", mibs.size, arcstats.size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hdr_size", mibs.hdr_size, arcstats.hdr_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.data_size", mibs.data_size, arcstats.data_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.metadata_size", mibs.metadata_size, arcstats.metadata_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.other_size", mibs.other_size, arcstats.other_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.anon_size", mibs.anon_size, arcstats.anon_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.anon_evictable_data", mibs.anon_evictable_data, arcstats.anon_evictable_data); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.anon_evictable_metadata", mibs.anon_evictable_metadata, arcstats.anon_evictable_metadata); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_size", mibs.mru_size, arcstats.mru_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_evictable_data", mibs.mru_evictable_data, arcstats.mru_evictable_data); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_evictable_metadata", mibs.mru_evictable_metadata, arcstats.mru_evictable_metadata); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_ghost_size", mibs.mru_ghost_size, arcstats.mru_ghost_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_ghost_evictable_data", mibs.mru_ghost_evictable_data, arcstats.mru_ghost_evictable_data); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mru_ghost_evictable_metadata", mibs.mru_ghost_evictable_metadata, arcstats.mru_ghost_evictable_metadata); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_size", mibs.mfu_size, arcstats.mfu_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_evictable_data", mibs.mfu_evictable_data, arcstats.mfu_evictable_data); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_evictable_metadata", mibs.mfu_evictable_metadata, arcstats.mfu_evictable_metadata); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_ghost_size", mibs.mfu_ghost_size, arcstats.mfu_ghost_size); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_ghost_evictable_data", mibs.mfu_ghost_evictable_data, arcstats.mfu_ghost_evictable_data); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.mfu_ghost_evictable_metadata", mibs.mfu_ghost_evictable_metadata, arcstats.mfu_ghost_evictable_metadata); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_hits", mibs.l2_hits, arcstats.l2_hits); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_misses", mibs.l2_misses, arcstats.l2_misses); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_feeds", mibs.l2_feeds, arcstats.l2_feeds); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_rw_clash", mibs.l2_rw_clash, arcstats.l2_rw_clash); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_read_bytes", mibs.l2_read_bytes, arcstats.l2_read_bytes); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_write_bytes", mibs.l2_write_bytes, arcstats.l2_write_bytes); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_writes_sent", mibs.l2_writes_sent, arcstats.l2_writes_sent); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_writes_done", mibs.l2_writes_done, arcstats.l2_writes_done); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_writes_error", mibs.l2_writes_error, arcstats.l2_writes_error); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_writes_lock_retry", mibs.l2_writes_lock_retry, arcstats.l2_writes_lock_retry); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_evict_lock_retry", mibs.l2_evict_lock_retry, arcstats.l2_evict_lock_retry); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_evict_reading", mibs.l2_evict_reading, arcstats.l2_evict_reading); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_evict_l1cached", mibs.l2_evict_l1cached, arcstats.l2_evict_l1cached); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_free_on_write", mibs.l2_free_on_write, arcstats.l2_free_on_write); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_cdata_free_on_write", mibs.l2_cdata_free_on_write, arcstats.l2_cdata_free_on_write); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_abort_lowmem", mibs.l2_abort_lowmem, arcstats.l2_abort_lowmem); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_cksum_bad", mibs.l2_cksum_bad, arcstats.l2_cksum_bad); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_io_error", mibs.l2_io_error, arcstats.l2_io_error); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_size", mibs.l2_size, arcstats.l2_size); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_asize", mibs.l2_asize, arcstats.l2_asize); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_hdr_size", mibs.l2_hdr_size, arcstats.l2_hdr_size); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_compress_successes", mibs.l2_compress_successes, arcstats.l2_compress_successes); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_compress_zeros", mibs.l2_compress_zeros, arcstats.l2_compress_zeros); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.l2_compress_failures", mibs.l2_compress_failures, arcstats.l2_compress_failures); - GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.memory_throttle_count", mibs.memory_throttle_count, arcstats.memory_throttle_count); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.duplicate_buffers", mibs.duplicate_buffers, arcstats.duplicate_buffers); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.duplicate_buffers_size", mibs.duplicate_buffers_size, arcstats.duplicate_buffers_size); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.duplicate_reads", mibs.duplicate_reads, arcstats.duplicate_reads); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.memory_direct_count", mibs.memory_direct_count, arcstats.memory_direct_count); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.memory_indirect_count", mibs.memory_indirect_count, arcstats.memory_indirect_count); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_no_grow", mibs.arc_no_grow, arcstats.arc_no_grow); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_tempreserve", mibs.arc_tempreserve, arcstats.arc_tempreserve); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_loaned_bytes", mibs.arc_loaned_bytes, arcstats.arc_loaned_bytes); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_prune", mibs.arc_prune, arcstats.arc_prune); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_meta_used", mibs.arc_meta_used, arcstats.arc_meta_used); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_meta_limit", mibs.arc_meta_limit, arcstats.arc_meta_limit); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_meta_max", mibs.arc_meta_max, arcstats.arc_meta_max); - // not used: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_meta_min", mibs.arc_meta_min, arcstats.arc_meta_min); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_need_free", mibs.arc_need_free, arcstats.arc_need_free); - // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_sys_free", mibs.arc_sys_free, arcstats.arc_sys_free); - - generate_charts_arcstats("freebsd", update_every); - generate_charts_arc_summary("freebsd", update_every); - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// kstat.zfs.misc.zio_trim - -int do_kstat_zfs_misc_zio_trim(int update_every, usec_t dt) { - (void)dt; - static int mib_bytes[5] = {0, 0, 0, 0, 0}, mib_success[5] = {0, 0, 0, 0, 0}, - mib_failed[5] = {0, 0, 0, 0, 0}, mib_unsupported[5] = {0, 0, 0, 0, 0}; - uint64_t bytes, success, failed, unsupported; - - if (unlikely(GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.bytes", mib_bytes, bytes) || - GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.success", mib_success, success) || - GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.failed", mib_failed, failed) || - GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.unsupported", mib_unsupported, unsupported))) { - error("DISABLED: zfs.trim_bytes chart"); - error("DISABLED: zfs.trim_success chart"); - error("DISABLED: kstat.zfs.misc.zio_trim module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - static RRDSET *st_bytes = NULL; - static RRDDIM *rd_bytes = NULL; - - if (unlikely(!st_bytes)) { - st_bytes = rrdset_create_localhost( - "zfs", - "trim_bytes", - NULL, - "trim", - NULL, - "Successfully TRIMmed bytes", - "bytes", - "freebsd", - "zfs", - 2320, - update_every, - RRDSET_TYPE_LINE - ); - - rd_bytes = rrddim_add(st_bytes, "TRIMmed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_bytes); - - rrddim_set_by_pointer(st_bytes, rd_bytes, bytes); - rrdset_done(st_bytes); - - // -------------------------------------------------------------------- - - static RRDSET *st_requests = NULL; - static RRDDIM *rd_successful = NULL, *rd_failed = NULL, *rd_unsupported = NULL; - - if (unlikely(!st_requests)) { - st_requests = rrdset_create_localhost( - "zfs", - "trim_requests", - NULL, - "trim", - NULL, - "TRIM requests", - "requests", - "freebsd", - "zfs", - 2321, - update_every, - RRDSET_TYPE_STACKED - ); - - rd_successful = rrddim_add(st_requests, "successful", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_failed = rrddim_add(st_requests, "failed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_unsupported = rrddim_add(st_requests, "unsupported", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_requests); - - rrddim_set_by_pointer(st_requests, rd_successful, success); - rrddim_set_by_pointer(st_requests, rd_failed, failed); - rrddim_set_by_pointer(st_requests, rd_unsupported, unsupported); - rrdset_done(st_requests); - - } - - return 0; -} \ No newline at end of file diff --git a/src/freebsd_sysctl.c b/src/freebsd_sysctl.c deleted file mode 100644 index 1e11255aa..000000000 --- a/src/freebsd_sysctl.c +++ /dev/null @@ -1,3171 +0,0 @@ -#include "common.h" - -#include -#include - -#define _KERNEL -#include -#include -#include -#undef _KERNEL - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// -------------------------------------------------------------------------------------------------------------------- -// common definitions and variables - -int system_pagesize = PAGE_SIZE; -int number_of_cpus = 1; -#if __FreeBSD_version >= 1200029 -struct __vmmeter { - uint64_t v_swtch; - uint64_t v_trap; - uint64_t v_syscall; - uint64_t v_intr; - uint64_t v_soft; - uint64_t v_vm_faults; - uint64_t v_io_faults; - uint64_t v_cow_faults; - uint64_t v_cow_optim; - uint64_t v_zfod; - uint64_t v_ozfod; - uint64_t v_swapin; - uint64_t v_swapout; - uint64_t v_swappgsin; - uint64_t v_swappgsout; - uint64_t v_vnodein; - uint64_t v_vnodeout; - uint64_t v_vnodepgsin; - uint64_t v_vnodepgsout; - uint64_t v_intrans; - uint64_t v_reactivated; - uint64_t v_pdwakeups; - uint64_t v_pdpages; - uint64_t v_pdshortfalls; - uint64_t v_dfree; - uint64_t v_pfree; - uint64_t v_tfree; - uint64_t v_forks; - uint64_t v_vforks; - uint64_t v_rforks; - uint64_t v_kthreads; - uint64_t v_forkpages; - uint64_t v_vforkpages; - uint64_t v_rforkpages; - uint64_t v_kthreadpages; - u_int v_page_size; - u_int v_page_count; - u_int v_free_reserved; - u_int v_free_target; - u_int v_free_min; - u_int v_free_count; - u_int v_wire_count; - u_int v_active_count; - u_int v_inactive_target; - u_int v_inactive_count; - u_int v_laundry_count; - u_int v_pageout_free_min; - u_int v_interrupt_free_min; - u_int v_free_severe; -}; -typedef struct __vmmeter vmmeter_t; -#else -typedef struct vmmeter vmmeter_t; -#endif - -// -------------------------------------------------------------------------------------------------------------------- -// FreeBSD plugin initialization - -int freebsd_plugin_init() -{ - system_pagesize = getpagesize(); - if (system_pagesize <= 0) { - error("FREEBSD: can't get system page size"); - return 1; - } - - if (unlikely(GETSYSCTL_BY_NAME("kern.smp.cpus", number_of_cpus))) { - error("FREEBSD: can't get number of cpus"); - return 1; - } - - if (unlikely(!number_of_cpus)) { - error("FREEBSD: wrong number of cpus"); - return 1; - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.loadavg - -// FreeBSD calculates load averages once every 5 seconds -#define MIN_LOADAVG_UPDATE_EVERY 5 - -int do_vm_loadavg(int update_every, usec_t dt){ - static usec_t next_loadavg_dt = 0; - - if (next_loadavg_dt <= dt) { - static int mib[2] = {0, 0}; - struct loadavg sysload; - - if (unlikely(GETSYSCTL_SIMPLE("vm.loadavg", mib, sysload))) { - error("DISABLED: system.load chart"); - error("DISABLED: vm.loadavg module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd_load1 = NULL, *rd_load2 = NULL, *rd_load3 = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "load", - NULL, - "load", - NULL, - "System Load Average", - "load", - "freebsd", - "vm.loadavg", - 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; - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.vmtotal - -int do_vm_vmtotal(int update_every, usec_t dt) { - (void)dt; - static int do_all_processes = -1, do_processes = -1, do_committed = -1; - - 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); - } - - if (likely(do_all_processes | do_processes | do_committed)) { - 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 chart"); - do_processes = 0; - error("DISABLED: system.processes chart"); - do_committed = 0; - 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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "active_processes", - NULL, - "processes", - NULL, - "System Active Processes", - "processes", - "freebsd", - "vm.vmtotal", - 750, - update_every, - RRDSET_TYPE_LINE - ); - rd = rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - 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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "processes", - NULL, - "processes", - NULL, - "System Processes", - "processes", - "freebsd", - "vm.vmtotal", - 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_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)) { - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "mem", - "committed", - NULL, - "system", - NULL, - "Committed (Allocated) Memory", - "MB", - "freebsd", - "vm.vmtotal", - NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED, - 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_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 (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 { - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "kern.cp_time", - 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 (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; - static int old_number_of_cpus = 0; - - if(unlikely(number_of_cpus != old_number_of_cpus)) - 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 { - - // -------------------------------------------------------------------- - - 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; - - 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)); - } - - 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", - "freebsd", - "kern.cp_times", - 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); - } - } - - old_number_of_cpus = number_of_cpus; - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// dev.cpu.temperature - -int do_dev_cpu_temperature(int update_every, usec_t dt) { - (void)dt; - - int i; - static int *mib = NULL; - static int *pcpu_temperature = NULL; - static int old_number_of_cpus = 0; - char char_mib[MAX_INT_DIGITS + 21]; - char char_rd[MAX_INT_DIGITS + 9]; - - if (unlikely(number_of_cpus != old_number_of_cpus)) { - pcpu_temperature = reallocz(pcpu_temperature, sizeof(int) * number_of_cpus); - mib = reallocz(mib, sizeof(int) * number_of_cpus * 4); - if (unlikely(number_of_cpus > old_number_of_cpus)) - memset(&mib[old_number_of_cpus * 4], 0, sizeof(RRDDIM) * (number_of_cpus - old_number_of_cpus)); - } - for (i = 0; i < number_of_cpus; i++) { - if (unlikely(!(mib[i * 4]))) - sprintf(char_mib, "dev.cpu.%d.temperature", i); - if (unlikely(getsysctl_simple(char_mib, &mib[i * 4], 4, &pcpu_temperature[i], sizeof(int)))) { - error("DISABLED: cpu.temperature chart"); - error("DISABLED: dev.cpu.temperature module"); - return 1; - } - } - - // -------------------------------------------------------------------- - - static RRDSET *st; - static RRDDIM **rd_pcpu_temperature; - - if (unlikely(number_of_cpus != old_number_of_cpus)) { - rd_pcpu_temperature = reallocz(rd_pcpu_temperature, sizeof(RRDDIM) * number_of_cpus); - if (unlikely(number_of_cpus > old_number_of_cpus)) - memset(&rd_pcpu_temperature[old_number_of_cpus], 0, sizeof(RRDDIM) * (number_of_cpus - old_number_of_cpus)); - } - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "cpu", - "temperature", - NULL, - "temperature", - "cpu.temperatute", - "Core temperature", - "Celsius", - "freebsd", - "dev.cpu.temperature", - 1050, - update_every, - RRDSET_TYPE_LINE - ); - } - else rrdset_next(st); - - for (i = 0; i < number_of_cpus; i++) { - if (unlikely(!rd_pcpu_temperature[i])) { - sprintf(char_rd, "cpu%d.temp", i); - rd_pcpu_temperature[i] = rrddim_add(st, char_rd, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - - rrddim_set_by_pointer(st, rd_pcpu_temperature[i], (collected_number) ((double)pcpu_temperature[i] / 10 - 273.15)); - } - - rrdset_done(st); - - old_number_of_cpus = number_of_cpus; - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// dev.cpu.0.freq - -int do_dev_cpu_0_freq(int update_every, usec_t dt) { - (void)dt; - static int mib[4] = {0, 0, 0, 0}; - int cpufreq; - - if (unlikely(GETSYSCTL_SIMPLE("dev.cpu.0.freq", mib, cpufreq))) { - error("DISABLED: cpu.scaling_cur_freq chart"); - error("DISABLED: dev.cpu.0.freq module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "cpu", - "scaling_cur_freq", - NULL, - "cpufreq", - NULL, - "Current CPU Scaling Frequency", - "MHz", - "freebsd", - "dev.cpu.0.freq", - 5003, - update_every, - RRDSET_TYPE_LINE - ); - - rd = rrddim_add(st, "frequency", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd, cpufreq); - rrdset_done(st); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// 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 = 0; - 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 old_nintr = 0; - static unsigned long *intrcnt = NULL; - unsigned long long totalintr = 0; - - nintr = intrcnt_size / sizeof(u_long); - if (unlikely(nintr != old_nintr)) - 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 { - for (i = 0; i < nintr; i++) - totalintr += intrcnt[i]; - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "hw.intrcnt", - 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); - - // -------------------------------------------------------------------- - - size_t size; - static int mib_hw_intrnames[2] = {0, 0}; - static char *intrnames = NULL; - - size = nintr * (MAXCOMLEN + 1); - if (unlikely(nintr != old_nintr)) - 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 { - - // -------------------------------------------------------------------- - - static RRDSET *st_interrupts = NULL; - void *p; - - if (unlikely(!st_interrupts)) - st_interrupts = rrdset_create_localhost( - "system", - "interrupts", - NULL, - "interrupts", - NULL, - "System interrupts", - "interrupts/s", - "freebsd", - "hw.intrcnt", - 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))) { - RRDDIM *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_interrupts); - } - } - - old_nintr = nintr; - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.stats.sys.v_intr - -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; - - 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 { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "dev_intr", - NULL, - "interrupts", - NULL, - "Device Interrupts", - "interrupts/s", - "freebsd", - "vm.stats.sys.v_intr", - 1000, - 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, int_number); - rrdset_done(st); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// 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 (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 { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "soft_intr", - NULL, - "interrupts", - NULL, - "Software Interrupts", - "interrupts/s", - "freebsd", - "vm.stats.sys.v_soft", - 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; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.stats.sys.v_swtch - -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; - - 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 { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "ctxt", - NULL, - "processes", - NULL, - "CPU Context Switches", - "context switches/s", - "freebsd", - "vm.stats.sys.v_swtch", - 800, - update_every, - RRDSET_TYPE_LINE - ); - - rd = rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd, ctxt_number); - rrdset_done(st); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.stats.vm.v_forks - -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; - - 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 { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "forks", - NULL, - "processes", - NULL, - "Started Processes", - "processes/s", - "freebsd", - "vm.stats.sys.v_swtch", - 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); - - rrddim_set_by_pointer(st, rd, forks_number); - rrdset_done(st); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.swap_info - -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; - } - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd_free = NULL, *rd_used = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "swap", - NULL, - "swap", - NULL, - "System Swap", - "MB", - "freebsd", - "vm.swap_info", - 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_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); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// system.ram - -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}; - vmmeter_t vmmeter_data; - int vfs_bufspace_count; - - 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 { - - // -------------------------------------------------------------------- - - 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 (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "ram", - NULL, - "ram", - NULL, - "System RAM", - "MB", - "freebsd", - "system.ram", - 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); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.stats.vm.v_swappgs - -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}; - vmmeter_t 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 { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "swapio", - NULL, - "swap", - NULL, - "Swap I/O", - "kilobytes/s", - "freebsd", - "vm.stats.vm.v_swappgs", - 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); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// vm.stats.vm.v_pgfaults - -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}; - vmmeter_t 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 { - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "vm.stats.vm.v_pgfaults", - NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS, - 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 - -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 (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; - static int old_semmni = 0; - - if (unlikely(ipc_sem.semmni != old_semmni)) { - ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni); - old_semmni = 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; - - 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; - } - } - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "kern.ipc.sem", - 1000, - update_every, - RRDSET_TYPE_AREA - ); - - rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_semaphores); - - rrddim_set_by_pointer(st_semaphores, rd_semaphores, ipc_sem.semaphores); - rrdset_done(st_semaphores); - - // -------------------------------------------------------------------- - - if (unlikely(!st_semaphore_arrays)) { - st_semaphore_arrays = rrdset_create_localhost( - "system", - "ipc_semaphore_arrays", - NULL, - "ipc semaphores", - NULL, - "IPC Semaphore Arrays", - "arrays", - "freebsd", - "kern.ipc.sem", - 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_semaphore_arrays); - - rrddim_set_by_pointer(st_semaphore_arrays, rd_semaphore_arrays, ipc_sem.sets); - rrdset_done(st_semaphore_arrays); - } - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// 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 (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; - static u_long old_shmmni = 0; - - if (unlikely(ipc_shm.shmmni != old_shmmni)) { - ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni); - old_shmmni = 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 { - unsigned long i; - - 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; - } - } - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "kern.ipc.shm", - 1000, - update_every, - RRDSET_TYPE_AREA - ); - - rd_segments = rrddim_add(st_segs, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_segs); - - rrddim_set_by_pointer(st_segs, rd_segments, ipc_shm.segs); - rrdset_done(st_segs); - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "kern.ipc.shm", - 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 (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; - static int old_msgmni = 0; - - if (unlikely(ipc_msq.msgmni != old_msgmni)) { - ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni); - old_msgmni = 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 { - 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; - } - } - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "kern.ipc.msq", - 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_by_pointer(st_queues, rd_queues, ipc_msq.queues); - rrdset_done(st_queues); - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "kern.ipc.msq", - 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_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", - "freebsd", - "kern.ipc.msq", - 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); - } - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// uptime - -int do_uptime(int update_every, usec_t dt) { - (void)dt; - struct timespec up_time; - - clock_gettime(CLOCK_UPTIME, &up_time); - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "system", - "uptime", - NULL, - "uptime", - NULL, - "System Uptime", - "seconds", - "freebsd", - "uptime", - 1000, - update_every, - RRDSET_TYPE_LINE - ); - - rd = rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd, up_time.tv_sec); - rrdset_done(st); - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// net.isr - -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 = 0, netisr_work_size = 0; - 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_SIZE("net.isr.workstream", mib_workstream, netisr_workstream_size))) { - common_error = 1; - } else if (unlikely(GETSYSCTL_SIZE("net.isr.work", mib_work, netisr_work_size))) { - common_error = 1; - } else { - static size_t old_netisr_workstream_size = 0; - - num_netisr_workstreams = netisr_workstream_size / sizeof(struct sysctl_netisr_workstream); - if (unlikely(netisr_workstream_size != old_netisr_workstream_size)) { - netisr_workstream = reallocz(netisr_workstream, - num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)); - old_netisr_workstream_size = netisr_workstream_size; - } - if (unlikely(GETSYSCTL_WSIZE("net.isr.workstream", mib_workstream, netisr_workstream, - num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){ - common_error = 1; - } else { - static size_t old_netisr_work_size = 0; - - num_netisr_works = netisr_work_size / sizeof(struct sysctl_netisr_work); - if (unlikely(netisr_work_size != old_netisr_work_size)) { - netisr_work = reallocz(netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work)); - old_netisr_work_size = netisr_work_size; - } - 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 chart"); - do_netisr_per_core = 0; - error("DISABLED: system.cpuX_softnet_stat chart"); - common_error = 0; - error("DISABLED: net.isr module"); - return 1; - } else { - unsigned long i, n; - int j; - static int old_number_of_cpus = 0; - - if (unlikely(number_of_cpus != old_number_of_cpus)) { - netisr_stats = reallocz(netisr_stats, (number_of_cpus + 1) * sizeof(struct netisr_stats)); - old_number_of_cpus = number_of_cpus; - } - 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) { - netisr_stats[netisr_workstream[i].snws_cpu].dispatched += netisr_work[n].snw_dispatched; - netisr_stats[netisr_workstream[i].snws_cpu].hybrid_dispatched += netisr_work[n].snw_hybrid_dispatched; - netisr_stats[netisr_workstream[i].snws_cpu].qdrops += netisr_work[n].snw_qdrops; - netisr_stats[netisr_workstream[i].snws_cpu].queued += netisr_work[n].snw_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)) { - 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_localhost( - "system", - "softnet_stat", - NULL, - "softnet_stat", - NULL, - "System softnet_stat", - "events/s", - "freebsd", - "net.isr", - 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_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)) { - 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; - } - - 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", - "freebsd", - "net.isr", - 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(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); - } - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// 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]; - - // 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 { - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "tcpsock", - NULL, - "tcp", - NULL, - "IPv4 TCP Connections", - "active connections", - "freebsd", - "net.inet.tcp.states", - 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); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// net.inet.tcp.stats - -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_tcpext_listen = -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_tcpext_listen = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP listen issues", - 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_syncookies || do_tcpext_listen || 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 chart"); - do_tcp_errors = 0; - error("DISABLED: ipv4.tcperrors chart"); - do_tcp_handshake = 0; - error("DISABLED: ipv4.tcphandshake chart"); - do_tcpext_connaborts = 0; - error("DISABLED: ipv4.tcpconnaborts chart"); - do_tcpext_ofo = 0; - error("DISABLED: ipv4.tcpofo chart"); - do_tcpext_syncookies = 0; - error("DISABLED: ipv4.tcpsyncookies chart"); - do_tcpext_listen = 0; - error("DISABLED: ipv4.tcplistenissues chart"); - do_ecn = 0; - error("DISABLED: ipv4.ecnpkts chart"); - error("DISABLED: net.inet.tcp.stats module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - if (likely(do_tcp_packets)) { - static RRDSET *st = NULL; - static RRDDIM *rd_in_segs = NULL, *rd_out_segs = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "tcppackets", - NULL, - "tcp", - NULL, - "IPv4 TCP Packets", - "packets/s", - "freebsd", - "net.inet.tcp.stats", - 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_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)) { - 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_localhost( - "ipv4", - "tcperrors", - NULL, - "tcp", - NULL, - "IPv4 TCP Errors", - "packets/s", - "freebsd", - "net.inet.tcp.stats", - 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_by_pointer(st, rd_in_errs, tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull + - tcpstat.tcps_rcvshort); -#else - rrddim_set_by_pointer(st, rd_in_errs, tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort); -#endif - 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)) { - 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_localhost( - "ipv4", - "tcphandshake", - NULL, - "tcp", - NULL, - "IPv4 TCP Handshake Issues", - "events/s", - "freebsd", - "net.inet.tcp.stats", - 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_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_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; - - 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", - "freebsd", - "net.inet.tcp.stats", - 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_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_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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "tcpofo", - NULL, - "tcp", - NULL, - "TCP Out-Of-Order Queue", - "packets/s", - "freebsd", - "net.inet.tcp.stats", - 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_by_pointer(st, rd_ofo_queue, tcpstat.tcps_rcvoopack); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - - static RRDSET *st = NULL; - static RRDDIM *rd_recv = NULL, *rd_send = NULL, *rd_failed = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "tcpsyncookies", - NULL, - "tcp", - NULL, - "TCP SYN Cookies", - "packets/s", - "freebsd", - "net.inet.tcp.stats", - 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_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_tcpext_listen == CONFIG_BOOLEAN_YES || (do_tcpext_listen == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_listendrop)) { - do_tcpext_listen = CONFIG_BOOLEAN_YES; - - static RRDSET *st_listen = NULL; - static RRDDIM *rd_overflows = NULL; - - if(unlikely(!st_listen)) { - - st_listen = rrdset_create_localhost( - "ipv4", - "tcplistenissues", - NULL, - "tcp", - NULL, - "TCP Listen Socket Issues", - "packets/s", - "freebsd", - "net.inet.tcp.stats", - 3015, - update_every, - RRDSET_TYPE_LINE - ); - - rd_overflows = rrddim_add(st_listen, "ListenOverflows", "overflows", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_listen); - - rrddim_set_by_pointer(st_listen, rd_overflows, tcpstat.tcps_listendrop); - - rrdset_done(st_listen); - } - - // -------------------------------------------------------------------- - - 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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "ecnpkts", - NULL, - "ecn", - NULL, - "IPv4 ECN Statistics", - "packets/s", - "freebsd", - "net.inet.tcp.stats", - 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_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)) { - 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 chart"); - do_udp_errors = 0; - error("DISABLED: ipv4.udperrors chart"); - error("DISABLED: net.inet.udp.stats module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - if (likely(do_udp_packets)) { - static RRDSET *st = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "udppackets", - NULL, - "udp", - NULL, - "IPv4 UDP Packets", - "packets/s", - "freebsd", - "net.inet.udp.stats", - 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_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)) { - 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_localhost( - "ipv4", - "udperrors", - NULL, - "udp", - NULL, - "IPv4 UDP Errors", - "events/s", - "freebsd", - "net.inet.udp.stats", - 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_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_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 chart"); - do_icmp_errors = 0; - error("DISABLED: ipv4.icmp_errors chart"); - do_icmpmsg = 0; - 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]; - icmp_total.msgs_out += icmpstat.icps_outhist[i]; - } - icmp_total.msgs_in += icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort; - - // -------------------------------------------------------------------- - - if (likely(do_icmp_packets)) { - static RRDSET *st = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "icmp" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Packets" - , "packets/s" - , "freebsd" - , "net.inet.icmp.stats" - , 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_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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "icmp_errors" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Errors" - , "packets/s" - , "freebsd" - , "net.inet.icmp.stats" - , 2603 - , update_every - , RRDSET_TYPE_LINE - ); - - 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_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); - } - - // -------------------------------------------------------------------- - - if (likely(do_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_localhost( - "ipv4" - , "icmpmsg" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Messages" - , "packets/s" - , "freebsd" - , "net.inet.icmp.stats" - , 2604 - , update_every - , RRDSET_TYPE_LINE - ); - - 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_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)) { - 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 chart"); - do_ip_fragsout = 0; - error("DISABLED: ipv4.fragsout chart"); - do_ip_fragsin = 0; - error("DISABLED: ipv4.fragsin chart"); - do_ip_errors = 0; - error("DISABLED: ipv4.errors chart"); - error("DISABLED: net.inet.ip.stats module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - if (likely(do_ip_packets)) { - static RRDSET *st = NULL; - static RRDDIM *rd_in_receives = NULL, *rd_out_requests = NULL, *rd_forward_datagrams = NULL, - *rd_in_delivers = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "packets", - NULL, - "packets", - NULL, - "IPv4 Packets", - "packets/s", - "freebsd", - "net.inet.ip.stats", - 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_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)) { - static RRDSET *st = NULL; - static RRDDIM *rd_ok = NULL, *rd_fails = NULL, *rd_created = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "fragsout", - NULL, - "fragments", - NULL, - "IPv4 Fragments Sent", - "packets/s", - "freebsd", - "net.inet.ip.stats", - 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_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)) { - static RRDSET *st = NULL; - static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "fragsin", - NULL, - "fragments", - NULL, - "IPv4 Fragments Reassembly", - "packets/s", - "freebsd", - "net.inet.ip.stats", - 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_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)) { - 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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4", - "errors", - NULL, - "errors", - NULL, - "IPv4 Errors", - "packets/s", - "freebsd", - "net.inet.ip.stats", - 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_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)) { - 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 chart"); - do_ip6_fragsout = 0; - error("DISABLED: ipv6.fragsout chart"); - do_ip6_fragsin = 0; - error("DISABLED: ipv6.fragsin chart"); - do_ip6_errors = 0; - error("DISABLED: ipv6.errors chart"); - error("DISABLED: net.inet6.ip6.stats module"); - return 1; - } else { - - // -------------------------------------------------------------------- - - 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", - "freebsd", - "net.inet6.ip6.stats", - 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_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_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO && - (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag || - ip6stat.ip6s_ofragments))) { - do_ip6_fragsout = CONFIG_BOOLEAN_YES; - - 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", - "freebsd", - "net.inet6.ip6.stats", - 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_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_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_localhost( - "ipv6", - "fragsin", - NULL, - "fragments", - NULL, - "IPv6 Fragments Reassembly", - "packets/s", - "freebsd", - "net.inet6.ip6.stats", - 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_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_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && ( - ip6stat.ip6s_toosmall || - ip6stat.ip6s_odropped || - ip6stat.ip6s_badoptions || - ip6stat.ip6s_badvers || - ip6stat.ip6s_exthdrtoolong || - ip6stat.ip6s_sources_none || - ip6stat.ip6s_tooshort || - ip6stat.ip6s_cantforward || - ip6stat.ip6s_noroute))) { - do_ip6_errors = CONFIG_BOOLEAN_YES; - - 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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6", - "errors", - NULL, - "errors", - NULL, - "IPv6 Errors", - "packets/s", - "freebsd", - "net.inet6.ip6.stats", - 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_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)) { - 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 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_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", - "freebsd", - "net.inet6.icmp6.stats", - 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_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_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) { - do_icmp6_redir = CONFIG_BOOLEAN_YES; - - 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", - "freebsd", - "net.inet6.icmp6.stats", - 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_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_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_localhost( - "ipv6", - "icmperrors", - NULL, "icmp", - NULL, - "IPv6 ICMP Errors", - "errors/s", - "freebsd", - "net.inet6.icmp6.stats", - 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_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_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; - - 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", - "freebsd", - "net.inet6.icmp6.stats", - 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_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_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; - - 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", - "freebsd", - "net.inet6.icmp6.stats", - 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_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_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; - - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6", - "icmpneighbor", - NULL, - "icmp", - NULL, - "IPv6 Neighbor Messages", - "messages/s", - "freebsd", - "net.inet6.icmp6.stats", - 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_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_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_localhost( - "ipv6", - "icmptypes", - NULL, - "icmp", - NULL, - "IPv6 ICMP Types", - "messages/s", - "freebsd", - "net.inet6.icmp6.stats", - 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_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; -} diff --git a/src/freeipmi_plugin.c b/src/freeipmi_plugin.c deleted file mode 100644 index df4c019a4..000000000 --- a/src/freeipmi_plugin.c +++ /dev/null @@ -1,1680 +0,0 @@ -/* - * 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 - * UCRL-CODE-222073 - */ - -#include "common.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_FREEIPMI - -#include -#include - -/* 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; // this is the minimum update frequency -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 int *excluded_record_ids = NULL; -size_t excluded_record_ids_length = 0; - -static void excluded_record_ids_parse(const char *s) { - if(!s) return; - - while(*s) { - while(*s && !isdigit(*s)) s++; - - if(isdigit(*s)) { - char *e; - unsigned long n = strtoul(s, &e, 10); - s = e; - - if(n != 0) { - excluded_record_ids = realloc(excluded_record_ids, (excluded_record_ids_length + 1) * sizeof(int)); - if(!excluded_record_ids) { - fprintf(stderr, "freeipmi.plugin: failed to allocate memory. Exiting."); - exit(1); - } - excluded_record_ids[excluded_record_ids_length++] = (int)n; - } - } - } - - if(debug) { - fprintf(stderr, "freeipmi.plugin: excluded record ids:"); - size_t i; - for(i = 0; i < excluded_record_ids_length; i++) { - fprintf(stderr, " %d", excluded_record_ids[i]); - } - fprintf(stderr, "\n"); - } -} - - -static int excluded_record_ids_check(int record_id) { - size_t i; - - for(i = 0; i < excluded_record_ids_length; i++) { - if(excluded_record_ids[i] == record_id) - return 1; - } - - return 0; -} - -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 - - // check if it is excluded - if(excluded_record_ids_check(record_id)) - return; - - 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, ×tamp) < 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 (int)(( 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(isdigit(*argv[i]) && !freq) { - int n = atoi(argv[i]); - if(n > 0 && freq < 86400) { - freq = n; - continue; - } - } - else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) { - printf("freeipmi.plugin %s\n", VERSION); - exit(0); - } - 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 \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" - " ignore N1,N2,N3,... sensor IDs to ignore\n" - " default: none\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; - } - else if(i < argc && strcmp("ignore", argv[i]) == 0) { - excluded_record_ids_parse(argv[++i]); - continue; - } - - error("freeipmi.plugin: ignoring parameter '%s'", argv[i]); - } - - errno = 0; - - 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(freq > netdata_update_every) { - 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 deleted file mode 100644 index 4f34e92df..000000000 --- a/src/global_statistics.c +++ /dev/null @@ -1,414 +0,0 @@ -#include "common.h" - -volatile struct global_statistics global_statistics = { - .connected_clients = 0, - .web_requests = 0, - .web_usec = 0, - .bytes_received = 0, - .bytes_sent = 0, - .content_size = 0, - .compressed_content_size = 0, - .web_client_count = 1 -}; - -netdata_mutex_t global_statistics_mutex = NETDATA_MUTEX_INITIALIZER; - -inline void global_statistics_lock(void) { - netdata_mutex_lock(&global_statistics_mutex); -} - -inline void global_statistics_unlock(void) { - netdata_mutex_unlock(&global_statistics_mutex); -} - -void finished_web_request_statistics(uint64_t dt, - uint64_t bytes_received, - uint64_t bytes_sent, - uint64_t content_size, - uint64_t compressed_content_size) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - uint64_t old_web_usec_max = global_statistics.web_usec_max; - while(dt > old_web_usec_max) - __atomic_compare_exchange(&global_statistics.web_usec_max, &old_web_usec_max, &dt, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - - __atomic_fetch_add(&global_statistics.web_requests, 1, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&global_statistics.web_usec, dt, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&global_statistics.bytes_received, bytes_received, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&global_statistics.bytes_sent, bytes_sent, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&global_statistics.content_size, content_size, __ATOMIC_SEQ_CST); - __atomic_fetch_add(&global_statistics.compressed_content_size, compressed_content_size, __ATOMIC_SEQ_CST); -#else -#warning NOT using atomic operations - using locks for global statistics - if (web_server_is_multithreaded) - global_statistics_lock(); - - if (dt > global_statistics.web_usec_max) - global_statistics.web_usec_max = dt; - - global_statistics.web_requests++; - global_statistics.web_usec += dt; - global_statistics.bytes_received += bytes_received; - global_statistics.bytes_sent += bytes_sent; - global_statistics.content_size += content_size; - global_statistics.compressed_content_size += compressed_content_size; - - if (web_server_is_multithreaded) - global_statistics_unlock(); -#endif -} - -uint64_t web_client_connected(void) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_add(&global_statistics.connected_clients, 1, __ATOMIC_SEQ_CST); - uint64_t id = __atomic_fetch_add(&global_statistics.web_client_count, 1, __ATOMIC_SEQ_CST); -#else - if (web_server_is_multithreaded) - global_statistics_lock(); - - global_statistics.connected_clients++; - uint64_t id = global_statistics.web_client_count++; - - if (web_server_is_multithreaded) - global_statistics_unlock(); -#endif - - return id; -} - -void web_client_disconnected(void) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - __atomic_fetch_sub(&global_statistics.connected_clients, 1, __ATOMIC_SEQ_CST); -#else - if (web_server_is_multithreaded) - global_statistics_lock(); - - global_statistics.connected_clients--; - - if (web_server_is_multithreaded) - global_statistics_unlock(); -#endif -} - - -inline void global_statistics_copy(struct global_statistics *gs, uint8_t options) { -#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) - gs->connected_clients = __atomic_fetch_add(&global_statistics.connected_clients, 0, __ATOMIC_SEQ_CST); - gs->web_requests = __atomic_fetch_add(&global_statistics.web_requests, 0, __ATOMIC_SEQ_CST); - gs->web_usec = __atomic_fetch_add(&global_statistics.web_usec, 0, __ATOMIC_SEQ_CST); - gs->web_usec_max = __atomic_fetch_add(&global_statistics.web_usec_max, 0, __ATOMIC_SEQ_CST); - gs->bytes_received = __atomic_fetch_add(&global_statistics.bytes_received, 0, __ATOMIC_SEQ_CST); - gs->bytes_sent = __atomic_fetch_add(&global_statistics.bytes_sent, 0, __ATOMIC_SEQ_CST); - gs->content_size = __atomic_fetch_add(&global_statistics.content_size, 0, __ATOMIC_SEQ_CST); - gs->compressed_content_size = __atomic_fetch_add(&global_statistics.compressed_content_size, 0, __ATOMIC_SEQ_CST); - gs->web_client_count = __atomic_fetch_add(&global_statistics.web_client_count, 0, __ATOMIC_SEQ_CST); - - if(options & GLOBAL_STATS_RESET_WEB_USEC_MAX) { - uint64_t n = 0; - __atomic_compare_exchange(&global_statistics.web_usec_max, &gs->web_usec_max, &n, 1, __ATOMIC_SEQ_CST, - __ATOMIC_SEQ_CST); - } -#else - global_statistics_lock(); - - memcpy(gs, (const void *)&global_statistics, sizeof(struct global_statistics)); - - if (options & GLOBAL_STATS_RESET_WEB_USEC_MAX) - global_statistics.web_usec_max = 0; - - global_statistics_unlock(); -#endif -} - -void global_statistics_charts(void) { - static unsigned long long old_web_requests = 0, - old_web_usec = 0, - old_content_size = 0, - old_compressed_content_size = 0; - - static collected_number compression_ratio = -1, - average_response_time = -1; - - struct global_statistics gs; - struct rusage me, thread; - - global_statistics_copy(&gs, GLOBAL_STATS_RESET_WEB_USEC_MAX); - getrusage(RUSAGE_THREAD, &thread); - getrusage(RUSAGE_SELF, &me); - - { - static RRDSET *st_cpu_thread = NULL; - static RRDDIM *rd_cpu_thread_user = NULL, - *rd_cpu_thread_system = NULL; - -#ifdef __FreeBSD__ - if (unlikely(!st_cpu_thread)) { - st_cpu_thread = rrdset_create_localhost( - "netdata" - , "plugin_freebsd_cpu" - , NULL - , "freebsd" - , NULL - , "NetData FreeBSD Plugin CPU usage" - , "milliseconds/s" - , "netdata" - , "stats" - , 132000 - , localhost->rrd_update_every - , RRDSET_TYPE_STACKED - ); -#else - if (unlikely(!st_cpu_thread)) { - st_cpu_thread = rrdset_create_localhost( - "netdata" - , "plugin_proc_cpu" - , NULL - , "proc" - , NULL - , "NetData Proc Plugin CPU usage" - , "milliseconds/s" - , "netdata" - , "stats" - , 132000 - , localhost->rrd_update_every - , RRDSET_TYPE_STACKED - ); -#endif - - rd_cpu_thread_user = rrddim_add(st_cpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rd_cpu_thread_system = rrddim_add(st_cpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_cpu_thread); - - rrddim_set_by_pointer(st_cpu_thread, rd_cpu_thread_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set_by_pointer(st_cpu_thread, rd_cpu_thread_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); - rrdset_done(st_cpu_thread); - } - - // ---------------------------------------------------------------- - - { - static RRDSET *st_cpu = NULL; - static RRDDIM *rd_cpu_user = NULL, - *rd_cpu_system = NULL; - - if (unlikely(!st_cpu)) { - st_cpu = rrdset_create_localhost( - "netdata" - , "server_cpu" - , NULL - , "netdata" - , NULL - , "NetData CPU usage" - , "milliseconds/s" - , "netdata" - , "stats" - , 130000 - , localhost->rrd_update_every - , RRDSET_TYPE_STACKED - ); - - rd_cpu_user = rrddim_add(st_cpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rd_cpu_system = rrddim_add(st_cpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_cpu); - - rrddim_set_by_pointer(st_cpu, rd_cpu_user, me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec); - rrddim_set_by_pointer(st_cpu, rd_cpu_system, me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec); - rrdset_done(st_cpu); - } - - // ---------------------------------------------------------------- - - { - static RRDSET *st_clients = NULL; - static RRDDIM *rd_clients = NULL; - - if (unlikely(!st_clients)) { - st_clients = rrdset_create_localhost( - "netdata" - , "clients" - , NULL - , "netdata" - , NULL - , "NetData Web Clients" - , "connected clients" - , "netdata" - , "stats" - , 130200 - , localhost->rrd_update_every - , RRDSET_TYPE_LINE - ); - - rd_clients = rrddim_add(st_clients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_clients); - - rrddim_set_by_pointer(st_clients, rd_clients, gs.connected_clients); - rrdset_done(st_clients); - } - - // ---------------------------------------------------------------- - - { - static RRDSET *st_reqs = NULL; - static RRDDIM *rd_requests = NULL; - - if (unlikely(!st_reqs)) { - st_reqs = rrdset_create_localhost( - "netdata" - , "requests" - , NULL - , "netdata" - , NULL - , "NetData Web Requests" - , "requests/s" - , "netdata" - , "stats" - , 130300 - , localhost->rrd_update_every - , RRDSET_TYPE_LINE - ); - - rd_requests = rrddim_add(st_reqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_reqs); - - rrddim_set_by_pointer(st_reqs, rd_requests, (collected_number) gs.web_requests); - rrdset_done(st_reqs); - } - - // ---------------------------------------------------------------- - - { - static RRDSET *st_bytes = NULL; - static RRDDIM *rd_in = NULL, - *rd_out = NULL; - - if (unlikely(!st_bytes)) { - st_bytes = rrdset_create_localhost( - "netdata" - , "net" - , NULL - , "netdata" - , NULL - , "NetData Network Traffic" - , "kilobits/s" - , "netdata" - , "stats" - , 130000 - , localhost->rrd_update_every - , RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_bytes); - - rrddim_set_by_pointer(st_bytes, rd_in, (collected_number) gs.bytes_received); - rrddim_set_by_pointer(st_bytes, rd_out, (collected_number) gs.bytes_sent); - rrdset_done(st_bytes); - } - - // ---------------------------------------------------------------- - - { - static RRDSET *st_duration = NULL; - static RRDDIM *rd_average = NULL, - *rd_max = NULL; - - if (unlikely(!st_duration)) { - st_duration = rrdset_create_localhost( - "netdata" - , "response_time" - , NULL - , "netdata" - , NULL - , "NetData API Response Time" - , "ms/request" - , "netdata" - , "stats" - , 130400 - , localhost->rrd_update_every - , RRDSET_TYPE_LINE - ); - - rd_average = rrddim_add(st_duration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_max = rrddim_add(st_duration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_duration); - - uint64_t gweb_usec = gs.web_usec; - uint64_t gweb_requests = gs.web_requests; - - uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0; - uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0; - - old_web_usec = gweb_usec; - old_web_requests = gweb_requests; - - if (web_requests) - average_response_time = (collected_number) (web_usec / web_requests); - - if (unlikely(average_response_time != -1)) - rrddim_set_by_pointer(st_duration, rd_average, average_response_time); - else - rrddim_set_by_pointer(st_duration, rd_average, 0); - - rrddim_set_by_pointer(st_duration, rd_max, ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time)); - rrdset_done(st_duration); - } - - // ---------------------------------------------------------------- - - { - static RRDSET *st_compression = NULL; - static RRDDIM *rd_savings = NULL; - - if (unlikely(!st_compression)) { - st_compression = rrdset_create_localhost( - "netdata" - , "compression_ratio" - , NULL - , "netdata" - , NULL - , "NetData API Responses Compression Savings Ratio" - , "percentage" - , "netdata" - , "stats" - , 130500 - , localhost->rrd_update_every - , RRDSET_TYPE_LINE - ); - - rd_savings = rrddim_add(st_compression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_compression); - - // since we don't lock here to read the global statistics - // read the smaller value first - unsigned long long gcompressed_content_size = gs.compressed_content_size; - unsigned long long gcontent_size = gs.content_size; - - unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size; - unsigned long long content_size = gcontent_size - old_content_size; - - old_compressed_content_size = gcompressed_content_size; - old_content_size = gcontent_size; - - if (content_size && content_size >= compressed_content_size) - compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size; - - if (compression_ratio != -1) - rrddim_set_by_pointer(st_compression, rd_savings, compression_ratio); - - rrdset_done(st_compression); - } -} diff --git a/src/global_statistics.h b/src/global_statistics.h deleted file mode 100644 index 62fee6e36..000000000 --- a/src/global_statistics.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef NETDATA_GLOBAL_STATISTICS_H -#define NETDATA_GLOBAL_STATISTICS_H 1 - -// ---------------------------------------------------------------------------- -// global statistics - -struct global_statistics { - volatile uint16_t connected_clients; - - volatile uint64_t web_requests; - volatile uint64_t web_usec; - volatile uint64_t web_usec_max; - volatile uint64_t bytes_received; - volatile uint64_t bytes_sent; - volatile uint64_t content_size; - volatile uint64_t compressed_content_size; - - volatile uint64_t web_client_count; -}; - -extern volatile struct global_statistics global_statistics; - -extern void global_statistics_lock(void); -extern void global_statistics_unlock(void); -extern void finished_web_request_statistics(uint64_t dt, - uint64_t bytes_received, - uint64_t bytes_sent, - uint64_t content_size, - uint64_t compressed_content_size); - -extern uint64_t web_client_connected(void); -extern void web_client_disconnected(void); - -#define GLOBAL_STATS_RESET_WEB_USEC_MAX 0x01 -extern void global_statistics_copy(struct global_statistics *gs, uint8_t options); -extern void global_statistics_charts(void); - -#endif /* NETDATA_GLOBAL_STATISTICS_H */ diff --git a/src/health.c b/src/health.c deleted file mode 100644 index 04e04f089..000000000 --- a/src/health.c +++ /dev/null @@ -1,737 +0,0 @@ -#define NETDATA_HEALTH_INTERNALS -#include "common.h" - -int default_health_enabled = 1; - -// ---------------------------------------------------------------------------- -// health initialization - -inline char *health_config_dir(void) { - char buffer[FILENAME_MAX + 1]; - 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(!(default_health_enabled = config_get_boolean(CONFIG_SECTION_HEALTH, "enabled", 1))) { - debug(D_HEALTH, "Health is disabled."); - return; - } -} - -// ---------------------------------------------------------------------------- -// re-load health configuration - -void health_reload_host(RRDHOST *host) { - if(unlikely(!host->health_enabled)) - return; - - char *path = health_config_dir(); - - // free all running alarms - rrdhost_wrlock(host); - - while(host->templates) - rrdcalctemplate_unlink_and_free(host, host->templates); - - while(host->alarms) - rrdcalc_unlink_and_free(host, host->alarms); - - rrdhost_unlock(host); - - // invalidate all previous entries in the alarm log - ALARM_ENTRY *t; - 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; - rrdset_foreach_read(st, host) { - st->green = NAN; - st->red = NAN; - } - rrdhost_unlock(host); - - // load the new alarms - rrdhost_wrlock(host); - health_readdir(host, path); - - // link the loaded alarms to their charts - rrdset_foreach_write(st, host) { - rrdsetcalc_link_matching(st); - rrdcalctemplate_link_matching(st); - } - - rrdhost_unlock(host); -} - -void health_reload(void) { - - rrd_rdlock(); - - RRDHOST *host; - rrdhost_foreach_read(host) - health_reload_host(host); - - rrd_unlock(); -} - -// ---------------------------------------------------------------------------- -// health main thread and friends - -static inline RRDCALC_STATUS rrdcalc_value2status(calculated_number n) { - if(isnan(n) || isinf(n)) return RRDCALC_STATUS_UNDEFINED; - if(n) return RRDCALC_STATUS_RAISED; - return RRDCALC_STATUS_CLEAR; -} - -#define ALARM_EXEC_COMMAND_LENGTH 8192 - -static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) { - ae->flags |= HEALTH_ENTRY_FLAG_PROCESSED; - - 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) { - if(t->alarm_id == id && t->flags & HEALTH_ENTRY_FLAG_EXEC_RUN) - break; - } - - if(likely(t)) { - // we have executed this alarm notification in the past - if(t && t->new_status == ae->new_status) { - // don't send the notification for the same status again - debug(D_HEALTH, "Health not sending again notification for alarm '%s.%s' status %s", ae->chart, ae->name - , rrdcalc_status2string(ae->new_status)); - goto done; - } - } - else { - // we have not executed this alarm notification in the past - // so, don't send CLEAR notifications - if(unlikely(ae->new_status == RRDCALC_STATUS_CLEAR)) { - debug(D_HEALTH, "Health not sending notification for first initialization of alarm '%s.%s' status %s" - , ae->chart, ae->name, rrdcalc_status2string(ae->new_status)); - goto done; - } - } - } - - static char command_to_run[ALARM_EXEC_COMMAND_LENGTH + 1]; - pid_t command_pid; - - const char *exec = (ae->exec) ? ae->exec : host->health_default_exec; - const char *recipient = (ae->recipient) ? ae->recipient : host->health_default_recipient; - - snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '" CALCULATED_NUMBER_FORMAT_ZERO "' '" CALCULATED_NUMBER_FORMAT_ZERO "' '%s' '%u' '%u' '%s' '%s' '%s' '%s'", - exec, - recipient, - host->registry_hostname, - ae->unique_id, - ae->alarm_id, - ae->alarm_event_id, - (unsigned long)ae->when, - ae->name, - ae->chart?ae->chart:"NOCAHRT", - ae->family?ae->family:"NOFAMILY", - rrdcalc_status2string(ae->new_status), - rrdcalc_status2string(ae->old_status), - ae->new_value, - ae->old_value, - ae->source?ae->source:"UNKNOWN", - (uint32_t)ae->duration, - (uint32_t)ae->non_clear_duration, - ae->units?ae->units:"", - ae->info?ae->info:"", - ae->new_value_string, - ae->old_value_string - ); - - ae->flags |= HEALTH_ENTRY_FLAG_EXEC_RUN; - ae->exec_run_timestamp = now_realtime_sec(); - - debug(D_HEALTH, "executing command '%s'", command_to_run); - FILE *fp = mypopen(command_to_run, &command_pid); - if(!fp) { - error("HEALTH: Cannot popen(\"%s\", \"r\").", command_to_run); - goto done; - } - debug(D_HEALTH, "HEALTH reading from command"); - char *s = fgets(command_to_run, FILENAME_MAX, fp); - (void)s; - ae->exec_code = mypclose(fp, command_pid); - debug(D_HEALTH, "done executing command - returned with code %d", ae->exec_code); - - if(ae->exec_code != 0) - ae->flags |= HEALTH_ENTRY_FLAG_EXEC_FAILED; - -done: - health_alarm_log_save(host, ae); -} - -static inline void health_process_notifications(RRDHOST *host, ALARM_ENTRY *ae) { - debug(D_HEALTH, "Health alarm '%s.%s' = " CALCULATED_NUMBER_FORMAT_AUTO " - changed status from %s to %s", - ae->chart?ae->chart:"NOCHART", ae->name, - ae->new_value, - rrdcalc_status2string(ae->old_status), - rrdcalc_status2string(ae->new_status) - ); - - health_alarm_execute(host, ae); -} - -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(); - - netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock); - - ALARM_ENTRY *ae; - for(ae = host->health_log.alarms; ae && ae->unique_id >= host->health_last_processed_id ; ae = ae->next) { - if(unlikely( - !(ae->flags & HEALTH_ENTRY_FLAG_PROCESSED) && - !(ae->flags & HEALTH_ENTRY_FLAG_UPDATED) - )) { - - if(unlikely(ae->unique_id < first_waiting)) - first_waiting = ae->unique_id; - - if(likely(now >= ae->delay_up_to_timestamp)) - health_process_notifications(host, ae); - } - } - - // remember this for the next iteration - host->health_last_processed_id = first_waiting; - - 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 - netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock); - - ALARM_ENTRY *last = NULL; - unsigned int count = host->health_log.max * 2 / 3; - for(ae = host->health_log.alarms; ae && count ; count--, last = ae, ae = ae->next) ; - - if(ae && last && last->next == ae) - last->next = NULL; - else - ae = NULL; - - while(ae) { - debug(D_HEALTH, "Health removing alarm log entry with id: %u", ae->unique_id); - - ALARM_ENTRY *t = ae->next; - - health_alarm_log_free_one_nochecks_nounlink(ae); - - ae = t; - host->health_log.count--; - } - - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock); -} - -static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) { - if(unlikely(!rc->rrdset)) { - debug(D_HEALTH, "Health not running alarm '%s.%s'. It is not linked to a chart.", rc->chart?rc->chart:"NOCHART", rc->name); - return 0; - } - - if(unlikely(rc->next_update > now)) { - if (unlikely(*next_run > rc->next_update)) { - // update the next_run time of the main loop - // to run this alarm precisely the time required - *next_run = rc->next_update; - } - - debug(D_HEALTH, "Health not examining alarm '%s.%s' yet (will do in %d secs).", rc->chart?rc->chart:"NOCHART", rc->name, (int) (rc->next_update - now)); - return 0; - } - - if(unlikely(!rc->update_every)) { - debug(D_HEALTH, "Health not running alarm '%s.%s'. It does not have an update frequency", rc->chart?rc->chart:"NOCHART", rc->name); - 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; - } - - int update_every = rc->rrdset->update_every; - time_t first = rrdset_first_entry_t(rc->rrdset); - time_t last = rrdset_last_entry_t(rc->rrdset); - - if(unlikely(now + update_every < first /* || now - update_every > last */)) { - debug(D_HEALTH - , "Health not examining alarm '%s.%s' yet (wanted time is out of bounds - we need %lu but got %lu - %lu)." - , rc->chart ? rc->chart : "NOCHART", rc->name, (unsigned long) now, (unsigned long) first - , (unsigned long) last); - return 0; - } - - if(RRDCALC_HAS_DB_LOOKUP(rc)) { - time_t needed = now + rc->before + rc->after; - - if(needed + update_every < first || needed - update_every > last) { - debug(D_HEALTH - , "Health not examining alarm '%s.%s' yet (not enough data yet - we need %lu but got %lu - %lu)." - , rc->chart ? rc->chart : "NOCHART", rc->name, (unsigned long) needed, (unsigned long) first - , (unsigned long) last); - return 0; - } - } - - return 1; -} - -static inline int check_if_resumed_from_suspention(void) { - static usec_t last_realtime = 0, last_monotonic = 0; - usec_t realtime = now_realtime_usec(), monotonic = now_monotonic_usec(); - int ret = 0; - - // detect if monotonic and realtime have twice the difference - // in which case we assume the system was just waken from hibernation - - if(last_realtime && last_monotonic && realtime - last_realtime > 2 * (monotonic - last_monotonic)) - ret = 1; - - last_realtime = realtime; - last_monotonic = monotonic; - - return ret; -} - -static void health_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *health_main(void *ptr) { - netdata_thread_cleanup_push(health_main_cleanup, ptr); - - 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; - - time_t now = now_realtime_sec(); - time_t hibernation_delay = config_get_number(CONFIG_SECTION_HEALTH, "postpone alarms during hibernation for seconds", 60); - - unsigned int loop = 0; - while(!netdata_exit) { - loop++; - debug(D_HEALTH, "Health monitoring iteration no %u started", loop); - - int runnable = 0, apply_hibernation_delay = 0; - time_t next_run = now + min_run_every; - RRDCALC *rc; - - if(unlikely(check_if_resumed_from_suspention())) { - apply_hibernation_delay = 1; - - info("Postponing alarm checks for %ld seconds, because it seems that the system was just resumed from suspension." - , hibernation_delay - ); - } - - rrd_rdlock(); - - RRDHOST *host; - rrdhost_foreach_read(host) { - if(unlikely(!host->health_enabled)) - continue; - - if(unlikely(apply_hibernation_delay)) { - - info("Postponing health checks for %ld seconds, on host '%s'." - , hibernation_delay - , host->hostname - ); - - host->health_delay_up_to = now + hibernation_delay; - } - - if(unlikely(host->health_delay_up_to)) { - if(unlikely(now < host->health_delay_up_to)) - continue; - - info("Resuming health checks on host '%s'.", host->hostname); - host->health_delay_up_to = 0; - } - - rrdhost_rdlock(host); - - // 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; - } - - 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 - , NULL - , &rc->value - , rc->dimensions - , 1 - , rc->after - , rc->before - , rc->group - , 0 - , rc->options - , &rc->db_after - , &rc->db_before - , &value_is_null - ); - - if(unlikely(ret != 200)) { - // database lookup failed - rc->value = NAN; - rc->rrdcalc_flags |= RRDCALC_FLAG_DB_ERROR; - - 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 - 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 - - debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database is stale", host->hostname, 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(value_is_null)) { - // collected value is null - rc->value = NAN; - rc->rrdcalc_flags |= RRDCALC_FLAG_DB_NAN; - - 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 - ); - } - - // ------------------------------------------------------------ - // if there is calculation expression, run it - - if(unlikely(rc->calculation)) { - if(unlikely(!expression_evaluate(rc->calculation))) { - // calculation failed - rc->value = NAN; - rc->rrdcalc_flags |= RRDCALC_FLAG_CALC_ERROR; - - 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 { - rc->rrdcalc_flags &= ~RRDCALC_FLAG_CALC_ERROR; - - 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; - } - } - } - rrdhost_unlock(host); - - if(unlikely(runnable && !netdata_exit)) { - rrdhost_rdlock(host); - - for(rc = host->alarms; rc; rc = rc->next) { - if(unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE))) - continue; - - RRDCALC_STATUS warning_status = RRDCALC_STATUS_UNDEFINED; - RRDCALC_STATUS critical_status = RRDCALC_STATUS_UNDEFINED; - - // -------------------------------------------------------- - // check the warning expression - - if(likely(rc->warning)) { - if(unlikely(!expression_evaluate(rc->warning))) { - // calculation failed - rc->rrdcalc_flags |= RRDCALC_FLAG_WARN_ERROR; - - 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 { - rc->rrdcalc_flags &= ~RRDCALC_FLAG_WARN_ERROR; - 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); - } - } - - // -------------------------------------------------------- - // check the critical expression - - if(likely(rc->critical)) { - if(unlikely(!expression_evaluate(rc->critical))) { - // calculation failed - rc->rrdcalc_flags |= RRDCALC_FLAG_CRIT_ERROR; - - 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 { - 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); - } - } - - // -------------------------------------------------------- - // decide the final alarm status - - RRDCALC_STATUS 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; - } - - switch(critical_status) { - case RRDCALC_STATUS_CLEAR: - if(status == RRDCALC_STATUS_UNDEFINED) - status = RRDCALC_STATUS_CLEAR; - break; - - case RRDCALC_STATUS_RAISED: - status = RRDCALC_STATUS_CRITICAL; - break; - - default: - break; - } - - // -------------------------------------------------------- - // check if the new status and the old differ - - if(status != rc->status) { - int delay = 0; - - // apply trigger hysteresis - - 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) - 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 - ); - - rc->last_status_change = now; - rc->status = status; - } - - rc->last_updated = now; - rc->next_update = now + rc->update_every; - - if(next_run > rc->next_update) - next_run = rc->next_update; - } - - rrdhost_unlock(host); - } - - if(unlikely(netdata_exit)) - break; - - // execute notifications - // and cleanup - health_alarm_log_process(host); - - if(unlikely(netdata_exit)) - break; - - } /* rrdhost_foreach */ - - rrd_unlock(); - - 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)); - sleep_usec(USEC_PER_SEC * (usec_t) (next_run - now)); - now = now_realtime_sec(); - } - else - debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration now", loop); - - } // forever - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/health.h b/src/health.h deleted file mode 100644 index f41571803..000000000 --- a/src/health.h +++ /dev/null @@ -1,438 +0,0 @@ -#ifndef NETDATA_HEALTH_H -#define NETDATA_HEALTH_H - -extern int default_health_enabled; - -extern int rrdvar_compare(void *a, void *b); - -typedef enum rrdvar_type { - RRDVAR_TYPE_CALCULATED = 1, - RRDVAR_TYPE_TIME_T = 2, - RRDVAR_TYPE_COLLECTED = 3, - RRDVAR_TYPE_TOTAL = 4, - RRDVAR_TYPE_INT = 5, - RRDVAR_TYPE_CALCULATED_ALLOCATED = 6 // a custom variable, allocated on purpose (ie. not inherited from charts) - // used only for custom host global variables -} RRDVAR_TYPE; - -// the variables as stored in the variables indexes -// there are 3 indexes: -// 1. at each chart (RRDSET.rrdvar_root_index) -// 2. at each context (RRDFAMILY.rrdvar_root_index) -// 3. at each host (RRDHOST.rrdvar_root_index) -typedef struct rrdvar { - avl avl; - - char *name; - uint32_t hash; - - RRDVAR_TYPE type; - void *value; - - time_t last_updated; -} RRDVAR; - -// variables linked to charts -// We link variables to point to the values that are already -// calculated / processed by the normal data collection process -// This means, there will be no speed penalty for using -// these variables - -typedef enum rrdvar_options { - RRDVAR_OPTION_DEFAULT = (0 << 0), - RRDVAR_OPTION_ALLOCATED = (1 << 0) // the value ptr is allocated (not a reference) - // future use -} RRDVAR_OPTIONS; - -typedef struct rrdsetvar { - char *variable; // variable name - uint32_t hash; // variable name hash - - char *key_fullid; // chart type.chart id.variable - char *key_fullname; // chart type.chart name.variable - - RRDVAR_TYPE type; - void *value; - - RRDVAR_OPTIONS options; - - RRDVAR *var_local; - RRDVAR *var_family; - RRDVAR *var_host; - RRDVAR *var_family_name; - RRDVAR *var_host_name; - - struct rrdset *rrdset; - - struct rrdsetvar *next; -} RRDSETVAR; - - -// variables linked to individual dimensions -// We link variables to point the values that are already -// calculated / processed by the normal data collection process -// This means, there will be no speed penalty for using -// these variables -typedef struct rrddimvar { - char *prefix; - char *suffix; - - char *key_id; // dimension id - char *key_name; // dimension name - char *key_contextid; // context + dimension id - char *key_contextname; // context + dimension name - char *key_fullidid; // chart type.chart id + dimension id - char *key_fullidname; // chart type.chart id + dimension name - char *key_fullnameid; // chart type.chart name + dimension id - char *key_fullnamename; // chart type.chart name + dimension name - - RRDVAR_TYPE type; - void *value; - - RRDVAR_OPTIONS options; - - RRDVAR *var_local_id; - RRDVAR *var_local_name; - - RRDVAR *var_family_id; - RRDVAR *var_family_name; - RRDVAR *var_family_contextid; - RRDVAR *var_family_contextname; - - RRDVAR *var_host_chartidid; - RRDVAR *var_host_chartidname; - RRDVAR *var_host_chartnameid; - RRDVAR *var_host_chartnamename; - - struct rrddim *rrddim; - - struct rrddimvar *next; -} RRDDIMVAR; - -// calculated variables (defined in health configuration) -// These aggregate time-series data at fixed intervals -// (defined in their update_every member below) -// They increase the overhead of netdata. -// -// These calculations are allocated and linked (->next) -// under RRDHOST. -// Then are also linked to RRDSET (of course only when the -// chart is found, via ->rrdset_next and ->rrdset_prev). -// This double-linked list is maintained sorted at all times -// having as RRDSET.calculations the RRDCALC to be processed -// next. - -#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 - uint32_t next_event_id; // the next event id that will be used for this alarm - - char *name; // the name of this alarm - uint32_t hash; - - char *exec; // the command to execute when this alarm switches state - char *recipient; // the recipient of the alarm (the first parameter to exec) - - char *chart; // the chart id this should be linked to - uint32_t hash_chart; - - char *source; // the source of this alarm - char *units; // the units of the alarm - char *info; // a short description of the alarm - - int update_every; // update frequency for the alarm - - // the red and green threshold of this alarm (to be set to the chart) - calculated_number green; - calculated_number red; - - // ------------------------------------------------------------------------ - // database lookup settings - - char *dimensions; // the chart dimensions - int group; // grouping method: average, max, etc. - int before; // ending point in time-series - int after; // starting point in time-series - uint32_t options; // calculation options - - // ------------------------------------------------------------------------ - // expressions related to the alarm - - EVAL_EXPRESSION *calculation; // expression to calculate the value of the alarm - EVAL_EXPRESSION *warning; // expression to check the warning condition - EVAL_EXPRESSION *critical; // expression to check the critical condition - - // ------------------------------------------------------------------------ - // notification delay settings - - int delay_up_duration; // duration to delay notifications when alarm raises - int delay_down_duration; // duration to delay notifications when alarm lowers - int delay_max_duration; // the absolute max delay to apply to this alarm - float delay_multiplier; // multiplier for all delays when alarms switch status - // while now < delay_up_to - - // ------------------------------------------------------------------------ - // runtime information - - RRDCALC_STATUS status; // the current status of the alarm - - calculated_number value; // the current value of the alarm - calculated_number old_value; // the previous value of the alarm - - uint32_t rrdcalc_flags; // check RRDCALC_FLAG_* - - time_t last_updated; // the last update timestamp of the alarm - time_t next_update; // the next update timestamp of the alarm - time_t last_status_change; // the timestamp of the last time this alarm changed status - - time_t db_after; // the first timestamp evaluated by the db lookup - time_t db_before; // the last timestamp evaluated by the db lookup - - time_t delay_up_to_timestamp; // the timestamp up to which we should delay notifications - int delay_up_current; // the current up notification delay duration - int delay_down_current; // the current down notification delay duration - int delay_last; // the last delay we used - - // ------------------------------------------------------------------------ - // variables this alarm exposes to the rest of the alarms - - RRDVAR *local; - RRDVAR *family; - RRDVAR *hostid; - RRDVAR *hostname; - - // ------------------------------------------------------------------------ - // the chart this alarm it is linked to - - struct rrdset *rrdset; - - // linking of this alarm on its chart - struct rrdcalc *rrdset_next; - struct rrdcalc *rrdset_prev; - - struct rrdcalc *next; -} RRDCALC; - -#define RRDCALC_HAS_DB_LOOKUP(rc) ((rc)->after) - -// RRDCALCTEMPLATE -// these are to be applied to charts found dynamically -// based on their context. -typedef struct rrdcalctemplate { - char *name; - uint32_t hash_name; - - char *exec; - char *recipient; - - char *context; - uint32_t hash_context; - - char *family_match; - SIMPLE_PATTERN *family_pattern; - - char *source; // the source of this alarm - char *units; // the units of the alarm - char *info; // a short description of the alarm - - int update_every; // update frequency for the alarm - - // the red and green threshold of this alarm (to be set to the chart) - calculated_number green; - calculated_number red; - - // ------------------------------------------------------------------------ - // database lookup settings - - char *dimensions; // the chart dimensions - int group; // grouping method: average, max, etc. - int before; // ending point in time-series - int after; // starting point in time-series - uint32_t options; // calculation options - - // ------------------------------------------------------------------------ - // notification delay settings - - int delay_up_duration; // duration to delay notifications when alarm raises - int delay_down_duration; // duration to delay notifications when alarm lowers - int delay_max_duration; // the absolute max delay to apply to this alarm - float delay_multiplier; // multiplier for all delays when alarms switch status - - // ------------------------------------------------------------------------ - // expressions related to the alarm - - EVAL_EXPRESSION *calculation; - EVAL_EXPRESSION *warning; - EVAL_EXPRESSION *critical; - - struct rrdcalctemplate *next; -} 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_NO_CLEAR_NOTIFICATION 0x80000000 - -typedef struct alarm_entry { - uint32_t unique_id; - uint32_t alarm_id; - uint32_t alarm_event_id; - - time_t when; - time_t duration; - time_t non_clear_duration; - - char *name; - uint32_t hash_name; - - char *chart; - uint32_t hash_chart; - - char *family; - - char *exec; - char *recipient; - time_t exec_run_timestamp; - int exec_code; - - char *source; - char *units; - char *info; - - calculated_number old_value; - calculated_number new_value; - - char *old_value_string; - char *new_value_string; - - RRDCALC_STATUS old_status; - RRDCALC_STATUS new_status; - - uint32_t flags; - - int delay; - time_t delay_up_to_timestamp; - - uint32_t updated_by_id; - uint32_t updates_id; - - struct alarm_entry *next; -} ALARM_ENTRY; - -typedef struct alarm_log { - uint32_t next_log_id; - uint32_t next_alarm_id; - unsigned int count; - unsigned int max; - ALARM_ENTRY *alarms; - netdata_rwlock_t alarm_log_rwlock; -} ALARM_LOG; - -#include "rrd.h" - -extern void rrdsetvar_rename_all(RRDSET *st); -extern RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, RRDVAR_TYPE type, void *value, RRDVAR_OPTIONS options); -extern void rrdsetvar_free(RRDSETVAR *rs); - -extern void rrddimvar_rename_all(RRDDIM *rd); -extern RRDDIMVAR *rrddimvar_create(RRDDIM *rd, RRDVAR_TYPE type, const char *prefix, const char *suffix, void *value, RRDVAR_OPTIONS options); -extern void rrddimvar_free(RRDDIMVAR *rs); - -extern void rrdsetcalc_link_matching(RRDSET *st); -extern void rrdsetcalc_unlink(RRDCALC *rc); -extern void rrdcalctemplate_link_matching(RRDSET *st); -extern RRDCALC *rrdcalc_find(RRDSET *st, const char *name); - -extern void health_init(void); -extern void *health_main(void *ptr); - -extern void health_reload(void); - -extern int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result); -extern void health_alarms2json(RRDHOST *host, BUFFER *wb, int all); -extern void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after); - -void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf); - -extern RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name); -extern void rrdvar_custom_host_variable_set(RRDHOST *host, RRDVAR *rv, calculated_number value); - -extern RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name); -extern void rrdsetvar_custom_chart_variable_set(RRDSETVAR *rv, calculated_number value); - -extern void rrdvar_free_remaining_variables(RRDHOST *host, avl_tree_lock *tree_lock); - -extern const char *rrdcalc_status2string(RRDCALC_STATUS 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, - RRDCALC_STATUS old_status, - RRDCALC_STATUS 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(RRDCALC *rc); -extern void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc); - -extern void rrdcalctemplate_free(RRDCALCTEMPLATE *rt); -extern void rrdcalctemplate_unlink_and_free(RRDHOST *host, RRDCALCTEMPLATE *rt); - -extern int rrdvar_callback_for_all_host_variables(RRDHOST *host, int (*callback)(void *rrdvar, void *data), void *data); - -#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, RRDVAR_TYPE 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 deleted file mode 100644 index a25ee7227..000000000 --- a/src/health_config.c +++ /dev/null @@ -1,900 +0,0 @@ -#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_HOST_KEY "hosts" -#define HEALTH_OS_KEY "os" -#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->calculation && !rc->warning && !rc->critical) { - error("Health configuration for alarm '%s.%s' is useless (no db lookup, no calculation, no warning and no critical expressions)", 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 " CALCULATED_NUMBER_FORMAT_AUTO ", red " CALCULATED_NUMBER_FORMAT_AUTO ", 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) - && !strcmp(t->family_match?t->family_match:"*", rt->family_match?rt->family_match:"*") - )) { - error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname); - return 0; - } - } - - debug(D_HEALTH, "Health configuration adding template '%s': context '%s', exec '%s', recipient '%s', green " CALCULATED_NUMBER_FORMAT_AUTO ", red " CALCULATED_NUMBER_FORMAT_AUTO ", 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 = str2ld(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 = (int)((*delay_up_duration) * (*delay_multiplier)); - - if((*delay_max_duration) < (*delay_down_duration) * (*delay_multiplier)) - *delay_max_duration = (int)((*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, "match-ids") || !strcasecmp(key, "match_ids")) { - *options |= RRDR_OPTION_MATCH_IDS; - } - else if(!strcasecmp(key, "match-names") || !strcasecmp(key, "match_names")) { - *options |= RRDR_OPTION_MATCH_NAMES; - } - else if(!strcasecmp(key, "of")) { - if(*s && strcasecmp(s, "all") != 0) - *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 *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_os = 0, - hash_on = 0, - hash_host = 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_os = simple_uhash(HEALTH_OS_KEY); - hash_host = simple_uhash(HEALTH_HOST_KEY); - hash_families = simple_uhash(HEALTH_FAMILIES_KEY); - hash_calc = simple_uhash(HEALTH_CALC_KEY); - hash_lookup = simple_uhash(HEALTH_LOOKUP_KEY); - 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; - - int ignore_this = 0; - size_t line = 0, append = 0; - char *s; - while((s = fgets(&buffer[append], (int)(HEALTH_CONF_MAX_LINE - append), fp)) || append) { - int stop_appending = !s; - line++; - s = trim(buffer); - if(!s || *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(key); - value = trim_all(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 && (ignore_this || !rrdcalc_add_alarm_from_config(host, rc))) - rrdcalc_free(rc); - - if(rt) { - if (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt)) - rrdcalctemplate_free(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); - - ignore_this = 0; - } - else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) { - if(rc) { - if(ignore_this || !rrdcalc_add_alarm_from_config(host, rc)) - rrdcalc_free(rc); - - rc = NULL; - } - - if(rt && (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt))) - rrdcalctemplate_free(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); - - ignore_this = 0; - } - else if(hash == hash_os && !strcasecmp(key, HEALTH_OS_KEY)) { - char *os_match = value; - SIMPLE_PATTERN *os_pattern = simple_pattern_create(os_match, NULL, SIMPLE_PATTERN_EXACT); - - if(!simple_pattern_matches(os_pattern, host->os)) { - if(rc) - debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s/%s: host O/S does not match '%s'", host->hostname, rc->name, line, path, filename, os_match); - - if(rt) - debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s/%s: host O/S does not match '%s'", host->hostname, rt->name, line, path, filename, os_match); - - ignore_this = 1; - } - - simple_pattern_free(os_pattern); - } - else if(hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) { - char *host_match = value; - SIMPLE_PATTERN *host_pattern = simple_pattern_create(host_match, NULL, SIMPLE_PATTERN_EXACT); - - if(!simple_pattern_matches(host_pattern, host->hostname)) { - if(rc) - debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s/%s: hostname does not match '%s'", host->hostname, rc->name, line, path, filename, host_match); - - if(rt) - debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s/%s: hostname does not match '%s'", host->hostname, rt->name, line, path, filename, host_match); - - ignore_this = 1; - } - - simple_pattern_free(host_pattern); - } - else if(rc) { - if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) { - if(rc->chart) { - if(strcmp(rc->chart, value) != 0) - 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 = str2ld(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 = str2ld(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) != 0) - 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) != 0) - 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) != 0) - 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) != 0) - 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) != 0) - 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, NULL, 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 = str2ld(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 = str2ld(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) != 0) - 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) != 0) - 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) != 0) - 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) != 0) - 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 && (ignore_this || !rrdcalc_add_alarm_from_config(host, rc))) - rrdcalc_free(rc); - - if(rt && (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt))) - rrdcalctemplate_free(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 deleted file mode 100644 index aba7425d7..000000000 --- a/src/health_json.c +++ /dev/null @@ -1,260 +0,0 @@ -#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\":\"", prefix, label); - buffer_strcat_htmlescape(wb, value); - buffer_strcat(wb, "\""); - buffer_strcat(wb, 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\"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:"" - , (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 - ); - - health_string2json(wb, "\t\t", "info", ae->info?ae->info:"", ",\n"); - - 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 deleted file mode 100644 index a44fbadb0..000000000 --- a/src/health_log.c +++ /dev/null @@ -1,463 +0,0 @@ -#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" CALCULATED_NUMBER_FORMAT_AUTO "\t" CALCULATED_NUMBER_FORMAT_AUTO - "\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 - - , ae->new_value - , 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) { - 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]); - - 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 > host->health_max_unique_id)) - host->health_max_unique_id = ae->unique_id; - - if(unlikely(ae->alarm_id >= host->health_max_alarm_id)) - host->health_max_alarm_id = ae->alarm_id; - } - else { - error("HEALTH [%s]: line %zu of file '%s' is invalid (unrecognized entry type '%s').", host->hostname, line, filename, pointers[0]); - errored++; - } - } - - netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock); - - freez(buf); - - if(!host->health_max_unique_id) host->health_max_unique_id = (uint32_t)now_realtime_sec(); - if(!host->health_max_alarm_id) host->health_max_alarm_id = (uint32_t)now_realtime_sec(); - - host->health_log.next_log_id = host->health_max_unique_id + 1; - host->health_log.next_alarm_id = host->health_max_alarm_id + 1; - - debug(D_HEALTH, "HEALTH [%s]: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", host->hostname, filename, loaded, updated, errored, duplicate); - return loaded; -} - -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, - RRDCALC_STATUS old_status, - RRDCALC_STATUS 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; - - 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 deleted file mode 100644 index 9ab2dca73..000000000 --- a/src/inlined.h +++ /dev/null @@ -1,291 +0,0 @@ -#ifndef NETDATA_INLINED_H -#define NETDATA_INLINED_H - -#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 - -static inline uint32_t simple_hash(const char *name) { - unsigned char *s = (unsigned char *) name; - uint32_t hval = 0x811c9dc5; - while (*s) { - hval *= 16777619; - hval ^= (uint32_t) *s++; - } - return hval; -} - -static inline uint32_t simple_uhash(const char *name) { - unsigned char *s = (unsigned char *) name; - uint32_t hval = 0x811c9dc5, c; - while ((c = *s++)) { - if (unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A'; - hval *= 16777619; - hval ^= c; - } - return hval; -} - -static inline int simple_hash_strcmp(const char *name, const char *b, uint32_t *hash) { - unsigned char *s = (unsigned char *) name; - uint32_t hval = 0x811c9dc5; - int ret = 0; - while (*s) { - if(!ret) ret = *s - *b++; - hval *= 16777619; - hval ^= (uint32_t) *s++; - } - *hash = hval; - return ret; -} - -static inline int str2i(const char *s) { - int n = 0; - char c, negative = (*s == '-'); - - for(c = (negative)?*(++s):*s; c >= '0' && c <= '9' ; c = *(++s)) { - n *= 10; - n += c - '0'; - } - - if(unlikely(negative)) - return -n; - - return n; -} - -static inline long str2l(const char *s) { - long n = 0; - char c, negative = (*s == '-'); - - for(c = (negative)?*(++s):*s; c >= '0' && c <= '9' ; c = *(++s)) { - n *= 10; - n += c - '0'; - } - - if(unlikely(negative)) - return -n; - - 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; - for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) { - n *= 10; - n += c - '0'; - } - return n; -} - -static inline unsigned long long str2ull(const char *s) { - unsigned long long n = 0; - char c; - for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) { - n *= 10; - n += c - '0'; - } - return n; -} - -static inline long long str2ll(const char *s, char **endptr) { - int negative = 0; - - if(unlikely(*s == '-')) { - s++; - negative = 1; - } - else if(unlikely(*s == '+')) - s++; - - long long n = 0; - char c; - for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) { - n *= 10; - n += c - '0'; - } - - if(unlikely(endptr)) - *endptr = (char *)s; - - if(unlikely(negative)) - return -n; - else - return n; -} - -static inline long double str2ld(const char *s, char **endptr) { - int negative = 0; - const char *start = s; - unsigned long long integer_part = 0; - unsigned long decimal_part = 0; - size_t decimal_digits = 0; - - switch(*s) { - case '-': - s++; - negative = 1; - break; - - case '+': - s++; - break; - - case 'n': - if(s[1] == 'a' && s[2] == 'n') { - if(endptr) *endptr = (char *)&s[3]; - return NAN; - } - break; - - case 'i': - if(s[1] == 'n' && s[2] == 'f') { - if(endptr) *endptr = (char *)&s[3]; - return INFINITY; - } - break; - - default: - break; - } - - while (*s >= '0' && *s <= '9') { - integer_part = (integer_part * 10) + (*s - '0'); - s++; - } - - if(unlikely(*s == '.')) { - decimal_part = 0; - s++; - - while (*s >= '0' && *s <= '9') { - decimal_part = (decimal_part * 10) + (*s - '0'); - s++; - decimal_digits++; - } - } - - if(unlikely(*s == 'e' || *s == 'E')) - return strtold(start, endptr); - - if(unlikely(endptr)) - *endptr = (char *)s; - - if(unlikely(negative)) { - if(unlikely(decimal_digits)) - return -((long double)integer_part + (long double)decimal_part / powl(10.0, decimal_digits)); - else - return -((long double)integer_part); - } - else { - if(unlikely(decimal_digits)) - return (long double)integer_part + (long double)decimal_part / powl(10.0, decimal_digits); - else - return (long double)integer_part; - } -} - -#ifdef NETDATA_STRCMP_OVERRIDE -#ifdef strcmp -#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; -} - -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_file(const char *filename, char *buffer, size_t size) { - int fd = open(filename, O_RDONLY, 0666); - if(unlikely(fd == -1)) - return 1; - - ssize_t r = read(fd, buffer, size); - if(unlikely(r == -1)) { - close(fd); - return 2; - } - buffer[r] = '\0'; - - close(fd); - return 0; -} - -static inline int read_single_number_file(const char *filename, unsigned long long *result) { - char buffer[30 + 1]; - - int ret = read_file(filename, buffer, 30); - if(unlikely(ret)) { - *result = 0; - return ret; - } - - buffer[30] = '\0'; - *result = str2ull(buffer); - return 0; -} - -static inline int read_single_signed_number_file(const char *filename, long long *result) { - char buffer[30 + 1]; - - int ret = read_file(filename, buffer, 30); - if(unlikely(ret)) { - *result = 0; - return ret; - } - - buffer[30] = '\0'; - *result = atoll(buffer); - return 0; -} - -#endif //NETDATA_INLINED_H diff --git a/src/ipc.c b/src/ipc.c deleted file mode 100644 index a9076fca4..000000000 --- a/src/ipc.c +++ /dev/null @@ -1,261 +0,0 @@ -#include "common.h" - -#include -#include -#include - - -#ifndef SEMVMX -#define SEMVMX 32767 /* <= 32767 semaphore maximum value */ -#endif - -/* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */ -#ifndef IPC_INFO -#define IPC_INFO 3 -#endif - -struct ipc_limits { - uint64_t shmmni; /* max number of segments */ - uint64_t shmmax; /* max segment size */ - uint64_t shmall; /* max total shared memory */ - uint64_t shmmin; /* min segment size */ - - int semmni; /* max number of arrays */ - int semmsl; /* max semaphores per array */ - int semmns; /* max semaphores system wide */ - int semopm; /* max ops per semop call */ - unsigned int semvmx; /* semaphore max value (constant) */ - - int msgmni; /* max queues system wide */ - size_t msgmax; /* max size of message */ - int msgmnb; /* default max size of queue */ -}; - -struct ipc_status { - int semusz; /* current number of arrays */ - int semaem; /* current semaphores system wide */ -}; - -/* - * The last arg of semctl is a union semun, but where is it defined? X/OPEN - * tells us to define it ourselves, but until recently Linux include files - * would also define it. - */ -#ifndef HAVE_UNION_SEMUN -/* according to X/OPEN we have to define it ourselves */ -union semun { - int val; - struct semid_ds *buf; - unsigned short int *array; - struct seminfo *__buf; -}; -#endif - -static inline int ipc_sem_get_limits(struct ipc_limits *lim) { - static procfile *ff = NULL; - static int error_shown = 0; - static char filename[FILENAME_MAX + 1] = ""; - - if(unlikely(!filename[0])) - snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", netdata_configured_host_prefix); - - if(unlikely(!ff)) { - ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) { - if(unlikely(!error_shown)) { - error("IPC: Cannot open file '%s'.", filename); - error_shown = 1; - } - goto ipc; - } - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) { - if(unlikely(!error_shown)) { - error("IPC: Cannot read file '%s'.", filename); - error_shown = 1; - } - goto ipc; - } - - if(procfile_lines(ff) >= 1 && procfile_linewords(ff, 0) >= 4) { - lim->semvmx = SEMVMX; - lim->semmsl = str2i(procfile_lineword(ff, 0, 0)); - lim->semmns = str2i(procfile_lineword(ff, 0, 1)); - lim->semopm = str2i(procfile_lineword(ff, 0, 2)); - lim->semmni = str2i(procfile_lineword(ff, 0, 3)); - return 0; - } - else { - if(unlikely(!error_shown)) { - error("IPC: Invalid content in file '%s'.", filename); - error_shown = 1; - } - goto ipc; - } - -ipc: - // cannot do it from the file - // query IPC - { - struct seminfo seminfo = {.semmni = 0}; - union semun arg = {.array = (ushort *) &seminfo}; - - if(unlikely(semctl(0, 0, IPC_INFO, arg) < 0)) { - error("IPC: Failed to read '%s' and request IPC_INFO with semctl().", filename); - goto error; - } - - lim->semvmx = SEMVMX; - lim->semmni = seminfo.semmni; - lim->semmsl = seminfo.semmsl; - lim->semmns = seminfo.semmns; - lim->semopm = seminfo.semopm; - return 0; - } - -error: - lim->semvmx = 0; - lim->semmni = 0; - lim->semmsl = 0; - lim->semmns = 0; - lim->semopm = 0; - return -1; -} - -/* -printf ("------ Semaphore Limits --------\n"); -printf ("max number of arrays = %d\n", limits.semmni); -printf ("max semaphores per array = %d\n", limits.semmsl); -printf ("max semaphores system wide = %d\n", limits.semmns); -printf ("max ops per semop call = %d\n", limits.semopm); -printf ("semaphore max value = %u\n", limits.semvmx); - -printf ("------ Semaphore Status --------\n"); -printf ("used arrays = %d\n", status.semusz); -printf ("allocated semaphores = %d\n", status.semaem); -*/ - -static inline int ipc_sem_get_status(struct ipc_status *st) { - struct seminfo seminfo; - union semun arg; - - arg.array = (ushort *) (void *) &seminfo; - - if(unlikely(semctl (0, 0, SEM_INFO, arg) < 0)) { - /* kernel not configured for semaphores */ - static int error_shown = 0; - if(unlikely(!error_shown)) { - error("IPC: kernel is not configured for semaphores"); - error_shown = 1; - } - st->semusz = 0; - st->semaem = 0; - return -1; - } - - st->semusz = seminfo.semusz; - st->semaem = seminfo.semaem; - return 0; -} - -int do_ipc(int update_every, usec_t dt) { - (void)dt; - - static int initialized = 0, read_limits_next = -1; - static struct ipc_limits limits; - static struct ipc_status status; - static RRDSETVAR *arrays_max = NULL, *semaphores_max = NULL; - static RRDSET *st_semaphores = NULL, *st_arrays = NULL; - static RRDDIM *rd_semaphores = NULL, *rd_arrays = NULL; - - if(unlikely(!initialized)) { - initialized = 1; - - // make sure it works - if(ipc_sem_get_limits(&limits) == -1) { - error("unable to fetch semaphore limits"); - return 1; - } - - // make sure it works - if(ipc_sem_get_status(&status) == -1) { - error("unable to fetch semaphore statistics"); - return 1; - } - - // create the charts - if(unlikely(!st_semaphores)) { - st_semaphores = rrdset_create_localhost( - "system" - , "ipc_semaphores" - , NULL - , "ipc semaphores" - , NULL - , "IPC Semaphores" - , "semaphores" - , "linux" - , "ipc" - , 1000 - , localhost->rrd_update_every - , RRDSET_TYPE_AREA - ); - rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - - if(unlikely(!st_arrays)) { - st_arrays = rrdset_create_localhost( - "system" - , "ipc_semaphore_arrays" - , NULL - , "ipc semaphores" - , NULL - , "IPC Semaphore Arrays" - , "arrays" - , "linux" - , "ipc" - , 1000 - , localhost->rrd_update_every - , RRDSET_TYPE_AREA - ); - rd_arrays = rrddim_add(st_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - - // variables - semaphores_max = rrdsetvar_custom_chart_variable_create(st_semaphores, "ipc.semaphores.max"); - arrays_max = rrdsetvar_custom_chart_variable_create(st_arrays, "ipc.semaphores.arrays.max"); - } - - if(unlikely(read_limits_next < 0)) { - if(unlikely(ipc_sem_get_limits(&limits) == -1)) { - error("Unable to fetch semaphore limits."); - } - else { - if(semaphores_max) rrdsetvar_custom_chart_variable_set(semaphores_max, limits.semmns); - if(arrays_max) rrdsetvar_custom_chart_variable_set(arrays_max, limits.semmni); - - st_arrays->red = limits.semmni; - st_semaphores->red = limits.semmns; - - read_limits_next = 60 / update_every; - } - } - else - read_limits_next--; - - if(unlikely(ipc_sem_get_status(&status) == -1)) { - error("Unable to get semaphore statistics"); - return 0; - } - - if(st_semaphores->counter_done) rrdset_next(st_semaphores); - rrddim_set_by_pointer(st_semaphores, rd_semaphores, status.semaem); - rrdset_done(st_semaphores); - - if(st_arrays->counter_done) rrdset_next(st_arrays); - rrddim_set_by_pointer(st_arrays, rd_arrays, status.semusz); - rrdset_done(st_arrays); - - return 0; -} diff --git a/src/ipc.h b/src/ipc.h deleted file mode 100644 index 04f9df5cd..000000000 --- a/src/ipc.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef NETDATA_PLUGIN_IPC_H -#define NETDATA_PLUGIN_IPC_H 1 - -extern int do_ipc(int update_every, usec_t dt); - -#endif /* NETDATA_PLUGIN_IPC_H */ - diff --git a/src/locks.c b/src/locks.c deleted file mode 100644 index c5b42c921..000000000 --- a/src/locks.c +++ /dev/null @@ -1,319 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// automatic thread cancelability management, based on locks - -static __thread int netdata_thread_first_cancelability = 0; -static __thread int netdata_thread_lock_cancelability = 0; - -inline void netdata_thread_disable_cancelability(void) { - int old; - int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old); - if(ret != 0) - error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d", netdata_thread_tag(), ret); - else { - if(!netdata_thread_lock_cancelability) - netdata_thread_first_cancelability = old; - - netdata_thread_lock_cancelability++; - } -} - -inline void netdata_thread_enable_cancelability(void) { - if(netdata_thread_lock_cancelability < 1) { - error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): invalid thread cancelability count %d on thread %s - results will be undefined - please report this!", netdata_thread_lock_cancelability, netdata_thread_tag()); - } - else if(netdata_thread_lock_cancelability == 1) { - int old = 1; - int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old); - if(ret != 0) - error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d", netdata_thread_tag(), ret); - else { - if(old != PTHREAD_CANCEL_DISABLE) - error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): old thread cancelability on thread %s was changed, expected DISABLED (%d), found %s (%d) - please report this!", netdata_thread_tag(), PTHREAD_CANCEL_DISABLE, (old == PTHREAD_CANCEL_ENABLE)?"ENABLED":"UNKNOWN", old); - } - - netdata_thread_lock_cancelability = 0; - } - else - netdata_thread_lock_cancelability--; -} - -// ---------------------------------------------------------------------------- -// mutex - -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; -} - -int __netdata_mutex_lock(netdata_mutex_t *mutex) { - netdata_thread_disable_cancelability(); - - int ret = pthread_mutex_lock(mutex); - if(unlikely(ret != 0)) { - netdata_thread_enable_cancelability(); - error("MUTEX_LOCK: failed to get lock (code %d)", ret); - } - return ret; -} - -int __netdata_mutex_trylock(netdata_mutex_t *mutex) { - netdata_thread_disable_cancelability(); - - int ret = pthread_mutex_trylock(mutex); - if(ret != 0) - netdata_thread_enable_cancelability(); - - return ret; -} - -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); - else - netdata_thread_enable_cancelability(); - - return ret; -} - -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; -} - -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; -} - -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; -} - -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; -} - - -// ---------------------------------------------------------------------------- -// r/w lock - -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; -} - -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; -} - -int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) { - netdata_thread_disable_cancelability(); - - int ret = pthread_rwlock_rdlock(rwlock); - if(unlikely(ret != 0)) { - netdata_thread_enable_cancelability(); - error("RW_LOCK: failed to obtain read lock (code %d)", ret); - } - - return ret; -} - -int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) { - netdata_thread_disable_cancelability(); - - int ret = pthread_rwlock_wrlock(rwlock); - if(unlikely(ret != 0)) { - error("RW_LOCK: failed to obtain write lock (code %d)", ret); - netdata_thread_enable_cancelability(); - } - - return ret; -} - -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); - else - netdata_thread_enable_cancelability(); - - return ret; -} - -int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) { - netdata_thread_disable_cancelability(); - - int ret = pthread_rwlock_tryrdlock(rwlock); - if(ret != 0) - netdata_thread_enable_cancelability(); - - return ret; -} - -int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) { - netdata_thread_disable_cancelability(); - - int ret = pthread_rwlock_trywrlock(rwlock); - if(ret != 0) - netdata_thread_enable_cancelability(); - - return ret; -} - - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} diff --git a/src/locks.h b/src/locks.h deleted file mode 100644 index 36962fef2..000000000 --- a/src/locks.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef NETDATA_LOCKS_H -#define NETDATA_LOCKS_H - -typedef pthread_mutex_t netdata_mutex_t; -#define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER - -typedef pthread_rwlock_t netdata_rwlock_t; -#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER - -extern int __netdata_mutex_init(netdata_mutex_t *mutex); -extern int __netdata_mutex_lock(netdata_mutex_t *mutex); -extern int __netdata_mutex_trylock(netdata_mutex_t *mutex); -extern int __netdata_mutex_unlock(netdata_mutex_t *mutex); - -extern int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock); -extern int __netdata_rwlock_init(netdata_rwlock_t *rwlock); -extern int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock); -extern int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock); -extern int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock); -extern int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock); -extern int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock); - -extern int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); -extern int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); -extern int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); -extern int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); - -extern int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -extern int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -extern int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -extern int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -extern int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -extern int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -extern int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); - -extern void netdata_thread_disable_cancelability(void); -extern void netdata_thread_enable_cancelability(void); - -#ifdef NETDATA_INTERNAL_CHECKS - -#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) - -#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_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) - -#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 deleted file mode 100644 index edb4482a0..000000000 --- a/src/log.c +++ /dev/null @@ -1,427 +0,0 @@ -#include "common.h" - -int web_server_is_multithreaded = 1; - -const char *program_name = ""; -uint64_t debug_flags = DEBUG; - -int access_log_syslog = 1; -int error_log_syslog = 1; -int output_log_syslog = 1; // debug log - -int stdaccess_fd = -1; -FILE *stdaccess = NULL; - -const char *stdaccess_filename = NULL; -const char *stderr_filename = NULL; -const char *stdout_filename = NULL; - -void syslog_init(void) { - static int i = 0; - - if(!i) { - openlog(program_name, LOG_PID, LOG_DAEMON); - i = 1; - } -} - -#define LOG_DATE_LENGTH 26 - -static inline void log_date(char *buffer, size_t len) { - if(unlikely(!buffer || !len)) - return; - - time_t t; - struct tm *tmp, tmbuf; - - t = now_realtime_sec(); - tmp = localtime_r(&t, &tmbuf); - - if (tmp == NULL) { - buffer[0] = '\0'; - return; - } - - if (unlikely(strftime(buffer, len, "%Y-%m-%d %H:%M:%S", tmp) == 0)) - buffer[0] = '\0'; - - buffer[len - 1] = '\0'; -} - -static netdata_mutex_t log_mutex = NETDATA_MUTEX_INITIALIZER; -static inline void log_lock() { - netdata_mutex_lock(&log_mutex); -} -static inline void log_unlock() { - netdata_mutex_unlock(&log_mutex); -} - -int open_log_file(int fd, FILE **fp, const char *filename, int *enabled_syslog) { - int f, devnull = 0; - - if(!filename || !*filename || !strcmp(filename, "none") || !strcmp(filename, "/dev/null")) { - filename = "/dev/null"; - devnull = 1; - } - - if(!strcmp(filename, "syslog")) { - filename = "/dev/null"; - devnull = 1; - syslog_init(); - if(enabled_syslog) *enabled_syslog = 1; - } - else if(enabled_syslog) *enabled_syslog = 0; - - // don't do anything if the user is willing - // to have the standard one - if(!strcmp(filename, "system")) { - if(fd != -1 && fp != &stdaccess) - return fd; - - filename = "stderr"; - } - - if(!strcmp(filename, "stdout")) - f = STDOUT_FILENO; - - else if(!strcmp(filename, "stderr")) - f = STDERR_FILENO; - - else { - f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664); - if(f == -1) { - error("Cannot open file '%s'. Leaving %d to its default.", filename, fd); - return fd; - } - } - - if(devnull && fp == &stdaccess) { - fd = -1; - *fp = NULL; - } - - // if there is a level-2 file pointer - // flush it before switching the level-1 fds - if(fp && *fp) - fflush(*fp); - - if(fd != f && fd != -1) { - // it automatically closes - int t = dup2(f, fd); - if (t == -1) { - error("Cannot dup2() new fd %d to old fd %d for '%s'", f, fd, filename); - close(f); - return fd; - } - // info("dup2() new fd %d to old fd %d for '%s'", f, fd, filename); - close(f); - } - else fd = f; - - if(fp && !*fp) { - *fp = fdopen(fd, "a"); - if (!*fp) - error("Cannot fdopen() fd %d ('%s')", fd, filename); - else { - if (setvbuf(*fp, NULL, _IOLBF, 0) != 0) - error("Cannot set line buffering on fd %d ('%s')", fd, filename); - } - } - - return fd; -} - -void reopen_all_log_files() { - if(stdout_filename) - open_log_file(STDOUT_FILENO, (FILE **)&stdout, stdout_filename, &output_log_syslog); - - if(stderr_filename) - open_log_file(STDERR_FILENO, (FILE **)&stderr, stderr_filename, &error_log_syslog); - - if(stdaccess_filename) - stdaccess_fd = open_log_file(stdaccess_fd, (FILE **)&stdaccess, stdaccess_filename, &access_log_syslog); -} - -void open_all_log_files() { - // disable stdin - open_log_file(STDIN_FILENO, (FILE **)&stdin, "/dev/null", NULL); - - open_log_file(STDOUT_FILENO, (FILE **)&stdout, stdout_filename, &output_log_syslog); - open_log_file(STDERR_FILENO, (FILE **)&stderr, stderr_filename, &error_log_syslog); - stdaccess_fd = open_log_file(stdaccess_fd, (FILE **)&stdaccess, stdaccess_filename, &access_log_syslog); -} - -// ---------------------------------------------------------------------------- -// error log throttling - -time_t error_log_throttle_period_backup = 0; -time_t error_log_throttle_period = 1200; -unsigned long error_log_errors_per_period = 200; - -int error_log_limit(int reset) { - static time_t start = 0; - static unsigned long counter = 0, prevented = 0; - - // do not throttle if the period is 0 - if(error_log_throttle_period == 0) - return 0; - - // prevent all logs if the errors per period is 0 - if(error_log_errors_per_period == 0) -#ifdef NETDATA_INTERNAL_CHECKS - return 0; -#else - return 1; -#endif - - time_t now = now_monotonic_sec(); - if(!start) start = now; - - if(reset) { - if(prevented) { - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - fprintf(stderr, "%s: %s Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n" - , date - , program_name - , program_name - , prevented - , now - start - ); - } - - start = now; - counter = 0; - prevented = 0; - } - - // detect if we log too much - counter++; - - if(now - start > error_log_throttle_period) { - if(prevented) { - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - fprintf(stderr, "%s: %s Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n" - , date - , program_name - , program_name - , prevented - , error_log_throttle_period - ); - } - - // restart the period accounting - start = now; - counter = 1; - prevented = 0; - - // log this error - return 0; - } - - if(counter > error_log_errors_per_period) { - if(!prevented) { - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - fprintf(stderr, "%s: %s Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n" - , date - , program_name - , counter - , now - start - , error_log_errors_per_period - , error_log_throttle_period - , program_name - , start + error_log_throttle_period - now); - } - - prevented++; - - // prevent logging this error -#ifdef NETDATA_INTERNAL_CHECKS - return 0; -#else - return 1; -#endif - } - - return 0; -} - -// ---------------------------------------------------------------------------- -// debug log - -void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) { - va_list args; - - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - - va_start( args, fmt ); - printf("%s: %s DEBUG : %s : (%04lu@%-10.10s:%-15.15s): ", date, program_name, netdata_thread_tag(), line, file, function); - vprintf(fmt, args); - va_end( args ); - putchar('\n'); - - if(output_log_syslog) { - va_start( args, fmt ); - vsyslog(LOG_ERR, fmt, args ); - va_end( args ); - } - - fflush(stdout); -} - -// ---------------------------------------------------------------------------- -// info log - -void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) -{ - va_list args; - - // prevent logging too much - if(error_log_limit(0)) return; - - if(error_log_syslog) { - va_start( args, fmt ); - vsyslog(LOG_INFO, fmt, args ); - va_end( args ); - } - - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - - log_lock(); - - va_start( args, fmt ); - if(debug_flags) fprintf(stderr, "%s: %s INFO : %s : (%04lu@%-10.10s:%-15.15s): ", date, program_name, netdata_thread_tag(), line, file, function); - else fprintf(stderr, "%s: %s INFO : %s : ", date, program_name, netdata_thread_tag()); - vfprintf( stderr, fmt, args ); - va_end( args ); - - fputc('\n', stderr); - - log_unlock(); -} - -// ---------------------------------------------------------------------------- -// error log - -#if defined(STRERROR_R_CHAR_P) -// GLIBC version of strerror_r -static const char *strerror_result(const char *a, const char *b) { (void)b; return a; } -#elif defined(HAVE_STRERROR_R) -// POSIX version of strerror_r -static const char *strerror_result(int a, const char *b) { (void)a; return b; } -#elif defined(HAVE_C__GENERIC) - -// what a trick! -// http://stackoverflow.com/questions/479207/function-overloading-in-c -static const char *strerror_result_int(int a, const char *b) { (void)a; return b; } -static const char *strerror_result_string(const char *a, const char *b) { (void)b; return a; } - -#define strerror_result(a, b) _Generic((a), \ - int: strerror_result_int, \ - char *: strerror_result_string \ - )(a, b) - -#else -#error "cannot detect the format of function strerror_r()" -#endif - -void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... ) { - // save a copy of errno - just in case this function generates a new error - int __errno = errno; - - va_list args; - - // prevent logging too much - if(error_log_limit(0)) return; - - if(error_log_syslog) { - va_start( args, fmt ); - vsyslog(LOG_ERR, fmt, args ); - va_end( args ); - } - - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - - log_lock(); - - va_start( args, fmt ); - if(debug_flags) fprintf(stderr, "%s: %s %-5.5s : %s : (%04lu@%-10.10s:%-15.15s): ", date, program_name, prefix, netdata_thread_tag(), line, file, function); - else fprintf(stderr, "%s: %s %-5.5s : %s : ", date, program_name, prefix, netdata_thread_tag()); - vfprintf( stderr, fmt, args ); - va_end( args ); - - if(__errno) { - char buf[1024]; - fprintf(stderr, " (errno %d, %s)\n", __errno, strerror_result(strerror_r(__errno, buf, 1023), buf)); - errno = 0; - } - else - fputc('\n', stderr); - - log_unlock(); -} - -void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) { - va_list args; - - if(error_log_syslog) { - va_start( args, fmt ); - vsyslog(LOG_CRIT, fmt, args ); - va_end( args ); - } - - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - - log_lock(); - - va_start( args, fmt ); - if(debug_flags) fprintf(stderr, "%s: %s FATAL : %s : (%04lu@%-10.10s:%-15.15s): ", date, program_name, netdata_thread_tag(), line, file, function); - else fprintf(stderr, "%s: %s FATAL : %s :", date, program_name, netdata_thread_tag()); - vfprintf( stderr, fmt, args ); - va_end( args ); - - perror(" # "); - fputc('\n', stderr); - - log_unlock(); - - netdata_cleanup_and_exit(1); -} - -// ---------------------------------------------------------------------------- -// access log - -void log_access( const char *fmt, ... ) { - va_list args; - - if(access_log_syslog) { - va_start( args, fmt ); - vsyslog(LOG_INFO, fmt, args ); - va_end( args ); - } - - if(stdaccess) { - static netdata_mutex_t access_mutex = NETDATA_MUTEX_INITIALIZER; - - if(web_server_is_multithreaded) - netdata_mutex_lock(&access_mutex); - - char date[LOG_DATE_LENGTH]; - log_date(date, LOG_DATE_LENGTH); - fprintf(stdaccess, "%s: ", date); - - va_start( args, fmt ); - vfprintf( stdaccess, fmt, args ); - va_end( args ); - fputc('\n', stdaccess); - - if(web_server_is_multithreaded) - netdata_mutex_unlock(&access_mutex); - } -} diff --git a/src/log.h b/src/log.h deleted file mode 100644 index 81c85481b..000000000 --- a/src/log.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef NETDATA_LOG_H -#define NETDATA_LOG_H 1 - -#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_BACKEND 0x0000000008000000 -#define D_STATSD 0x0000000010000000 -#define D_POLLFD 0x0000000020000000 -#define D_STREAM 0x0000000040000000 -#define D_SYSTEM 0x8000000000000000 - -//#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS) -//#define DEBUG 0xffffffff -#define DEBUG (0) - -extern int web_server_is_multithreaded; - -extern uint64_t debug_flags; - -extern const char *program_name; - -extern int stdaccess_fd; -extern FILE *stdaccess; - -extern const char *stdaccess_filename; -extern const char *stderr_filename; -extern const char *stdout_filename; - -extern int access_log_syslog; -extern int error_log_syslog; -extern int output_log_syslog; - -extern time_t error_log_throttle_period, error_log_throttle_period_backup; -extern unsigned long error_log_errors_per_period; -extern int error_log_limit(int reset); - -extern void open_all_log_files(); -extern void reopen_all_log_files(); - -static inline void debug_dummy(void) {} - -#define error_log_limit_reset() do { error_log_throttle_period = error_log_throttle_period_backup; error_log_limit(1); } while(0) -#define error_log_limit_unlimited() do { error_log_throttle_period = 0; } while(0) - -#ifdef NETDATA_INTERNAL_CHECKS -#define debug(type, args...) do { if(unlikely(debug_flags & type)) debug_int(__FILE__, __FUNCTION__, __LINE__, ##args); } while(0) -#else -#define debug(type, args...) debug_dummy() -#endif - -#define info(args...) info_int(__FILE__, __FUNCTION__, __LINE__, ##args) -#define infoerr(args...) error_int("INFO", __FILE__, __FUNCTION__, __LINE__, ##args) -#define error(args...) error_int("ERROR", __FILE__, __FUNCTION__, __LINE__, ##args) -#define fatal(args...) fatal_int(__FILE__, __FUNCTION__, __LINE__, ##args) - -extern void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) PRINTFLIKE(4, 5); -extern void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) PRINTFLIKE(4, 5); -extern void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... ) PRINTFLIKE(5, 6); -extern void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) NORETURN PRINTFLIKE(4, 5); -extern void log_access( const char *fmt, ... ) PRINTFLIKE(1, 2); - -#endif /* NETDATA_LOG_H */ diff --git a/src/macos_fw.c b/src/macos_fw.c deleted file mode 100644 index 5e8ce0ee4..000000000 --- a/src/macos_fw.c +++ /dev/null @@ -1,684 +0,0 @@ -#include "common.h" -#include -#include -#include -#include -// NEEDED BY do_space, do_inodes -#include -// NEEDED BY: struct ifaddrs, getifaddrs() -#include -#include - -// NEEDED BY: do_bandwidth -#define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s) - -#define MAXDRIVENAME 31 - -#define KILO_FACTOR 1024 -#define MEGA_FACTOR 1048576 // 1024 * 1024 -#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024 - -int do_macos_iokit(int update_every, usec_t dt) { - (void)dt; - - static int do_io = -1, do_space = -1, do_inodes = -1, do_bandwidth = -1; - - if (unlikely(do_io == -1)) { - do_io = config_get_boolean("plugin:macos:iokit", "disk i/o", 1); - do_space = config_get_boolean("plugin:macos:sysctl", "space usage for all disks", 1); - do_inodes = config_get_boolean("plugin:macos:sysctl", "inodes usage for all disks", 1); - do_bandwidth = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1); - } - - RRDSET *st; - - mach_port_t master_port; - io_registry_entry_t drive, drive_media; - io_iterator_t drive_list; - CFDictionaryRef properties, statistics; - CFStringRef name; - CFNumberRef number; - kern_return_t status; - collected_number total_disk_reads = 0; - collected_number total_disk_writes = 0; - struct diskstat { - char name[MAXDRIVENAME]; - collected_number bytes_read; - collected_number bytes_write; - collected_number reads; - collected_number writes; - collected_number time_read; - collected_number time_write; - collected_number latency_read; - collected_number latency_write; - } diskstat; - struct cur_diskstat { - collected_number duration_read_ns; - collected_number duration_write_ns; - collected_number busy_time_ns; - } cur_diskstat; - struct prev_diskstat { - collected_number bytes_read; - collected_number bytes_write; - collected_number operations_read; - collected_number operations_write; - collected_number duration_read_ns; - collected_number duration_write_ns; - collected_number busy_time_ns; - } prev_diskstat; - - // NEEDED BY: do_space, do_inodes - struct statfs *mntbuf; - int mntsize, i; - char mntonname[MNAMELEN + 1]; - char title[4096 + 1]; - - // NEEDED BY: do_bandwidth - struct ifaddrs *ifa, *ifap; - - /* Get ports and services for drive statistics. */ - if (unlikely(IOMasterPort(bootstrap_port, &master_port))) { - error("MACOS: IOMasterPort() failed"); - do_io = 0; - error("DISABLED: system.io"); - /* Get the list of all drive objects. */ - } else if (unlikely(IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))) { - error("MACOS: IOServiceGetMatchingServices() failed"); - do_io = 0; - error("DISABLED: system.io"); - } else { - while ((drive = IOIteratorNext(drive_list)) != 0) { - properties = 0; - statistics = 0; - number = 0; - bzero(&diskstat, sizeof(diskstat)); - - /* Get drive media object. */ - status = IORegistryEntryGetChildEntry(drive, kIOServicePlane, &drive_media); - if (unlikely(status != KERN_SUCCESS)) { - IOObjectRelease(drive); - continue; - } - - /* Get drive media properties. */ - if (likely(!IORegistryEntryCreateCFProperties(drive_media, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) { - /* Get disk name. */ - if (likely(name = (CFStringRef)CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)))) { - CFStringGetCString(name, diskstat.name, MAXDRIVENAME, kCFStringEncodingUTF8); - } - } - - /* Release. */ - CFRelease(properties); - IOObjectRelease(drive_media); - - if(unlikely(!diskstat.name || !*diskstat.name)) { - IOObjectRelease(drive); - continue; - } - - /* Obtain the properties for this drive object. */ - if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) { - IOObjectRelease(drive); - error("MACOS: IORegistryEntryCreateCFProperties() failed"); - do_io = 0; - error("DISABLED: system.io"); - break; - } else if (likely(properties)) { - /* Obtain the statistics from the drive properties. */ - if (likely(statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)))) { - - // -------------------------------------------------------------------- - - /* Get bytes read. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_read); - total_disk_reads += diskstat.bytes_read; - } - - /* Get bytes written. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_write); - total_disk_writes += diskstat.bytes_write; - } - - st = rrdset_find_bytype_localhost("disk", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk" - , diskstat.name - , NULL - , diskstat.name - , "disk.io" - , "Disk I/O Bandwidth" - , "kilobytes/s" - , "macos" - , "iokit" - , 2000 - , update_every - , RRDSET_TYPE_AREA - ); - - rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - prev_diskstat.bytes_read = rrddim_set(st, "reads", diskstat.bytes_read); - prev_diskstat.bytes_write = rrddim_set(st, "writes", diskstat.bytes_write); - rrdset_done(st); - - // -------------------------------------------------------------------- - - /* Get number of reads. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.reads); - } - - /* Get number of writes. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes); - } - - st = rrdset_find_bytype_localhost("disk_ops", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk_ops" - , diskstat.name - , NULL - , diskstat.name - , "disk.ops" - , "Disk Completed I/O Operations" - , "operations/s" - , "macos" - , "iokit" - , 2001 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - prev_diskstat.operations_read = rrddim_set(st, "reads", diskstat.reads); - prev_diskstat.operations_write = rrddim_set(st, "writes", diskstat.writes); - rrdset_done(st); - - // -------------------------------------------------------------------- - - /* Get reads time. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_read); - } - - /* Get writes time. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write); - } - - st = rrdset_find_bytype_localhost("disk_util", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk_util" - , diskstat.name - , NULL - , diskstat.name - , "disk.util" - , "Disk Utilization Time" - , "% of time working" - , "macos" - , "iokit" - , 2004 - , update_every - , RRDSET_TYPE_AREA - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "utilization", NULL, 1, 10000000, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - cur_diskstat.busy_time_ns = (diskstat.time_read + diskstat.time_write); - prev_diskstat.busy_time_ns = rrddim_set(st, "utilization", cur_diskstat.busy_time_ns); - rrdset_done(st); - - // -------------------------------------------------------------------- - - /* Get reads latency. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_read); - } - - /* Get writes latency. */ - if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) { - CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write); - } - - st = rrdset_find_bytype_localhost("disk_iotime", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk_iotime" - , diskstat.name - , NULL - , diskstat.name - , "disk.iotime" - , "Disk Total I/O Time" - , "milliseconds/s" - , "macos" - , "iokit" - , 2022 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - cur_diskstat.duration_read_ns = diskstat.time_read + diskstat.latency_read; - cur_diskstat.duration_write_ns = diskstat.time_write + diskstat.latency_write; - prev_diskstat.duration_read_ns = rrddim_set(st, "reads", cur_diskstat.duration_read_ns); - prev_diskstat.duration_write_ns = rrddim_set(st, "writes", cur_diskstat.duration_write_ns); - rrdset_done(st); - - // -------------------------------------------------------------------- - // calculate differential charts - // only if this is not the first time we run - - if (likely(dt)) { - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("disk_await", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk_await" - , diskstat.name - , NULL - , diskstat.name - , "disk.await" - , "Average Completed I/O Operation Time" - , "ms per operation" - , "macos" - , "iokit" - , 2005 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ? - (cur_diskstat.duration_read_ns - prev_diskstat.duration_read_ns) / (diskstat.reads - prev_diskstat.operations_read) : 0); - rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ? - (cur_diskstat.duration_write_ns - prev_diskstat.duration_write_ns) / (diskstat.writes - prev_diskstat.operations_write) : 0); - rrdset_done(st); - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("disk_avgsz", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk_avgsz" - , diskstat.name - , NULL - , diskstat.name - , "disk.avgsz" - , "Average Completed I/O Operation Bandwidth" - , "kilobytes per operation" - , "macos" - , "iokit" - , 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); - - rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ? - (diskstat.bytes_read - prev_diskstat.bytes_read) / (diskstat.reads - prev_diskstat.operations_read) : 0); - rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ? - (diskstat.bytes_write - prev_diskstat.bytes_write) / (diskstat.writes - prev_diskstat.operations_write) : 0); - rrdset_done(st); - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("disk_svctm", diskstat.name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "disk_svctm" - , diskstat.name - , NULL - , diskstat.name - , "disk.svctm" - , "Average Service Time" - , "ms per operation" - , "macos" - , "iokit" - , 2007 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "svctm", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set(st, "svctm", ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) ? - (cur_diskstat.busy_time_ns - prev_diskstat.busy_time_ns) / ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) : 0); - rrdset_done(st); - } - } - - /* Release. */ - CFRelease(properties); - } - - /* Release. */ - IOObjectRelease(drive); - } - IOIteratorReset(drive_list); - - /* Release. */ - IOObjectRelease(drive_list); - } - - if (likely(do_io)) { - st = rrdset_find_bytype_localhost("system", "io"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "io" - , NULL - , "disk" - , NULL - , "Disk I/O" - , "kilobytes/s" - , "macos" - , "iokit" - , 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); - - rrddim_set(st, "in", total_disk_reads); - rrddim_set(st, "out", total_disk_writes); - rrdset_done(st); - } - - // Can be merged with FreeBSD plugin - // -------------------------------------------------------------------------- - - if (likely(do_space || do_inodes)) { - // there is no mount info in sysctl MIBs - if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) { - error("MACOS: getmntinfo() failed"); - do_space = 0; - error("DISABLED: disk_space.X"); - do_inodes = 0; - error("DISABLED: disk_inodes.X"); - } else { - 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) - continue; - - // -------------------------------------------------------------------------- - - if (likely(do_space)) { - 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_localhost( - "disk_space" - , mntbuf[i].f_mntonname - , NULL - , mntbuf[i].f_mntonname - , "disk.space" - , title - , "GB" - , "macos" - , "iokit" - , 2023 - , update_every - , RRDSET_TYPE_STACKED - ); - - 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, RRD_ALGORITHM_ABSOLUTE); - } else - rrdset_next(st); - - 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); - } - - // -------------------------------------------------------------------------- - - if (likely(do_inodes)) { - 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_localhost( - "disk_inodes" - , mntbuf[i].f_mntonname - , NULL - , mntbuf[i].f_mntonname - , "disk.inodes" - , title - , "Inodes" - , "macos" - , "iokit" - , 2024 - , update_every - , RRDSET_TYPE_STACKED - ); - - 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); - - 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); - } - } - } - } - - // Can be merged with FreeBSD plugin - // -------------------------------------------------------------------- - - if (likely(do_bandwidth)) { - if (unlikely(getifaddrs(&ifap))) { - error("MACOS: getifaddrs()"); - do_bandwidth = 0; - error("DISABLED: system.ipv4"); - } else { - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("net", ifa->ifa_name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "net" - , ifa->ifa_name - , NULL - , ifa->ifa_name - , "net.net" - , "Bandwidth" - , "kilobits/s" - , "macos" - , "iokit" - , 7000 - , update_every - , RRDSET_TYPE_AREA - ); - - rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "received", IFA_DATA(ibytes)); - rrddim_set(st, "sent", IFA_DATA(obytes)); - rrdset_done(st); - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("net_packets", ifa->ifa_name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "net_packets" - , ifa->ifa_name - , NULL - , ifa->ifa_name - , "net.packets" - , "Packets" - , "packets/s" - , "macos" - , "iokit" - , 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); - - 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_localhost("net_errors", ifa->ifa_name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "net_errors" - , ifa->ifa_name - , NULL - , ifa->ifa_name - , "net.errors" - , "Interface Errors" - , "errors/s" - , "macos" - , "iokit" - , 7002 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "outbound", NULL, -1, 1, RRD_ALGORITHM_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_localhost("net_drops", ifa->ifa_name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "net_drops" - , ifa->ifa_name - , NULL - , ifa->ifa_name - , "net.drops" - , "Interface Drops" - , "drops/s" - , "macos" - , "iokit" - , 7003 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "inbound", IFA_DATA(iqdrops)); - rrdset_done(st); - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("net_events", ifa->ifa_name); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "net_events" - , ifa->ifa_name - , NULL - , ifa->ifa_name - , "net.events" - , "Network Interface Events" - , "events/s" - , "macos" - , "iokit" - , 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); - - rrddim_set(st, "collisions", IFA_DATA(collisions)); - rrdset_done(st); - } - - freeifaddrs(ifap); - } - } - - - return 0; -} diff --git a/src/macos_mach_smi.c b/src/macos_mach_smi.c deleted file mode 100644 index 47d32a9f7..000000000 --- a/src/macos_mach_smi.c +++ /dev/null @@ -1,238 +0,0 @@ -#include "common.h" -#include - -int do_macos_mach_smi(int update_every, usec_t dt) { - (void)dt; - - static int do_cpu = -1, do_ram = - 1, do_swapio = -1, do_pgfaults = -1; - - if (unlikely(do_cpu == -1)) { - do_cpu = config_get_boolean("plugin:macos:mach_smi", "cpu utilization", 1); - do_ram = config_get_boolean("plugin:macos:mach_smi", "system ram", 1); - do_swapio = config_get_boolean("plugin:macos:mach_smi", "swap i/o", 1); - do_pgfaults = config_get_boolean("plugin:macos:mach_smi", "memory page faults", 1); - } - - RRDSET *st; - - kern_return_t kr; - mach_msg_type_number_t count; - host_t host; - vm_size_t system_pagesize; - - - // NEEDED BY: do_cpu - natural_t cp_time[CPU_STATE_MAX]; - - // NEEDED BY: do_ram, do_swapio, do_pgfaults -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) - vm_statistics64_data_t vm_statistics; -#else - vm_statistics_data_t vm_statistics; -#endif - - host = mach_host_self(); - kr = host_page_size(host, &system_pagesize); - if (unlikely(kr != KERN_SUCCESS)) - return -1; - - // -------------------------------------------------------------------- - - if (likely(do_cpu)) { - if (unlikely(HOST_CPU_LOAD_INFO_COUNT != 4)) { - error("MACOS: There are %d CPU states (4 was expected)", HOST_CPU_LOAD_INFO_COUNT); - do_cpu = 0; - error("DISABLED: system.cpu"); - } else { - count = HOST_CPU_LOAD_INFO_COUNT; - kr = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)cp_time, &count); - if (unlikely(kr != KERN_SUCCESS)) { - error("MACOS: host_statistics() failed: %s", mach_error_string(kr)); - do_cpu = 0; - error("DISABLED: system.cpu"); - } else { - - st = rrdset_find_bytype_localhost("system", "cpu"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "cpu" - , NULL - , "cpu" - , "system.cpu" - , "Total CPU utilization" - , "percentage" - , "macos" - , "mach_smi" - , 100 - , update_every - , RRDSET_TYPE_STACKED - ); - - 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); - - rrddim_set(st, "user", cp_time[CPU_STATE_USER]); - rrddim_set(st, "nice", cp_time[CPU_STATE_NICE]); - rrddim_set(st, "system", cp_time[CPU_STATE_SYSTEM]); - rrddim_set(st, "idle", cp_time[CPU_STATE_IDLE]); - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - if (likely(do_ram || do_swapio || do_pgfaults)) { -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) - count = sizeof(vm_statistics64_data_t); - kr = host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_statistics, &count); -#else - count = sizeof(vm_statistics_data_t); - kr = host_statistics(host, HOST_VM_INFO, (host_info_t)&vm_statistics, &count); -#endif - if (unlikely(kr != KERN_SUCCESS)) { - error("MACOS: host_statistics64() failed: %s", mach_error_string(kr)); - do_ram = 0; - error("DISABLED: system.ram"); - do_swapio = 0; - error("DISABLED: system.swapio"); - do_pgfaults = 0; - error("DISABLED: mem.pgfaults"); - } else { - if (likely(do_ram)) { - st = rrdset_find_localhost("system.ram"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "ram" - , NULL - , "ram" - , NULL - , "System RAM" - , "MB" - , "macos" - , "mach_smi" - , 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); -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - rrddim_add(st, "throttled", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "compressor", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); -#endif - 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); - - rrddim_set(st, "active", vm_statistics.active_count); - rrddim_set(st, "wired", vm_statistics.wire_count); -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - rrddim_set(st, "throttled", vm_statistics.throttled_count); - rrddim_set(st, "compressor", vm_statistics.compressor_page_count); -#endif - rrddim_set(st, "inactive", vm_statistics.inactive_count); - rrddim_set(st, "purgeable", vm_statistics.purgeable_count); - rrddim_set(st, "speculative", vm_statistics.speculative_count); - rrddim_set(st, "free", (vm_statistics.free_count - vm_statistics.speculative_count)); - rrdset_done(st); - } - -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - // -------------------------------------------------------------------- - - if (likely(do_swapio)) { - st = rrdset_find_localhost("system.swapio"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "swapio" - , NULL - , "swap" - , NULL - , "Swap I/O" - , "kilobytes/s" - , "macos" - , "mach_smi" - , 250 - , update_every - , RRDSET_TYPE_AREA - ); - - 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); - - rrddim_set(st, "in", vm_statistics.swapins); - rrddim_set(st, "out", vm_statistics.swapouts); - rrdset_done(st); - } -#endif - - // -------------------------------------------------------------------- - - if (likely(do_pgfaults)) { - st = rrdset_find_localhost("mem.pgfaults"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "mem" - , "pgfaults" - , NULL - , "system" - , NULL - , "Memory Page Faults" - , "page faults/s" - , "macos" - , "mach_smi" - , NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS - , 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); -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - rrddim_add(st, "compress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "decompress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); -#endif - 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); - - rrddim_set(st, "memory", vm_statistics.faults); - rrddim_set(st, "cow", vm_statistics.cow_faults); - rrddim_set(st, "pagein", vm_statistics.pageins); - rrddim_set(st, "pageout", vm_statistics.pageouts); -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - rrddim_set(st, "compress", vm_statistics.compressions); - rrddim_set(st, "decompress", vm_statistics.decompressions); -#endif - rrddim_set(st, "zero_fill", vm_statistics.zero_fill_count); - rrddim_set(st, "reactivate", vm_statistics.reactivations); - rrddim_set(st, "purge", vm_statistics.purges); - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - return 0; -} diff --git a/src/macos_sysctl.c b/src/macos_sysctl.c deleted file mode 100644 index cb6fa8af9..000000000 --- a/src/macos_sysctl.c +++ /dev/null @@ -1,1504 +0,0 @@ -#include "common.h" -#include -#include -// NEEDED BY: do_bandwidth -#include -// NEEDED BY do_tcp... -#include -#include -#include -// NEEDED BY do_udp..., do_ip... -#include -// NEEDED BY do_udp... -#include -#include -// NEEDED BY do_icmp... -#include -#include -#include -// NEEDED BY do_icmp6... -#include -// NEEDED BY do_uptime -#include - -// MacOS calculates load averages once every 5 seconds -#define MIN_LOADAVG_UPDATE_EVERY 5 - -int do_macos_sysctl(int update_every, usec_t 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, - 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_uptime = -1; - - - if (unlikely(do_loadavg == -1)) { - do_loadavg = config_get_boolean("plugin:macos:sysctl", "enable load average", 1); - do_swap = config_get_boolean("plugin:macos:sysctl", "system swap", 1); - do_bandwidth = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1); - 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_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); - do_icmpmsg = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP messages", 1); - do_ip_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 packets", 1); - 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_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); - } - - RRDSET *st; - - int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize? - int i, n; - int common_error = 0; - size_t size; - - // NEEDED BY: do_loadavg - static usec_t next_loadavg_dt = 0; - struct loadavg sysload; - - // NEEDED BY: do_swap - struct xsw_usage swap_usage; - - // NEEDED BY: do_bandwidth - int mib[6]; - static char *ifstatdata = NULL; - char *lim, *next; - struct if_msghdr *ifm; - struct iftot { - u_long ift_ibytes; - u_long ift_obytes; - } iftot = {0, 0}; - - // NEEDED BY: do_tcp... - struct tcpstat tcpstat; - uint64_t tcps_states[TCP_NSTATES]; - - // NEEDED BY: do_udp... - struct udpstat udpstat; - - // NEEDED BY: do_icmp... - struct icmpstat icmpstat; - struct icmp_total { - u_long msgs_in; - u_long msgs_out; - } icmp_total = {0, 0}; - - // NEEDED BY: do_ip... - struct ipstat ipstat; - - // NEEDED BY: do_ip6... - /* - * Dirty workaround for /usr/include/netinet6/ip6_var.h absence. - * Struct ip6stat was copied from bsd/netinet6/ip6_var.h from xnu sources. - * Do the same for previously missing scope6_var.h on OS X < 10.11. - */ -#define IP6S_SRCRULE_COUNT 16 - -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100) -#ifndef _NETINET6_SCOPE6_VAR_H_ -#define _NETINET6_SCOPE6_VAR_H_ -#include - -#define SCOPE6_ID_MAX 16 -#endif -#else -#include -#endif - - struct ip6stat { - u_quad_t ip6s_total; /* total packets received */ - u_quad_t ip6s_tooshort; /* packet too short */ - u_quad_t ip6s_toosmall; /* not enough data */ - u_quad_t ip6s_fragments; /* fragments received */ - u_quad_t ip6s_fragdropped; /* frags dropped(dups, out of space) */ - u_quad_t ip6s_fragtimeout; /* fragments timed out */ - u_quad_t ip6s_fragoverflow; /* fragments that exceeded limit */ - u_quad_t ip6s_forward; /* packets forwarded */ - u_quad_t ip6s_cantforward; /* packets rcvd for unreachable dest */ - u_quad_t ip6s_redirectsent; /* packets forwarded on same net */ - u_quad_t ip6s_delivered; /* datagrams delivered to upper level */ - u_quad_t ip6s_localout; /* total ip packets generated here */ - u_quad_t ip6s_odropped; /* lost packets due to nobufs, etc. */ - u_quad_t ip6s_reassembled; /* total packets reassembled ok */ - u_quad_t ip6s_atmfrag_rcvd; /* atomic fragments received */ - u_quad_t ip6s_fragmented; /* datagrams successfully fragmented */ - u_quad_t ip6s_ofragments; /* output fragments created */ - u_quad_t ip6s_cantfrag; /* don't fragment flag was set, etc. */ - u_quad_t ip6s_badoptions; /* error in option processing */ - u_quad_t ip6s_noroute; /* packets discarded due to no route */ - u_quad_t ip6s_badvers; /* ip6 version != 6 */ - u_quad_t ip6s_rawout; /* total raw ip packets generated */ - u_quad_t ip6s_badscope; /* scope error */ - u_quad_t ip6s_notmember; /* don't join this multicast group */ - u_quad_t ip6s_nxthist[256]; /* next header history */ - u_quad_t ip6s_m1; /* one mbuf */ - u_quad_t ip6s_m2m[32]; /* two or more mbuf */ - u_quad_t ip6s_mext1; /* one ext mbuf */ - u_quad_t ip6s_mext2m; /* two or more ext mbuf */ - u_quad_t ip6s_exthdrtoolong; /* ext hdr are not continuous */ - u_quad_t ip6s_nogif; /* no match gif found */ - u_quad_t ip6s_toomanyhdr; /* discarded due to too many headers */ - - /* - * statistics for improvement of the source address selection - * algorithm: - */ - /* number of times that address selection fails */ - u_quad_t ip6s_sources_none; - /* number of times that an address on the outgoing I/F is chosen */ - u_quad_t ip6s_sources_sameif[SCOPE6_ID_MAX]; - /* number of times that an address on a non-outgoing I/F is chosen */ - u_quad_t ip6s_sources_otherif[SCOPE6_ID_MAX]; - /* - * number of times that an address that has the same scope - * from the destination is chosen. - */ - u_quad_t ip6s_sources_samescope[SCOPE6_ID_MAX]; - /* - * number of times that an address that has a different scope - * from the destination is chosen. - */ - u_quad_t ip6s_sources_otherscope[SCOPE6_ID_MAX]; - /* number of times that a deprecated address is chosen */ - u_quad_t ip6s_sources_deprecated[SCOPE6_ID_MAX]; - - u_quad_t ip6s_forward_cachehit; - u_quad_t ip6s_forward_cachemiss; - - /* number of times that each rule of source selection is applied. */ - u_quad_t ip6s_sources_rule[IP6S_SRCRULE_COUNT]; - - /* number of times we ignored address on expensive secondary interfaces */ - u_quad_t ip6s_sources_skip_expensive_secondary_if; - - /* pkt dropped, no mbufs for control data */ - u_quad_t ip6s_pktdropcntrl; - - /* total packets trimmed/adjusted */ - u_quad_t ip6s_adj; - /* hwcksum info discarded during adjustment */ - u_quad_t ip6s_adj_hwcsum_clr; - - /* duplicate address detection collisions */ - u_quad_t ip6s_dad_collide; - - /* DAD NS looped back */ - u_quad_t ip6s_dad_loopcount; - } ip6stat; - - // 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_uptime - struct timespec boot_time, cur_time; - - // -------------------------------------------------------------------- - - if (next_loadavg_dt <= dt) { - if (likely(do_loadavg)) { - if (unlikely(GETSYSCTL_BY_NAME("vm.loadavg", sysload))) { - do_loadavg = 0; - error("DISABLED: system.load"); - } else { - - st = rrdset_find_bytype_localhost("system", "load"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "load" - , NULL - , "load" - , NULL - , "System Load Average" - , "load" - , "macos" - , "sysctl" - , 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); - - 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); - } - } - - next_loadavg_dt = st->update_every * USEC_PER_SEC; - } - else next_loadavg_dt -= dt; - - // -------------------------------------------------------------------- - - if (likely(do_swap)) { - if (unlikely(GETSYSCTL_BY_NAME("vm.swapusage", swap_usage))) { - do_swap = 0; - error("DISABLED: system.swap"); - } else { - st = rrdset_find_localhost("system.swap"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "swap" - , NULL - , "swap" - , NULL - , "System Swap" - , "MB" - , "macos" - , "sysctl" - , 201 - , update_every - , RRDSET_TYPE_STACKED - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rrddim_add(st, "free", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "used", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set(st, "free", swap_usage.xsu_avail); - rrddim_set(st, "used", swap_usage.xsu_used); - rrdset_done(st); - } - } - - // -------------------------------------------------------------------- - - if (likely(do_bandwidth)) { - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET; - mib[4] = NET_RT_IFLIST2; - mib[5] = 0; - if (unlikely(sysctl(mib, 6, NULL, &size, NULL, 0))) { - error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno)); - do_bandwidth = 0; - error("DISABLED: system.ipv4"); - } else { - ifstatdata = reallocz(ifstatdata, size); - if (unlikely(sysctl(mib, 6, ifstatdata, &size, NULL, 0) < 0)) { - error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno)); - do_bandwidth = 0; - error("DISABLED: system.ipv4"); - } else { - lim = ifstatdata + size; - iftot.ift_ibytes = iftot.ift_obytes = 0; - for (next = ifstatdata; next < lim; ) { - ifm = (struct if_msghdr *)next; - next += ifm->ifm_msglen; - - if (ifm->ifm_type == RTM_IFINFO2) { - struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm; - - iftot.ift_ibytes += if2m->ifm_data.ifi_ibytes; - iftot.ift_obytes += if2m->ifm_data.ifi_obytes; - } - } - st = rrdset_find_localhost("system.ipv4"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "ipv4" - , NULL - , "network" - , NULL - , "IPv4 Bandwidth" - , "kilobits/s" - , "macos" - , "sysctl" - , 500 - , update_every - , RRDSET_TYPE_AREA - ); - - rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "InOctets", iftot.ift_ibytes); - rrddim_set(st, "OutOctets", iftot.ift_obytes); - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - // 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_BY_NAME("net.inet.tcp.stats", tcpstat))){ - do_tcp_packets = 0; - error("DISABLED: ipv4.tcppackets"); - do_tcp_errors = 0; - error("DISABLED: ipv4.tcperrors"); - do_tcp_handshake = 0; - error("DISABLED: ipv4.tcphandshake"); - do_tcpext_connaborts = 0; - error("DISABLED: ipv4.tcpconnaborts"); - do_tcpext_ofo = 0; - error("DISABLED: ipv4.tcpofo"); - do_tcpext_syscookies = 0; - error("DISABLED: ipv4.tcpsyncookies"); - do_ecn = 0; - error("DISABLED: ipv4.ecnpkts"); - } else { - if (likely(do_tcp_packets)) { - st = rrdset_find_localhost("ipv4.tcppackets"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "tcppackets" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Packets" - , "packets/s" - , "macos" - , "sysctl" - , 2600 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_tcp_errors)) { - st = rrdset_find_localhost("ipv4.tcperrors"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "tcperrors" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Errors" - , "packets/s" - , "macos" - , "sysctl" - , 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); - - rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort); - rrddim_set(st, "InCsumErrors", tcpstat.tcps_rcvbadsum); - rrddim_set(st, "RetransSegs", tcpstat.tcps_sndrexmitpack); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_tcp_handshake)) { - st = rrdset_find_localhost("ipv4.tcphandshake"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "tcphandshake" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Handshake Issues" - , "events/s" - , "macos" - , "sysctl" - , 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); - - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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_localhost( - "ipv4" - , "tcpconnaborts" - , NULL - , "tcp" - , NULL - , "TCP Connection Aborts" - , "connections/s" - , "macos" - , "sysctl" - , 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); - } - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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_localhost( - "ipv4" - , "tcpofo" - , NULL - , "tcp" - , NULL - , "TCP Out-Of-Order Queue" - , "packets/s" - , "macos" - , "sysctl" - , 3050 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "TCPOFOQueue", tcpstat.tcps_rcvoopack); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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_localhost("ipv4.tcpsyncookies"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "tcpsyncookies" - , NULL - , "tcp" - , NULL - , "TCP SYN Cookies" - , "packets/s" - , "macos" - , "sysctl" - , 3100 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) - 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_localhost( - "ipv4" - , "ecnpkts" - , NULL - , "ecn" - , NULL - , "IPv4 ECN Statistics" - , "packets/s" - , "macos" - , "sysctl" - , 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); - } - else rrdset_next(st); - - rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_recv_ce); - rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_not_supported); - rrdset_done(st); - } -#endif - - } - } - - // -------------------------------------------------------------------- - - // see http://net-snmp.sourceforge.net/docs/mibs/udp.html - if (likely(do_udp_packets || do_udp_errors)) { - 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_localhost("ipv4.udppackets"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "udppackets" - , NULL - , "udp" - , NULL - , "IPv4 UDP Packets" - , "packets/s" - , "macos" - , "sysctl" - , 2601 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_udp_errors)) { - st = rrdset_find_localhost("ipv4.udperrors"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "udperrors" - , NULL - , "udp" - , NULL - , "IPv4 UDP Errors" - , "events/s" - , "macos" - , "sysctl" - , 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); -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); -#endif - } 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); -#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - rrddim_set(st, "InCsumErrors", udpstat.udps_badsum + udpstat.udps_nosum); - rrddim_set(st, "IgnoredMulti", udpstat.udps_filtermcast); -#else - rrddim_set(st, "InCsumErrors", udpstat.udps_badsum); -#endif - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - if (likely(do_icmp_packets || do_icmpmsg)) { - if (unlikely(GETSYSCTL_BY_NAME("net.inet.icmp.stats", icmpstat))) { - do_icmp_packets = 0; - error("DISABLED: ipv4.icmp"); - error("DISABLED: ipv4.icmp_errors"); - do_icmpmsg = 0; - error("DISABLED: ipv4.icmpmsg"); - } else { - for (i = 0; i <= ICMP_MAXTYPE; i++) { - icmp_total.msgs_in += icmpstat.icps_inhist[i]; - icmp_total.msgs_out += icmpstat.icps_outhist[i]; - } - icmp_total.msgs_in += icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort; - - // -------------------------------------------------------------------- - - if (likely(do_icmp_packets)) { - st = rrdset_find_localhost("ipv4.icmp"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "icmp" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Packets" - , "packets/s" - , "macos" - , "sysctl" - , 2602 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - 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); - - rrdset_done(st); - - // -------------------------------------------------------------------- - - st = rrdset_find_localhost("ipv4.icmp_errors"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "icmp_errors" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Errors" - , "packets/s" - , "macos" - , "sysctl" - , 2603 - , 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); - } 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); - - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_icmpmsg)) { - st = rrdset_find_localhost("ipv4.icmpmsg"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "icmpmsg" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Messages" - , "packets/s" - , "macos" - , "sysctl" - , 2604 - , update_every - , RRDSET_TYPE_LINE - ); - - 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); - - 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]); - - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - // 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_BY_NAME("net.inet.ip.stats", ipstat))) { - do_ip_packets = 0; - error("DISABLED: ipv4.packets"); - do_ip_fragsout = 0; - error("DISABLED: ipv4.fragsout"); - do_ip_fragsin = 0; - error("DISABLED: ipv4.fragsin"); - do_ip_errors = 0; - error("DISABLED: ipv4.errors"); - } else { - if (likely(do_ip_packets)) { - st = rrdset_find_localhost("ipv4.packets"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "packets" - , NULL - , "packets" - , NULL - , "IPv4 Packets" - , "packets/s" - , "macos" - , "sysctl" - , 3000 - , update_every - , RRDSET_TYPE_LINE - ); - - 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); - - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_ip_fragsout)) { - st = rrdset_find_localhost("ipv4.fragsout"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "fragsout" - , NULL - , "fragments" - , NULL - , "IPv4 Fragments Sent" - , "packets/s" - , "macos" - , "sysctl" - , 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); - - rrddim_set(st, "FragOKs", ipstat.ips_fragmented); - rrddim_set(st, "FragFails", ipstat.ips_cantfrag); - rrddim_set(st, "FragCreates", ipstat.ips_ofragments); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_ip_fragsin)) { - st = rrdset_find_localhost("ipv4.fragsin"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "fragsin" - , NULL - , "fragments" - , NULL - , "IPv4 Fragments Reassembly" - , "packets/s" - , "macos" - , "sysctl" - , 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); - - rrddim_set(st, "ReasmOKs", ipstat.ips_fragments); - rrddim_set(st, "ReasmFails", ipstat.ips_fragdropped); - rrddim_set(st, "ReasmReqds", ipstat.ips_reassembled); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (likely(do_ip_errors)) { - st = rrdset_find_localhost("ipv4.errors"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "errors" - , NULL - , "errors" - , NULL - , "IPv4 Errors" - , "packets/s" - , "macos" - , "sysctl" - , 3002 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - 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, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutNoRoutes", 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); - } 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); - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) { - if (unlikely(GETSYSCTL_BY_NAME("net.inet6.ip6.stats", ip6stat))) { - do_ip6_packets = 0; - error("DISABLED: ipv6.packets"); - do_ip6_fragsout = 0; - error("DISABLED: ipv6.fragsout"); - do_ip6_fragsin = 0; - error("DISABLED: ipv6.fragsin"); - do_ip6_errors = 0; - error("DISABLED: ipv6.errors"); - } else { - 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; - st = rrdset_find_localhost("ipv6.packets"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "packets" - , NULL - , "packets" - , NULL - , "IPv6 Packets" - , "packets/s" - , "macos" - , "sysctl" - , 3000 - , update_every - , RRDSET_TYPE_LINE - ); - - 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); - - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.fragsout"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "fragsout" - , NULL - , "fragments" - , NULL - , "IPv6 Fragments Sent" - , "packets/s" - , "macos" - , "sysctl" - , 3010 - , 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, "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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.fragsin"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "fragsin" - , NULL - , "fragments" - , NULL - , "IPv6 Fragments Reassembly" - , "packets/s" - , "macos" - , "sysctl" - , 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); - - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if (do_ip6_errors == CONFIG_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && ( - ip6stat.ip6s_toosmall || - ip6stat.ip6s_odropped || - ip6stat.ip6s_badoptions || - ip6stat.ip6s_badvers || - ip6stat.ip6s_exthdrtoolong || - ip6stat.ip6s_sources_none || - ip6stat.ip6s_tooshort || - ip6stat.ip6s_cantforward || - ip6stat.ip6s_noroute))) { - do_ip6_errors = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost("ipv6.errors"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "errors" - , NULL - , "errors" - , NULL - , "IPv6 Errors" - , "packets/s" - , "macos" - , "sysctl" - , 3002 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - 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, 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, 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); - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - 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_BY_NAME("net.inet6.icmp6.stats", icmp6stat))) { - do_icmp6 = 0; - error("DISABLED: ipv6.icmp"); - } else { - 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_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_localhost( - "ipv6" - , "icmp" - , NULL - , "icmp" - , NULL - , "IPv6 ICMP Messages" - , "messages/s" - , "macos" - , "sysctl" - , 10000 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - 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); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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_localhost( - "ipv6" - , "icmpredir" - , NULL - , "icmp" - , NULL - , "IPv6 ICMP Redirects" - , "redirects/s" - , "macos" - , "sysctl" - , 10050 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - 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]); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.icmperrors"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "icmperrors" - , NULL - , "icmp" - , NULL - , "IPv6 ICMP Errors" - , "errors/s" - , "macos" - , "sysctl" - , 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); - - 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]); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.icmpechos"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "icmpechos" - , NULL - , "icmp" - , NULL - , "IPv6 ICMP Echo" - , "messages/s" - , "macos" - , "sysctl" - , 10200 - , update_every - , RRDSET_TYPE_LINE - ); - - 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); - - 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]); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.icmprouter"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "icmprouter" - , NULL - , "icmp" - , NULL - , "IPv6 Router Messages" - , "messages/s" - , "macos" - , "sysctl" - , 10400 - , 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); - - 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]); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.icmpneighbor"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "icmpneighbor" - , NULL - , "icmp" - , NULL - , "IPv6 Neighbor Messages" - , "messages/s" - , "macos" - , "sysctl" - , 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); - - 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]); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - 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; - st = rrdset_find_localhost("ipv6.icmptypes"); - if (unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "icmptypes" - , NULL - , "icmp" - , NULL - , "IPv6 ICMP Types" - , "messages/s" - , "macos" - , "sysctl" - , 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); - - 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]); - rrdset_done(st); - } - } - } - - // -------------------------------------------------------------------- - - if (likely(do_uptime)) { - 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_localhost("system.uptime"); - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "uptime" - , NULL - , "uptime" - , NULL - , "System Uptime" - , "seconds" - , "macos" - , "sysctl" - , 1000 - , update_every - , RRDSET_TYPE_LINE - ); - rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set(st, "uptime", cur_time.tv_sec - boot_time.tv_sec); - rrdset_done(st); - } - } - - return 0; -} - -int getsysctl_by_name(const char *name, void *ptr, size_t len) -{ - size_t nlen = len; - - if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) { - error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno)); - return 1; - } - if (unlikely(nlen != len)) { - error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen); - return 1; - } - return 0; -} diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 798c7f0fc..000000000 --- a/src/main.c +++ /dev/null @@ -1,1071 +0,0 @@ -#include "common.h" - -extern void *cgroups_main(void *ptr); - -void netdata_cleanup_and_exit(int ret) { - // enabling this, is wrong - // because the threads will be cancelled while cleaning up - // netdata_exit = 1; - - error_log_limit_unlimited(); - info("EXIT: netdata prepares to exit with code %d...", ret); - - // cleanup/save the database and exit - info("EXIT: cleaning up the database..."); - rrdhost_cleanup_all(); - - if(!ret) { - // exit cleanly - - // stop everything - info("EXIT: stopping master threads..."); - cancel_main_threads(); - - // free the database - info("EXIT: freeing database memory..."); - rrdhost_free_all(); - } - - // unlink the pid - if(pidfile[0]) { - info("EXIT: removing netdata PID file '%s'...", pidfile); - if(unlink(pidfile) != 0) - error("EXIT: cannot unlink pidfile '%s'.", pidfile); - } - - info("EXIT: all done - netdata is now exiting - bye bye..."); - exit(ret); -} - -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 - {"PLUGIN[nfacct]", CONFIG_SECTION_PLUGINS, "nfacct", 1, NULL, NULL, nfacct_main}, -#endif - -#ifdef NETDATA_INTERNAL_CHECKS - // debugging plugin - {"PLUGIN[check]", CONFIG_SECTION_PLUGINS, "checks", 0, NULL, NULL, checks_main}, -#endif - -#if defined(__FreeBSD__) - // FreeBSD internal plugins - {"PLUGIN[freebsd]", CONFIG_SECTION_PLUGINS, "freebsd", 1, NULL, NULL, freebsd_main}, -#elif defined(__APPLE__) - // macOS internal plugins - {"PLUGIN[macos]", CONFIG_SECTION_PLUGINS, "macos", 1, NULL, NULL, macos_main}, -#else - // linux internal plugins - {"PLUGIN[proc]", CONFIG_SECTION_PLUGINS, "proc", 1, NULL, NULL, proc_main}, - {"PLUGIN[diskspace]", CONFIG_SECTION_PLUGINS, "diskspace", 1, NULL, NULL, proc_diskspace_main}, - {"PLUGIN[cgroup]", CONFIG_SECTION_PLUGINS, "cgroups", 1, NULL, NULL, cgroups_main}, - {"PLUGIN[tc]", CONFIG_SECTION_PLUGINS, "tc", 1, NULL, NULL, tc_main}, -#endif /* __FreeBSD__, __APPLE__*/ - - // common plugins for all systems - {"PLUGIN[idlejitter]", CONFIG_SECTION_PLUGINS, "idlejitter", 1, NULL, NULL, cpuidlejitter_main}, - {"BACKENDS", NULL, NULL, 1, NULL, NULL, backends_main}, - {"HEALTH", NULL, NULL, 1, NULL, NULL, health_main}, - {"PLUGINSD", NULL, NULL, 1, NULL, NULL, pluginsd_main}, - {"WEB_SERVER[multi]", NULL, NULL, 1, NULL, NULL, socket_listen_main_multi_threaded}, - {"WEB_SERVER[single]", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded}, - {"WEB_SERVER[static1]", NULL, NULL, 0, NULL, NULL, socket_listen_main_static_threaded}, - {"STREAM", NULL, NULL, 0, NULL, NULL, rrdpush_sender_thread}, - {"STATSD", NULL, NULL, 1, NULL, NULL, statsd_main}, - - {NULL, NULL, NULL, 0, NULL, NULL, NULL} -}; - -void web_server_threading_selection(void) { - 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 static_threaded = (web_server_mode == WEB_SERVER_MODE_STATIC_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 = multi_threaded; - - if (static_threads[i].start_routine == socket_listen_main_single_threaded) - static_threads[i].enabled = single_threaded; - - if (static_threads[i].start_routine == socket_listen_main_static_threaded) - static_threads[i].enabled = static_threaded; - } -} - -void web_server_config_options(void) { - web_client_timeout = (int) config_get_number(CONFIG_SECTION_WEB, "disconnect idle clients after seconds", web_client_timeout); - web_client_first_request_timeout = (int) config_get_number(CONFIG_SECTION_WEB, "timeout for first request", web_client_first_request_timeout); - - 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; - - web_allow_connections_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow connections from", "localhost *"), NULL, SIMPLE_PATTERN_EXACT); - web_allow_dashboard_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow dashboard from", "localhost *"), NULL, SIMPLE_PATTERN_EXACT); - web_allow_badges_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow badges from", "*"), NULL, SIMPLE_PATTERN_EXACT); - web_allow_registry_from = simple_pattern_create(config_get(CONFIG_SECTION_REGISTRY, "allow from", "*"), NULL, SIMPLE_PATTERN_EXACT); - web_allow_streaming_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow streaming from", "*"), NULL, SIMPLE_PATTERN_EXACT); - web_allow_netdataconf_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow netdata.conf from", "localhost fd* 10.* 192.168.* 172.16.* 172.17.* 172.18.* 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.* 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.* 172.31.*"), NULL, SIMPLE_PATTERN_EXACT); - -#ifdef NETDATA_WITH_ZLIB - web_enable_gzip = config_get_boolean(CONFIG_SECTION_WEB, "enable gzip compression", web_enable_gzip); - - 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")) - web_gzip_strategy = Z_FILTERED; - else if(!strcmp(s, "huffman only")) - web_gzip_strategy = Z_HUFFMAN_ONLY; - else if(!strcmp(s, "rle")) - web_gzip_strategy = Z_RLE; - else if(!strcmp(s, "fixed")) - web_gzip_strategy = Z_FIXED; - else { - error("Invalid compression strategy '%s'. Valid strategies are 'default', 'filtered', 'huffman only', 'rle' and 'fixed'. Proceeding with 'default'.", s); - web_gzip_strategy = Z_DEFAULT_STRATEGY; - } - - 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; - } - else if(web_gzip_level > 9) { - error("Invalid compression level %d. Valid levels are 1 (fastest) to 9 (best ratio). Proceeding with level 9 (best compression).", web_gzip_level); - web_gzip_level = 9; - } -#endif /* NETDATA_WITH_ZLIB */ -} - - -int killpid(pid_t pid, int sig) -{ - int ret = -1; - debug(D_EXIT, "Request to kill pid %d", pid); - - errno = 0; - if(kill(pid, 0) == -1) { - switch(errno) { - case ESRCH: - error("Request to kill pid %d, but it is not running.", pid); - break; - - case EPERM: - error("Request to kill pid %d, but I do not have enough permissions.", pid); - break; - - default: - error("Request to kill pid %d, but I received an error.", pid); - break; - } - } - else { - errno = 0; - ret = kill(pid, sig); - if(ret == -1) { - switch(errno) { - case ESRCH: - error("Cannot kill pid %d, but it is not running.", pid); - break; - - case EPERM: - error("Cannot kill pid %d, but I do not have enough permissions.", pid); - break; - - default: - error("Cannot kill pid %d, but I received an error.", pid); - break; - } - } - } - - return ret; -} - -void cancel_main_threads() { - error_log_limit_unlimited(); - - int i, found = 0, max = 5 * USEC_PER_SEC, step = 100000; - for (i = 0; static_threads[i].name != NULL ; i++) { - if(static_threads[i].enabled == NETDATA_MAIN_THREAD_RUNNING) { - info("EXIT: Stopping master thread: %s", static_threads[i].name); - netdata_thread_cancel(*static_threads[i].thread); - found++; - } - } - - while(found && max > 0) { - max -= step; - info("Waiting %d threads to finish...", found); - sleep_usec(step); - found = 0; - for (i = 0; static_threads[i].name != NULL ; i++) { - if (static_threads[i].enabled != NETDATA_MAIN_THREAD_EXITED) - found++; - } - } - - if(found) { - for (i = 0; static_threads[i].name != NULL ; i++) { - if (static_threads[i].enabled != NETDATA_MAIN_THREAD_EXITED) - error("Master thread %s takes too long to exit. Giving up...", static_threads[i].name); - } - } - else - info("All threads finished."); -} - -struct option_def option_definitions[] = { - // opt description arg name default value - { 'c', "Configuration file to load.", "filename", CONFIG_DIR "/" CONFIG_FILENAME}, - { 'D', "Do not fork. Run in the foreground.", NULL, "run in the background"}, - { '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"}, - { '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}, -}; - -int help(int exitcode) { - FILE *stream; - if(exitcode == 0) - stream = stdout; - else - stream = stderr; - - int num_opts = sizeof(option_definitions) / sizeof(struct option_def); - int i; - int max_len_arg = 0; - - // Compute maximum argument length - for( i = 0; i < num_opts; i++ ) { - if(option_definitions[i].arg_name) { - int len_arg = (int)strlen(option_definitions[i].arg_name); - if(len_arg > max_len_arg) max_len_arg = len_arg; - } - } - - if(max_len_arg > 30) max_len_arg = 30; - if(max_len_arg < 20) max_len_arg = 20; - - fprintf(stream, "%s", "\n" - " ^\n" - " |.-. .-. .-. .-. . netdata \n" - " | '-' '-' '-' '-' real-time performance monitoring, done right! \n" - " +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->\n" - "\n" - " Copyright (C) 2016-2017, Costa Tsaousis \n" - " Released under GNU General Public License v3 or later.\n" - " All rights reserved.\n" - "\n" - " Home Page : https://my-netdata.io\n" - " Source Code: https://github.com/firehol/netdata\n" - " Wiki / Docs: https://github.com/firehol/netdata/wiki\n" - " Support : https://github.com/firehol/netdata/issues\n" - " License : https://github.com/firehol/netdata/blob/master/LICENSE.md\n" - "\n" - " Twitter : https://twitter.com/linuxnetdata\n" - " Facebook : https://www.facebook.com/linuxnetdata/\n" - "\n" - " netdata is a https://firehol.org project.\n" - "\n" - "\n" - ); - - fprintf(stream, " SYNOPSIS: netdata [options]\n"); - fprintf(stream, "\n"); - fprintf(stream, " Options:\n\n"); - - // Output options description. - for( i = 0; i < num_opts; i++ ) { - fprintf(stream, " -%c %-*s %s", option_definitions[i].val, max_len_arg, option_definitions[i].arg_name ? option_definitions[i].arg_name : "", option_definitions[i].description); - if(option_definitions[i].default_value) { - fprintf(stream, "\n %c %-*s Default: %s\n", ' ', max_len_arg, "", option_definitions[i].default_value); - } else { - fprintf(stream, "\n"); - } - fprintf(stream, "\n"); - } - - fprintf(stream, "\n Advanced options:\n\n" - " -W stacksize=N Set the stacksize (in bytes).\n\n" - " -W debug_flags=N Set runtime tracing to debug.log.\n\n" - " -W unittest Run internal unittests and exit.\n\n" - " -W set section option value\n" - " set netdata.conf option from the command line.\n\n" - " -W simple-pattern pattern string\n" - " Check if string matches pattern and exit.\n\n" - ); - - fprintf(stream, "\n Signals netdata handles:\n\n" - " - HUP Close and reopen log files.\n" - " - USR1 Save internal DB to disk.\n" - " - USR2 Reload health configuration.\n" - "\n" - ); - - fflush(stream); - return exitcode; -} - -// TODO: Remove this function with the nix major release. -void remove_option(int opt_index, int *argc, char **argv) { - int i = opt_index; - // remove the options. - do { - *argc = *argc - 1; - for(i = opt_index; i < *argc; i++) { - argv[i] = argv[i+1]; - } - i = opt_index; - } while(argv[i][0] != '-' && opt_index >= *argc); -} - -static const char *verify_required_directory(const char *dir) { - if(chdir(dir) == -1) - fatal("Cannot cd to directory '%s'", dir); - - DIR *d = opendir(dir); - if(!d) - fatal("Cannot examine the contents of directory '%s'", dir); - closedir(d); - - return dir; -} - -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"); - - config_move(CONFIG_SECTION_BACKEND, "opentsdb host tags", - CONFIG_SECTION_BACKEND, "host tags"); -} - -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); - - // ------------------------------------------------------------------------ - // 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; - } - - // ------------------------------------------------------------------------ - // 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_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); - - { - char plugins_dirs[(FILENAME_MAX * 2) + 1]; - snprintfz(plugins_dirs, FILENAME_MAX * 2, "\"%s\" \"%s/custom-plugins.d\"", PLUGINS_DIR, CONFIG_DIR); - netdata_configured_plugins_dir_base = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory", plugins_dirs)); - quoted_strings_splitter(netdata_configured_plugins_dir_base, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace); - netdata_configured_plugins_dir = plugin_directories[0]; - } - - // ------------------------------------------------------------------------ - // 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(); -} - -static void get_system_timezone(void) { - // avoid flood calls to stat(/etc/localtime) - // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux - const char *tz = getenv("TZ"); - if(!tz || !*tz) - setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0); - - char buffer[FILENAME_MAX + 1] = ""; - const char *timezone = NULL; - ssize_t ret; - - // use the TZ variable - if(tz && *tz && *tz != ':') { - timezone = tz; - // info("TIMEZONE: using TZ variable '%s'", timezone); - } - - // use the contents of /etc/timezone - if(!timezone && !read_file("/etc/timezone", buffer, FILENAME_MAX)) { - timezone = buffer; - // info("TIMEZONE: using the contents of /etc/timezone: '%s'", timezone); - } - - // read the link /etc/localtime - if(!timezone) { - ret = readlink("/etc/localtime", buffer, FILENAME_MAX); - - if(ret > 0) { - buffer[ret] = '\0'; - - char *cmp = "/usr/share/zoneinfo/"; - size_t cmp_len = strlen(cmp); - - char *s = strstr(buffer, cmp); - if (s && s[cmp_len]) { - timezone = &s[cmp_len]; - // info("TIMEZONE: using the link of /etc/localtime: '%s'", timezone); - } - } - else - buffer[0] = '\0'; - } - - // find the timezone from strftime() - if(!timezone) { - time_t t; - struct tm *tmp, tmbuf; - - t = now_realtime_sec(); - tmp = localtime_r(&t, &tmbuf); - - if (tmp != NULL) { - if(strftime(buffer, FILENAME_MAX, "%Z", tmp) == 0) - buffer[0] = '\0'; - else { - buffer[FILENAME_MAX] = '\0'; - timezone = buffer; - // info("TIMEZONE: using strftime(): '%s'", timezone); - } - } - } - - if(timezone && *timezone) { - // make sure it does not have illegal characters - // info("TIMEZONE: fixing '%s'", timezone); - - size_t len = strlen(timezone); - char tmp[len + 1]; - char *d = tmp; - *d = '\0'; - - while(*timezone) { - if(isalnum(*timezone) || *timezone == '_' || *timezone == '/') - *d++ = *timezone++; - else - timezone++; - } - *d = '\0'; - strncpyz(buffer, tmp, len); - timezone = buffer; - // info("TIMEZONE: fixed as '%s'", timezone); - } - - if(!timezone || !*timezone) - timezone = "unknown"; - - netdata_configured_timezone = config_get(CONFIG_SECTION_GLOBAL, "timezone", timezone); -} - -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); - - get_system_timezone(); - - // 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 default_stacksize; - - // set the name for logging - program_name = "netdata"; - - // parse depercated options - // TODO: Remove this block with the next major release. - { - i = 1; - while(i < argc) { - if(strcmp(argv[i], "-pidfile") == 0 && (i+1) < argc) { - strncpyz(pidfile, argv[i+1], FILENAME_MAX); - fprintf(stderr, "%s: deprecated option -- %s -- please use -P instead.\n", argv[0], argv[i]); - remove_option(i, &argc, argv); - } - else if(strcmp(argv[i], "-nodaemon") == 0 || strcmp(argv[i], "-nd") == 0) { - dont_fork = 1; - fprintf(stderr, "%s: deprecated option -- %s -- please use -D instead.\n ", argv[0], argv[i]); - remove_option(i, &argc, argv); - } - else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) { - 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(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); - } - else i++; - } - } - - // parse options - { - int num_opts = sizeof(option_definitions) / sizeof(struct option_def); - char optstring[(num_opts * 2) + 1]; - - int string_i = 0; - for( i = 0; i < num_opts; i++ ) { - optstring[string_i] = option_definitions[i].val; - string_i++; - if(option_definitions[i].arg_name) { - optstring[string_i] = ':'; - string_i++; - } - } - // terminate optstring - optstring[string_i] ='\0'; - optstring[(num_opts *2)] ='\0'; - - int opt; - while( (opt = getopt(argc, argv, optstring)) != -1 ) { - switch(opt) { - case 'c': - if(config_load(optarg, 1) != 1) { - error("Cannot load configuration file %s.", optarg); - return 1; - } - else { - debug(D_OPTIONS, "Configuration loaded from %s.", optarg); - config_loaded = 1; - } - break; - case 'D': - dont_fork = 1; - break; - case 'h': - return help(0); - case 'i': - 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(CONFIG_SECTION_GLOBAL, "default port", optarg); - break; - case 's': - config_set(CONFIG_SECTION_GLOBAL, "host access prefix", optarg); - break; - case 't': - config_set(CONFIG_SECTION_GLOBAL, "update every", optarg); - break; - case 'u': - config_set(CONFIG_SECTION_GLOBAL, "run as user", optarg); - break; - case 'v': - 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) { - if(unit_test_buffer()) return 1; - if(unit_test_str2ld()) return 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()) return 1; - if(unit_test_storage()) return 1; - fprintf(stderr, "\n\nALL TESTS PASSED\n\n"); - return 0; - } - else if(strcmp(optarg, "simple-pattern") == 0) { - if(optind + 2 > argc) { - fprintf(stderr, "%s", "\nUSAGE: -W simple-pattern 'pattern' 'string'\n\n" - " Checks if 'pattern' matches the given 'string'.\n" - " - 'pattern' can be one or more space separated words.\n" - " - each 'word' can contain one or more asterisks.\n" - " - words starting with '!' give negative matches.\n" - " - words are processed left to right\n" - "\n" - "Examples:\n" - "\n" - " > match all veth interfaces, except veth0:\n" - "\n" - " -W simple-pattern '!veth0 veth*' 'veth12'\n" - "\n" - "\n" - " > match all *.ext files directly in /path/:\n" - " (this will not match *.ext files in a subdir of /path/)\n" - "\n" - " -W simple-pattern '!/path/*/*.ext /path/*.ext' '/path/test.ext'\n" - "\n" - ); - return 1; - } - - const char *heystack = argv[optind]; - const char *needle = argv[optind + 1]; - size_t len = strlen(needle) + 1; - char wildcarded[len]; - - SIMPLE_PATTERN *p = simple_pattern_create(heystack, NULL, SIMPLE_PATTERN_EXACT); - int ret = simple_pattern_matches_extract(p, needle, wildcarded, len); - simple_pattern_free(p); - - if(ret) { - fprintf(stdout, "RESULT: MATCHED - pattern '%s' matches '%s', wildcarded '%s'\n", heystack, needle, wildcarded); - return 0; - } - else { - fprintf(stdout, "RESULT: NOT MATCHED - pattern '%s' does not match '%s', wildcarded '%s'\n", heystack, needle, wildcarded); - return 1; - } - } - else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) { - optarg += strlen(stacksize_string); - 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(CONFIG_SECTION_GLOBAL, "debug flags", optarg); - debug_flags = strtoull(optarg, NULL, 0); - } - else if(strcmp(optarg, "set") == 0) { - if(optind + 3 > argc) { - fprintf(stderr, "%s", "\nUSAGE: -W set 'section' 'key' 'value'\n\n" - " Overwrites settings of netdata.conf.\n" - "\n" - " These options interact with: -c netdata.conf\n" - " If -c netdata.conf is given on the command line,\n" - " before -W set... the user may overwrite command\n" - " line parameters at netdata.conf\n" - " If -c netdata.conf is given after (or missing)\n" - " -W set... the user cannot overwrite the command line\n" - " parameters." - "\n" - ); - return 1; - } - const char *section = argv[optind]; - const char *key = argv[optind + 1]; - const char *value = argv[optind + 2]; - optind += 3; - - // set this one as the default - // only if it is not already set in the config file - // so the caller can use -c netdata.conf before or - // after this parameter to prevent or allow overwriting - // variables at netdata.conf - config_set_default(section, key, value); - - // fprintf(stderr, "SET section '%s', key '%s', value '%s'\n", section, key, value); - } - else if(strcmp(optarg, "get") == 0) { - if(optind + 3 > argc) { - fprintf(stderr, "%s", "\nUSAGE: -W get 'section' 'key' 'value'\n\n" - " Prints settings of netdata.conf.\n" - "\n" - " These options interact with: -c netdata.conf\n" - " -c netdata.conf has to be given before -W get.\n" - "\n" - ); - return 1; - } - - if(!config_loaded) { - fprintf(stderr, "warning: no configuration file has been loaded. Use -c CONFIG_FILE, before -W get. Using default config.\n"); - config_load(NULL, 0); - } - - backwards_compatible_config(); - get_netdata_configured_variables(); - - const char *section = argv[optind]; - const char *key = argv[optind + 1]; - const char *def = argv[optind + 2]; - const char *value = config_get(section, key, def); - printf("%s\n", value); - return 0; - } - else { - fprintf(stderr, "Unknown -W parameter '%s'\n", optarg); - return help(1); - } - } - break; - - default: /* ? */ - fprintf(stderr, "Unknown parameter '%c'\n", opt); - return help(1); - } - } - } - -#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) - config_load(NULL, 0); - - // ------------------------------------------------------------------------ - // initialize netdata - { - 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) - i = (int)config_get_number(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for netdata", 1); - if(i > 0) - mallopt(M_ARENA_MAX, 1); -#endif - - // prepare configuration environment variables for the plugins - - 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(netdata_configured_config_dir) == -1) - fatal("Cannot cd to '%s'", netdata_configured_config_dir); - } - - char *user = NULL; - - { - // -------------------------------------------------------------------- - // 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%" 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..."); - -#ifdef HAVE_SYS_PRCTL_H - prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); -#endif - } - - - // -------------------------------------------------------------------- - // get log filenames and settings - - log_init(); - error_log_limit_unlimited(); - - - // -------------------------------------------------------------------- - // load stream.conf - { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/stream.conf", netdata_configured_config_dir); - appconfig_load(&stream_config, filename, 0); - } - - - // -------------------------------------------------------------------- - // setup process signals - - // block signals while initializing threads. - // this causes the threads to block signals. - signals_block(); - - // setup the signals we want to use - signals_init(); - - // setup threads configs - default_stacksize = netdata_threads_init(); - - - // -------------------------------------------------------------------- - // 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(); - } - - - // -------------------------------------------------------------------- - // get the user we should run - - // IMPORTANT: this is required before web_files_uid() - 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:""); - } - - // -------------------------------------------------------------------- - // create the listening sockets - - web_client_api_v1_init(); - web_server_threading_selection(); - - if(web_server_mode != WEB_SERVER_MODE_NONE) - api_listen_sockets_setup(); - } - - // initialize the log files - open_all_log_files(); - -#ifdef NETDATA_INTERNAL_CHECKS - 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..."); -#ifdef HAVE_SYS_PRCTL_H - prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); -#endif - } -#endif /* NETDATA_INTERNAL_CHECKS */ - - // get the max file limit - if(getrlimit(RLIMIT_NOFILE, &rlimit_nofile) != 0) - error("getrlimit(RLIMIT_NOFILE) failed"); - else - info("resources control: allowed file descriptors: soft = %zu, max = %zu", rlimit_nofile.rlim_cur, rlimit_nofile.rlim_max); - - // 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()); - - // IMPORTANT: these have to run once, while single threaded - // but after we have switched user - web_files_uid(); - web_files_gid(); - - netdata_threads_init_after_fork((size_t)config_get_number(CONFIG_SECTION_GLOBAL, "pthread stack size", (long)default_stacksize)); - - // ------------------------------------------------------------------------ - // initialize rrd, registry, health, rrdpush, etc. - - rrd_init(netdata_configured_hostname); - - - // ------------------------------------------------------------------------ - // enable log flood protection - - error_log_limit_reset(); - - - // ------------------------------------------------------------------------ - // spawn the threads - - web_server_config_options(); - - for (i = 0; static_threads[i].name != NULL ; i++) { - struct netdata_static_thread *st = &static_threads[i]; - - if(st->enabled) { - st->thread = mallocz(sizeof(netdata_thread_t)); - debug(D_SYSTEM, "Starting thread %s.", st->name); - netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st); - } - else debug(D_SYSTEM, "Not starting thread %s.", st->name); - } - - info("netdata initialization completed. Enjoy real-time performance monitoring!"); - - - // ------------------------------------------------------------------------ - // unblock signals - - signals_unblock(); - - // ------------------------------------------------------------------------ - // Handle signals - - signals_handle(); - - // should never reach this point - // but we need it for rpmlint #2752 - return 1; -} diff --git a/src/main.h b/src/main.h deleted file mode 100644 index d29bf74e7..000000000 --- a/src/main.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef NETDATA_MAIN_H -#define NETDATA_MAIN_H 1 - -#define NETDATA_MAIN_THREAD_RUNNING CONFIG_BOOLEAN_YES -#define NETDATA_MAIN_THREAD_EXITING (CONFIG_BOOLEAN_YES + 1) -#define NETDATA_MAIN_THREAD_EXITED CONFIG_BOOLEAN_NO - -/** - * This struct contains information about command line options. - */ -struct option_def { - /** The option character */ - const char val; - /** The name of the long option. */ - const char *description; - /** Short descripton what the option does */ - /** Name of the argument displayed in SYNOPSIS */ - const char *arg_name; - /** Default value if not set */ - const char *default_value; -}; - -struct netdata_static_thread { - char *name; - - char *config_section; - char *config_name; - - volatile sig_atomic_t enabled; - - netdata_thread_t *thread; - - void (*init_routine) (void); - void *(*start_routine) (void *); -}; - -extern void cancel_main_threads(void); -extern int killpid(pid_t pid, int signal); -extern void netdata_cleanup_and_exit(int ret) NORETURN; - -#endif /* NETDATA_MAIN_H */ diff --git a/src/plugin_checks.c b/src/plugin_checks.c deleted file mode 100644 index b99b97d40..000000000 --- a/src/plugin_checks.c +++ /dev/null @@ -1,127 +0,0 @@ -#include "common.h" - -#ifdef NETDATA_INTERNAL_CHECKS - -static void checks_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *checks_main(void *ptr) { - netdata_thread_cleanup_push(checks_main_cleanup, ptr); - - 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_localhost( - "netdata" - , "check1" - , NULL - , "netdata" - , NULL - , "Caller gives microseconds" - , "a million !" - , "netdata" - , "checks" - , 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_localhost( - "netdata" - , "check2" - , NULL - , "netdata" - , NULL - , "Netdata calcs microseconds" - , "a million !" - , "netdata" - , "checks" - , 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_localhost( - "netdata" - , "checkdt" - , NULL - , "netdata" - , NULL - , "Clock difference" - , "microseconds diff" - , "netdata" - , "checks" - , 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(!netdata_exit) { - usleep(susec); - - // find the time to sleep in order to wait exactly update_every seconds - now_realtime_timeval(&now); - loop_usec = dt_usec(&now, &last); - 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 < (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 - - last.tv_sec = now.tv_sec; - last.tv_usec = now.tv_usec; - total_susec += loop_usec; - - // -------------------------------------------------------------------- - // check chart 1 - - if(check1->counter_done) rrdset_next_usec(check1, loop_usec); - rrddim_set(check1, "absolute", 1000000); - rrddim_set(check1, "incremental", total_susec); - rrdset_done(check1); - - // -------------------------------------------------------------------- - // check chart 2 - - if(check2->counter_done) rrdset_next(check2); - rrddim_set(check2, "absolute", 1000000); - rrddim_set(check2, "incremental", total_susec); - rrdset_done(check2); - - // -------------------------------------------------------------------- - // check chart 3 - - 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)); - rrddim_set(check3, "netdata", (long long) dt_usec(&loop, &check2->last_collected_time)); - if(apps_cpu) rrddim_set(check3, "apps.plugin", (long long) dt_usec(&loop, &apps_cpu->last_collected_time)); - rrdset_done(check3); - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - -#endif // NETDATA_INTERNAL_CHECKS diff --git a/src/plugin_checks.h b/src/plugin_checks.h deleted file mode 100644 index 05a40bea0..000000000 --- a/src/plugin_checks.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef NETDATA_PLUGIN_CHECKS_H -#define NETDATA_PLUGIN_CHECKS_H 1 - -#ifdef NETDATA_INTERNAL_CHECKS -void *checks_main(void *ptr); -#endif // NETDATA_INTERNAL_CHECKS - -#endif /* NETDATA_PLUGIN_PROC_H */ diff --git a/src/plugin_freebsd.c b/src/plugin_freebsd.c deleted file mode 100644 index a0d3dc2ea..000000000 --- a/src/plugin_freebsd.c +++ /dev/null @@ -1,173 +0,0 @@ -#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 }, - { .name = "dev.cpu.temperature", .dim = "cpu_temperature", .enabled = 1, .func = do_dev_cpu_temperature }, - { .name = "dev.cpu.0.freq", .dim = "cpu_frequency", .enabled = 1, .func = do_dev_cpu_0_freq }, - - // 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 }, - - // ZFS metrics - { .name = "kstat.zfs.misc.arcstats", .dim = "arcstats", .enabled = 1, .func = do_kstat_zfs_misc_arcstats }, - { .name = "kstat.zfs.misc.zio_trim", .dim = "trim", .enabled = 1, .func = do_kstat_zfs_misc_zio_trim }, - - // ipfw metrics - { .name = "ipfw", .dim = "ipfw", .enabled = 1, .func = do_ipfw }, - - // the terminator of this array - { .name = NULL, .dim = NULL, .enabled = 0, .func = NULL } -}; - -static void freebsd_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *freebsd_main(void *ptr) { - netdata_thread_cleanup_push(freebsd_main_cleanup, ptr); - - int vdo_cpu_netdata = config_get_boolean("plugin:freebsd", "netdata server resources", 1); - - // initialize FreeBSD plugin - if (freebsd_plugin_init()) - netdata_cleanup_and_exit(1); - - // check the enabled status for each module - int i; - for(i = 0 ; freebsd_modules[i].name ;i++) { - struct freebsd_module *pm = &freebsd_modules[i]; - - pm->enabled = config_get_boolean("plugin:freebsd", pm->name, pm->enabled); - pm->duration = 0ULL; - pm->rd = NULL; - } - - usec_t step = localhost->rrd_update_every * USEC_PER_SEC; - heartbeat_t hb; - heartbeat_init(&hb); - - while(!netdata_exit) { - usec_t hb_dt = heartbeat_next(&hb, step); - usec_t duration = 0ULL; - - if(unlikely(netdata_exit)) break; - - // BEGIN -- the job to be done - - 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; - } - - // END -- the job is done - - // -------------------------------------------------------------------- - - 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" - , "netdata" - , "stats" - , 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(); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/plugin_freebsd.h b/src/plugin_freebsd.h deleted file mode 100644 index 0a6f40c15..000000000 --- a/src/plugin_freebsd.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef NETDATA_PLUGIN_FREEBSD_H -#define NETDATA_PLUGIN_FREEBSD_H 1 - -#include - -#define KILO_FACTOR 1024 -#define MEGA_FACTOR 1048576 // 1024 * 1024 -#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024 - -#define MAX_INT_DIGITS 10 // maximum number of digits for int - -void *freebsd_main(void *ptr); - -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_dev_cpu_temperature(int update_every, usec_t dt); -extern int do_dev_cpu_0_freq(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); -extern int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt); -extern int do_kstat_zfs_misc_zio_trim(int update_every, usec_t dt); -extern int do_ipfw(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; - - 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 deleted file mode 100644 index 77bd95d55..000000000 --- a/src/plugin_idlejitter.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "common.h" - -#define CPU_IDLEJITTER_SLEEP_TIME_MS 20 - -static void cpuidlejitter_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *cpuidlejitter_main(void *ptr) { - netdata_thread_cleanup_push(cpuidlejitter_main_cleanup, ptr); - - usec_t sleep_ut = config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS) * USEC_PER_MS; - if(sleep_ut <= 0) { - config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS); - sleep_ut = CPU_IDLEJITTER_SLEEP_TIME_MS * USEC_PER_MS; - } - - RRDSET *st = rrdset_create_localhost( - "system" - , "idlejitter" - , NULL - , "idlejitter" - , NULL - , "CPU Idle Jitter" - , "microseconds lost/s" - , "idlejitter" - , NULL - , 800 - , localhost->rrd_update_every - , RRDSET_TYPE_AREA - ); - RRDDIM *rd_min = rrddim_add(st, "min", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_max = rrddim_add(st, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_avg = rrddim_add(st, "average", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - - usec_t update_every_ut = localhost->rrd_update_every * USEC_PER_SEC; - struct timeval before, after; - unsigned long long counter; - - for(counter = 0; 1 ;counter++) { - int iterations = 0; - usec_t error_total = 0, - error_min = 0, - error_max = 0, - elapsed = 0; - - if(netdata_exit) break; - - while(elapsed < update_every_ut) { - now_monotonic_timeval(&before); - sleep_usec(sleep_ut); - now_monotonic_timeval(&after); - - usec_t dt = dt_usec(&after, &before); - elapsed += dt; - - usec_t error = dt - sleep_ut; - error_total += error; - - if(unlikely(!iterations)) - error_min = error; - else if(error < error_min) - error_min = error; - - if(error > error_max) - error_max = error; - - iterations++; - } - - if(netdata_exit) break; - - if(iterations) { - if (likely(counter)) rrdset_next(st); - rrddim_set_by_pointer(st, rd_min, error_min); - rrddim_set_by_pointer(st, rd_max, error_max); - rrddim_set_by_pointer(st, rd_avg, error_total / iterations); - rrdset_done(st); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - diff --git a/src/plugin_idlejitter.h b/src/plugin_idlejitter.h deleted file mode 100644 index dc82f052f..000000000 --- a/src/plugin_idlejitter.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef NETDATA_PLUGIN_IDLEJITTER_H -#define NETDATA_PLUGIN_IDLEJITTER_H 1 - -extern void *cpuidlejitter_main(void *ptr); - -#endif /* NETDATA_PLUGIN_IDLEJITTER_H */ diff --git a/src/plugin_macos.c b/src/plugin_macos.c deleted file mode 100644 index 6ac3d25d1..000000000 --- a/src/plugin_macos.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "common.h" - -static void macos_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *macos_main(void *ptr) { - netdata_thread_cleanup_push(macos_main_cleanup, ptr); - - // 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); - int vdo_macos_mach_smi = !config_get_boolean("plugin:macos", "mach system management interface", 1); - int vdo_macos_iokit = !config_get_boolean("plugin:macos", "iokit", 1); - - // keep track of the time each module was called - unsigned long long sutime_macos_sysctl = 0ULL; - unsigned long long sutime_macos_mach_smi = 0ULL; - unsigned long long sutime_macos_iokit = 0ULL; - - usec_t step = localhost->rrd_update_every * USEC_PER_SEC; - heartbeat_t hb; - heartbeat_init(&hb); - - while(!netdata_exit) { - usec_t hb_dt = heartbeat_next(&hb, step); - - if(unlikely(netdata_exit)) break; - - // BEGIN -- the job to be done - - if(!vdo_macos_sysctl) { - debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_sysctl()."); - 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()."); - 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()."); - vdo_macos_iokit = do_macos_iokit(localhost->rrd_update_every, hb_dt); - } - if(unlikely(netdata_exit)) break; - - // END -- the job is done - - // -------------------------------------------------------------------- - - if(!vdo_cpu_netdata) { - global_statistics_charts(); - registry_statistics(); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/plugin_macos.h b/src/plugin_macos.h deleted file mode 100644 index 6ccf3e861..000000000 --- a/src/plugin_macos.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef NETDATA_PLUGIN_MACOS_H -#define NETDATA_PLUGIN_MACOS_H 1 - -void *macos_main(void *ptr); - -#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var)) - -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); -extern int do_macos_iokit(int update_every, usec_t dt); - -#endif /* NETDATA_PLUGIN_MACOS_H */ diff --git a/src/plugin_nfacct.c b/src/plugin_nfacct.c deleted file mode 100644 index 02815ef04..000000000 --- a/src/plugin_nfacct.c +++ /dev/null @@ -1,819 +0,0 @@ -#include "common.h" - -#ifdef INTERNAL_PLUGIN_NFACCT - -#ifdef HAVE_LIBMNL -#include - -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 - -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 = {} -}; - - -static int nfstat_init(int update_every) { - nfstat_root.update_every = update_every; - - nfstat_root.buf_size = mnl_buffer_size(); - nfstat_root.buf = mallocz(nfstat_root.buf_size); - - nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER); - if(!nfstat_root.mnl) { - error("NFSTAT: mnl_socket_open() failed"); - return 1; - } - - nfstat_root.seq = (unsigned int)now_realtime_sec() - 1; - - 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; -} - -static void nfstat_cleanup() { - if(nfstat_root.mnl) { - mnl_socket_close(nfstat_root.mnl); - nfstat_root.mnl = NULL; - } - - 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; - } - - 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"); - - return MNL_CB_OK; -} - -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; - - // 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); - - // 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; - } - - // 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; - } - - return 0; -} - -static int nfexp_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_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; - } - - 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])); - } - } - - return MNL_CB_OK; -} - -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; - - // 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; - } - - // 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; - } - - // 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; -} - -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" - , "nfacct" - , NULL - , 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); - - 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" - , "nfacct" - , NULL - , 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); - - 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]); - - 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" - , "nfacct" - , NULL - , 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]); - - 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" - , "nfacct" - , NULL - , 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]); - - rrdset_done(st_errors); - } - - // ---------------------------------------------------------------- - - { - 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" - , "nfacct" - , NULL - , 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 - - -// ---------------------------------------------------------------------------- -// DO_NFACCT - collect netfilter accounting statistics via netlink - -#ifdef HAVE_LIBNETFILTER_ACCT -#define DO_NFACCT 1 - -#include - -struct nfacct_data { - char *name; - uint32_t hash; - - uint64_t pkts; - uint64_t bytes; - - RRDDIM *rd_bytes; - RRDDIM *rd_packets; - - int updated; - - struct nfacct_data *next; -}; - -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 -}; - -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; - } - - d = callocz(1, sizeof(struct nfacct_data)); - d->name = strdupz(name); - d->hash = hash; - - 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" - , "nfacct" - , NULL - , 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" - , "nfacct" - , NULL - , 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 - -// ---------------------------------------------------------------------------- - -static void nfacct_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - info("cleaning up..."); - -#ifdef DO_NFACCT - nfacct_cleanup(); -#endif - -#ifdef DO_NFSTAT - nfstat_cleanup(); -#endif - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *nfacct_main(void *ptr) { - netdata_thread_cleanup_push(nfacct_main_cleanup, ptr); - - 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; - -#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 - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - -#endif // INTERNAL_PLUGIN_NFACCT diff --git a/src/plugin_nfacct.h b/src/plugin_nfacct.h deleted file mode 100644 index 88a3a9230..000000000 --- a/src/plugin_nfacct.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef NETDATA_NFACCT_H -#define NETDATA_NFACCT_H 1 - -extern void *nfacct_main(void *ptr); - -#endif /* NETDATA_NFACCT_H */ - diff --git a/src/plugin_proc.c b/src/plugin_proc.c deleted file mode 100644 index e0afb0d6d..000000000 --- a/src/plugin_proc.c +++ /dev/null @@ -1,201 +0,0 @@ -#include "common.h" - -static struct proc_module { - const char *name; - const char *dim; - - int enabled; - - int (*func)(int update_every, usec_t dt); - usec_t duration; - - RRDDIM *rd; - -} proc_modules[] = { - - // system metrics - { .name = "/proc/stat", .dim = "stat", .func = do_proc_stat }, - { .name = "/proc/uptime", .dim = "uptime", .func = do_proc_uptime }, - { .name = "/proc/loadavg", .dim = "loadavg", .func = do_proc_loadavg }, - { .name = "/proc/sys/kernel/random/entropy_avail", .dim = "entropy", .func = do_proc_sys_kernel_random_entropy_avail }, - - // CPU metrics - { .name = "/proc/interrupts", .dim = "interrupts", .func = do_proc_interrupts }, - { .name = "/proc/softirqs", .dim = "softirqs", .func = do_proc_softirqs }, - - // memory metrics - { .name = "/proc/vmstat", .dim = "vmstat", .func = do_proc_vmstat }, - { .name = "/proc/meminfo", .dim = "meminfo", .func = do_proc_meminfo }, - { .name = "/sys/kernel/mm/ksm", .dim = "ksm", .func = do_sys_kernel_mm_ksm }, - { .name = "/sys/devices/system/edac/mc", .dim = "ecc", .func = do_proc_sys_devices_system_edac_mc }, - { .name = "/sys/devices/system/node", .dim = "numa", .func = do_proc_sys_devices_system_node }, - - // network metrics - { .name = "/proc/net/dev", .dim = "netdev", .func = do_proc_net_dev }, - { .name = "/proc/net/sockstat", .dim = "sockstat", .func = do_proc_net_sockstat }, - { .name = "/proc/net/sockstat6", .dim = "sockstat6", .func = do_proc_net_sockstat6 }, - { .name = "/proc/net/netstat", .dim = "netstat", .func = do_proc_net_netstat }, // this has to be before /proc/net/snmp, because there is a shared metric - { .name = "/proc/net/snmp", .dim = "snmp", .func = do_proc_net_snmp }, - { .name = "/proc/net/snmp6", .dim = "snmp6", .func = do_proc_net_snmp6 }, - { .name = "/proc/net/softnet_stat", .dim = "softnet", .func = do_proc_net_softnet_stat }, - { .name = "/proc/net/ip_vs/stats", .dim = "ipvs", .func = do_proc_net_ip_vs_stats }, - - // firewall metrics - { .name = "/proc/net/stat/conntrack", .dim = "conntrack", .func = do_proc_net_stat_conntrack }, - { .name = "/proc/net/stat/synproxy", .dim = "synproxy", .func = do_proc_net_stat_synproxy }, - - // disk metrics - { .name = "/proc/diskstats", .dim = "diskstats", .func = do_proc_diskstats }, - - // NFS metrics - { .name = "/proc/net/rpc/nfsd", .dim = "nfsd", .func = do_proc_net_rpc_nfsd }, - { .name = "/proc/net/rpc/nfs", .dim = "nfs", .func = do_proc_net_rpc_nfs }, - - // ZFS metrics - { .name = "/proc/spl/kstat/zfs/arcstats", .dim = "zfs_arcstats", .func = do_proc_spl_kstat_zfs_arcstats }, - - // BTRFS metrics - { .name = "/sys/fs/btrfs", .dim = "btrfs", .func = do_sys_fs_btrfs }, - - // IPC metrics - { .name = "ipc", .dim = "ipc", .func = do_ipc }, - - // the terminator of this array - { .name = NULL, .dim = NULL, .func = NULL } -}; - -static void proc_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *proc_main(void *ptr) { - netdata_thread_cleanup_push(proc_main_cleanup, ptr); - - int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1); - - // check the enabled status for each module - int i; - for(i = 0 ; proc_modules[i].name ;i++) { - struct proc_module *pm = &proc_modules[i]; - - pm->enabled = config_get_boolean("plugin:proc", pm->name, 1); - pm->duration = 0ULL; - pm->rd = NULL; - } - - usec_t step = localhost->rrd_update_every * USEC_PER_SEC; - heartbeat_t hb; - heartbeat_init(&hb); - - while(!netdata_exit) { - usec_t hb_dt = heartbeat_next(&hb, step); - usec_t duration = 0ULL; - - if(unlikely(netdata_exit)) break; - - // BEGIN -- the job to be done - - for(i = 0 ; proc_modules[i].name ;i++) { - struct proc_module *pm = &proc_modules[i]; - if(unlikely(!pm->enabled)) continue; - - debug(D_PROCNETDEV_LOOP, "PROC 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; - } - - // END -- the job is done - - // -------------------------------------------------------------------- - - if(vdo_cpu_netdata) { - static RRDSET *st = NULL; - - if(unlikely(!st)) { - st = rrdset_find_bytype_localhost("netdata", "plugin_proc_modules"); - - if(!st) { - st = rrdset_create_localhost( - "netdata" - , "plugin_proc_modules" - , NULL - , "proc" - , NULL - , "NetData Proc Plugin Modules Durations" - , "milliseconds/run" - , "netdata" - , "stats" - , 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, RRD_ALGORITHM_ABSOLUTE); - } - } - } - else rrdset_next(st); - - for(i = 0 ; proc_modules[i].name ;i++) { - struct proc_module *pm = &proc_modules[i]; - if(unlikely(!pm->enabled)) continue; - - rrddim_set_by_pointer(st, pm->rd, pm->duration); - } - rrdset_done(st); - - global_statistics_charts(); - registry_statistics(); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - -int get_numa_node_count(void) -{ - static int numa_node_count = -1; - - if (numa_node_count != -1) - return numa_node_count; - - numa_node_count = 0; - - char name[FILENAME_MAX + 1]; - 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); - if(dir) { - struct dirent *de = NULL; - while((de = readdir(dir))) { - if(de->d_type != DT_DIR) - continue; - - if(strncmp(de->d_name, "node", 4) != 0) - continue; - - if(!isdigit(de->d_name[4])) - continue; - - numa_node_count++; - } - closedir(dir); - } - - return numa_node_count; -} diff --git a/src/plugin_proc.h b/src/plugin_proc.h deleted file mode 100644 index a7f9b4e38..000000000 --- a/src/plugin_proc.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef NETDATA_PLUGIN_PROC_H -#define NETDATA_PLUGIN_PROC_H 1 - -void *proc_main(void *ptr); - -extern int do_proc_net_dev(int update_every, usec_t dt); -extern int do_proc_diskstats(int update_every, usec_t dt); -extern int do_proc_net_snmp(int update_every, usec_t dt); -extern int do_proc_net_snmp6(int update_every, usec_t dt); -extern int do_proc_net_netstat(int update_every, usec_t dt); -extern int do_proc_net_stat_conntrack(int update_every, usec_t dt); -extern int do_proc_net_ip_vs_stats(int update_every, usec_t dt); -extern int do_proc_stat(int update_every, usec_t dt); -extern int do_proc_meminfo(int update_every, usec_t dt); -extern int do_proc_vmstat(int update_every, usec_t dt); -extern int do_proc_net_rpc_nfs(int update_every, usec_t dt); -extern int do_proc_net_rpc_nfsd(int update_every, usec_t dt); -extern int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt); -extern int do_proc_interrupts(int update_every, usec_t dt); -extern int do_proc_softirqs(int update_every, usec_t dt); -extern int do_sys_kernel_mm_ksm(int update_every, usec_t dt); -extern int do_proc_loadavg(int update_every, usec_t dt); -extern int do_proc_net_stat_synproxy(int update_every, usec_t dt); -extern int do_proc_net_softnet_stat(int update_every, usec_t dt); -extern int do_proc_uptime(int update_every, usec_t dt); -extern int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt); -extern int do_proc_sys_devices_system_node(int update_every, usec_t dt); -extern int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt); -extern int do_sys_fs_btrfs(int update_every, usec_t dt); -extern int do_proc_net_sockstat(int update_every, usec_t dt); -extern int do_proc_net_sockstat6(int update_every, usec_t dt); - -extern int get_numa_node_count(void); - -// metrics that need to be shared among data collectors -extern unsigned long long tcpext_TCPSynRetrans; - -// netdev renames -extern void netdev_rename_device_add(const char *host_device, const char *container_device, const char *container_name); -extern void netdev_rename_device_del(const char *host_device); - -#endif /* NETDATA_PLUGIN_PROC_H */ diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c deleted file mode 100644 index 0a229f38e..000000000 --- a/src/plugin_proc_diskspace.c +++ /dev/null @@ -1,460 +0,0 @@ -#include "common.h" - -#define DELAULT_EXCLUDED_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; -static int cleanup_mount_points = 1; - -static inline void mountinfo_reload(int force) { - static time_t last_loaded = 0; - time_t now = now_realtime_sec(); - - if(force || now - last_loaded >= check_for_new_mountpoints_every) { - // mountinfo_free_all() can be called with NULL disk_mountinfo_root - mountinfo_free_all(disk_mountinfo_root); - - // re-read mountinfo in case something changed - disk_mountinfo_root = mountinfo_read(0); - - last_loaded = now; - } -} - -// 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 - - 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; - RRDDIM *rd_inodes_reserved; -}; - -static DICTIONARY *dict_mountpoints = NULL; - -#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_is_obsolete(st); (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(cleanup_mount_points && 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 SIMPLE_PATTERN *excluded_mountpoints = NULL; - static SIMPLE_PATTERN *excluded_filesystems = NULL; - int do_space, do_inodes; - - if(unlikely(!dict_mountpoints)) { - SIMPLE_PREFIX_MODE mode = SIMPLE_PATTERN_EXACT; - - 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; - } - - excluded_mountpoints = simple_pattern_create( - config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths", DELAULT_EXCLUDED_PATHS) - , NULL - , mode - ); - - excluded_filesystems = simple_pattern_create( - config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on filesystems", DEFAULT_EXCLUDED_FILESYSTEMS) - , NULL - , SIMPLE_PATTERN_EXACT - ); - - dict_mountpoints = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED); - } - - 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(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_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; - } - - // check if the mount point is a directory #2407 - { - struct stat bs; - if(stat(mi->mount_point, &bs) == -1) { - error("DISKSPACE: Cannot stat() mount point '%s' (disk '%s', filesystem '%s', root '%s')." - , mi->mount_point - , disk - , mi->filesystem?mi->filesystem:"" - , mi->root?mi->root:"" - ); - def_space = CONFIG_BOOLEAN_NO; - def_inodes = CONFIG_BOOLEAN_NO; - } - else { - if((bs.st_mode & S_IFMT) != S_IFDIR) { - error("DISKSPACE: Mount point '%s' (disk '%s', filesystem '%s', root '%s') is not a directory." - , mi->mount_point - , disk - , mi->filesystem?mi->filesystem:"" - , mi->root?mi->root:"" - ); - def_space = CONFIG_BOOLEAN_NO; - def_inodes = CONFIG_BOOLEAN_NO; - } - } - } - - do_space = config_get_boolean_ondemand(var_name, "space usage", def_space); - do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes); - - struct mount_point_metadata mp = { - .do_space = do_space, - .do_inodes = do_inodes, - .shown_error = 0, - .updated = 0, - - .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, - .rd_inodes_reserved = NULL - }; - - m = dictionary_set(dict_mountpoints, mi->mount_point, &mp, sizeof(struct mount_point_metadata)); - } - - 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)) - return; - - struct statvfs buff_statvfs; - if (statvfs(mi->mount_point, &buff_statvfs) < 0) { - if(!m->shown_error) { - error("DISKSPACE: failed to statvfs() mount point '%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; - - fsblkcnt_t bavail = buff_statvfs.f_bavail; - fsblkcnt_t btotal = buff_statvfs.f_blocks; - fsblkcnt_t bavail_root = buff_statvfs.f_bfree; - fsblkcnt_t breserved_root = bavail_root - bavail; - fsblkcnt_t bused; - if(likely(btotal >= bavail_root)) - bused = btotal - bavail_root; - else - bused = bavail_root - btotal; - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(btotal != bavail + breserved_root + bused)) - error("DISKSPACE: disk block statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)btotal, (unsigned long long)bavail, (unsigned long long)breserved_root, (unsigned long long)bused); -#endif - - // -------------------------------------------------------------------------- - - fsfilcnt_t favail = buff_statvfs.f_favail; - fsfilcnt_t ftotal = buff_statvfs.f_files; - fsfilcnt_t favail_root = buff_statvfs.f_ffree; - fsfilcnt_t freserved_root = favail_root - favail; - fsfilcnt_t fused = ftotal - favail_root; - - if(m->do_inodes == CONFIG_BOOLEAN_AUTO && favail == (fsfilcnt_t)-1) { - // this file system does not support inodes reporting - // eg. cephfs - m->do_inodes = CONFIG_BOOLEAN_NO; - } - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(btotal != bavail + breserved_root + bused)) - error("DISKSPACE: disk inode statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)ftotal, (unsigned long long)favail, (unsigned long long)freserved_root, (unsigned long long)fused); -#endif - - // -------------------------------------------------------------------------- - - int rendered = 0; - - 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_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_localhost( - "disk_space" - , disk - , NULL - , family - , "disk.space" - , title - , "GB" - , "diskspace" - , NULL - , 2023 - , update_every - , RRDSET_TYPE_STACKED - ); - } - - 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); - - rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number)bavail); - rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number)bused); - rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number)breserved_root); - rrdset_done(m->st_space); - - rendered++; - } - - // -------------------------------------------------------------------------- - - 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_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_localhost( - "disk_inodes" - , disk - , NULL - , family - , "disk.inodes" - , title - , "Inodes" - , "diskspace" - , NULL - , 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); - 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); - - rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number)favail); - rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number)fused); - rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_reserved, (collected_number)freserved_root); - rrdset_done(m->st_inodes); - - rendered++; - } - - // -------------------------------------------------------------------------- - - if(likely(rendered)) - m->collected++; -} - -static void diskspace_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *proc_diskspace_main(void *ptr) { - netdata_thread_cleanup_push(diskspace_main_cleanup, ptr); - - int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1); - - cleanup_mount_points = config_get_boolean(CONFIG_SECTION_DISKSPACE, "remove charts of unmounted disks" , cleanup_mount_points); - - int update_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "update every", localhost->rrd_update_every); - if(update_every < localhost->rrd_update_every) - update_every = localhost->rrd_update_every; - - 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 duration = 0; - usec_t step = update_every * USEC_PER_SEC; - heartbeat_t hb; - heartbeat_init(&hb); - while(!netdata_exit) { - duration = heartbeat_dt_usec(&hb); - /* usec_t hb_dt = */ heartbeat_next(&hb, step); - - if(unlikely(netdata_exit)) break; - - - // -------------------------------------------------------------------------- - // this is smart enough not to reload it every time - - mountinfo_reload(0); - - - // -------------------------------------------------------------------------- - // disk space metrics - - struct mountinfo *mi; - for(mi = disk_mountinfo_root; mi; mi = mi->next) { - - if(unlikely(mi->flags & (MOUNTINFO_IS_DUMMY | MOUNTINFO_IS_BIND))) - continue; - - do_disk_space_stats(mi, update_every); - if(unlikely(netdata_exit)) break; - } - - if(unlikely(netdata_exit)) break; - - if(dict_mountpoints) - 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; - - // ---------------------------------------------------------------- - - getrusage(RUSAGE_THREAD, &thread); - - if(unlikely(!stcpu_thread)) { - stcpu_thread = rrdset_create_localhost( - "netdata" - , "plugin_diskspace" - , NULL - , "diskspace" - , NULL - , "NetData Disk Space Plugin CPU usage" - , "milliseconds/s" - , "diskspace" - , NULL - , 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); - - rrddim_set_by_pointer(stcpu_thread, rd_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set_by_pointer(stcpu_thread, rd_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); - rrdset_done(stcpu_thread); - - // ---------------------------------------------------------------- - - if(unlikely(!st_duration)) { - st_duration = rrdset_create_localhost( - "netdata" - , "plugin_diskspace_dt" - , NULL - , "diskspace" - , NULL - , "NetData Disk Space Plugin Duration" - , "milliseconds/run" - , "diskspace" - , NULL - , 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, duration); - rrdset_done(st_duration); - - // ---------------------------------------------------------------- - - if(unlikely(netdata_exit)) break; - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/plugin_proc_diskspace.h b/src/plugin_proc_diskspace.h deleted file mode 100644 index dcec28f75..000000000 --- a/src/plugin_proc_diskspace.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef NETDATA_PLUGIN_PROC_DISKSPACE_H -#define NETDATA_PLUGIN_PROC_DISKSPACE_H - -extern void *proc_diskspace_main(void *ptr); - -#endif //NETDATA_PLUGIN_PROC_DISKSPACE_H diff --git a/src/plugin_tc.c b/src/plugin_tc.c deleted file mode 100644 index 4b6d84e11..000000000 --- a/src/plugin_tc.c +++ /dev/null @@ -1,1164 +0,0 @@ -#include "common.h" - -#define RRD_TYPE_TC "tc" - -// ---------------------------------------------------------------------------- -// /sbin/tc processor -// this requires the script plugins.d/tc-qos-helper.sh - -#define TC_LINE_MAX 1024 - -struct tc_class { - avl avl; - - char *id; - uint32_t hash; - - char *name; - - char *leafid; - uint32_t leaf_hash; - - char *parentid; - uint32_t parent_hash; - - char hasparent; - char isleaf; - char isqdisc; - char render; - - unsigned long long bytes; - unsigned long long packets; - unsigned long long dropped; - unsigned long long overlimits; - unsigned long long requeues; - unsigned long long lended; - unsigned long long borrowed; - unsigned long long giants; - unsigned long long tokens; - unsigned long long ctokens; - - RRDDIM *rd_bytes; - RRDDIM *rd_packets; - RRDDIM *rd_dropped; - RRDDIM *rd_tokens; - RRDDIM *rd_ctokens; - - char name_updated; - char updated; // updated bytes - int unupdated; // the number of times, this has been found un-updated - - struct tc_class *next; - struct tc_class *prev; -}; - -struct tc_device { - avl avl; - - char *id; - uint32_t hash; - - char *name; - char *family; - - char name_updated; - char family_updated; - - char enabled; - char enabled_bytes; - char enabled_packets; - char enabled_dropped; - char enabled_tokens; - char enabled_ctokens; - char enabled_all_classes_qdiscs; - - RRDSET *st_bytes; - RRDSET *st_packets; - RRDSET *st_dropped; - RRDSET *st_tokens; - RRDSET *st_ctokens; - - avl_tree classes_index; - - struct tc_class *classes; - struct tc_class *last_class; - - struct tc_device *next; - struct tc_device *prev; -}; - - -struct tc_device *tc_device_root = NULL; - -// ---------------------------------------------------------------------------- -// tc_device index - -static int tc_device_compare(void* a, void* b) { - if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1; - else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1; - else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id); -} - -avl_tree tc_device_root_index = { - NULL, - tc_device_compare -}; - -#define tc_device_index_add(st) (struct tc_device *)avl_insert(&tc_device_root_index, (avl *)(st)) -#define tc_device_index_del(st) (struct tc_device *)avl_remove(&tc_device_root_index, (avl *)(st)) - -static inline struct tc_device *tc_device_index_find(const char *id, uint32_t hash) { - struct tc_device tmp; - tmp.id = (char *)id; - tmp.hash = (hash)?hash:simple_hash(tmp.id); - - return (struct tc_device *)avl_search(&(tc_device_root_index), (avl *)&tmp); -} - - -// ---------------------------------------------------------------------------- -// tc_class index - -static int tc_class_compare(void* a, void* b) { - if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1; - else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1; - else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id); -} - -#define tc_class_index_add(st, rd) (struct tc_class *)avl_insert(&((st)->classes_index), (avl *)(rd)) -#define tc_class_index_del(st, rd) (struct tc_class *)avl_remove(&((st)->classes_index), (avl *)(rd)) - -static inline struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) { - struct tc_class tmp; - tmp.id = (char *)id; - tmp.hash = (hash)?hash:simple_hash(tmp.id); - - return (struct tc_class *)avl_search(&(st->classes_index), (avl *) &tmp); -} - -// ---------------------------------------------------------------------------- - -static inline void tc_class_free(struct tc_device *n, struct tc_class *c) { - if(c == n->classes) { - if(likely(c->next)) - n->classes = c->next; - else - n->classes = c->prev; - } - - if(c == n->last_class) { - if(unlikely(c->next)) - n->last_class = c->next; - else - n->last_class = c->prev; - } - - if(c->next) c->next->prev = c->prev; - if(c->prev) c->prev->next = c->next; - - debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', unused=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->unupdated); - - if(unlikely(tc_class_index_del(n, c) != c)) - error("plugin_tc: INTERNAL ERROR: attempt remove class '%s' from device '%s': removed a different calls", c->id, n->id); - - freez(c->id); - freez(c->name); - freez(c->leafid); - freez(c->parentid); - freez(c); -} - -static inline void tc_device_classes_cleanup(struct tc_device *d) { - static int cleanup_every = 999; - - if(unlikely(cleanup_every > 0)) { - cleanup_every = (int) config_get_number("plugin:tc", "cleanup unused classes every", 120); - if(cleanup_every < 0) cleanup_every = -cleanup_every; - } - - d->name_updated = 0; - d->family_updated = 0; - - struct tc_class *c = d->classes; - while(c) { - if(unlikely(cleanup_every && c->unupdated >= cleanup_every)) { - struct tc_class *nc = c->next; - tc_class_free(d, c); - c = nc; - } - else { - c->updated = 0; - c->name_updated = 0; - - c = c->next; - } - } -} - -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, 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_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 /*, *root = NULL */; - unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0, tokens_sum = 0, ctokens_sum = 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 - - for(c = d->classes ; c ; c = c->next) { - 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++; // 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++; - } - } - - 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; - } - - 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); - - // set all classes to !updated - for(c = d->classes ; c ; c = c->next) - if(unlikely(!c->isqdisc && c->updated)) - c->updated = 0; - - updated_classes = 0; - } - - // 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; - } - } - } - } - - for(c = d->classes ; c ; c = c->next) { - 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(!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); - //} - } - -#ifdef NETDATA_INTERNAL_CHECKS - // dump all the list to see what we know - - 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 - - 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, 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, - d->enabled_packets, enable_packets, - d->enabled_dropped, enable_dropped, - d->enabled_tokens, enable_tokens, - d->enabled_ctokens, enable_ctokens, - d->enabled_all_classes_qdiscs, enabled_all_classes_qdiscs, - bytes_sum, - packets_sum, - dropped_sum, - tokens_sum, - ctokens_sum - ); - - // -------------------------------------------------------------------- - // bytes - - 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_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" - , "tc" - , NULL - , 7000 - , localhost->rrd_update_every - , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED - ); - - else { - rrdset_next(d->st_bytes); - if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, d->name); - - // FIXME - // update the family - } - - for(c = d->classes ; c ; c = c->next) { - if(unlikely(!c->render)) continue; - - if(unlikely(!c->rd_bytes)) - c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - else if(unlikely(c->name_updated)) - rrddim_set_name(d->st_bytes, c->rd_bytes, c->name); - - rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes); - } - rrdset_done(d->st_bytes); - } - - // -------------------------------------------------------------------- - // packets - - if(d->enabled_packets == CONFIG_BOOLEAN_YES || (d->enabled_packets == CONFIG_BOOLEAN_AUTO && packets_sum)) { - d->enabled_packets = CONFIG_BOOLEAN_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); - - 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" - , "tc" - , NULL - , 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(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id); - rrdset_set_name(d->st_packets, name); - } - - // FIXME - // update the family - } - - for(c = d->classes ; c ; c = c->next) { - if(unlikely(!c->render)) continue; - - 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); - - rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets); - } - rrdset_done(d->st_packets); - } - - // -------------------------------------------------------------------- - // dropped - - 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" - , "tc" - , NULL - , 7020 - , localhost->rrd_update_every - , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED - ); - } - else { - rrdset_next(d->st_dropped); - - if(unlikely(d->name_updated)) { - char name[RRD_ID_LENGTH_MAX + 1]; - snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id); - rrdset_set_name(d->st_dropped, name); - } - - // FIXME - // update the family - } - - for(c = d->classes ; c ; c = c->next) { - if(unlikely(!c->render)) continue; - - 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); - - rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped); - } - rrdset_done(d->st_dropped); - } - - // -------------------------------------------------------------------- - // tokens - - 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" - , "tc" - , NULL - , 7030 - , localhost->rrd_update_every - , RRDSET_TYPE_LINE - ); - } - else { - rrdset_next(d->st_tokens); - - if(unlikely(d->name_updated)) { - char name[RRD_ID_LENGTH_MAX + 1]; - snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id); - rrdset_set_name(d->st_tokens, name); - } - - // 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); - - rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens); - } - rrdset_done(d->st_tokens); - } - - // -------------------------------------------------------------------- - // ctokens - - if(d->enabled_ctokens == CONFIG_BOOLEAN_YES || (d->enabled_ctokens == CONFIG_BOOLEAN_AUTO && ctokens_sum)) { - d->enabled_ctokens = CONFIG_BOOLEAN_YES; - - 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); - - 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" - , "tc" - , NULL - , 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); - - if(unlikely(d->name_updated)) { - char name[RRD_ID_LENGTH_MAX + 1]; - snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id); - rrdset_set_name(d->st_ctokens, name); - } - - // FIXME - // update the family - } - - for(c = d->classes ; c ; c = c->next) { - if(unlikely(!c->render)) continue; - - 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); - - 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) { - if(unlikely(!name || !*name)) return; - - struct tc_class *c = tc_class_index_find(d, id, 0); - if(likely(c)) { - 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); - c->name = strdupz(name); - c->name_updated = 1; - } - } -} - -static inline void tc_device_set_device_name(struct tc_device *d, char *name) { - 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)) { - debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name); - d->name = strdupz(name); - d->name_updated = 1; - } -} - -static inline void tc_device_set_device_family(struct tc_device *d, char *family) { - freez(d->family); - d->family = NULL; - - if(likely(family && *family && strcmp(d->id, family) != 0)) { - debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family); - d->family = strdupz(family); - d->family_updated = 1; - } - // no need for null termination - it is already null -} - -static inline struct tc_device *tc_device_create(char *id) -{ - struct tc_device *d = tc_device_index_find(id, 0); - - if(!d) { - debug(D_TC_LOOP, "TC: Creating device '%s'", id); - - d = callocz(1, sizeof(struct tc_device)); - - d->id = strdupz(id); - d->hash = simple_hash(d->id); - d->enabled = (char)-1; - - avl_init(&d->classes_index, tc_class_compare); - if(unlikely(tc_device_index_add(d) != d)) - error("plugin_tc: INTERNAL ERROR: removing device '%s' removed a different device.", d->id); - - if(!tc_device_root) { - tc_device_root = d; - } - else { - d->next = tc_device_root; - tc_device_root->prev = d; - tc_device_root = d; - } - } - - return(d); -} - -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); - - if(!c) { - debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:""); - - c = callocz(1, sizeof(struct tc_class)); - - if(unlikely(!n->classes)) - n->classes = c; - - else if(likely(n->last_class)) { - n->last_class->next = c; - c->prev = n->last_class; - } - - n->last_class = c; - - 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); - } - - if(leafid && *leafid) { - c->leafid = strdupz(leafid); - c->leaf_hash = simple_hash(c->leafid); - } - - if(unlikely(tc_class_index_add(n, c) != c)) - error("plugin_tc: INTERNAL ERROR: attempt index class '%s' on device '%s': already exists", c->id, n->id); - } - return(c); -} - -static inline void tc_device_free(struct tc_device *n) -{ - if(n->next) n->next->prev = n->prev; - if(n->prev) n->prev->next = n->next; - if(tc_device_root == n) { - if(n->next) tc_device_root = n->next; - else tc_device_root = n->prev; - } - - if(unlikely(tc_device_index_del(n) != n)) - error("plugin_tc: INTERNAL ERROR: removing device '%s' removed a different device.", n->id); - - while(n->classes) tc_class_free(n, n->classes); - - freez(n->id); - freez(n->name); - freez(n->family); - freez(n); -} - -static inline void tc_device_free_all() -{ - while(tc_device_root) - tc_device_free(tc_device_root); -} - -#define PLUGINSD_MAX_WORDS 20 - -static inline int tc_space(char c) { - switch(c) { - case ' ': - case '\t': - case '\r': - case '\n': - return 1; - - default: - return 0; - } -} - -static inline void tc_split_words(char *str, char **words, int max_words) { - char *s = str; - int i = 0; - - // skip all white space - while(tc_space(*s)) s++; - - // store the first word - words[i++] = s; - - // while we have something - while(*s) { - // if it is a space - if(unlikely(tc_space(*s))) { - - // terminate the word - *s++ = '\0'; - - // skip all white space - while(tc_space(*s)) s++; - - // if we reached the end, stop - if(!*s) break; - - // store the next word - if(i < max_words) words[i++] = s; - else break; - } - else s++; - } - - // terminate the words - while(i < max_words) words[i++] = NULL; -} - -static pid_t tc_child_pid = 0; - -static void tc_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - if(tc_child_pid) { - info("TC: killing with SIGTERM tc-qos-helper process %d", tc_child_pid); - if(killpid(tc_child_pid, SIGTERM) != -1) { - siginfo_t info; - - info("TC: waiting for tc plugin child process pid %d to exit...", tc_child_pid); - waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED); - // info("TC: finished tc plugin child process pid %d.", tc_child_pid); - } - - tc_child_pid = 0; - } - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *tc_main(void *ptr) { - netdata_thread_cleanup_push(tc_main_cleanup, ptr); - - struct rusage thread; - - char buffer[TC_LINE_MAX+1] = ""; - char *words[PLUGINSD_MAX_WORDS] = { NULL }; - - 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:"); - uint32_t TOKENS_HASH = simple_hash("tokens:"); - uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME"); - uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP"); - uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME"); - uint32_t WORKTIME_HASH = simple_hash("WORKTIME"); -#ifdef DETACH_PLUGINS_FROM_NETDATA - uint32_t MYPID_HASH = simple_hash("MYPID"); -#endif - uint32_t first_hash; - - 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); - - while(!netdata_exit) { - FILE *fp; - struct tc_device *device = NULL; - struct tc_class *class = NULL; - - 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); - if(unlikely(!fp)) { - error("TC: Cannot popen(\"%s\", \"r\").", buffer); - goto cleanup; - } - - while(fgets(buffer, TC_LINE_MAX, fp) != NULL) { - if(unlikely(netdata_exit)) break; - - buffer[TC_LINE_MAX] = '\0'; - // debug(D_TC_LOOP, "TC: read '%s'", buffer); - - tc_split_words(buffer, words, PLUGINSD_MAX_WORDS); - - if(unlikely(!words[0] || !*words[0])) { - // debug(D_TC_LOOP, "empty line"); - continue; - } - // else debug(D_TC_LOOP, "First word is '%s'", words[0]); - - first_hash = simple_hash(words[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]); - - 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"); - - 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; - - 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(parent_is_root) { - parentid = NULL; - leafid = NULL; - } - else if(!leaf || strcmp(leaf, "leaf") != 0) - leafid = NULL; - - char leafbuf[20 + 1] = ""; - if(leafid && leafid[strlen(leafid) - 1] == ':') { - strncpyz(leafbuf, leafid, 20 - 1); - strcat(leafbuf, "1"); - leafid = leafbuf; - } - - class = tc_class_add(device, id, qdisc, parentid, leafid); - } - else { - // clear the last class - class = NULL; - } - } - else if(unlikely(first_hash == END_HASH && strcmp(words[0], "END") == 0)) { - // debug(D_TC_LOOP, "END line"); - - if(likely(device)) { - netdata_thread_disable_cancelability(); - tc_device_commit(device); - // tc_device_free(device); - netdata_thread_enable_cancelability(); - } - - device = NULL; - class = NULL; - } - else if(unlikely(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0)) { - // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]); - - if(likely(words[1] && *words[1])) { - device = tc_device_create(words[1]); - } - else { - // tc_device_free(device); - device = NULL; - } - - class = NULL; - } - else if(unlikely(device && class && first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0)) { - // debug(D_TC_LOOP, "SENT line '%s'", words[1]); - if(likely(words[1] && *words[1])) { - class->bytes = str2ull(words[1]); - class->updated = 1; - } - else { - class->updated = 0; - } - - if(likely(words[3] && *words[3])) - class->packets = str2ull(words[3]); - - if(likely(words[6] && *words[6])) - class->dropped = str2ull(words[6]); - - if(likely(words[8] && *words[8])) - class->overlimits = str2ull(words[8]); - - if(likely(words[10] && *words[10])) - class->requeues = str2ull(words[8]); - } - else if(unlikely(device && class && class->updated && first_hash == LENDED_HASH && strcmp(words[0], "lended:") == 0)) { - // debug(D_TC_LOOP, "LENDED line '%s'", words[1]); - if(likely(words[1] && *words[1])) - class->lended = str2ull(words[1]); - - if(likely(words[3] && *words[3])) - class->borrowed = str2ull(words[3]); - - if(likely(words[5] && *words[5])) - class->giants = str2ull(words[5]); - } - else if(unlikely(device && class && class->updated && first_hash == TOKENS_HASH && strcmp(words[0], "tokens:") == 0)) { - // debug(D_TC_LOOP, "TOKENS line '%s'", words[1]); - if(likely(words[1] && *words[1])) - class->tokens = str2ull(words[1]); - - if(likely(words[3] && *words[3])) - class->ctokens = str2ull(words[3]); - } - else if(unlikely(device && first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0)) { - // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]); - if(likely(words[1] && *words[1])) - tc_device_set_device_name(device, words[1]); - } - else if(unlikely(device && first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0)) { - // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]); - if(likely(words[1] && *words[1])) - tc_device_set_device_family(device, words[1]); - } - else if(unlikely(device && first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0)) { - // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]); - char *id = words[1]; - char *path = words[2]; - if(likely(id && *id && path && *path)) - tc_device_set_class_name(device, id, path); - } - else if(unlikely(first_hash == WORKTIME_HASH && strcmp(words[0], "WORKTIME") == 0)) { - // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]); - getrusage(RUSAGE_THREAD, &thread); - - static RRDSET *stcpu = NULL; - static RRDDIM *rd_user = NULL, *rd_system = NULL; - - if(unlikely(!stcpu)) { - stcpu = rrdset_create_localhost( - "netdata" - , "plugin_tc_cpu" - , NULL - , "tc.helper" - , NULL - , "NetData TC CPU usage" - , "milliseconds/s" - , "tc" - , NULL - , 135000 - , localhost->rrd_update_every - , RRDSET_TYPE_STACKED - ); - rd_user = rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rd_system = rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(stcpu); - - rrddim_set_by_pointer(stcpu, rd_user , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set_by_pointer(stcpu, rd_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); - rrdset_done(stcpu); - - static RRDSET *sttime = NULL; - static RRDDIM *rd_run_time = NULL; - - if(unlikely(!sttime)) { - sttime = rrdset_create_localhost( - "netdata" - , "plugin_tc_time" - , NULL - , "tc.helper" - , NULL - , "NetData TC script execution" - , "milliseconds/run" - , "tc" - , NULL - , 135001 - , localhost->rrd_update_every - , RRDSET_TYPE_AREA - ); - rd_run_time = rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(sttime); - - rrddim_set_by_pointer(sttime, rd_run_time, str2ll(words[1], NULL)); - rrdset_done(sttime); - - } -#ifdef DETACH_PLUGINS_FROM_NETDATA - else if(unlikely(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0))) { - // debug(D_TC_LOOP, "MYPID line '%s'", words[1]); - char *id = words[1]; - pid_t pid = atol(id); - - if(likely(pid)) tc_child_pid = pid; - - debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid); - } -#endif - //else { - // debug(D_TC_LOOP, "IGNORED line"); - //} - } - - // fgets() failed or loop broke - int code = mypclose(fp, (pid_t)tc_child_pid); - tc_child_pid = 0; - - if(unlikely(device)) { - // tc_device_free(device); - device = NULL; - class = NULL; - } - - if(unlikely(netdata_exit)) { - tc_device_free_all(); - goto cleanup; - } - - if(code == 1 || code == 127) { - // 1 = DISABLE - // 127 = cannot even run it - error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code); - - tc_device_free_all(); - goto cleanup; - } - - sleep((unsigned int) localhost->rrd_update_every); - } - -cleanup: ; // added semi-colon to prevent older gcc error: label at end of compound statement - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/plugin_tc.h b/src/plugin_tc.h deleted file mode 100644 index 792c6496f..000000000 --- a/src/plugin_tc.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef NETDATA_PLUGIN_TC_H -#define NETDATA_PLUGIN_TC_H 1 - -extern void *tc_main(void *ptr); - -#endif /* NETDATA_PLUGIN_TC_H */ - diff --git a/src/plugins_d.c b/src/plugins_d.c deleted file mode 100644 index 5693dda06..000000000 --- a/src/plugins_d.c +++ /dev/null @@ -1,694 +0,0 @@ -#include "common.h" - -char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL }; -char *netdata_configured_plugins_dir_base; - -struct plugind *pluginsd_root = NULL; - -static inline int pluginsd_space(char c) { - switch(c) { - case ' ': - case '\t': - case '\r': - case '\n': - case '=': - return 1; - - default: - return 0; - } -} - -inline int config_isspace(char c) { - switch(c) { - case ' ': - case '\t': - case '\r': - case '\n': - case ',': - return 1; - - default: - return 0; - } -} - -// split a text into words, respecting quotes -inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)) { - char *s = str, quote = 0; - int i = 0, j; - - // skip all white space - while(unlikely(custom_isspace(*s))) s++; - - // check for quote - if(unlikely(*s == '\'' || *s == '"')) { - quote = *s; // remember the quote - s++; // skip the quote - } - - // store the first word - words[i++] = s; - - // while we have something - while(likely(*s)) { - // if it is escape - if(unlikely(*s == '\\' && s[1])) { - s += 2; - continue; - } - - // if it is quote - else if(unlikely(*s == quote)) { - quote = 0; - *s = ' '; - continue; - } - - // if it is a space - else if(unlikely(quote == 0 && custom_isspace(*s))) { - - // terminate the word - *s++ = '\0'; - - // skip all white space - while(likely(custom_isspace(*s))) s++; - - // check for quote - if(unlikely(*s == '\'' || *s == '"')) { - quote = *s; // remember the quote - s++; // skip the quote - } - - // if we reached the end, stop - if(unlikely(!*s)) break; - - // store the next word - if(likely(i < max_words)) words[i++] = s; - else break; - } - - // anything else - else s++; - } - - // terminate the words - j = i; - while(likely(j < max_words)) words[j++] = NULL; - - return i; -} - -inline int pluginsd_split_words(char *str, char **words, int max_words) { - return quoted_strings_splitter(str, words, max_words, pluginsd_space); -} - -inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) { - int enabled = cd->enabled; - - if(!fp || !enabled) { - cd->enabled = 0; - return 0; - } - - size_t count = 0; - - char line[PLUGINSD_LINE_MAX + 1]; - - char *words[PLUGINSD_MAX_WORDS] = { NULL }; - uint32_t BEGIN_HASH = simple_hash(PLUGINSD_KEYWORD_BEGIN); - uint32_t END_HASH = simple_hash(PLUGINSD_KEYWORD_END); - uint32_t FLUSH_HASH = simple_hash(PLUGINSD_KEYWORD_FLUSH); - uint32_t CHART_HASH = simple_hash(PLUGINSD_KEYWORD_CHART); - uint32_t DIMENSION_HASH = simple_hash(PLUGINSD_KEYWORD_DIMENSION); - uint32_t DISABLE_HASH = simple_hash(PLUGINSD_KEYWORD_DISABLE); - uint32_t VARIABLE_HASH = simple_hash(PLUGINSD_KEYWORD_VARIABLE); - - RRDSET *st = NULL; - uint32_t hash; - - errno = 0; - clearerr(fp); - - if(unlikely(fileno(fp) == -1)) { - error("file descriptor given is not a valid stream"); - goto cleanup; - } - - while(!ferror(fp)) { - if(unlikely(netdata_exit)) break; - - char *r = fgets(line, PLUGINSD_LINE_MAX, fp); - if(unlikely(!r)) { - error("read failed"); - break; - } - - if(unlikely(netdata_exit)) break; - - line[PLUGINSD_LINE_MAX] = '\0'; - - int w = pluginsd_split_words(line, words, PLUGINSD_MAX_WORDS); - char *s = words[0]; - if(unlikely(!s || !*s || !w)) { - continue; - } - - // 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(likely(!simple_hash_strcmp(s, "SET", &hash))) { - char *dimension = words[1]; - char *value = words[2]; - - if(unlikely(!dimension || !*dimension)) { - error("requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id, host->hostname); - enabled = 0; - break; - } - - if(unlikely(!value || !*value)) value = NULL; - - if(unlikely(!st)) { - error("requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", dimension, value?value:"", host->hostname); - enabled = 0; - break; - } - - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) - debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value?value:""); - - if(value) { - RRDDIM *rd = rrddim_find(st, dimension); - if(unlikely(!rd)) { - error("requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.", dimension, st->name, st->id, st->rrdhost->hostname); - enabled = 0; - break; - } - else - rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0)); - } - } - else if(likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) { - char *id = words[1]; - char *microseconds_txt = words[2]; - - if(unlikely(!id)) { - error("requested a BEGIN without a chart id for host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - st = rrdset_find(host, id); - if(unlikely(!st)) { - error("requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, host->hostname); - enabled = 0; - break; - } - - if(likely(st->counter_done)) { - usec_t microseconds = 0; - if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt); - - 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, PLUGINSD_KEYWORD_END))) { - if(unlikely(!st)) { - error("requested an END, without a BEGIN on host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) - debug(D_PLUGINSD, "requested an END on chart %s", st->id); - - rrdset_done(st); - st = NULL; - - count++; - } - else if(likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) { - st = NULL; - - char *type = words[1]; - char *name = words[2]; - char *title = words[3]; - char *units = words[4]; - char *family = words[5]; - char *context = words[6]; - char *chart = words[7]; - char *priority_s = words[8]; - char *update_every_s = words[9]; - char *options = words[10]; - char *plugin = words[11]; - char *module = words[12]; - - // parse the id from type - char *id = NULL; - if(likely(type && (id = strchr(type, '.')))) { - *id = '\0'; - id++; - } - - // make sure we have the required variables - if(unlikely(!type || !*type || !id || !*id)) { - error("requested a CHART, without a type.id, on host '%s'. Disabling it.", host->hostname); - enabled = 0; - break; - } - - // parse the name, and make sure it does not include 'type.' - if(unlikely(name && *name)) { - // when data are coming from slaves - // name will be type.name - // so we have to remove 'type.' from name too - size_t len = strlen(type); - if(strncmp(type, name, len) == 0 && name[len] == '.') - name = &name[len + 1]; - - // if the name is the same with the id, - // or is just 'NULL', clear it. - if(unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) - name = NULL; - } - - int priority = 1000; - if(likely(priority_s && *priority_s)) priority = str2i(priority_s); - - int update_every = cd->update_every; - if(likely(update_every_s && *update_every_s)) update_every = str2i(update_every_s); - if(unlikely(!update_every)) update_every = cd->update_every; - - RRDSET_TYPE chart_type = RRDSET_TYPE_LINE; - if(unlikely(chart)) chart_type = rrdset_type_id(chart); - - if(unlikely(name && !*name)) name = NULL; - if(unlikely(family && !*family)) family = NULL; - if(unlikely(context && !*context)) context = NULL; - if(unlikely(!title)) title = ""; - if(unlikely(!units)) units = "unknown"; - - debug(D_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 - , (plugin && *plugin)?plugin:cd->filename - , module - , priority - , update_every - , chart_type - ); - - if(options && *options) { - if(strstr(options, "obsolete")) - rrdset_is_obsolete(st); - else - rrdset_isnot_obsolete(st); - - if(strstr(options, "detail")) - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - else - rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); - - if(strstr(options, "hidden")) - rrdset_flag_set(st, RRDSET_FLAG_HIDDEN); - else - rrdset_flag_clear(st, RRDSET_FLAG_HIDDEN); - - if(strstr(options, "store_first")) - rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST); - else - rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); - } - else { - rrdset_isnot_obsolete(st); - rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); - rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); - } - } - else if(likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_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("requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname, st?st->id:"UNSET"); - enabled = 0; - break; - } - - if(unlikely(!st)) { - error("requested a DIMENSION, without a CHART, on host '%s'. Disabling it.", host->hostname); - enabled = 0; - 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(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) - debug(D_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_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 if(likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) { - char *name = words[1]; - char *value = words[2]; - int global = (st)?0:1; - - if(name && *name) { - if((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) { - global = 1; - name = words[2]; - value = words[3]; - } - else if((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) { - global = 0; - name = words[2]; - value = words[3]; - } - } - - if(unlikely(!name || !*name)) { - error("requested a VARIABLE on host '%s', without a variable name. Disabling it.", host->hostname); - enabled = 0; - break; - } - - if(unlikely(!value || !*value)) - value = NULL; - - if(value) { - char *endptr = NULL; - calculated_number v = (calculated_number)str2ld(value, &endptr); - - if(unlikely(endptr && *endptr)) { - if(endptr == value) - error("the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name, host->hostname); - else - error("the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name, host->hostname, endptr); - } - - if(global) { - RRDVAR *rv = rrdvar_custom_host_variable_create(host, name); - if (rv) rrdvar_custom_host_variable_set(host, rv, v); - else error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname); - } - else if(st) { - RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name); - if (rs) rrdsetvar_custom_chart_variable_set(rs, v); - else error("cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname, st->id); - } - else - error("cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", name, host->hostname); - } - else - error("cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global)?"HOST":"CHART", name, host->hostname); - } - else if(likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) { - debug(D_PLUGINSD, "requested a FLUSH"); - st = NULL; - } - else if(unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) { - info("called DISABLE. Disabling it."); - enabled = 0; - break; - } - else { - error("sent command '%s' which is not known by netdata, for host '%s'. Disabling it.", s, host->hostname); - enabled = 0; - break; - } - } - -cleanup: - cd->enabled = enabled; - - if(likely(count)) { - cd->successful_collections += count; - cd->serial_failures = 0; - } - else - cd->serial_failures++; - - return count; -} - -static void pluginsd_worker_thread_cleanup(void *arg) { - struct plugind *cd = (struct plugind *)arg; - - if(cd->enabled && !cd->obsolete) { - cd->obsolete = 1; - - info("data collection thread exiting"); - - if (cd->pid) { - siginfo_t info; - info("killing child process pid %d", cd->pid); - if (killpid(cd->pid, SIGTERM) != -1) { - info("waiting for child process pid %d to exit...", cd->pid); - waitid(P_PID, (id_t) cd->pid, &info, WEXITED); - } - cd->pid = 0; - } - } -} - -void *pluginsd_worker_thread(void *arg) { - netdata_thread_cleanup_push(pluginsd_worker_thread_cleanup, arg); - - struct plugind *cd = (struct plugind *)arg; - - cd->obsolete = 0; - size_t count = 0; - - while(!netdata_exit) { - FILE *fp = mypopen(cd->cmd, &cd->pid); - if(unlikely(!fp)) { - error("Cannot popen(\"%s\", \"r\").", cd->cmd); - break; - } - - info("connected to '%s' running on pid %d", cd->fullfilename, cd->pid); - count = pluginsd_process(localhost, cd, fp, 0); - error("'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count); - killpid(cd->pid, SIGTERM); - - // get the return code - int code = mypclose(fp, cd->pid); - - if(code != 0) { - // the plugin reports failure - - if(likely(!cd->successful_collections)) { - // nothing collected - disable it - error("'%s' (pid %d) exited with error code %d. Disabling it.", cd->fullfilename, cd->pid, code); - cd->enabled = 0; - } - else { - // we have collected something - - if(likely(cd->serial_failures <= 10)) { - error("'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s", cd->fullfilename, cd->pid, code, cd->successful_collections, cd->enabled?"Waiting a bit before starting it again.":"Will not start it again - it is disabled."); - sleep((unsigned int) (cd->update_every * 10)); - } - else { - error("'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). We tried %zu times to restart it, but it failed to generate data. Disabling it.", cd->fullfilename, cd->pid, code, cd->successful_collections, cd->serial_failures); - cd->enabled = 0; - } - } - } - else { - // the plugin reports success - - if(unlikely(!cd->successful_collections)) { - // we have collected nothing so far - - if(likely(cd->serial_failures <= 10)) { - error("'%s' (pid %d) does not generate useful output but it reports success (exits with 0). %s.", cd->fullfilename, cd->pid, cd->enabled?"Waiting a bit before starting it again.":"Will not start it again - it is now disabled."); - sleep((unsigned int) (cd->update_every * 10)); - } - else { - error("'%s' (pid %d) does not generate useful output, although it reports success (exits with 0), but we have tried %zu times to collect something. Disabling it.", cd->fullfilename, cd->pid, cd->serial_failures); - cd->enabled = 0; - } - } - else - sleep((unsigned int) cd->update_every); - } - cd->pid = 0; - - if(unlikely(!cd->enabled)) break; - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - -static void pluginsd_main_cleanup(void *data) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - info("cleaning up..."); - - struct plugind *cd; - for (cd = pluginsd_root; cd; cd = cd->next) { - if (cd->enabled && !cd->obsolete) { - info("stopping plugin thread: %s", cd->id); - netdata_thread_cancel(cd->thread); - } - } - - info("cleanup completed."); - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *pluginsd_main(void *ptr) { - netdata_thread_cleanup_push(pluginsd_main_cleanup, ptr); - - 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); - if(scan_frequency < 1) scan_frequency = 1; - - // store the errno for each plugins directory - // so that we don't log broken directories on each loop - int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 }; - - while(!netdata_exit) { - int idx; - const char *directory_name; - - for( idx = 0; idx < PLUGINSD_MAX_DIRECTORIES && (directory_name = plugin_directories[idx]) ; idx++ ) { - if(unlikely(netdata_exit)) break; - - errno = 0; - DIR *dir = opendir(directory_name); - if(unlikely(!dir)) { - if(directory_errors[idx] != errno) { - directory_errors[idx] = errno; - error("cannot open plugins directory '%s'", directory_name); - } - continue; - } - - struct dirent *file = NULL; - while(likely((file = readdir(dir)))) { - if(unlikely(netdata_exit)) break; - - debug(D_PLUGINSD, "examining file '%s'", file->d_name); - - if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue; - - int len = (int) strlen(file->d_name); - if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue; - if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) { - debug(D_PLUGINSD, "file '%s' does not end in '%s'", file->d_name, PLUGINSD_FILE_SUFFIX); - continue; - } - - 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(CONFIG_SECTION_PLUGINS, pluginname, automatic_run); - - if(unlikely(!enabled)) { - debug(D_PLUGINSD, "plugin '%s' is not enabled", file->d_name); - continue; - } - - // check if it runs already - struct plugind *cd; - for(cd = pluginsd_root ; cd ; cd = cd->next) - if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break; - - if(likely(cd && !cd->obsolete)) { - debug(D_PLUGINSD, "plugin '%s' is already running", cd->filename); - continue; - } - - // it is not running - // allocate a new one, or use the obsolete one - if(unlikely(!cd)) { - cd = callocz(sizeof(struct plugind), 1); - - snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname); - - strncpyz(cd->filename, file->d_name, FILENAME_MAX); - snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", directory_name, cd->filename); - - cd->enabled = enabled; - cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every); - cd->started_t = now_realtime_sec(); - - char *def = ""; - snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def)); - - // link it - if(likely(pluginsd_root)) cd->next = pluginsd_root; - pluginsd_root = cd; - - // it is not currently running - cd->obsolete = 1; - - if(cd->enabled) { - char tag[NETDATA_THREAD_TAG_MAX + 1]; - snprintfz(tag, NETDATA_THREAD_TAG_MAX, "PLUGINSD[%s]", pluginname); - // spawn a new thread for it - netdata_thread_create(&cd->thread, tag, NETDATA_THREAD_OPTION_DEFAULT, pluginsd_worker_thread, cd); - } - } - } - - closedir(dir); - } - - sleep((unsigned int) scan_frequency); - } - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/plugins_d.h b/src/plugins_d.h deleted file mode 100644 index 692d7cae1..000000000 --- a/src/plugins_d.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef NETDATA_PLUGINS_D_H -#define NETDATA_PLUGINS_D_H 1 - -#define PLUGINSD_FILE_SUFFIX ".plugin" -#define PLUGINSD_FILE_SUFFIX_LEN strlen(PLUGINSD_FILE_SUFFIX) -#define PLUGINSD_CMD_MAX (FILENAME_MAX*2) - -#define PLUGINSD_KEYWORD_CHART "CHART" -#define PLUGINSD_KEYWORD_DIMENSION "DIMENSION" -#define PLUGINSD_KEYWORD_BEGIN "BEGIN" -#define PLUGINSD_KEYWORD_END "END" -#define PLUGINSD_KEYWORD_FLUSH "FLUSH" -#define PLUGINSD_KEYWORD_DISABLE "DISABLE" -#define PLUGINSD_KEYWORD_VARIABLE "VARIABLE" - -#define PLUGINSD_LINE_MAX 1024 -#define PLUGINSD_MAX_WORDS 20 - -#define PLUGINSD_MAX_DIRECTORIES 20 -extern char *plugin_directories[PLUGINSD_MAX_DIRECTORIES]; - -struct plugind { - char id[CONFIG_MAX_NAME+1]; // config node id - - char filename[FILENAME_MAX+1]; // just the filename - char fullfilename[FILENAME_MAX+1]; // with path - char cmd[PLUGINSD_CMD_MAX+1]; // the command that it executes - - volatile pid_t pid; - netdata_thread_t thread; - - size_t successful_collections; // the number of times we have seen - // values collected from this plugin - - size_t serial_failures; // the number of times the plugin started - // without collecting values - - int update_every; // the plugin default data collection frequency - volatile sig_atomic_t obsolete; // do not touch this structure after setting this to 1 - volatile sig_atomic_t enabled; // if this is enabled or not - - time_t started_t; - - struct plugind *next; -}; - -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); -extern int pluginsd_split_words(char *str, char **words, int max_words); - -extern int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)); -extern int config_isspace(char c); - -#endif /* NETDATA_PLUGINS_D_H */ diff --git a/src/popen.c b/src/popen.c deleted file mode 100644 index eda1c05b9..000000000 --- a/src/popen.c +++ /dev/null @@ -1,204 +0,0 @@ -#include "common.h" - -/* -struct mypopen { - pid_t pid; - FILE *fp; - struct mypopen *next; - struct mypopen *prev; -}; - -static struct mypopen *mypopen_root = NULL; - -static void mypopen_add(FILE *fp, pid_t *pid) { - struct mypopen *mp = malloc(sizeof(struct mypopen)); - if(!mp) { - fatal("Cannot allocate %zu bytes", sizeof(struct mypopen)) - return; - } - - mp->fp = fp; - mp->pid = pid; - mp->next = popen_root; - mp->prev = NULL; - if(mypopen_root) mypopen_root->prev = mp; - mypopen_root = mp; -} - -static void mypopen_del(FILE *fp) { - struct mypopen *mp; - - for(mp = mypopen_root; mp; mp = mp->next) - if(mp->fd == fp) break; - - if(!mp) error("Cannot find mypopen() file pointer in open childs."); - else { - if(mp->next) mp->next->prev = mp->prev; - if(mp->prev) mp->prev->next = mp->next; - if(mypopen_root == mp) mypopen_root = mp->next; - free(mp); - } -} -*/ -#define PIPE_READ 0 -#define PIPE_WRITE 1 - -FILE *mypopen(const char *command, volatile pid_t *pidptr) -{ - int pipefd[2]; - - if(pipe(pipefd) == -1) return NULL; - - int pid = fork(); - if(pid == -1) { - close(pipefd[PIPE_READ]); - close(pipefd[PIPE_WRITE]); - return NULL; - } - if(pid != 0) { - // the parent - *pidptr = pid; - close(pipefd[PIPE_WRITE]); - FILE *fp = fdopen(pipefd[PIPE_READ], "r"); - /*mypopen_add(fp, pid);*/ - return(fp); - } - // the child - - // close all files - int i; - for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--) - if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i); - - // move the pipe to stdout - if(pipefd[PIPE_WRITE] != STDOUT_FILENO) { - dup2(pipefd[PIPE_WRITE], STDOUT_FILENO); - close(pipefd[PIPE_WRITE]); - } - -#ifdef DETACH_PLUGINS_FROM_NETDATA - // this was an attempt to detach the child and use the suspend mode charts.d - // unfortunatelly it does not work as expected. - - // fork again to become session leader - pid = fork(); - if(pid == -1) - error("pre-execution of command '%s' on pid %d: Cannot fork 2nd time.", command, getpid()); - - if(pid != 0) { - // the parent - exit(0); - } - - // set a new process group id for just this child - if( setpgid(0, 0) != 0 ) - error("pre-execution of command '%s' on pid %d: Cannot set a new process group.", command, getpid()); - - if( getpgid(0) != getpid() ) - error("pre-execution of command '%s' on pid %d: Cannot set a new process group. Process group set is incorrect. Expected %d, found %d", command, getpid(), getpid(), getpgid(0)); - - if( setsid() != 0 ) - error("pre-execution of command '%s' on pid %d: Cannot set session id.", command, getpid()); - - fprintf(stdout, "MYPID %d\n", getpid()); - fflush(NULL); -#endif - - // reset all signals - signals_unblock(); - signals_reset(); - - debug(D_CHILDS, "executing command: '%s' on pid %d.", command, getpid()); - execl("/bin/sh", "sh", "-c", command, NULL); - exit(1); -} - -FILE *mypopene(const char *command, volatile pid_t *pidptr, char **env) { - int pipefd[2]; - - if(pipe(pipefd) == -1) - return NULL; - - int pid = fork(); - if(pid == -1) { - close(pipefd[PIPE_READ]); - close(pipefd[PIPE_WRITE]); - return NULL; - } - if(pid != 0) { - // the parent - *pidptr = pid; - close(pipefd[PIPE_WRITE]); - FILE *fp = fdopen(pipefd[PIPE_READ], "r"); - return(fp); - } - // the child - - // close all files - int i; - for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--) - if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i); - - // move the pipe to stdout - if(pipefd[PIPE_WRITE] != STDOUT_FILENO) { - dup2(pipefd[PIPE_WRITE], STDOUT_FILENO); - close(pipefd[PIPE_WRITE]); - } - - execle("/bin/sh", "sh", "-c", command, NULL, env); - exit(1); -} - -int mypclose(FILE *fp, pid_t pid) { - debug(D_EXIT, "Request to mypclose() on pid %d", pid); - - /*mypopen_del(fp);*/ - - // close the pipe fd - // this is required in musl - // without it the childs do not exit - close(fileno(fp)); - - // close the pipe file pointer - fclose(fp); - - errno = 0; - - siginfo_t info; - if(waitid(P_PID, (id_t) pid, &info, WEXITED) != -1) { - switch(info.si_code) { - case CLD_EXITED: - if(info.si_status) - error("child pid %d exited with code %d.", info.si_pid, info.si_status); - return(info.si_status); - - case CLD_KILLED: - error("child pid %d killed by signal %d.", info.si_pid, info.si_status); - return(-1); - - case CLD_DUMPED: - error("child pid %d core dumped by signal %d.", info.si_pid, info.si_status); - return(-2); - - case CLD_STOPPED: - error("child pid %d stopped by signal %d.", info.si_pid, info.si_status); - return(0); - - case CLD_TRAPPED: - error("child pid %d trapped by signal %d.", info.si_pid, info.si_status); - return(-4); - - case CLD_CONTINUED: - error("child pid %d continued by signal %d.", info.si_pid, info.si_status); - return(0); - - default: - error("child pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status); - return(-5); - } - } - else - error("Cannot waitid() for pid %d", pid); - - return 0; -} diff --git a/src/popen.h b/src/popen.h deleted file mode 100644 index 3dd79bb4d..000000000 --- a/src/popen.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NETDATA_POPEN_H -#define NETDATA_POPEN_H 1 - -#define PIPE_READ 0 -#define PIPE_WRITE 1 - -extern FILE *mypopen(const char *command, volatile pid_t *pidptr); -extern FILE *mypopene(const char *command, volatile pid_t *pidptr, char **env); -extern int mypclose(FILE *fp, pid_t pid); - -#endif /* NETDATA_POPEN_H */ diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c deleted file mode 100644 index 8cde3334b..000000000 --- a/src/proc_diskstats.c +++ /dev/null @@ -1,1438 +0,0 @@ -#include "common.h" - -#define RRD_TYPE_DISK "disk" - -#define DISK_TYPE_UNKNOWN 0 -#define DISK_TYPE_PHYSICAL 1 -#define DISK_TYPE_PARTITION 2 -#define DISK_TYPE_VIRTUAL 3 - -#define CONFIG_SECTION_DISKSTATS "plugin:proc:/proc/diskstats" -#define DEFAULT_EXCLUDED_DISKS "loop* ram*" - -static struct disk { - char *disk; // the name of the disk (sda, sdb, etc, after being looked up) - char *device; // the device of the disk (before being looked up) - unsigned long major; - unsigned long minor; - int sector_size; - int type; - - char *mount_point; - - // disk options caching - int do_io; - int do_ops; - int do_mops; - int do_iotime; - int do_qops; - int do_util; - int do_backlog; - int do_bcache; - - int updated; - - int device_is_bcache; - - char *bcache_filename_dirty_data; - char *bcache_filename_writeback_rate; - char *bcache_filename_cache_congested; - char *bcache_filename_cache_available_percent; - char *bcache_filename_stats_five_minute_cache_hit_ratio; - char *bcache_filename_stats_hour_cache_hit_ratio; - char *bcache_filename_stats_day_cache_hit_ratio; - char *bcache_filename_stats_total_cache_hit_ratio; - char *bcache_filename_stats_total_cache_hits; - char *bcache_filename_stats_total_cache_misses; - char *bcache_filename_stats_total_cache_miss_collisions; - char *bcache_filename_stats_total_cache_bypass_hits; - char *bcache_filename_stats_total_cache_bypass_misses; - char *bcache_filename_stats_total_cache_readaheads; - - RRDSET *st_io; - RRDDIM *rd_io_reads; - RRDDIM *rd_io_writes; - - RRDSET *st_ops; - RRDDIM *rd_ops_reads; - RRDDIM *rd_ops_writes; - - RRDSET *st_qops; - RRDDIM *rd_qops_operations; - - RRDSET *st_backlog; - RRDDIM *rd_backlog_backlog; - - RRDSET *st_util; - RRDDIM *rd_util_utilization; - - RRDSET *st_mops; - RRDDIM *rd_mops_reads; - RRDDIM *rd_mops_writes; - - RRDSET *st_iotime; - RRDDIM *rd_iotime_reads; - RRDDIM *rd_iotime_writes; - - RRDSET *st_await; - RRDDIM *rd_await_reads; - RRDDIM *rd_await_writes; - - RRDSET *st_avgsz; - RRDDIM *rd_avgsz_reads; - RRDDIM *rd_avgsz_writes; - - RRDSET *st_svctm; - RRDDIM *rd_svctm_svctm; - - RRDSET *st_bcache_size; - RRDDIM *rd_bcache_dirty_size; - - RRDSET *st_bcache_usage; - RRDDIM *rd_bcache_available_percent; - - RRDSET *st_bcache_hit_ratio; - RRDDIM *rd_bcache_hit_ratio_5min; - RRDDIM *rd_bcache_hit_ratio_1hour; - RRDDIM *rd_bcache_hit_ratio_1day; - RRDDIM *rd_bcache_hit_ratio_total; - - RRDSET *st_bcache; - RRDDIM *rd_bcache_hits; - RRDDIM *rd_bcache_misses; - RRDDIM *rd_bcache_miss_collisions; - - RRDSET *st_bcache_bypass; - RRDDIM *rd_bcache_bypass_hits; - RRDDIM *rd_bcache_bypass_misses; - - RRDSET *st_bcache_rates; - RRDDIM *rd_bcache_rate_congested; - RRDDIM *rd_bcache_readaheads; - RRDDIM *rd_bcache_rate_writeback; - - struct disk *next; -} *disk_root = NULL; - -#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_is_obsolete(st); (st) = NULL; } } while(st) - -// static char *path_to_get_hw_sector_size = NULL; -// static char *path_to_get_hw_sector_size_partitions = NULL; -static char *path_to_sys_dev_block_major_minor_string = NULL; -static char *path_to_sys_block_device = NULL; -static char *path_to_sys_block_device_bcache = NULL; -static char *path_to_sys_devices_virtual_block_device = NULL; -static char *path_to_device_mapper = NULL; -static char *path_to_device_label = NULL; -static char *path_to_device_id = NULL; -static int name_disks_by_id = CONFIG_BOOLEAN_NO; - -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, - global_do_bcache = CONFIG_BOOLEAN_AUTO, - globals_initialized = 0, - global_cleanup_removed_disks = 1; - -static SIMPLE_PATTERN *excluded_disks = NULL; - -static unsigned long long int bcache_read_number_with_units(const char *filename) { - char buffer[50 + 1]; - if(read_file(filename, buffer, 50) == 0) { - static int unknown_units_error = 10; - - char *end = NULL; - long double value = str2ld(buffer, &end); - if(end && *end) { - if(*end == 'k') - return (unsigned long long int)(value * 1024.0); - else if(*end == 'M') - return (unsigned long long int)(value * 1024.0 * 1024.0); - else if(*end == 'G') - return (unsigned long long int)(value * 1024.0 * 1024.0 * 1024.0); - else if(unknown_units_error > 0) { - error("bcache file '%s' provides value '%s' with unknown units '%s'", filename, buffer, end); - unknown_units_error--; - } - } - - return (unsigned long long int)value; - } - - return 0; -} - -static inline int is_major_enabled(int major) { - static int8_t *major_configs = NULL; - static size_t major_size = 0; - - if(major < 0) return 1; - - size_t wanted_size = (size_t)major + 1; - - if(major_size < wanted_size) { - major_configs = reallocz(major_configs, wanted_size * sizeof(int8_t)); - - size_t i; - for(i = major_size; i < wanted_size ; i++) - major_configs[i] = -1; - - major_size = wanted_size; - } - - 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(CONFIG_SECTION_DISKSTATS, buffer, 1); - } - - return (int)major_configs[major]; -} - -static inline int get_disk_name_from_path(const char *path, char *result, size_t result_size, unsigned long major, unsigned long minor, char *disk) { - char filename[FILENAME_MAX + 1]; - int found = 0; - - result_size--; - - DIR *dir = opendir(path); - if (!dir) { - error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'. Disabling device-mapper support.", disk, major, minor, path); - goto cleanup; - } - - struct dirent *de = NULL; - while ((de = readdir(dir))) { - if(de->d_type != DT_LNK) continue; - - snprintfz(filename, FILENAME_MAX, "%s/%s", path, de->d_name); - ssize_t len = readlink(filename, result, result_size); - if(len <= 0) { - error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot read link '%s'.", disk, major, minor, filename); - continue; - } - - result[len] = '\0'; - if(result[0] != '/') - snprintfz(filename, FILENAME_MAX, "%s/%s", path, result); - else - strncpyz(filename, result, FILENAME_MAX); - - struct stat sb; - if(stat(filename, &sb) == -1) { - error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot stat() file '%s'.", disk, major, minor, filename); - continue; - } - - if((sb.st_mode & S_IFMT) != S_IFBLK) { - // info("DEVICE-MAPPER ('%s', %lu:%lu): file '%s' is not a block device.", disk, major, minor, filename); - continue; - } - - if(major(sb.st_rdev) != major || minor(sb.st_rdev) != minor) { - // info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' does not match %lu:%lu.", disk, major, minor, filename, (unsigned long)major(sb.st_rdev), (unsigned long)minor(sb.st_rdev)); - continue; - } - - // info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' matches.", disk, major, minor, filename); - - strncpy(result, de->d_name, result_size); - found = 1; - break; - } - closedir(dir); - - -cleanup: - - if(!found) - result[0] = '\0'; - - return found; -} - -static inline char *get_disk_name(unsigned long major, unsigned long minor, char *disk) { - char result[FILENAME_MAX + 1] = ""; - - if(!path_to_device_mapper || !*path_to_device_mapper || !get_disk_name_from_path(path_to_device_mapper, result, FILENAME_MAX + 1, major, minor, disk)) - if(!path_to_device_label || !*path_to_device_label || !get_disk_name_from_path(path_to_device_label, result, FILENAME_MAX + 1, major, minor, disk)) - if(name_disks_by_id != CONFIG_BOOLEAN_YES || !path_to_device_id || !*path_to_device_id || !get_disk_name_from_path(path_to_device_id, result, FILENAME_MAX + 1, major, minor, disk)) - strncpy(result, disk, FILENAME_MAX); - - if(!result[0]) - strncpy(result, disk, FILENAME_MAX); - - netdata_fix_chart_name(result); - return strdup(result); -} - -static void get_disk_config(struct disk *d) { - int def_enable = global_enable_new_disks_detected_at_runtime; - - if(def_enable != CONFIG_BOOLEAN_NO && (simple_pattern_matches(excluded_disks, d->device) || simple_pattern_matches(excluded_disks, d->disk))) - def_enable = CONFIG_BOOLEAN_NO; - - char var_name[4096 + 1]; - snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", d->disk); - - 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_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; - d->do_bcache = CONFIG_BOOLEAN_NO; - } - else { - // this disk is enabled - // check its direct settings - - int def_performance = CONFIG_BOOLEAN_AUTO; - - // since this is 'on demand' we can figure the performance settings - // based on the type of disk - - if(!d->device_is_bcache) { - switch(d->type) { - default: - case DISK_TYPE_UNKNOWN: - break; - - case DISK_TYPE_PHYSICAL: - def_performance = global_enable_performance_for_physical_disks; - break; - - case DISK_TYPE_PARTITION: - def_performance = global_enable_performance_for_partitions; - break; - - case DISK_TYPE_VIRTUAL: - def_performance = global_enable_performance_for_virtual_disks; - break; - } - } - - // check if we have to disable performance for this disk - if(def_performance) - def_performance = is_major_enabled((int)d->major); - - // ------------------------------------------------------------ - // now we have def_performance and def_space - // to work further - - // def_performance - // 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_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, - ddo_bcache = CONFIG_BOOLEAN_NO; - - // we enable individual performance charts only when def_performance is not disabled - if(unlikely(def_performance != CONFIG_BOOLEAN_NO)) { - ddo_io = global_do_io, - ddo_ops = global_do_ops, - ddo_mops = global_do_mops, - ddo_iotime = global_do_iotime, - ddo_qops = global_do_qops, - ddo_util = global_do_util, - ddo_backlog = global_do_backlog, - ddo_bcache = global_do_bcache; - } - - d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io); - d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops); - d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops); - d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime); - d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops); - 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); - - if(d->device_is_bcache) - d->do_bcache = config_get_boolean_ondemand(var_name, "bcache", ddo_bcache); - else - d->do_bcache = 0; - } -} - -static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) { - static struct mountinfo *disk_mountinfo_root = NULL; - - struct disk *d; - - // search for it in our RAM list. - // this is sequential, but since we just walk through - // and the number of disks / partitions in a system - // should not be that many, it should be acceptable - for(d = disk_root; d ; d = d->next) - if(unlikely(d->major == major && d->minor == minor)) - return d; - - // not found - // create a new disk structure - d = (struct disk *)callocz(1, sizeof(struct disk)); - - d->disk = get_disk_name(major, minor, disk); - d->device = strdupz(disk); - d->major = major; - d->minor = minor; - d->type = DISK_TYPE_UNKNOWN; // Default type. Changed later if not correct. - d->sector_size = 512; // the default, will be changed below - d->next = NULL; - - // append it to the list - if(unlikely(!disk_root)) - disk_root = d; - else { - struct disk *last; - for(last = disk_root; last->next ;last = last->next); - last->next = d; - } - - char buffer[FILENAME_MAX + 1]; - - // find if it is a physical disk - // by checking if /sys/block/DISK is readable. - snprintfz(buffer, FILENAME_MAX, path_to_sys_block_device, disk); - if(likely(access(buffer, R_OK) == 0)) { - // assign it here, but it will be overwritten if it is not a physical disk - d->type = DISK_TYPE_PHYSICAL; - } - - // find if it is a partition - // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable. - snprintfz(buffer, FILENAME_MAX, path_to_sys_dev_block_major_minor_string, major, minor, "partition"); - if(likely(access(buffer, R_OK) == 0)) { - d->type = DISK_TYPE_PARTITION; - } - else { - // find if it is a virtual disk - // by checking if /sys/devices/virtual/block/DISK is readable. - snprintfz(buffer, FILENAME_MAX, path_to_sys_devices_virtual_block_device, disk); - if(likely(access(buffer, R_OK) == 0)) { - d->type = DISK_TYPE_VIRTUAL; - } - else { - // find if it is a virtual device - // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries - snprintfz(buffer, FILENAME_MAX, path_to_sys_dev_block_major_minor_string, major, minor, "slaves/"); - DIR *dirp = opendir(buffer); - if (likely(dirp != NULL)) { - struct dirent *dp; - while ((dp = readdir(dirp))) { - // . and .. are also files in empty folders. - if (unlikely(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)) { - continue; - } - - d->type = DISK_TYPE_VIRTUAL; - - // Stop the loop after we found one file. - break; - } - if (unlikely(closedir(dirp) == -1)) - error("Unable to close dir %s", buffer); - } - } - } - - // ------------------------------------------------------------------------ - // check if we can find its mount point - - // mountinfo_find() can be called with NULL disk_mountinfo_root - struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor); - if(unlikely(!mi)) { - // mountinfo_free_all can be called with NULL - mountinfo_free_all(disk_mountinfo_root); - disk_mountinfo_root = mountinfo_read(0); - mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor); - } - - if(unlikely(mi)) - d->mount_point = strdupz(mi->mount_point); - else - d->mount_point = NULL; - - // ------------------------------------------------------------------------ - // find the disk sector size - - /* - * sector size is always 512 bytes inside the kernel #3481 - * - { - char tf[FILENAME_MAX + 1], *t; - strncpyz(tf, d->device, FILENAME_MAX); - - // replace all / with ! - for(t = tf; *t ;t++) - if(unlikely(*t == '/')) *t = '!'; - - if(likely(d->type == DISK_TYPE_PARTITION)) - snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size_partitions, d->major, d->minor, tf); - else - snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size, tf); - - FILE *fpss = fopen(buffer, "r"); - if(likely(fpss)) { - char buffer2[1024 + 1]; - char *tmp = fgets(buffer2, 1024, fpss); - - if(likely(tmp)) { - d->sector_size = str2i(tmp); - if(unlikely(d->sector_size <= 0)) { - error("Invalid sector size %d for device %s in %s. Assuming 512.", d->sector_size, d->device, buffer); - d->sector_size = 512; - } - } - else error("Cannot read data for sector size for device %s from %s. Assuming 512.", d->device, buffer); - - fclose(fpss); - } - else error("Cannot read sector size for device %s from %s. Assuming 512.", d->device, buffer); - } - */ - - // ------------------------------------------------------------------------ - // check if the device is a bcache - - struct stat bcache; - snprintfz(buffer, FILENAME_MAX, path_to_sys_block_device_bcache, disk); - if(unlikely(stat(buffer, &bcache) == 0 && (bcache.st_mode & S_IFMT) == S_IFDIR)) { - // we have the 'bcache' directory - d->device_is_bcache = 1; - - char buffer2[FILENAME_MAX + 1]; - - snprintfz(buffer2, FILENAME_MAX, "%s/cache/congested", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_cache_congested = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/readahead", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_readaheads = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/dirty_data", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_dirty_data = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/writeback_rate", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_writeback_rate = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/cache/cache_available_percent", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_cache_available_percent = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_hits", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_hits = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_five_minute/cache_hit_ratio", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_five_minute_cache_hit_ratio = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_hour/cache_hit_ratio", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_hour_cache_hit_ratio = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_day/cache_hit_ratio", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_day_cache_hit_ratio = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_hit_ratio", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_hit_ratio = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_misses", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_misses = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_bypass_hits", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_bypass_hits = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_bypass_misses", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_bypass_misses = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - - snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_miss_collisions", buffer); - if(access(buffer2, R_OK) == 0) - d->bcache_filename_stats_total_cache_miss_collisions = strdupz(buffer2); - else - error("bcache file '%s' cannot be read.", buffer2); - } - - get_disk_config(d); - return d; -} - -int do_proc_diskstats(int update_every, usec_t dt) { - static procfile *ff = NULL; - - if(unlikely(!globals_initialized)) { - globals_initialized = 1; - - 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); - global_do_bcache = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "bcache for all disks", global_do_bcache); - - global_cleanup_removed_disks = config_get_boolean(CONFIG_SECTION_DISKSTATS, "remove charts of removed disks" , global_cleanup_removed_disks); - - char buffer[FILENAME_MAX + 1]; - - snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s"); - path_to_sys_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device", buffer); - - snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/bcache"); - path_to_sys_block_device_bcache = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device bcache", buffer); - - snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/block/%s"); - path_to_sys_devices_virtual_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get virtual block device", buffer); - - snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s"); - path_to_sys_dev_block_major_minor_string = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer); - - //snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size"); - //path_to_get_hw_sector_size = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer); - - //snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size"); - //path_to_get_hw_sector_size_partitions = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size for partitions", buffer); - - snprintfz(buffer, FILENAME_MAX, "%s/dev/mapper", netdata_configured_host_prefix); - path_to_device_mapper = config_get(CONFIG_SECTION_DISKSTATS, "path to device mapper", buffer); - - snprintfz(buffer, FILENAME_MAX, "%s/dev/disk/by-label", netdata_configured_host_prefix); - path_to_device_label = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-label", buffer); - - snprintfz(buffer, FILENAME_MAX, "%s/dev/disk/by-id", netdata_configured_host_prefix); - path_to_device_id = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-id", buffer); - - name_disks_by_id = config_get_boolean(CONFIG_SECTION_DISKSTATS, "name disks by id", name_disks_by_id); - - excluded_disks = simple_pattern_create( - config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DEFAULT_EXCLUDED_DISKS) - , NULL - , SIMPLE_PATTERN_EXACT - ); - } - - // -------------------------------------------------------------------------- - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - collected_number system_read_kb = 0, system_write_kb = 0; - - for(l = 0; l < lines ;l++) { - // -------------------------------------------------------------------------- - // Read parameters - - char *disk; - unsigned long major = 0, minor = 0; - - collected_number reads = 0, mreads = 0, readsectors = 0, readms = 0, - writes = 0, mwrites = 0, writesectors = 0, writems = 0, - queued_ios = 0, busy_ms = 0, backlog_ms = 0; - - collected_number last_reads = 0, last_readsectors = 0, last_readms = 0, - last_writes = 0, last_writesectors = 0, last_writems = 0, - last_busy_ms = 0; - - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 14)) continue; - - major = str2ul(procfile_lineword(ff, l, 0)); - minor = str2ul(procfile_lineword(ff, l, 1)); - disk = procfile_lineword(ff, l, 2); - - // # of reads completed # of writes completed - // This is the total number of reads or writes completed successfully. - reads = str2ull(procfile_lineword(ff, l, 3)); // rd_ios - writes = str2ull(procfile_lineword(ff, l, 7)); // wr_ios - - // # of reads merged # of writes merged - // Reads and writes which are adjacent to each other may be merged for - // efficiency. Thus two 4K reads may become one 8K read before it is - // ultimately handed to the disk, and so it will be counted (and queued) - mreads = str2ull(procfile_lineword(ff, l, 4)); // rd_merges_or_rd_sec - mwrites = str2ull(procfile_lineword(ff, l, 8)); // wr_merges - - // # of sectors read # of sectors written - // This is the total number of sectors read or written successfully. - readsectors = str2ull(procfile_lineword(ff, l, 5)); // rd_sec_or_wr_ios - writesectors = str2ull(procfile_lineword(ff, l, 9)); // wr_sec - - // # of milliseconds spent reading # of milliseconds spent writing - // This is the total number of milliseconds spent by all reads or writes (as - // measured from __make_request() to end_that_request_last()). - readms = str2ull(procfile_lineword(ff, l, 6)); // rd_ticks_or_wr_sec - writems = str2ull(procfile_lineword(ff, l, 10)); // wr_ticks - - // # of I/Os currently in progress - // The only field that should go to zero. Incremented as requests are - // given to appropriate struct request_queue and decremented as they finish. - queued_ios = str2ull(procfile_lineword(ff, l, 11)); // ios_pgr - - // # of milliseconds spent doing I/Os - // This field increases so long as field queued_ios is nonzero. - busy_ms = str2ull(procfile_lineword(ff, l, 12)); // tot_ticks - - // weighted # of milliseconds spent doing I/Os - // This field is incremented at each I/O start, I/O completion, I/O - // merge, or read of these stats by the number of I/Os in progress - // (field queued_ios) times the number of milliseconds spent doing I/O since the - // last update of this field. This can provide an easy measure of both - // I/O completion time and the backlog that may be accumulating. - backlog_ms = str2ull(procfile_lineword(ff, l, 13)); // rq_ticks - - - // -------------------------------------------------------------------------- - // remove slashes from disk names - char *s; - for(s = disk; *s ;s++) - if(*s == '/') *s = '_'; - - // -------------------------------------------------------------------------- - // get a disk structure for the disk - - struct disk *d = get_disk(major, minor, disk); - d->updated = 1; - - // -------------------------------------------------------------------------- - // count the global system disk I/O of physical disks - - if(unlikely(d->type == DISK_TYPE_PHYSICAL)) { - system_read_kb += readsectors * d->sector_size / 1024; - system_write_kb += writesectors * d->sector_size / 1024; - } - - // -------------------------------------------------------------------------- - // Set its family based on mount point - - char *family = d->mount_point; - if(!family) family = d->disk; - - - // -------------------------------------------------------------------------- - // Do performance metrics - - 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 - , d->device - , d->disk - , family - , "disk.io" - , "Disk I/O Bandwidth" - , "kilobytes/s" - , "proc" - , "diskstats" - , 2000 - , update_every - , RRDSET_TYPE_AREA - ); - - d->rd_io_reads = rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL); - d->rd_io_writes = rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_io); - - last_readsectors = rrddim_set_by_pointer(d->st_io, d->rd_io_reads, readsectors); - last_writesectors = rrddim_set_by_pointer(d->st_io, d->rd_io_writes, writesectors); - rrdset_done(d->st_io); - } - - // -------------------------------------------------------------------- - - 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" - , d->device - , d->disk - , family - , "disk.ops" - , "Disk Completed I/O Operations" - , "operations/s" - , "proc" - , "diskstats" - , 2001 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_ops, RRDSET_FLAG_DETAIL); - - d->rd_ops_reads = rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_ops_writes = rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_ops); - - last_reads = rrddim_set_by_pointer(d->st_ops, d->rd_ops_reads, reads); - last_writes = rrddim_set_by_pointer(d->st_ops, d->rd_ops_writes, writes); - rrdset_done(d->st_ops); - } - - // -------------------------------------------------------------------- - - 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" - , d->device - , d->disk - , family - , "disk.qops" - , "Disk Current I/O Operations" - , "operations" - , "proc" - , "diskstats" - , 2002 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_qops, RRDSET_FLAG_DETAIL); - - d->rd_qops_operations = rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_qops); - - rrddim_set_by_pointer(d->st_qops, d->rd_qops_operations, queued_ios); - rrdset_done(d->st_qops); - } - - // -------------------------------------------------------------------- - - 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" - , d->device - , d->disk - , family - , "disk.backlog" - , "Disk Backlog" - , "backlog (ms)" - , "proc" - , "diskstats" - , 2003 - , update_every - , RRDSET_TYPE_AREA - ); - - rrdset_flag_set(d->st_backlog, RRDSET_FLAG_DETAIL); - - d->rd_backlog_backlog = rrddim_add(d->st_backlog, "backlog", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_backlog); - - rrddim_set_by_pointer(d->st_backlog, d->rd_backlog_backlog, backlog_ms); - rrdset_done(d->st_backlog); - } - - // -------------------------------------------------------------------- - - 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" - , d->device - , d->disk - , family - , "disk.util" - , "Disk Utilization Time" - , "% of time working" - , "proc" - , "diskstats" - , 2004 - , update_every - , RRDSET_TYPE_AREA - ); - - rrdset_flag_set(d->st_util, RRDSET_FLAG_DETAIL); - - d->rd_util_utilization = rrddim_add(d->st_util, "utilization", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_util); - - last_busy_ms = rrddim_set_by_pointer(d->st_util, d->rd_util_utilization, busy_ms); - rrdset_done(d->st_util); - } - - // -------------------------------------------------------------------- - - 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" - , d->device - , d->disk - , family - , "disk.mops" - , "Disk Merged Operations" - , "merged operations/s" - , "proc" - , "diskstats" - , 2021 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_mops, RRDSET_FLAG_DETAIL); - - d->rd_mops_reads = rrddim_add(d->st_mops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_mops_writes = rrddim_add(d->st_mops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_mops); - - rrddim_set_by_pointer(d->st_mops, d->rd_mops_reads, mreads); - rrddim_set_by_pointer(d->st_mops, d->rd_mops_writes, mwrites); - rrdset_done(d->st_mops); - } - - // -------------------------------------------------------------------- - - 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" - , d->device - , d->disk - , family - , "disk.iotime" - , "Disk Total I/O Time" - , "milliseconds/s" - , "proc" - , "diskstats" - , 2022 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_iotime, RRDSET_FLAG_DETAIL); - - d->rd_iotime_reads = rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_iotime_writes = rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_iotime); - - last_readms = rrddim_set_by_pointer(d->st_iotime, d->rd_iotime_reads, readms); - last_writems = rrddim_set_by_pointer(d->st_iotime, d->rd_iotime_writes, writems); - rrdset_done(d->st_iotime); - } - - // -------------------------------------------------------------------- - // calculate differential charts - // only if this is not the first time we run - - if(likely(dt)) { - 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" - , d->device - , d->disk - , family - , "disk.await" - , "Average Completed I/O Operation Time" - , "ms per operation" - , "proc" - , "diskstats" - , 2005 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_await, RRDSET_FLAG_DETAIL); - - d->rd_await_reads = rrddim_add(d->st_await, "reads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - d->rd_await_writes = rrddim_add(d->st_await, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_await); - - rrddim_set_by_pointer(d->st_await, d->rd_await_reads, (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0); - rrddim_set_by_pointer(d->st_await, d->rd_await_writes, (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0); - rrdset_done(d->st_await); - } - - 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" - , d->device - , d->disk - , family - , "disk.avgsz" - , "Average Completed I/O Operation Bandwidth" - , "kilobytes per operation" - , "proc" - , "diskstats" - , 2006 - , update_every - , RRDSET_TYPE_AREA - ); - - rrdset_flag_set(d->st_avgsz, RRDSET_FLAG_DETAIL); - - d->rd_avgsz_reads = rrddim_add(d->st_avgsz, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_ABSOLUTE); - d->rd_avgsz_writes = rrddim_add(d->st_avgsz, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_avgsz); - - rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_reads, (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0); - rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_writes, (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0); - rrdset_done(d->st_avgsz); - } - - 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" - , d->device - , d->disk - , family - , "disk.svctm" - , "Average Service Time" - , "ms per operation" - , "proc" - , "diskstats" - , 2007 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_svctm, RRDSET_FLAG_DETAIL); - - d->rd_svctm_svctm = rrddim_add(d->st_svctm, "svctm", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_svctm); - - rrddim_set_by_pointer(d->st_svctm, d->rd_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); - } - } - - // -------------------------------------------------------------------------- - // read bcache metrics and generate the bcache charts - - if(d->device_is_bcache && d->do_bcache != CONFIG_BOOLEAN_NO) { - unsigned long long int - stats_total_cache_bypass_hits = 0, - stats_total_cache_bypass_misses = 0, - stats_total_cache_hits = 0, - stats_total_cache_miss_collisions = 0, - stats_total_cache_misses = 0, - stats_five_minute_cache_hit_ratio = 0, - stats_hour_cache_hit_ratio = 0, - stats_day_cache_hit_ratio = 0, - stats_total_cache_hit_ratio = 0, - cache_available_percent = 0, - cache_readaheads = 0, - cache_congested = 0, - dirty_data = 0, - writeback_rate = 0; - - // read the bcache values - - if(d->bcache_filename_dirty_data) - dirty_data = bcache_read_number_with_units(d->bcache_filename_dirty_data); - - if(d->bcache_filename_writeback_rate) - writeback_rate = bcache_read_number_with_units(d->bcache_filename_writeback_rate); - - if(d->bcache_filename_cache_congested) - cache_congested = bcache_read_number_with_units(d->bcache_filename_cache_congested); - - if(d->bcache_filename_cache_available_percent) - read_single_number_file(d->bcache_filename_cache_available_percent, &cache_available_percent); - - if(d->bcache_filename_stats_five_minute_cache_hit_ratio) - read_single_number_file(d->bcache_filename_stats_five_minute_cache_hit_ratio, &stats_five_minute_cache_hit_ratio); - - if(d->bcache_filename_stats_hour_cache_hit_ratio) - read_single_number_file(d->bcache_filename_stats_hour_cache_hit_ratio, &stats_hour_cache_hit_ratio); - - if(d->bcache_filename_stats_day_cache_hit_ratio) - read_single_number_file(d->bcache_filename_stats_day_cache_hit_ratio, &stats_day_cache_hit_ratio); - - if(d->bcache_filename_stats_total_cache_hit_ratio) - read_single_number_file(d->bcache_filename_stats_total_cache_hit_ratio, &stats_total_cache_hit_ratio); - - if(d->bcache_filename_stats_total_cache_hits) - read_single_number_file(d->bcache_filename_stats_total_cache_hits, &stats_total_cache_hits); - - if(d->bcache_filename_stats_total_cache_misses) - read_single_number_file(d->bcache_filename_stats_total_cache_misses, &stats_total_cache_misses); - - if(d->bcache_filename_stats_total_cache_miss_collisions) - read_single_number_file(d->bcache_filename_stats_total_cache_miss_collisions, &stats_total_cache_miss_collisions); - - if(d->bcache_filename_stats_total_cache_bypass_hits) - read_single_number_file(d->bcache_filename_stats_total_cache_bypass_hits, &stats_total_cache_bypass_hits); - - if(d->bcache_filename_stats_total_cache_bypass_misses) - read_single_number_file(d->bcache_filename_stats_total_cache_bypass_misses, &stats_total_cache_bypass_misses); - - if(d->bcache_filename_stats_total_cache_readaheads) - cache_readaheads = bcache_read_number_with_units(d->bcache_filename_stats_total_cache_readaheads); - - - // update the charts - - { - - if(unlikely(!d->st_bcache_hit_ratio)) { - d->st_bcache_hit_ratio = rrdset_create_localhost( - "disk_bcache_hit_ratio" - , d->device - , d->disk - , family - , "disk.bcache_hit_ratio" - , "BCache Cache Hit Ratio" - , "percentage" - , "proc" - , "diskstats" - , 2120 - , update_every - , RRDSET_TYPE_LINE - ); - - d->rd_bcache_hit_ratio_5min = rrddim_add(d->st_bcache_hit_ratio, "5min", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - d->rd_bcache_hit_ratio_1hour = rrddim_add(d->st_bcache_hit_ratio, "1hour", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - d->rd_bcache_hit_ratio_1day = rrddim_add(d->st_bcache_hit_ratio, "1day", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - d->rd_bcache_hit_ratio_total = rrddim_add(d->st_bcache_hit_ratio, "ever", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_bcache_hit_ratio); - - rrddim_set_by_pointer(d->st_bcache_hit_ratio, d->rd_bcache_hit_ratio_5min, stats_five_minute_cache_hit_ratio); - rrddim_set_by_pointer(d->st_bcache_hit_ratio, d->rd_bcache_hit_ratio_1hour, stats_hour_cache_hit_ratio); - rrddim_set_by_pointer(d->st_bcache_hit_ratio, d->rd_bcache_hit_ratio_1day, stats_day_cache_hit_ratio); - rrddim_set_by_pointer(d->st_bcache_hit_ratio, d->rd_bcache_hit_ratio_total, stats_total_cache_hit_ratio); - rrdset_done(d->st_bcache_hit_ratio); - } - - { - - if(unlikely(!d->st_bcache_rates)) { - d->st_bcache_rates = rrdset_create_localhost( - "disk_bcache_rates" - , d->device - , d->disk - , family - , "disk.bcache_rates" - , "BCache Rates" - , "KB/s" - , "proc" - , "diskstats" - , 2121 - , update_every - , RRDSET_TYPE_AREA - ); - - d->rd_bcache_rate_congested = rrddim_add(d->st_bcache_rates, "congested", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - d->rd_bcache_rate_writeback = rrddim_add(d->st_bcache_rates, "writeback", NULL, -1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_bcache_rates); - - rrddim_set_by_pointer(d->st_bcache_rates, d->rd_bcache_rate_writeback, writeback_rate); - rrddim_set_by_pointer(d->st_bcache_rates, d->rd_bcache_rate_congested, cache_congested); - rrdset_done(d->st_bcache_rates); - } - - { - if(unlikely(!d->st_bcache_size)) { - d->st_bcache_size = rrdset_create_localhost( - "disk_bcache_size" - , d->device - , d->disk - , family - , "disk.bcache_size" - , "BCache Cache Sizes" - , "MB" - , "proc" - , "diskstats" - , 2122 - , update_every - , RRDSET_TYPE_AREA - ); - - d->rd_bcache_dirty_size = rrddim_add(d->st_bcache_size, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_bcache_size); - - rrddim_set_by_pointer(d->st_bcache_size, d->rd_bcache_dirty_size, dirty_data); - rrdset_done(d->st_bcache_size); - } - - { - if(unlikely(!d->st_bcache_usage)) { - d->st_bcache_usage = rrdset_create_localhost( - "disk_bcache_usage" - , d->device - , d->disk - , family - , "disk.bcache_usage" - , "BCache Cache Usage" - , "percent" - , "proc" - , "diskstats" - , 2123 - , update_every - , RRDSET_TYPE_AREA - ); - - d->rd_bcache_available_percent = rrddim_add(d->st_bcache_usage, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(d->st_bcache_usage); - - rrddim_set_by_pointer(d->st_bcache_usage, d->rd_bcache_available_percent, cache_available_percent); - rrdset_done(d->st_bcache_usage); - } - - if(d->do_bcache == CONFIG_BOOLEAN_YES || (d->do_bcache == CONFIG_BOOLEAN_AUTO && (stats_total_cache_hits != 0 || stats_total_cache_misses != 0 || stats_total_cache_miss_collisions != 0))) { - - if(unlikely(!d->st_bcache)) { - d->st_bcache = rrdset_create_localhost( - "disk_bcache" - , d->device - , d->disk - , family - , "disk.bcache" - , "BCache Cache I/O Operations" - , "operations/s" - , "proc" - , "diskstats" - , 2124 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_bcache, RRDSET_FLAG_DETAIL); - - d->rd_bcache_hits = rrddim_add(d->st_bcache, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_bcache_misses = rrddim_add(d->st_bcache, "misses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_bcache_miss_collisions = rrddim_add(d->st_bcache, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_bcache_readaheads = rrddim_add(d->st_bcache, "readaheads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_bcache); - - rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_hits, stats_total_cache_hits); - rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_misses, stats_total_cache_misses); - rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_miss_collisions, stats_total_cache_miss_collisions); - rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_readaheads, cache_readaheads); - rrdset_done(d->st_bcache); - } - - if(d->do_bcache == CONFIG_BOOLEAN_YES || (d->do_bcache == CONFIG_BOOLEAN_AUTO && (stats_total_cache_bypass_hits != 0 || stats_total_cache_bypass_misses != 0))) { - - if(unlikely(!d->st_bcache_bypass)) { - d->st_bcache_bypass = rrdset_create_localhost( - "disk_bcache_bypass" - , d->device - , d->disk - , family - , "disk.bcache_bypass" - , "BCache Cache Bypass I/O Operations" - , "operations/s" - , "proc" - , "diskstats" - , 2125 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_bcache_bypass, RRDSET_FLAG_DETAIL); - - d->rd_bcache_bypass_hits = rrddim_add(d->st_bcache_bypass, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_bcache_bypass_misses = rrddim_add(d->st_bcache_bypass, "misses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(d->st_bcache_bypass); - - rrddim_set_by_pointer(d->st_bcache_bypass, d->rd_bcache_bypass_hits, stats_total_cache_bypass_hits); - rrddim_set_by_pointer(d->st_bcache_bypass, d->rd_bcache_bypass_misses, stats_total_cache_bypass_misses); - rrdset_done(d->st_bcache_bypass); - } - } - } - - - // ------------------------------------------------------------------------ - // update the system total I/O - - if(global_do_io == CONFIG_BOOLEAN_YES || (global_do_io == CONFIG_BOOLEAN_AUTO && (system_read_kb || system_write_kb))) { - static RRDSET *st_io = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_io)) { - st_io = rrdset_create_localhost( - "system" - , "io" - , NULL - , "disk" - , NULL - , "Disk I/O" - , "kilobytes/s" - , "proc" - , "diskstats" - , 150 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_io); - - rrddim_set_by_pointer(st_io, rd_in, system_read_kb); - rrddim_set_by_pointer(st_io, rd_out, system_write_kb); - rrdset_done(st_io); - } - - - // ------------------------------------------------------------------------ - // cleanup removed disks - - struct disk *d = disk_root, *last = NULL; - while(d) { - if(unlikely(global_cleanup_removed_disks && !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); - rrdset_obsolete_and_pointer_null(d->st_bcache); - rrdset_obsolete_and_pointer_null(d->st_bcache_bypass); - rrdset_obsolete_and_pointer_null(d->st_bcache_rates); - rrdset_obsolete_and_pointer_null(d->st_bcache_size); - rrdset_obsolete_and_pointer_null(d->st_bcache_usage); - rrdset_obsolete_and_pointer_null(d->st_bcache_hit_ratio); - - if(d == disk_root) { - disk_root = d = d->next; - last = NULL; - } - else if(last) { - last->next = d = d->next; - } - - freez(t->bcache_filename_dirty_data); - freez(t->bcache_filename_writeback_rate); - freez(t->bcache_filename_cache_congested); - freez(t->bcache_filename_cache_available_percent); - freez(t->bcache_filename_stats_five_minute_cache_hit_ratio); - freez(t->bcache_filename_stats_hour_cache_hit_ratio); - freez(t->bcache_filename_stats_day_cache_hit_ratio); - freez(t->bcache_filename_stats_total_cache_hit_ratio); - freez(t->bcache_filename_stats_total_cache_hits); - freez(t->bcache_filename_stats_total_cache_misses); - freez(t->bcache_filename_stats_total_cache_miss_collisions); - freez(t->bcache_filename_stats_total_cache_bypass_hits); - freez(t->bcache_filename_stats_total_cache_bypass_misses); - freez(t->bcache_filename_stats_total_cache_readaheads); - - freez(t->disk); - freez(t->device); - freez(t->mount_point); - freez(t); - } - else { - d->updated = 0; - last = d; - d = d->next; - } - } - - return 0; -} diff --git a/src/proc_interrupts.c b/src/proc_interrupts.c deleted file mode 100644 index 867f39eb2..000000000 --- a/src/proc_interrupts.c +++ /dev/null @@ -1,253 +0,0 @@ -#include "common.h" - -#define MAX_INTERRUPT_NAME 50 - -struct cpu_interrupt { - unsigned long long value; - RRDDIM *rd; -}; - -struct interrupt { - int used; - char *id; - char name[MAX_INTERRUPT_NAME + 1]; - RRDDIM *rd; - unsigned long long total; - struct cpu_interrupt cpu[]; -}; - -// since each interrupt is variable in size -// we use this to calculate its record size -#define recordsize(cpus) (sizeof(struct interrupt) + ((cpus) * sizeof(struct cpu_interrupt))) - -// given a base, get a pointer to each record -#define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[(line) * recordsize(cpus)]) - -static inline struct interrupt *get_interrupts_array(size_t lines, int cpus) { - static struct interrupt *irrs = NULL; - static size_t allocated = 0; - - if(unlikely(lines != allocated)) { - size_t l; - int c; - - irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus)); - - // reset all interrupt RRDDIM pointers as any line could have shifted - for(l = 0; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - irr->rd = NULL; - irr->name[0] = '\0'; - for(c = 0; c < cpus ;c++) - irr->cpu[c].rd = NULL; - } - - allocated = lines; - } - - return irrs; -} - -int do_proc_interrupts(int update_every, usec_t dt) { - (void)dt; - static procfile *ff = NULL; - static int cpus = -1, do_per_core = -1; - struct interrupt *irrs = NULL; - - if(unlikely(do_per_core == -1)) - do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1); - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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)) - return 1; - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - size_t words = procfile_linewords(ff, 0); - - if(unlikely(!lines)) { - error("Cannot read /proc/interrupts, zero lines reported."); - return 1; - } - - // find how many CPUs are there - if(unlikely(cpus == -1)) { - uint32_t w; - cpus = 0; - for(w = 0; w < words ; w++) { - if(likely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)) - cpus++; - } - } - - if(unlikely(!cpus)) { - error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts"); - return 1; - } - - // allocate the size we need; - irrs = get_interrupts_array(lines, cpus); - irrs[0].used = 0; - - // loop through all lines - for(l = 1; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - irr->used = 0; - irr->total = 0; - - words = procfile_linewords(ff, l); - if(unlikely(!words)) continue; - - irr->id = procfile_lineword(ff, l, 0); - if(unlikely(!irr->id || !irr->id[0])) continue; - - size_t idlen = strlen(irr->id); - if(unlikely(idlen && irr->id[idlen - 1] == ':')) - irr->id[idlen - 1] = '\0'; - - int c; - for(c = 0; c < cpus ;c++) { - if(likely((c + 1) < (int)words)) - irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t)(c + 1))); - else - irr->cpu[c].value = 0; - - irr->total += irr->cpu[c].value; - } - - if(unlikely(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words)) { - strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME); - size_t nlen = strlen(irr->name); - idlen = strlen(irr->id); - if(likely(nlen + 1 + idlen <= MAX_INTERRUPT_NAME)) { - irr->name[nlen] = '_'; - strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen - 1); - } - else { - irr->name[MAX_INTERRUPT_NAME - idlen - 1] = '_'; - strncpyz(&irr->name[MAX_INTERRUPT_NAME - idlen], irr->id, idlen); - } - } - else { - strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME); - } - - irr->used = 1; - } - - // -------------------------------------------------------------------- - - static RRDSET *st_system_interrupts = NULL; - if(unlikely(!st_system_interrupts)) - st_system_interrupts = rrdset_create_localhost( - "system" - , "interrupts" - , NULL - , "interrupts" - , NULL - , "System interrupts" - , "interrupts/s" - , "proc" - , "interrupts" - , 1000 - , update_every - , RRDSET_TYPE_STACKED - ); - else - rrdset_next(st_system_interrupts); - - for(l = 0; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - if(unlikely(!irr->used)) continue; - - // some interrupt may have changed without changing the total number of lines - // if the same number of interrupts have been added and removed between two - // calls of this function. - if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) { - irr->rd = rrddim_find(st_system_interrupts, irr->id); - - if(unlikely(!irr->rd)) - irr->rd = rrddim_add(st_system_interrupts, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL); - else - rrddim_set_name(st_system_interrupts, irr->rd, irr->name); - - // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop - if(likely(do_per_core)) { - int c; - for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL; - } - } - - rrddim_set_by_pointer(st_system_interrupts, irr->rd, irr->total); - } - - rrdset_done(st_system_interrupts); - - // -------------------------------------------------------------------- - - if(likely(do_per_core)) { - static RRDSET **core_st = NULL; - static int old_cpus = 0; - - if(old_cpus < cpus) { - core_st = reallocz(core_st, sizeof(RRDSET *) * cpus); - memset(&core_st[old_cpus], 0, sizeof(RRDSET *) * (cpus - old_cpus)); - old_cpus = cpus; - } - - int c; - - for(c = 0; c < cpus ;c++) { - if(unlikely(!core_st[c])) { - char id[50+1]; - snprintfz(id, 50, "cpu%d_interrupts", c); - - char title[100+1]; - snprintfz(title, 100, "CPU%d Interrupts", c); - core_st[c] = rrdset_create_localhost( - "cpu" - , id - , NULL - , "interrupts" - , "cpu.interrupts" - , title - , "interrupts/s" - , "proc" - , "interrupts" - , 1100 + c - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(core_st[c]); - - for(l = 0; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - - if(unlikely(!irr->used)) continue; - - if(unlikely(!irr->cpu[c].rd)) { - irr->cpu[c].rd = rrddim_find(core_st[c], irr->id); - - if(unlikely(!irr->cpu[c].rd)) - irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL); - else - rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name); - } - - rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value); - } - - rrdset_done(core_st[c]); - } - } - - return 0; -} diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c deleted file mode 100644 index 868f7d50a..000000000 --- a/src/proc_loadavg.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "common.h" - -// linux calculates this once every 5 seconds -#define MIN_LOADAVG_UPDATE_EVERY 5 - -int do_proc_loadavg(int update_every, usec_t dt) { - static procfile *ff = NULL; - static int do_loadavg = -1, do_all_processes = -1; - static usec_t next_loadavg_dt = 0; - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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)) - return 1; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - if(unlikely(do_loadavg == -1)) { - do_loadavg = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1); - do_all_processes = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1); - } - - if(unlikely(procfile_lines(ff) < 1)) { - error("/proc/loadavg has no lines."); - return 1; - } - if(unlikely(procfile_linewords(ff, 0) < 6)) { - error("/proc/loadavg has less than 6 words in it."); - return 1; - } - - double load1 = strtod(procfile_lineword(ff, 0, 0), NULL); - double load5 = strtod(procfile_lineword(ff, 0, 1), NULL); - double load15 = strtod(procfile_lineword(ff, 0, 2), NULL); - - //unsigned long long running_processes = str2ull(procfile_lineword(ff, 0, 3)); - unsigned long long active_processes = str2ull(procfile_lineword(ff, 0, 4)); - //unsigned long long next_pid = str2ull(procfile_lineword(ff, 0, 5)); - - - // -------------------------------------------------------------------- - - if(next_loadavg_dt <= dt) { - if(likely(do_loadavg)) { - static RRDSET *load_chart = NULL; - static RRDDIM *rd_load1 = NULL, *rd_load5 = NULL, *rd_load15 = NULL; - - if(unlikely(!load_chart)) { - load_chart = rrdset_create_localhost( - "system" - , "load" - , NULL - , "load" - , NULL - , "System Load Average" - , "load" - , "proc" - , "loadavg" - , 100 - , (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every - , RRDSET_TYPE_LINE - ); - - rd_load1 = rrddim_add(load_chart, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_load5 = rrddim_add(load_chart, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_load15 = rrddim_add(load_chart, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(load_chart); - - rrddim_set_by_pointer(load_chart, rd_load1, (collected_number) (load1 * 1000)); - rrddim_set_by_pointer(load_chart, rd_load5, (collected_number) (load5 * 1000)); - rrddim_set_by_pointer(load_chart, rd_load15, (collected_number) (load15 * 1000)); - rrdset_done(load_chart); - - next_loadavg_dt = load_chart->update_every * USEC_PER_SEC; - } - else next_loadavg_dt = MIN_LOADAVG_UPDATE_EVERY * USEC_PER_SEC; - } - else next_loadavg_dt -= dt; - - // -------------------------------------------------------------------- - - if(likely(do_all_processes)) { - static RRDSET *processes_chart = NULL; - static RRDDIM *rd_active = NULL; - - if(unlikely(!processes_chart)) { - processes_chart = rrdset_create_localhost( - "system" - , "active_processes" - , NULL - , "processes" - , NULL - , "System Active Processes" - , "processes" - , "proc" - , "loadavg" - , 750 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_active = rrddim_add(processes_chart, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(processes_chart); - - rrddim_set_by_pointer(processes_chart, rd_active, active_processes); - rrdset_done(processes_chart); - } - - return 0; -} diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c deleted file mode 100644 index 3915bf0e9..000000000 --- a/src/proc_meminfo.c +++ /dev/null @@ -1,514 +0,0 @@ -#include "common.h" - -int do_proc_meminfo(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - static int do_ram = -1, do_swap = -1, do_hwcorrupt = -1, do_committed = -1, do_writeback = -1, do_kernel = -1, do_slab = -1, do_hugepages = -1, do_transparent_hugepages = -1; - - static ARL_BASE *arl_base = NULL; - static ARL_ENTRY *arl_hwcorrupted = NULL, *arl_memavailable = NULL; - - static unsigned long long - MemTotal = 0, - MemFree = 0, - MemAvailable = 0, - Buffers = 0, - Cached = 0, - //SwapCached = 0, - //Active = 0, - //Inactive = 0, - //ActiveAnon = 0, - //InactiveAnon = 0, - //ActiveFile = 0, - //InactiveFile = 0, - //Unevictable = 0, - //Mlocked = 0, - SwapTotal = 0, - SwapFree = 0, - Dirty = 0, - Writeback = 0, - //AnonPages = 0, - //Mapped = 0, - //Shmem = 0, - Slab = 0, - SReclaimable = 0, - SUnreclaim = 0, - KernelStack = 0, - PageTables = 0, - NFS_Unstable = 0, - Bounce = 0, - WritebackTmp = 0, - //CommitLimit = 0, - Committed_AS = 0, - //VmallocTotal = 0, - VmallocUsed = 0, - //VmallocChunk = 0, - AnonHugePages = 0, - ShmemHugePages = 0, - HugePages_Total = 0, - HugePages_Free = 0, - HugePages_Rsvd = 0, - HugePages_Surp = 0, - Hugepagesize = 0, - //DirectMap4k = 0, - //DirectMap2M = 0, - HardwareCorrupted = 0; - - 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_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); - do_slab = config_get_boolean("plugin:proc:/proc/meminfo", "slab memory", 1); - do_hugepages = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hugepages", CONFIG_BOOLEAN_AUTO); - do_transparent_hugepages = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "transparent hugepages", CONFIG_BOOLEAN_AUTO); - - arl_base = arl_create("meminfo", NULL, 60); - arl_expect(arl_base, "MemTotal", &MemTotal); - arl_expect(arl_base, "MemFree", &MemFree); - arl_memavailable = arl_expect(arl_base, "MemAvailable", &MemAvailable); - arl_expect(arl_base, "Buffers", &Buffers); - arl_expect(arl_base, "Cached", &Cached); - //arl_expect(arl_base, "SwapCached", &SwapCached); - //arl_expect(arl_base, "Active", &Active); - //arl_expect(arl_base, "Inactive", &Inactive); - //arl_expect(arl_base, "ActiveAnon", &ActiveAnon); - //arl_expect(arl_base, "InactiveAnon", &InactiveAnon); - //arl_expect(arl_base, "ActiveFile", &ActiveFile); - //arl_expect(arl_base, "InactiveFile", &InactiveFile); - //arl_expect(arl_base, "Unevictable", &Unevictable); - //arl_expect(arl_base, "Mlocked", &Mlocked); - arl_expect(arl_base, "SwapTotal", &SwapTotal); - arl_expect(arl_base, "SwapFree", &SwapFree); - arl_expect(arl_base, "Dirty", &Dirty); - arl_expect(arl_base, "Writeback", &Writeback); - //arl_expect(arl_base, "AnonPages", &AnonPages); - //arl_expect(arl_base, "Mapped", &Mapped); - //arl_expect(arl_base, "Shmem", &Shmem); - arl_expect(arl_base, "Slab", &Slab); - arl_expect(arl_base, "SReclaimable", &SReclaimable); - arl_expect(arl_base, "SUnreclaim", &SUnreclaim); - arl_expect(arl_base, "KernelStack", &KernelStack); - arl_expect(arl_base, "PageTables", &PageTables); - arl_expect(arl_base, "NFS_Unstable", &NFS_Unstable); - arl_expect(arl_base, "Bounce", &Bounce); - arl_expect(arl_base, "WritebackTmp", &WritebackTmp); - //arl_expect(arl_base, "CommitLimit", &CommitLimit); - arl_expect(arl_base, "Committed_AS", &Committed_AS); - //arl_expect(arl_base, "VmallocTotal", &VmallocTotal); - arl_expect(arl_base, "VmallocUsed", &VmallocUsed); - //arl_expect(arl_base, "VmallocChunk", &VmallocChunk); - arl_hwcorrupted = arl_expect(arl_base, "HardwareCorrupted", &HardwareCorrupted); - arl_expect(arl_base, "AnonHugePages", &AnonHugePages); - arl_expect(arl_base, "ShmemHugePages", &ShmemHugePages); - arl_expect(arl_base, "HugePages_Total", &HugePages_Total); - arl_expect(arl_base, "HugePages_Free", &HugePages_Free); - arl_expect(arl_base, "HugePages_Rsvd", &HugePages_Rsvd); - arl_expect(arl_base, "HugePages_Surp", &HugePages_Surp); - arl_expect(arl_base, "Hugepagesize", &Hugepagesize); - //arl_expect(arl_base, "DirectMap4k", &DirectMap4k); - //arl_expect(arl_base, "DirectMap2M", &DirectMap2M); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - arl_begin(arl_base); - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 2)) continue; - - if(unlikely(arl_check(arl_base, - procfile_lineword(ff, l, 0), - procfile_lineword(ff, l, 1)))) break; - } - - // -------------------------------------------------------------------- - - // http://stackoverflow.com/questions/3019748/how-to-reliably-measure-available-memory-in-linux - unsigned long long MemCached = Cached + Slab; - unsigned long long MemUsed = MemTotal - MemFree - MemCached - Buffers; - - if(do_ram) { - { - static RRDSET *st_system_ram = NULL; - static RRDDIM *rd_free = NULL, *rd_used = NULL, *rd_cached = NULL, *rd_buffers = NULL; - - if(unlikely(!st_system_ram)) { - st_system_ram = rrdset_create_localhost( - "system" - , "ram" - , NULL - , "ram" - , NULL - , "System RAM" - , "MB" - , "proc" - , "meminfo" - , 200 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_cached = rrddim_add(st_system_ram, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_buffers = rrddim_add(st_system_ram, "buffers", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_system_ram); - - rrddim_set_by_pointer(st_system_ram, rd_free, MemFree); - rrddim_set_by_pointer(st_system_ram, rd_used, MemUsed); - rrddim_set_by_pointer(st_system_ram, rd_cached, MemCached); - rrddim_set_by_pointer(st_system_ram, rd_buffers, Buffers); - - rrdset_done(st_system_ram); - } - - if(arl_memavailable->flags & ARL_ENTRY_FLAG_FOUND) { - static RRDSET *st_mem_available = NULL; - static RRDDIM *rd_avail = NULL; - - if(unlikely(!st_mem_available)) { - st_mem_available = rrdset_create_localhost( - "mem" - , "available" - , NULL - , "system" - , NULL - , "Available RAM for applications" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE - , update_every - , RRDSET_TYPE_AREA - ); - - rd_avail = rrddim_add(st_mem_available, "MemAvailable", "avail", 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_available); - - rrddim_set_by_pointer(st_mem_available, rd_avail, MemAvailable); - - rrdset_done(st_mem_available); - } - } - - // -------------------------------------------------------------------- - - unsigned long long SwapUsed = SwapTotal - SwapFree; - - if(do_swap == CONFIG_BOOLEAN_YES || SwapTotal || SwapUsed || SwapFree) { - do_swap = CONFIG_BOOLEAN_YES; - - static RRDSET *st_system_swap = NULL; - static RRDDIM *rd_free = NULL, *rd_used = NULL; - - if(unlikely(!st_system_swap)) { - st_system_swap = rrdset_create_localhost( - "system" - , "swap" - , NULL - , "swap" - , NULL - , "System Swap" - , "MB" - , "proc" - , "meminfo" - , 201 - , update_every - , RRDSET_TYPE_STACKED - ); - - rrdset_flag_set(st_system_swap, RRDSET_FLAG_DETAIL); - - rd_free = rrddim_add(st_system_swap, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_used = rrddim_add(st_system_swap, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_system_swap); - - rrddim_set_by_pointer(st_system_swap, rd_used, SwapUsed); - rrddim_set_by_pointer(st_system_swap, rd_free, SwapFree); - - rrdset_done(st_system_swap); - } - - // -------------------------------------------------------------------- - - 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; - - static RRDSET *st_mem_hwcorrupt = NULL; - static RRDDIM *rd_corrupted = NULL; - - if(unlikely(!st_mem_hwcorrupt)) { - st_mem_hwcorrupt = rrdset_create_localhost( - "mem" - , "hwcorrupt" - , NULL - , "ecc" - , NULL - , "Corrupted Memory, detected by ECC" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_HW - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_mem_hwcorrupt, RRDSET_FLAG_DETAIL); - - rd_corrupted = rrddim_add(st_mem_hwcorrupt, "HardwareCorrupted", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_hwcorrupt); - - rrddim_set_by_pointer(st_mem_hwcorrupt, rd_corrupted, HardwareCorrupted); - - rrdset_done(st_mem_hwcorrupt); - } - - // -------------------------------------------------------------------- - - if(do_committed) { - static RRDSET *st_mem_committed = NULL; - static RRDDIM *rd_committed = NULL; - - if(unlikely(!st_mem_committed)) { - st_mem_committed = rrdset_create_localhost( - "mem" - , "committed" - , NULL - , "system" - , NULL - , "Committed (Allocated) Memory" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED - , update_every - , RRDSET_TYPE_AREA - ); - - rrdset_flag_set(st_mem_committed, RRDSET_FLAG_DETAIL); - - rd_committed = rrddim_add(st_mem_committed, "Committed_AS", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_committed); - - rrddim_set_by_pointer(st_mem_committed, rd_committed, Committed_AS); - - rrdset_done(st_mem_committed); - } - - // -------------------------------------------------------------------- - - if(do_writeback) { - static RRDSET *st_mem_writeback = NULL; - static RRDDIM *rd_dirty = NULL, *rd_writeback = NULL, *rd_fusewriteback = NULL, *rd_nfs_writeback = NULL, *rd_bounce = NULL; - - if(unlikely(!st_mem_writeback)) { - st_mem_writeback = rrdset_create_localhost( - "mem" - , "writeback" - , NULL - , "kernel" - , NULL - , "Writeback Memory" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_KERNEL - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st_mem_writeback, RRDSET_FLAG_DETAIL); - - rd_dirty = rrddim_add(st_mem_writeback, "Dirty", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_writeback = rrddim_add(st_mem_writeback, "Writeback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_fusewriteback = rrddim_add(st_mem_writeback, "FuseWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_nfs_writeback = rrddim_add(st_mem_writeback, "NfsWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_bounce = rrddim_add(st_mem_writeback, "Bounce", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_writeback); - - rrddim_set_by_pointer(st_mem_writeback, rd_dirty, Dirty); - rrddim_set_by_pointer(st_mem_writeback, rd_writeback, Writeback); - rrddim_set_by_pointer(st_mem_writeback, rd_fusewriteback, WritebackTmp); - rrddim_set_by_pointer(st_mem_writeback, rd_nfs_writeback, NFS_Unstable); - rrddim_set_by_pointer(st_mem_writeback, rd_bounce, Bounce); - - rrdset_done(st_mem_writeback); - } - - // -------------------------------------------------------------------- - - if(do_kernel) { - static RRDSET *st_mem_kernel = NULL; - static RRDDIM *rd_slab = NULL, *rd_kernelstack = NULL, *rd_pagetables = NULL, *rd_vmallocused = NULL; - - if(unlikely(!st_mem_kernel)) { - st_mem_kernel = rrdset_create_localhost( - "mem" - , "kernel" - , NULL - , "kernel" - , NULL - , "Memory Used by Kernel" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_KERNEL + 1 - , update_every - , RRDSET_TYPE_STACKED - ); - - rrdset_flag_set(st_mem_kernel, RRDSET_FLAG_DETAIL); - - rd_slab = rrddim_add(st_mem_kernel, "Slab", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_kernelstack = rrddim_add(st_mem_kernel, "KernelStack", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_pagetables = rrddim_add(st_mem_kernel, "PageTables", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_vmallocused = rrddim_add(st_mem_kernel, "VmallocUsed", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_kernel); - - rrddim_set_by_pointer(st_mem_kernel, rd_slab, Slab); - rrddim_set_by_pointer(st_mem_kernel, rd_kernelstack, KernelStack); - rrddim_set_by_pointer(st_mem_kernel, rd_pagetables, PageTables); - rrddim_set_by_pointer(st_mem_kernel, rd_vmallocused, VmallocUsed); - - rrdset_done(st_mem_kernel); - } - - // -------------------------------------------------------------------- - - if(do_slab) { - static RRDSET *st_mem_slab = NULL; - static RRDDIM *rd_reclaimable = NULL, *rd_unreclaimable = NULL; - - if(unlikely(!st_mem_slab)) { - st_mem_slab = rrdset_create_localhost( - "mem" - , "slab" - , NULL - , "slab" - , NULL - , "Reclaimable Kernel Memory" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_SLAB - , update_every - , RRDSET_TYPE_STACKED - ); - - rrdset_flag_set(st_mem_slab, RRDSET_FLAG_DETAIL); - - rd_reclaimable = rrddim_add(st_mem_slab, "reclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_unreclaimable = rrddim_add(st_mem_slab, "unreclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_slab); - - rrddim_set_by_pointer(st_mem_slab, rd_reclaimable, SReclaimable); - rrddim_set_by_pointer(st_mem_slab, rd_unreclaimable, SUnreclaim); - - rrdset_done(st_mem_slab); - } - - // -------------------------------------------------------------------- - - if(do_hugepages == CONFIG_BOOLEAN_YES || (do_hugepages == CONFIG_BOOLEAN_AUTO && Hugepagesize != 0 && HugePages_Total != 0)) { - do_hugepages = CONFIG_BOOLEAN_YES; - - static RRDSET *st_mem_hugepages = NULL; - static RRDDIM *rd_used = NULL, *rd_free = NULL, *rd_rsvd = NULL, *rd_surp = NULL; - - if(unlikely(!st_mem_hugepages)) { - st_mem_hugepages = rrdset_create_localhost( - "mem" - , "hugepages" - , NULL - , "hugepages" - , NULL - , "Dedicated HugePages Memory" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_HUGEPAGES + 1 - , update_every - , RRDSET_TYPE_STACKED - ); - - rrdset_flag_set(st_mem_hugepages, RRDSET_FLAG_DETAIL); - - rd_free = rrddim_add(st_mem_hugepages, "free", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_used = rrddim_add(st_mem_hugepages, "used", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_surp = rrddim_add(st_mem_hugepages, "surplus", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_rsvd = rrddim_add(st_mem_hugepages, "reserved", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_hugepages); - - rrddim_set_by_pointer(st_mem_hugepages, rd_used, HugePages_Total - HugePages_Free - HugePages_Rsvd); - rrddim_set_by_pointer(st_mem_hugepages, rd_free, HugePages_Free); - rrddim_set_by_pointer(st_mem_hugepages, rd_rsvd, HugePages_Rsvd); - rrddim_set_by_pointer(st_mem_hugepages, rd_surp, HugePages_Surp); - - rrdset_done(st_mem_hugepages); - } - - // -------------------------------------------------------------------- - - if(do_transparent_hugepages == CONFIG_BOOLEAN_YES || (do_transparent_hugepages == CONFIG_BOOLEAN_AUTO && (AnonHugePages != 0 || ShmemHugePages != 0))) { - do_transparent_hugepages = CONFIG_BOOLEAN_YES; - - static RRDSET *st_mem_transparent_hugepages = NULL; - static RRDDIM *rd_anonymous = NULL, *rd_shared = NULL; - - if(unlikely(!st_mem_transparent_hugepages)) { - st_mem_transparent_hugepages = rrdset_create_localhost( - "mem" - , "transparent_hugepages" - , NULL - , "hugepages" - , NULL - , "Transparent HugePages Memory" - , "MB" - , "proc" - , "meminfo" - , NETDATA_CHART_PRIO_MEM_HUGEPAGES - , update_every - , RRDSET_TYPE_STACKED - ); - - rrdset_flag_set(st_mem_transparent_hugepages, RRDSET_FLAG_DETAIL); - - rd_anonymous = rrddim_add(st_mem_transparent_hugepages, "anonymous", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - rd_shared = rrddim_add(st_mem_transparent_hugepages, "shmem", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_mem_transparent_hugepages); - - rrddim_set_by_pointer(st_mem_transparent_hugepages, rd_anonymous, AnonHugePages); - rrddim_set_by_pointer(st_mem_transparent_hugepages, rd_shared, ShmemHugePages); - - rrdset_done(st_mem_transparent_hugepages); - } - - return 0; -} - diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c deleted file mode 100644 index 341b9e0ca..000000000 --- a/src/proc_net_dev.c +++ /dev/null @@ -1,894 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// netdev list - -static struct netdev { - char *name; - uint32_t hash; - size_t len; - - // flags - int virtual; - int configured; - int enabled; - int updated; - - int do_bandwidth; - int do_packets; - int do_errors; - int do_drops; - int do_fifo; - int do_compressed; - int do_events; - - const char *chart_type_net_bytes; - const char *chart_type_net_packets; - const char *chart_type_net_errors; - const char *chart_type_net_fifo; - const char *chart_type_net_events; - const char *chart_type_net_drops; - const char *chart_type_net_compressed; - - const char *chart_id_net_bytes; - const char *chart_id_net_packets; - const char *chart_id_net_errors; - const char *chart_id_net_fifo; - const char *chart_id_net_events; - const char *chart_id_net_drops; - const char *chart_id_net_compressed; - - const char *chart_family; - - int flipped; - unsigned long priority; - - // data collected - kernel_uint_t rbytes; - kernel_uint_t rpackets; - 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; - RRDSET *st_packets; - RRDSET *st_errors; - RRDSET *st_drops; - RRDSET *st_fifo; - RRDSET *st_compressed; - RRDSET *st_events; - - // dimensions - RRDDIM *rd_rbytes; - RRDDIM *rd_rpackets; - RRDDIM *rd_rerrors; - RRDDIM *rd_rdrops; - RRDDIM *rd_rfifo; - RRDDIM *rd_rframe; - RRDDIM *rd_rcompressed; - RRDDIM *rd_rmulticast; - - RRDDIM *rd_tbytes; - RRDDIM *rd_tpackets; - RRDDIM *rd_terrors; - RRDDIM *rd_tdrops; - RRDDIM *rd_tfifo; - RRDDIM *rd_tcollisions; - RRDDIM *rd_tcarrier; - RRDDIM *rd_tcompressed; - - struct netdev *next; -} *netdev_root = NULL, *netdev_last_used = NULL; - -static size_t netdev_added = 0, netdev_found = 0; - -// ---------------------------------------------------------------------------- - -static void netdev_charts_release(struct netdev *d) { - if(d->st_bandwidth) rrdset_is_obsolete(d->st_bandwidth); - if(d->st_packets) rrdset_is_obsolete(d->st_packets); - if(d->st_errors) rrdset_is_obsolete(d->st_errors); - if(d->st_drops) rrdset_is_obsolete(d->st_drops); - if(d->st_fifo) rrdset_is_obsolete(d->st_fifo); - if(d->st_compressed) rrdset_is_obsolete(d->st_compressed); - if(d->st_events) rrdset_is_obsolete(d->st_events); - - d->st_bandwidth = NULL; - d->st_compressed = NULL; - d->st_drops = NULL; - d->st_errors = NULL; - d->st_events = NULL; - d->st_fifo = NULL; - d->st_packets = NULL; - - d->rd_rbytes = NULL; - d->rd_rpackets = NULL; - d->rd_rerrors = NULL; - d->rd_rdrops = NULL; - d->rd_rfifo = NULL; - d->rd_rframe = NULL; - d->rd_rcompressed = NULL; - d->rd_rmulticast = NULL; - - d->rd_tbytes = NULL; - d->rd_tpackets = NULL; - d->rd_terrors = NULL; - d->rd_tdrops = NULL; - d->rd_tfifo = NULL; - d->rd_tcollisions = NULL; - d->rd_tcarrier = NULL; - d->rd_tcompressed = NULL; -} - -static void netdev_free_strings(struct netdev *d) { - freez((void *)d->chart_type_net_bytes); - freez((void *)d->chart_type_net_compressed); - freez((void *)d->chart_type_net_drops); - freez((void *)d->chart_type_net_errors); - freez((void *)d->chart_type_net_events); - freez((void *)d->chart_type_net_fifo); - freez((void *)d->chart_type_net_packets); - - freez((void *)d->chart_id_net_bytes); - freez((void *)d->chart_id_net_compressed); - freez((void *)d->chart_id_net_drops); - freez((void *)d->chart_id_net_errors); - freez((void *)d->chart_id_net_events); - freez((void *)d->chart_id_net_fifo); - freez((void *)d->chart_id_net_packets); - - freez((void *)d->chart_family); -} - -static void netdev_free(struct netdev *d) { - netdev_charts_release(d); - netdev_free_strings(d); - - freez((void *)d->name); - freez((void *)d); - netdev_added--; -} - - -// ---------------------------------------------------------------------------- -// netdev renames - -static struct netdev_rename { - const char *host_device; - uint32_t hash; - - const char *container_device; - const char *container_name; - - int processed; - - struct netdev_rename *next; -} *netdev_rename_root = NULL; - -static int netdev_pending_renames = 0; -static netdata_mutex_t netdev_rename_mutex = NETDATA_MUTEX_INITIALIZER; - -static struct netdev_rename *netdev_rename_find(const char *host_device, uint32_t hash) { - struct netdev_rename *r; - - for(r = netdev_rename_root; r ; r = r->next) - if(r->hash == hash && !strcmp(host_device, r->host_device)) - return r; - - return NULL; -} - -// other threads can call this function to register a rename to a netdev -void netdev_rename_device_add(const char *host_device, const char *container_device, const char *container_name) { - netdata_mutex_lock(&netdev_rename_mutex); - - uint32_t hash = simple_hash(host_device); - struct netdev_rename *r = netdev_rename_find(host_device, hash); - if(!r) { - r = callocz(1, sizeof(struct netdev_rename)); - r->host_device = strdupz(host_device); - r->container_device = strdupz(container_device); - r->container_name = strdupz(container_name); - r->hash = hash; - r->next = netdev_rename_root; - r->processed = 0; - netdev_rename_root = r; - netdev_pending_renames++; - info("CGROUP: registered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name); - } - else { - if(strcmp(r->container_device, container_device) != 0 || strcmp(r->container_name, container_name) != 0) { - freez((void *) r->container_device); - freez((void *) r->container_name); - - r->container_device = strdupz(container_device); - r->container_name = strdupz(container_name); - r->processed = 0; - netdev_pending_renames++; - info("CGROUP: altered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name); - } - } - - netdata_mutex_unlock(&netdev_rename_mutex); -} - -// other threads can call this function to delete a rename to a netdev -void netdev_rename_device_del(const char *host_device) { - netdata_mutex_lock(&netdev_rename_mutex); - - struct netdev_rename *r, *last = NULL; - - uint32_t hash = simple_hash(host_device); - for(r = netdev_rename_root; r ; last = r, r = r->next) { - if (r->hash == hash && !strcmp(host_device, r->host_device)) { - if (netdev_rename_root == r) - netdev_rename_root = r->next; - else if (last) - last->next = r->next; - - if(!r->processed) - netdev_pending_renames--; - - info("CGROUP: unregistered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name); - - freez((void *) r->host_device); - freez((void *) r->container_name); - freez((void *) r->container_device); - freez((void *) r); - break; - } - } - - netdata_mutex_unlock(&netdev_rename_mutex); -} - -static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *r) { - info("CGROUP: renaming network interface '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name); - - netdev_charts_release(d); - netdev_free_strings(d); - - char buffer[RRD_ID_LENGTH_MAX + 1]; - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "cgroup_%s", r->container_name); - d->chart_type_net_bytes = strdupz(buffer); - d->chart_type_net_compressed = strdupz(buffer); - d->chart_type_net_drops = strdupz(buffer); - d->chart_type_net_errors = strdupz(buffer); - d->chart_type_net_events = strdupz(buffer); - d->chart_type_net_fifo = strdupz(buffer); - d->chart_type_net_packets = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_%s", r->container_device); - d->chart_id_net_bytes = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_compressed_%s", r->container_device); - d->chart_id_net_compressed = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_drops_%s", r->container_device); - d->chart_id_net_drops = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_errors_%s", r->container_device); - d->chart_id_net_errors = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_events_%s", r->container_device); - d->chart_id_net_events = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_fifo_%s", r->container_device); - d->chart_id_net_fifo = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_packets_%s", r->container_device); - d->chart_id_net_packets = strdupz(buffer); - - snprintfz(buffer, RRD_ID_LENGTH_MAX, "net %s", r->container_device); - d->chart_family = strdupz(buffer); - - d->priority = 43000; - d->flipped = 1; -} - -static inline void netdev_rename(struct netdev *d) { - struct netdev_rename *r = netdev_rename_find(d->name, d->hash); - if(unlikely(r && !r->processed)) { - netdev_rename_cgroup(d, r); - r->processed = 1; - netdev_pending_renames--; - } -} - -static inline void netdev_rename_lock(struct netdev *d) { - netdata_mutex_lock(&netdev_rename_mutex); - netdev_rename(d); - netdata_mutex_unlock(&netdev_rename_mutex); -} - -static inline void netdev_rename_all_lock(void) { - netdata_mutex_lock(&netdev_rename_mutex); - - struct netdev *d; - for(d = netdev_root; d ; d = d->next) - netdev_rename(d); - - netdev_pending_renames = 0; - netdata_mutex_unlock(&netdev_rename_mutex); -} - -// ---------------------------------------------------------------------------- -// netdev data collection - -static void netdev_cleanup() { - if(likely(netdev_found == netdev_added)) return; - - 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) { - struct netdev *d; - - uint32_t hash = simple_hash(name); - - // search it, from the last position to the end - for(d = netdev_last_used ; d ; d = d->next) { - if(unlikely(hash == d->hash && !strcmp(name, d->name))) { - netdev_last_used = d->next; - return d; - } - } - - // search it from the beginning to the last position we used - for(d = netdev_root ; d != netdev_last_used ; d = d->next) { - if(unlikely(hash == d->hash && !strcmp(name, d->name))) { - netdev_last_used = d->next; - return d; - } - } - - // create a new one - d = callocz(1, sizeof(struct netdev)); - d->name = strdupz(name); - d->hash = simple_hash(d->name); - d->len = strlen(d->name); - - d->chart_type_net_bytes = strdupz("net"); - d->chart_type_net_compressed = strdupz("net_compressed"); - d->chart_type_net_drops = strdupz("net_drops"); - d->chart_type_net_errors = strdupz("net_errors"); - d->chart_type_net_events = strdupz("net_events"); - d->chart_type_net_fifo = strdupz("net_fifo"); - d->chart_type_net_packets = strdupz("net_packets"); - - d->chart_id_net_bytes = strdupz(d->name); - d->chart_id_net_compressed = strdupz(d->name); - d->chart_id_net_drops = strdupz(d->name); - d->chart_id_net_errors = strdupz(d->name); - d->chart_id_net_events = strdupz(d->name); - d->chart_id_net_fifo = strdupz(d->name); - d->chart_id_net_packets = strdupz(d->name); - - d->chart_family = strdupz(d->name); - d->priority = 7000; - - netdev_rename_lock(d); - - netdev_added++; - - // link it to the end - if(netdev_root) { - struct netdev *e; - for(e = netdev_root; e->next ; e = e->next) ; - e->next = d; - } - else - netdev_root = d; - - return d; -} - -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; - static char *path_to_sys_devices_virtual_net = NULL; - - if(unlikely(enable_new_interfaces == -1)) { - char filename[FILENAME_MAX + 1]; - - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/net/%s"); - path_to_sys_devices_virtual_net = config_get("plugin:proc:/proc/net/dev", "path to get virtual interfaces", filename); - - 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_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"), NULL, SIMPLE_PATTERN_EXACT); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - // rename all the devices, if we have pending renames - if(unlikely(netdev_pending_renames)) - netdev_rename_all_lock(); - - netdev_found = 0; - - kernel_uint_t system_rbytes = 0; - kernel_uint_t system_tbytes = 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 - - // remember we configured it - d->configured = 1; - - d->enabled = enable_new_interfaces; - - if(d->enabled) - d->enabled = !simple_pattern_matches(disabled_list, d->name); - - char buffer[FILENAME_MAX + 1]; - - snprintfz(buffer, FILENAME_MAX, path_to_sys_devices_virtual_net, d->name); - if(likely(access(buffer, R_OK) == 0)) { - d->virtual = 1; - } - else - d->virtual = 0; - - snprintfz(buffer, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name); - d->enabled = config_get_boolean_ondemand(buffer, "enabled", d->enabled); - d->virtual = config_get_boolean(buffer, "virtual", d->virtual); - - if(d->enabled == CONFIG_BOOLEAN_NO) - continue; - - d->do_bandwidth = config_get_boolean_ondemand(buffer, "bandwidth", do_bandwidth); - d->do_packets = config_get_boolean_ondemand(buffer, "packets", do_packets); - d->do_errors = config_get_boolean_ondemand(buffer, "errors", do_errors); - d->do_drops = config_get_boolean_ondemand(buffer, "drops", do_drops); - d->do_fifo = config_get_boolean_ondemand(buffer, "fifo", do_fifo); - d->do_compressed = config_get_boolean_ondemand(buffer, "compressed", do_compressed); - d->do_events = config_get_boolean_ondemand(buffer, "events", do_events); - } - - if(unlikely(!d->enabled)) - continue; - - if(likely(d->do_bandwidth != CONFIG_BOOLEAN_NO || !d->virtual)) { - d->rbytes = str2kernel_uint_t(procfile_lineword(ff, l, 1)); - d->tbytes = str2kernel_uint_t(procfile_lineword(ff, l, 9)); - - if(likely(!d->virtual)) { - system_rbytes += d->rbytes; - system_tbytes += d->tbytes; - } - } - - 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_BOOLEAN_AUTO && (d->rbytes || d->tbytes)))) - d->do_bandwidth = CONFIG_BOOLEAN_YES; - - if(d->do_bandwidth == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_bandwidth)) { - - d->st_bandwidth = rrdset_create_localhost( - d->chart_type_net_bytes - , d->chart_id_net_bytes - , NULL - , d->chart_family - , "net.net" - , "Bandwidth" - , "kilobits/s" - , "proc" - , "net/dev" - , d->priority - , update_every - , RRDSET_TYPE_AREA - ); - - d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - - if(d->flipped) { - // flip receive/trasmit - - RRDDIM *td = d->rd_rbytes; - d->rd_rbytes = d->rd_tbytes; - d->rd_tbytes = td; - } - } - else rrdset_next(d->st_bandwidth); - - 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_BOOLEAN_AUTO && (d->rpackets || d->tpackets || d->rmulticast)))) - d->do_packets = CONFIG_BOOLEAN_YES; - - if(d->do_packets == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_packets)) { - - d->st_packets = rrdset_create_localhost( - d->chart_type_net_packets - , d->chart_id_net_packets - , NULL - , d->chart_family - , "net.packets" - , "Packets" - , "packets/s" - , "proc" - , "net/dev" - , d->priority + 1 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_packets, RRDSET_FLAG_DETAIL); - - d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(d->flipped) { - // flip receive/trasmit - - RRDDIM *td = d->rd_rpackets; - d->rd_rpackets = d->rd_tpackets; - d->rd_tpackets = td; - } - } - else rrdset_next(d->st_packets); - - 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_BOOLEAN_AUTO && (d->rerrors || d->terrors)))) - d->do_errors = CONFIG_BOOLEAN_YES; - - if(d->do_errors == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_errors)) { - - d->st_errors = rrdset_create_localhost( - d->chart_type_net_errors - , d->chart_id_net_errors - , NULL - , d->chart_family - , "net.errors" - , "Interface Errors" - , "errors/s" - , "proc" - , "net/dev" - , d->priority + 2 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_errors, RRDSET_FLAG_DETAIL); - - d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(d->flipped) { - // flip receive/trasmit - - RRDDIM *td = d->rd_rerrors; - d->rd_rerrors = d->rd_terrors; - d->rd_terrors = td; - } - } - else rrdset_next(d->st_errors); - - 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_BOOLEAN_AUTO && (d->rdrops || d->tdrops)))) - d->do_drops = CONFIG_BOOLEAN_YES; - - if(d->do_drops == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_drops)) { - - d->st_drops = rrdset_create_localhost( - d->chart_type_net_drops - , d->chart_id_net_drops - , NULL - , d->chart_family - , "net.drops" - , "Interface Drops" - , "drops/s" - , "proc" - , "net/dev" - , d->priority + 3 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_drops, RRDSET_FLAG_DETAIL); - - d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(d->flipped) { - // flip receive/trasmit - - RRDDIM *td = d->rd_rdrops; - d->rd_rdrops = d->rd_tdrops; - d->rd_tdrops = td; - } - } - else rrdset_next(d->st_drops); - - 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_BOOLEAN_AUTO && (d->rfifo || d->tfifo)))) - d->do_fifo = CONFIG_BOOLEAN_YES; - - if(d->do_fifo == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_fifo)) { - - d->st_fifo = rrdset_create_localhost( - d->chart_type_net_fifo - , d->chart_id_net_fifo - , NULL - , d->chart_family - , "net.fifo" - , "Interface FIFO Buffer Errors" - , "errors" - , "proc" - , "net/dev" - , d->priority + 4 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_fifo, RRDSET_FLAG_DETAIL); - - d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(d->flipped) { - // flip receive/trasmit - - RRDDIM *td = d->rd_rfifo; - d->rd_rfifo = d->rd_tfifo; - d->rd_tfifo = td; - } - } - else rrdset_next(d->st_fifo); - - 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_BOOLEAN_AUTO && (d->rcompressed || d->tcompressed)))) - d->do_compressed = CONFIG_BOOLEAN_YES; - - if(d->do_compressed == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_compressed)) { - - d->st_compressed = rrdset_create_localhost( - d->chart_type_net_compressed - , d->chart_id_net_compressed - , NULL - , d->chart_family - , "net.compressed" - , "Compressed Packets" - , "packets/s" - , "proc" - , "net/dev" - , d->priority + 5 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_compressed, RRDSET_FLAG_DETAIL); - - d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(d->flipped) { - // flip receive/trasmit - - RRDDIM *td = d->rd_rcompressed; - d->rd_rcompressed = d->rd_tcompressed; - d->rd_tcompressed = td; - } - } - else rrdset_next(d->st_compressed); - - 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_BOOLEAN_AUTO && (d->rframe || d->tcollisions || d->tcarrier)))) - d->do_events = CONFIG_BOOLEAN_YES; - - if(d->do_events == CONFIG_BOOLEAN_YES) { - if(unlikely(!d->st_events)) { - - d->st_events = rrdset_create_localhost( - d->chart_type_net_events - , d->chart_id_net_events - , NULL - , d->chart_family - , "net.events" - , "Network Interface Events" - , "events/s" - , "proc" - , "net/dev" - , d->priority + 6 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(d->st_events, RRDSET_FLAG_DETAIL); - - d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - d->rd_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, (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); - } - } - - if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (system_rbytes || system_tbytes))) { - do_bandwidth = CONFIG_BOOLEAN_YES; - static RRDSET *st_system_net = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_system_net)) { - st_system_net = rrdset_create_localhost( - "system" - , "net" - , NULL - , "network" - , NULL - , "Physical Network Interfaces Aggregated Bandwidth" - , "kilobits/s" - , "proc" - , "net/dev" - , 500 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st_system_net, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_system_net, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_system_net); - - rrddim_set_by_pointer(st_system_net, rd_in, (collected_number)system_rbytes); - rrddim_set_by_pointer(st_system_net, rd_out, (collected_number)system_tbytes); - - rrdset_done(st_system_net); - } - - netdev_cleanup(); - - return 0; -} diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c deleted file mode 100644 index d76972f3c..000000000 --- a/src/proc_net_ip_vs_stats.c +++ /dev/null @@ -1,129 +0,0 @@ -#include "common.h" - -#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; - - if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1); - 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(!ff) { - char filename[FILENAME_MAX + 1]; - 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; - - ff = procfile_readall(ff); - if(!ff) return 0; // we return 0, so that we will retry to open it next time - - // make sure we have 3 lines - if(procfile_lines(ff) < 3) return 1; - - // make sure we have 5 words on the 3rd line - if(procfile_linewords(ff, 2) < 5) return 1; - - unsigned long long entries, InPackets, OutPackets, InBytes, OutBytes; - - entries = strtoull(procfile_lineword(ff, 2, 0), NULL, 16); - InPackets = strtoull(procfile_lineword(ff, 2, 1), NULL, 16); - OutPackets = strtoull(procfile_lineword(ff, 2, 2), NULL, 16); - InBytes = strtoull(procfile_lineword(ff, 2, 3), NULL, 16); - OutBytes = strtoull(procfile_lineword(ff, 2, 4), NULL, 16); - - - // -------------------------------------------------------------------- - - if(do_sockets) { - static RRDSET *st = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_IPVS - , "sockets" - , NULL - , RRD_TYPE_NET_IPVS - , NULL - , "IPVS New Connections" - , "connections/s" - , "proc" - , "net/ip_vs_stats" - , 3101 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "connections", entries); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_packets) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_IPVS - , "packets" - , NULL - , RRD_TYPE_NET_IPVS - , NULL - , "IPVS Packets" - , "packets/s" - , "proc" - , "net/ip_vs_stats" - , 3102 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "received", InPackets); - rrddim_set(st, "sent", OutPackets); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_bandwidth) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_IPVS - , "net" - , NULL - , RRD_TYPE_NET_IPVS - , NULL - , "IPVS Bandwidth" - , "kilobits/s" - , "proc" - , "net/ip_vs_stats" - , 3100 - , update_every - , RRDSET_TYPE_AREA - ); - - rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "received", InBytes); - rrddim_set(st, "sent", OutBytes); - rrdset_done(st); - } - - return 0; -} diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c deleted file mode 100644 index dd070e4c3..000000000 --- a/src/proc_net_netstat.c +++ /dev/null @@ -1,761 +0,0 @@ -#include "common.h" - -unsigned long long tcpext_TCPSynRetrans; - -static void parse_line_pair(procfile *ff, ARL_BASE *base, size_t header_line, size_t values_line) { - size_t hwords = procfile_linewords(ff, header_line); - size_t vwords = procfile_linewords(ff, values_line); - size_t w; - - if(unlikely(vwords > hwords)) { - error("File /proc/net/netstat on header line %zu has %zu words, but on value line %zu has %zu words.", header_line, hwords, values_line, vwords); - vwords = hwords; - } - - for(w = 1; w < vwords ;w++) { - if(unlikely(arl_check(base, procfile_lineword(ff, header_line, w), procfile_lineword(ff, values_line, w)))) - break; - } -} - -int do_proc_net_netstat(int update_every, usec_t dt) { - (void)dt; - - static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1, do_ecn = -1, \ - do_tcpext_reorder = -1, do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1, do_tcpext_memory = -1, - do_tcpext_listen = -1; - - static uint32_t hash_ipext = 0, hash_tcpext = 0; - static procfile *ff = NULL; - - static ARL_BASE *arl_tcpext = NULL; - static ARL_BASE *arl_ipext = NULL; - - // -------------------------------------------------------------------- - // IPv4 - - // IPv4 bandwidth - static unsigned long long ipext_InOctets = 0; - static unsigned long long ipext_OutOctets = 0; - - // IPv4 input errors - static unsigned long long ipext_InNoRoutes = 0; - static unsigned long long ipext_InTruncatedPkts = 0; - static unsigned long long ipext_InCsumErrors = 0; - - // IPv4 multicast bandwidth - static unsigned long long ipext_InMcastOctets = 0; - static unsigned long long ipext_OutMcastOctets = 0; - - // IPv4 multicast packets - static unsigned long long ipext_InMcastPkts = 0; - static unsigned long long ipext_OutMcastPkts = 0; - - // IPv4 broadcast bandwidth - static unsigned long long ipext_InBcastOctets = 0; - static unsigned long long ipext_OutBcastOctets = 0; - - // IPv4 broadcast packets - static unsigned long long ipext_InBcastPkts = 0; - static unsigned long long ipext_OutBcastPkts = 0; - - // IPv4 ECN - static unsigned long long ipext_InNoECTPkts = 0; - static unsigned long long ipext_InECT1Pkts = 0; - static unsigned long long ipext_InECT0Pkts = 0; - static unsigned long long ipext_InCEPkts = 0; - - // -------------------------------------------------------------------- - // IPv4 TCP - - // IPv4 TCP Reordering - static unsigned long long tcpext_TCPRenoReorder = 0; - static unsigned long long tcpext_TCPFACKReorder = 0; - static unsigned long long tcpext_TCPSACKReorder = 0; - static unsigned long long tcpext_TCPTSReorder = 0; - - // IPv4 TCP SYN Cookies - static unsigned long long tcpext_SyncookiesSent = 0; - static unsigned long long tcpext_SyncookiesRecv = 0; - static unsigned long long tcpext_SyncookiesFailed = 0; - - // IPv4 TCP Out Of Order Queue - // http://www.spinics.net/lists/netdev/msg204696.html - static unsigned long long tcpext_TCPOFOQueue = 0; // Number of packets queued in OFO queue - static unsigned long long tcpext_TCPOFODrop = 0; // Number of packets meant to be queued in OFO but dropped because socket rcvbuf limit hit. - static unsigned long long tcpext_TCPOFOMerge = 0; // Number of packets in OFO that were merged with other packets. - static unsigned long long tcpext_OfoPruned = 0; // packets dropped from out-of-order queue because of socket buffer overrun - - // IPv4 TCP connection resets - // https://github.com/ecki/net-tools/blob/bd8bceaed2311651710331a7f8990c3e31be9840/statistics.c - static unsigned long long tcpext_TCPAbortOnData = 0; // connections reset due to unexpected data - static unsigned long long tcpext_TCPAbortOnClose = 0; // connections reset due to early user close - static unsigned long long tcpext_TCPAbortOnMemory = 0; // connections aborted due to memory pressure - static unsigned long long tcpext_TCPAbortOnTimeout = 0; // connections aborted due to timeout - static unsigned long long tcpext_TCPAbortOnLinger = 0; // connections aborted after user close in linger timeout - static unsigned long long tcpext_TCPAbortFailed = 0; // times unable to send RST due to no memory - - // https://perfchron.com/2015/12/26/investigating-linux-network-issues-with-netstat-and-nstat/ - static unsigned long long tcpext_ListenOverflows = 0; // times the listen queue of a socket overflowed - static unsigned long long tcpext_ListenDrops = 0; // SYNs to LISTEN sockets ignored - - // IPv4 TCP memory pressures - static unsigned long long tcpext_TCPMemoryPressures = 0; - - // shared: tcpext_TCPSynRetrans - - - if(unlikely(!arl_ipext)) { - hash_ipext = simple_hash("IpExt"); - hash_tcpext = simple_hash("TcpExt"); - - 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); - do_tcpext_listen = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP listen issues", CONFIG_BOOLEAN_AUTO); - - arl_ipext = arl_create("netstat/ipext", NULL, 60); - arl_tcpext = arl_create("netstat/tcpext", NULL, 60); - - // -------------------------------------------------------------------- - // IPv4 - - if(do_bandwidth != CONFIG_BOOLEAN_NO) { - arl_expect(arl_ipext, "InOctets", &ipext_InOctets); - arl_expect(arl_ipext, "OutOctets", &ipext_OutOctets); - } - - 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_BOOLEAN_NO) { - arl_expect(arl_ipext, "InMcastOctets", &ipext_InMcastOctets); - arl_expect(arl_ipext, "OutMcastOctets", &ipext_OutMcastOctets); - } - - 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_BOOLEAN_NO) { - arl_expect(arl_ipext, "InBcastPkts", &ipext_InBcastPkts); - arl_expect(arl_ipext, "OutBcastPkts", &ipext_OutBcastPkts); - } - - 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_BOOLEAN_NO) { - arl_expect(arl_ipext, "InNoECTPkts", &ipext_InNoECTPkts); - arl_expect(arl_ipext, "InECT1Pkts", &ipext_InECT1Pkts); - arl_expect(arl_ipext, "InECT0Pkts", &ipext_InECT0Pkts); - arl_expect(arl_ipext, "InCEPkts", &ipext_InCEPkts); - } - - // -------------------------------------------------------------------- - // IPv4 TCP - - 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_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_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_BOOLEAN_NO) { - arl_expect(arl_tcpext, "TCPAbortOnData", &tcpext_TCPAbortOnData); - arl_expect(arl_tcpext, "TCPAbortOnClose", &tcpext_TCPAbortOnClose); - arl_expect(arl_tcpext, "TCPAbortOnMemory", &tcpext_TCPAbortOnMemory); - arl_expect(arl_tcpext, "TCPAbortOnTimeout", &tcpext_TCPAbortOnTimeout); - arl_expect(arl_tcpext, "TCPAbortOnLinger", &tcpext_TCPAbortOnLinger); - arl_expect(arl_tcpext, "TCPAbortFailed", &tcpext_TCPAbortFailed); - } - - if(do_tcpext_memory != CONFIG_BOOLEAN_NO) { - arl_expect(arl_tcpext, "TCPMemoryPressures", &tcpext_TCPMemoryPressures); - } - - if(do_tcpext_listen != CONFIG_BOOLEAN_NO) { - arl_expect(arl_tcpext, "ListenOverflows", &tcpext_ListenOverflows); - arl_expect(arl_tcpext, "ListenDrops", &tcpext_ListenDrops); - } - - // shared metrics - arl_expect(arl_tcpext, "TCPSynRetrans", &tcpext_TCPSynRetrans); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - 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); - - if(unlikely(hash == hash_ipext && strcmp(key, "IpExt") == 0)) { - size_t h = l++; - - words = procfile_linewords(ff, l); - if(unlikely(words < 2)) { - error("Cannot read /proc/net/netstat IpExt line. Expected 2+ params, read %zu.", words); - continue; - } - - parse_line_pair(ff, arl_ipext, h, l); - - // -------------------------------------------------------------------- - - if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (ipext_InOctets || ipext_OutOctets))) { - do_bandwidth = CONFIG_BOOLEAN_YES; - static RRDSET *st_system_ipv4 = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_system_ipv4)) { - st_system_ipv4 = rrdset_create_localhost( - "system" - , "ipv4" - , NULL - , "network" - , NULL - , "IPv4 Bandwidth" - , "kilobits/s" - , "proc" - , "net/netstat" - , 501 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st_system_ipv4, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_system_ipv4, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_system_ipv4); - - rrddim_set_by_pointer(st_system_ipv4, rd_in, ipext_InOctets); - rrddim_set_by_pointer(st_system_ipv4, rd_out, ipext_OutOctets); - - rrdset_done(st_system_ipv4); - } - - // -------------------------------------------------------------------- - - if(do_inerrors == CONFIG_BOOLEAN_YES || (do_inerrors == CONFIG_BOOLEAN_AUTO && (ipext_InNoRoutes || ipext_InTruncatedPkts))) { - do_inerrors = CONFIG_BOOLEAN_YES; - static RRDSET *st_ipv4_inerrors = NULL; - static RRDDIM *rd_noroutes = NULL, *rd_truncated = NULL, *rd_checksum = NULL; - - if(unlikely(!st_ipv4_inerrors)) { - st_ipv4_inerrors = rrdset_create_localhost( - "ipv4" - , "inerrors" - , NULL - , "errors" - , NULL - , "IPv4 Input Errors" - , "packets/s" - , "proc" - , "net/netstat" - , 4000 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_ipv4_inerrors, RRDSET_FLAG_DETAIL); - - rd_noroutes = rrddim_add(st_ipv4_inerrors, "InNoRoutes", "noroutes", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_truncated = rrddim_add(st_ipv4_inerrors, "InTruncatedPkts", "truncated", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_checksum = rrddim_add(st_ipv4_inerrors, "InCsumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_ipv4_inerrors); - - rrddim_set_by_pointer(st_ipv4_inerrors, rd_noroutes, ipext_InNoRoutes); - rrddim_set_by_pointer(st_ipv4_inerrors, rd_truncated, ipext_InTruncatedPkts); - rrddim_set_by_pointer(st_ipv4_inerrors, rd_checksum, ipext_InCsumErrors); - - rrdset_done(st_ipv4_inerrors); - } - - // -------------------------------------------------------------------- - - if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (ipext_InMcastOctets || ipext_OutMcastOctets))) { - do_mcast = CONFIG_BOOLEAN_YES; - static RRDSET *st_ipv4_mcast = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_ipv4_mcast)) { - st_ipv4_mcast = rrdset_create_localhost( - "ipv4" - , "mcast" - , NULL - , "multicast" - , NULL - , "IPv4 Multicast Bandwidth" - , "kilobits/s" - , "proc" - , "net/netstat" - , 9000 - , update_every - , RRDSET_TYPE_AREA - ); - - rrdset_flag_set(st_ipv4_mcast, RRDSET_FLAG_DETAIL); - - rd_in = rrddim_add(st_ipv4_mcast, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_ipv4_mcast, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_ipv4_mcast); - - rrddim_set_by_pointer(st_ipv4_mcast, rd_in, ipext_InMcastOctets); - rrddim_set_by_pointer(st_ipv4_mcast, rd_out, ipext_OutMcastOctets); - - rrdset_done(st_ipv4_mcast); - } - - // -------------------------------------------------------------------- - - if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (ipext_InBcastOctets || ipext_OutBcastOctets))) { - do_bcast = CONFIG_BOOLEAN_YES; - - static RRDSET *st_ipv4_bcast = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_ipv4_bcast)) { - st_ipv4_bcast = rrdset_create_localhost( - "ipv4" - , "bcast" - , NULL - , "broadcast" - , NULL - , "IPv4 Broadcast Bandwidth" - , "kilobits/s" - , "proc" - , "net/netstat" - , 8000 - , update_every - , RRDSET_TYPE_AREA - ); - - rrdset_flag_set(st_ipv4_bcast, RRDSET_FLAG_DETAIL); - - rd_in = rrddim_add(st_ipv4_bcast, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_ipv4_bcast, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_ipv4_bcast); - - rrddim_set_by_pointer(st_ipv4_bcast, rd_in, ipext_InBcastOctets); - rrddim_set_by_pointer(st_ipv4_bcast, rd_out, ipext_OutBcastOctets); - - rrdset_done(st_ipv4_bcast); - } - - // -------------------------------------------------------------------- - - if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InMcastPkts || ipext_OutMcastPkts))) { - do_mcast_p = CONFIG_BOOLEAN_YES; - - static RRDSET *st_ipv4_mcastpkts = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_ipv4_mcastpkts)) { - st_ipv4_mcastpkts = rrdset_create_localhost( - "ipv4" - , "mcastpkts" - , NULL - , "multicast" - , NULL - , "IPv4 Multicast Packets" - , "packets/s" - , "proc" - , "net/netstat" - , 8600 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_ipv4_mcastpkts, RRDSET_FLAG_DETAIL); - - rd_in = rrddim_add(st_ipv4_mcastpkts, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_ipv4_mcastpkts, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_ipv4_mcastpkts); - - rrddim_set_by_pointer(st_ipv4_mcastpkts, rd_in, ipext_InMcastPkts); - rrddim_set_by_pointer(st_ipv4_mcastpkts, rd_out, ipext_OutMcastPkts); - - rrdset_done(st_ipv4_mcastpkts); - } - - // -------------------------------------------------------------------- - - if(do_bcast_p == CONFIG_BOOLEAN_YES || (do_bcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InBcastPkts || ipext_OutBcastPkts))) { - do_bcast_p = CONFIG_BOOLEAN_YES; - - static RRDSET *st_ipv4_bcastpkts = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_ipv4_bcastpkts)) { - st_ipv4_bcastpkts = rrdset_create_localhost( - "ipv4" - , "bcastpkts" - , NULL - , "broadcast" - , NULL - , "IPv4 Broadcast Packets" - , "packets/s" - , "proc" - , "net/netstat" - , 8500 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_ipv4_bcastpkts, RRDSET_FLAG_DETAIL); - - rd_in = rrddim_add(st_ipv4_bcastpkts, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_ipv4_bcastpkts, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_ipv4_bcastpkts); - - rrddim_set_by_pointer(st_ipv4_bcastpkts, rd_in, ipext_InBcastPkts); - rrddim_set_by_pointer(st_ipv4_bcastpkts, rd_out, ipext_OutBcastPkts); - - rrdset_done(st_ipv4_bcastpkts); - } - - // -------------------------------------------------------------------- - - if(do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (ipext_InCEPkts || ipext_InECT0Pkts || ipext_InECT1Pkts || ipext_InNoECTPkts))) { - do_ecn = CONFIG_BOOLEAN_YES; - - static RRDSET *st_ecnpkts = NULL; - static RRDDIM *rd_cep = NULL, *rd_noectp = NULL, *rd_ectp0 = NULL, *rd_ectp1 = NULL; - - if(unlikely(!st_ecnpkts)) { - st_ecnpkts = rrdset_create_localhost( - "ipv4" - , "ecnpkts" - , NULL - , "ecn" - , NULL - , "IPv4 ECN Statistics" - , "packets/s" - , "proc" - , "net/netstat" - , 8700 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_ecnpkts, RRDSET_FLAG_DETAIL); - - rd_cep = rrddim_add(st_ecnpkts, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_noectp = rrddim_add(st_ecnpkts, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_ectp0 = rrddim_add(st_ecnpkts, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_ectp1 = rrddim_add(st_ecnpkts, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_ecnpkts); - - rrddim_set_by_pointer(st_ecnpkts, rd_cep, ipext_InCEPkts); - rrddim_set_by_pointer(st_ecnpkts, rd_noectp, ipext_InNoECTPkts); - rrddim_set_by_pointer(st_ecnpkts, rd_ectp0, ipext_InECT0Pkts); - rrddim_set_by_pointer(st_ecnpkts, rd_ectp1, ipext_InECT1Pkts); - - rrdset_done(st_ecnpkts); - } - } - else if(unlikely(hash == hash_tcpext && strcmp(key, "TcpExt") == 0)) { - size_t h = l++; - - words = procfile_linewords(ff, l); - if(unlikely(words < 2)) { - error("Cannot read /proc/net/netstat TcpExt line. Expected 2+ params, read %zu.", words); - continue; - } - - parse_line_pair(ff, arl_tcpext, h, l); - - // -------------------------------------------------------------------- - - if(do_tcpext_memory == CONFIG_BOOLEAN_YES || (do_tcpext_memory == CONFIG_BOOLEAN_AUTO && (tcpext_TCPMemoryPressures))) { - do_tcpext_memory = CONFIG_BOOLEAN_YES; - - static RRDSET *st_tcpmemorypressures = NULL; - static RRDDIM *rd_pressures = NULL; - - if(unlikely(!st_tcpmemorypressures)) { - st_tcpmemorypressures = rrdset_create_localhost( - "ipv4" - , "tcpmemorypressures" - , NULL - , "tcp" - , NULL - , "TCP Memory Pressures" - , "events/s" - , "proc" - , "net/netstat" - , 3000 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_pressures = rrddim_add(st_tcpmemorypressures, "TCPMemoryPressures", "pressures", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_tcpmemorypressures); - - rrddim_set_by_pointer(st_tcpmemorypressures, rd_pressures, tcpext_TCPMemoryPressures); - - rrdset_done(st_tcpmemorypressures); - } - - // -------------------------------------------------------------------- - - if(do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpext_TCPAbortOnData || tcpext_TCPAbortOnClose || tcpext_TCPAbortOnMemory || tcpext_TCPAbortOnTimeout || tcpext_TCPAbortOnLinger || tcpext_TCPAbortFailed))) { - do_tcpext_connaborts = CONFIG_BOOLEAN_YES; - - static RRDSET *st_tcpconnaborts = NULL; - static RRDDIM *rd_baddata = NULL, *rd_userclosed = NULL, *rd_nomemory = NULL, *rd_timeout = NULL, *rd_linger = NULL, *rd_failed = NULL; - - if(unlikely(!st_tcpconnaborts)) { - st_tcpconnaborts = rrdset_create_localhost( - "ipv4" - , "tcpconnaborts" - , NULL - , "tcp" - , NULL - , "TCP Connection Aborts" - , "connections/s" - , "proc" - , "net/netstat" - , 3010 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_baddata = rrddim_add(st_tcpconnaborts, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_userclosed = rrddim_add(st_tcpconnaborts, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_nomemory = rrddim_add(st_tcpconnaborts, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_timeout = rrddim_add(st_tcpconnaborts, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_linger = rrddim_add(st_tcpconnaborts, "TCPAbortOnLinger", "linger", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_failed = rrddim_add(st_tcpconnaborts, "TCPAbortFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_tcpconnaborts); - - rrddim_set_by_pointer(st_tcpconnaborts, rd_baddata, tcpext_TCPAbortOnData); - rrddim_set_by_pointer(st_tcpconnaborts, rd_userclosed, tcpext_TCPAbortOnClose); - rrddim_set_by_pointer(st_tcpconnaborts, rd_nomemory, tcpext_TCPAbortOnMemory); - rrddim_set_by_pointer(st_tcpconnaborts, rd_timeout, tcpext_TCPAbortOnTimeout); - rrddim_set_by_pointer(st_tcpconnaborts, rd_linger, tcpext_TCPAbortOnLinger); - rrddim_set_by_pointer(st_tcpconnaborts, rd_failed, tcpext_TCPAbortFailed); - - rrdset_done(st_tcpconnaborts); - } - - // -------------------------------------------------------------------- - - if(do_tcpext_reorder == CONFIG_BOOLEAN_YES || (do_tcpext_reorder == CONFIG_BOOLEAN_AUTO && (tcpext_TCPRenoReorder || tcpext_TCPFACKReorder || tcpext_TCPSACKReorder || tcpext_TCPTSReorder))) { - do_tcpext_reorder = CONFIG_BOOLEAN_YES; - - static RRDSET *st_tcpreorders = NULL; - static RRDDIM *rd_timestamp = NULL, *rd_sack = NULL, *rd_fack = NULL, *rd_reno = NULL; - - if(unlikely(!st_tcpreorders)) { - st_tcpreorders = rrdset_create_localhost( - "ipv4" - , "tcpreorders" - , NULL - , "tcp" - , NULL - , "TCP Reordered Packets by Detection Method" - , "packets/s" - , "proc" - , "net/netstat" - , 3020 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_timestamp = rrddim_add(st_tcpreorders, "TCPTSReorder", "timestamp", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_sack = rrddim_add(st_tcpreorders, "TCPSACKReorder", "sack", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_fack = rrddim_add(st_tcpreorders, "TCPFACKReorder", "fack", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_reno = rrddim_add(st_tcpreorders, "TCPRenoReorder", "reno", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_tcpreorders); - - rrddim_set_by_pointer(st_tcpreorders, rd_timestamp, tcpext_TCPTSReorder); - rrddim_set_by_pointer(st_tcpreorders, rd_sack, tcpext_TCPSACKReorder); - rrddim_set_by_pointer(st_tcpreorders, rd_fack, tcpext_TCPFACKReorder); - rrddim_set_by_pointer(st_tcpreorders, rd_reno, tcpext_TCPRenoReorder); - - rrdset_done(st_tcpreorders); - } - - // -------------------------------------------------------------------- - - if(do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && (tcpext_TCPOFOQueue || tcpext_TCPOFODrop || tcpext_TCPOFOMerge))) { - do_tcpext_ofo = CONFIG_BOOLEAN_YES; - - static RRDSET *st_ipv4_tcpofo = NULL; - static RRDDIM *rd_inqueue = NULL, *rd_dropped = NULL, *rd_merged = NULL, *rd_pruned = NULL; - - if(unlikely(!st_ipv4_tcpofo)) { - - st_ipv4_tcpofo = rrdset_create_localhost( - "ipv4" - , "tcpofo" - , NULL - , "tcp" - , NULL - , "TCP Out-Of-Order Queue" - , "packets/s" - , "proc" - , "net/netstat" - , 3050 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inqueue = rrddim_add(st_ipv4_tcpofo, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_dropped = rrddim_add(st_ipv4_tcpofo, "TCPOFODrop", "dropped", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_merged = rrddim_add(st_ipv4_tcpofo, "TCPOFOMerge", "merged", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_pruned = rrddim_add(st_ipv4_tcpofo, "OfoPruned", "pruned", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_ipv4_tcpofo); - - rrddim_set_by_pointer(st_ipv4_tcpofo, rd_inqueue, tcpext_TCPOFOQueue); - rrddim_set_by_pointer(st_ipv4_tcpofo, rd_dropped, tcpext_TCPOFODrop); - rrddim_set_by_pointer(st_ipv4_tcpofo, rd_merged, tcpext_TCPOFOMerge); - rrddim_set_by_pointer(st_ipv4_tcpofo, rd_pruned, tcpext_OfoPruned); - - rrdset_done(st_ipv4_tcpofo); - } - - // -------------------------------------------------------------------- - - if(do_tcpext_syscookies == CONFIG_BOOLEAN_YES || (do_tcpext_syscookies == CONFIG_BOOLEAN_AUTO && (tcpext_SyncookiesSent || tcpext_SyncookiesRecv || tcpext_SyncookiesFailed))) { - do_tcpext_syscookies = CONFIG_BOOLEAN_YES; - - static RRDSET *st_syncookies = NULL; - static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_failed = NULL; - - if(unlikely(!st_syncookies)) { - - st_syncookies = rrdset_create_localhost( - "ipv4" - , "tcpsyncookies" - , NULL - , "tcp" - , NULL - , "TCP SYN Cookies" - , "packets/s" - , "proc" - , "net/netstat" - , 3100 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_received = rrddim_add(st_syncookies, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_sent = rrddim_add(st_syncookies, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_failed = rrddim_add(st_syncookies, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_syncookies); - - rrddim_set_by_pointer(st_syncookies, rd_received, tcpext_SyncookiesRecv); - rrddim_set_by_pointer(st_syncookies, rd_sent, tcpext_SyncookiesSent); - rrddim_set_by_pointer(st_syncookies, rd_failed, tcpext_SyncookiesFailed); - - rrdset_done(st_syncookies); - } - - // -------------------------------------------------------------------- - - if(do_tcpext_listen == CONFIG_BOOLEAN_YES || (do_tcpext_listen == CONFIG_BOOLEAN_AUTO && (tcpext_ListenOverflows || tcpext_ListenDrops))) { - do_tcpext_listen = CONFIG_BOOLEAN_YES; - - static RRDSET *st_listen = NULL; - static RRDDIM *rd_overflows = NULL, *rd_drops = NULL; - - if(unlikely(!st_listen)) { - - st_listen = rrdset_create_localhost( - "ipv4" - , "tcplistenissues" - , NULL - , "tcp" - , NULL - , "TCP Listen Socket Issues" - , "packets/s" - , "proc" - , "net/netstat" - , 3015 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_overflows = rrddim_add(st_listen, "ListenOverflows", "overflows", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_drops = rrddim_add(st_listen, "ListenDrops", "drops", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_listen); - - rrddim_set_by_pointer(st_listen, rd_overflows, tcpext_ListenOverflows); - rrddim_set_by_pointer(st_listen, rd_drops, tcpext_ListenDrops); - - rrdset_done(st_listen); - } - } - } - - return 0; -} diff --git a/src/proc_net_rpc_nfs.c b/src/proc_net_rpc_nfs.c deleted file mode 100644 index a4c778cba..000000000 --- a/src/proc_net_rpc_nfs.c +++ /dev/null @@ -1,449 +0,0 @@ -#include "common.h" - -struct nfs_procs { - char name[30]; - unsigned long long value; - int present; - RRDDIM *rd; -}; - -struct nfs_procs nfs_proc2_values[] = { - { "null" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"root" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"readlink", 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"wrcache" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"symlink" , 0ULL, 0, NULL} - , {"mkdir" , 0ULL, 0, NULL} - , {"rmdir" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"fsstat" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - -struct nfs_procs nfs_proc3_values[] = { - { "null" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"access" , 0ULL, 0, NULL} - , {"readlink" , 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"mkdir" , 0ULL, 0, NULL} - , {"symlink" , 0ULL, 0, NULL} - , {"mknod" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rmdir" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"readdirplus", 0ULL, 0, NULL} - , {"fsstat" , 0ULL, 0, NULL} - , {"fsinfo" , 0ULL, 0, NULL} - , {"pathconf" , 0ULL, 0, NULL} - , {"commit" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - -struct nfs_procs nfs_proc4_values[] = { - { "null" , 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"commit" , 0ULL, 0, NULL} - , {"open" , 0ULL, 0, NULL} - , {"open_conf" , 0ULL, 0, NULL} - , {"open_noat" , 0ULL, 0, NULL} - , {"open_dgrd" , 0ULL, 0, NULL} - , {"close" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"fsinfo" , 0ULL, 0, NULL} - , {"renew" , 0ULL, 0, NULL} - , {"setclntid" , 0ULL, 0, NULL} - , {"confirm" , 0ULL, 0, NULL} - , {"lock" , 0ULL, 0, NULL} - , {"lockt" , 0ULL, 0, NULL} - , {"locku" , 0ULL, 0, NULL} - , {"access" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"lookup_root" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"symlink" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"pathconf" , 0ULL, 0, NULL} - , {"statfs" , 0ULL, 0, NULL} - , {"readlink" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"server_caps" , 0ULL, 0, NULL} - , {"delegreturn" , 0ULL, 0, NULL} - , {"getacl" , 0ULL, 0, NULL} - , {"setacl" , 0ULL, 0, NULL} - , {"fs_locations" , 0ULL, 0, NULL} - , {"rel_lkowner" , 0ULL, 0, NULL} - , {"secinfo" , 0ULL, 0, NULL} - , {"fsid_present" , 0ULL, 0, NULL} - , - - /* nfsv4.1 client ops */ - { "exchange_id" , 0ULL, 0, NULL} - , {"create_session" , 0ULL, 0, NULL} - , {"destroy_session" , 0ULL, 0, NULL} - , {"sequence" , 0ULL, 0, NULL} - , {"get_lease_time" , 0ULL, 0, NULL} - , {"reclaim_comp" , 0ULL, 0, NULL} - , {"layoutget" , 0ULL, 0, NULL} - , {"getdevinfo" , 0ULL, 0, NULL} - , {"layoutcommit" , 0ULL, 0, NULL} - , {"layoutreturn" , 0ULL, 0, NULL} - , {"secinfo_no" , 0ULL, 0, NULL} - , {"test_stateid" , 0ULL, 0, NULL} - , {"free_stateid" , 0ULL, 0, NULL} - , {"getdevicelist" , 0ULL, 0, NULL} - , {"bind_conn_to_ses", 0ULL, 0, NULL} - , {"destroy_clientid", 0ULL, 0, NULL} - , - - /* nfsv4.2 client ops */ - { "seek" , 0ULL, 0, NULL} - , {"allocate" , 0ULL, 0, NULL} - , {"deallocate" , 0ULL, 0, NULL} - , {"layoutstats" , 0ULL, 0, NULL} - , {"clone" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - -int do_proc_net_rpc_nfs(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - static int do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1; - static int proc2_warning = 0, proc3_warning = 0, proc4_warning = 0; - - if(!ff) { - char filename[FILENAME_MAX + 1]; - 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; - - ff = procfile_readall(ff); - if(!ff) return 0; // we return 0, so that we will retry to open it next time - - if(do_net == -1) do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "network", 1); - if(do_rpc == -1) do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "rpc", 1); - if(do_proc2 == -1) do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "NFS v2 procedures", 1); - if(do_proc3 == -1) do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "NFS v3 procedures", 1); - if(do_proc4 == -1) do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfs", "NFS v4 procedures", 1); - - // if they are enabled, reset them to 1 - // later we do them =2 to avoid doing strcmp() for all lines - if(do_net) do_net = 1; - if(do_rpc) do_rpc = 1; - if(do_proc2) do_proc2 = 1; - if(do_proc3) do_proc3 = 1; - if(do_proc4) do_proc4 = 1; - - size_t lines = procfile_lines(ff), l; - - char *type; - unsigned long long net_count = 0, net_udp_count = 0, net_tcp_count = 0, net_tcp_connections = 0; - unsigned long long rpc_calls = 0, rpc_retransmits = 0, rpc_auth_refresh = 0; - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(!words) continue; - - type = procfile_lineword(ff, l, 0); - - if(do_net == 1 && strcmp(type, "net") == 0) { - if(words < 5) { - error("%s line of /proc/net/rpc/nfs has %zu words, expected %d", type, words, 5); - continue; - } - - net_count = str2ull(procfile_lineword(ff, l, 1)); - net_udp_count = str2ull(procfile_lineword(ff, l, 2)); - net_tcp_count = str2ull(procfile_lineword(ff, l, 3)); - net_tcp_connections = str2ull(procfile_lineword(ff, l, 4)); - - unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections; - if(sum == 0ULL) do_net = -1; - else do_net = 2; - } - else if(do_rpc == 1 && strcmp(type, "rpc") == 0) { - if(words < 4) { - error("%s line of /proc/net/rpc/nfs has %zu words, expected %d", type, words, 6); - continue; - } - - rpc_calls = str2ull(procfile_lineword(ff, l, 1)); - rpc_retransmits = str2ull(procfile_lineword(ff, l, 2)); - rpc_auth_refresh = str2ull(procfile_lineword(ff, l, 3)); - - unsigned long long sum = rpc_calls + rpc_retransmits + rpc_auth_refresh; - if(sum == 0ULL) do_rpc = -1; - else do_rpc = 2; - } - else if(do_proc2 == 1 && strcmp(type, "proc2") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfs_proc2_values[i].name[0] ; i++, j++) { - nfs_proc2_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfs_proc2_values[i].present = 1; - sum += nfs_proc2_values[i].value; - } - - if(sum == 0ULL) { - if(!proc2_warning) { - error("Disabling /proc/net/rpc/nfs v2 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc2_warning = 1; - } - do_proc2 = 0; - } - else do_proc2 = 2; - } - else if(do_proc3 == 1 && strcmp(type, "proc3") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfs_proc3_values[i].name[0] ; i++, j++) { - nfs_proc3_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfs_proc3_values[i].present = 1; - sum += nfs_proc3_values[i].value; - } - - if(sum == 0ULL) { - if(!proc3_warning) { - info("Disabling /proc/net/rpc/nfs v3 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc3_warning = 1; - } - do_proc3 = 0; - } - else do_proc3 = 2; - } - else if(do_proc4 == 1 && strcmp(type, "proc4") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfs_proc4_values[i].name[0] ; i++, j++) { - nfs_proc4_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfs_proc4_values[i].present = 1; - sum += nfs_proc4_values[i].value; - } - - if(sum == 0ULL) { - if(!proc4_warning) { - info("Disabling /proc/net/rpc/nfs v4 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc4_warning = 1; - } - do_proc4 = 0; - } - else do_proc4 = 2; - } - } - - // -------------------------------------------------------------------- - - if(do_net == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_udp = NULL, - *rd_tcp = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfs" - , "net" - , NULL - , "network" - , NULL - , "NFS Client Network" - , "operations/s" - , "proc" - , "net/rpc/nfs" - , 2207 - , update_every - , RRDSET_TYPE_STACKED - ); - - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_udp = rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_tcp = rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - // ignore net_count, net_tcp_connections - (void)net_count; - (void)net_tcp_connections; - - rrddim_set_by_pointer(st, rd_udp, net_udp_count); - rrddim_set_by_pointer(st, rd_tcp, net_tcp_count); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_rpc == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_calls = NULL, - *rd_retransmits = NULL, - *rd_auth_refresh = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfs" - , "rpc" - , NULL - , "rpc" - , NULL - , "NFS Client Remote Procedure Calls Statistics" - , "calls/s" - , "proc" - , "net/rpc/nfs" - , 2208 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_calls = rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_retransmits = rrddim_add(st, "retransmits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_auth_refresh = rrddim_add(st, "auth_refresh", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_calls, rpc_calls); - rrddim_set_by_pointer(st, rd_retransmits, rpc_retransmits); - rrddim_set_by_pointer(st, rd_auth_refresh, rpc_auth_refresh); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc2 == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfs" - , "proc2" - , NULL - , "nfsv2rpc" - , NULL - , "NFS v2 Client Remote Procedure Calls" - , "calls/s" - , "proc" - , "net/rpc/nfs" - , 2209 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfs_proc2_values[i].present ; i++) { - if(unlikely(!nfs_proc2_values[i].rd)) - nfs_proc2_values[i].rd = rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfs_proc2_values[i].rd, nfs_proc2_values[i].value); - } - - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc3 == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfs" - , "proc3" - , NULL - , "nfsv3rpc" - , NULL - , "NFS v3 Client Remote Procedure Calls" - , "calls/s" - , "proc" - , "net/rpc/nfs" - , 2210 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfs_proc3_values[i].present ; i++) { - if(unlikely(!nfs_proc3_values[i].rd)) - nfs_proc3_values[i].rd = rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfs_proc3_values[i].rd, nfs_proc3_values[i].value); - } - - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc4 == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfs" - , "proc4" - , NULL - , "nfsv4rpc" - , NULL - , "NFS v4 Client Remote Procedure Calls" - , "calls/s" - , "proc" - , "net/rpc/nfs" - , 2211 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfs_proc4_values[i].present ; i++) { - if(unlikely(!nfs_proc4_values[i].rd)) - nfs_proc4_values[i].rd = rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfs_proc4_values[i].rd, nfs_proc4_values[i].value); - } - - rrdset_done(st); - } - - return 0; -} diff --git a/src/proc_net_rpc_nfsd.c b/src/proc_net_rpc_nfsd.c deleted file mode 100644 index 8aca31aed..000000000 --- a/src/proc_net_rpc_nfsd.c +++ /dev/null @@ -1,1002 +0,0 @@ -#include "common.h" - -struct nfsd_procs { - char name[30]; - unsigned long long value; - int present; - RRDDIM *rd; -}; - -struct nfsd_procs nfsd_proc2_values[] = { - { "null" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"root" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"readlink", 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"wrcache" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"symlink" , 0ULL, 0, NULL} - , {"mkdir" , 0ULL, 0, NULL} - , {"rmdir" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"fsstat" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - -struct nfsd_procs nfsd_proc3_values[] = { - { "null" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"access" , 0ULL, 0, NULL} - , {"readlink" , 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"mkdir" , 0ULL, 0, NULL} - , {"symlink" , 0ULL, 0, NULL} - , {"mknod" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rmdir" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"readdirplus", 0ULL, 0, NULL} - , {"fsstat" , 0ULL, 0, NULL} - , {"fsinfo" , 0ULL, 0, NULL} - , {"pathconf" , 0ULL, 0, NULL} - , {"commit" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - -struct nfsd_procs nfsd_proc4_values[] = { - { "null" , 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"commit" , 0ULL, 0, NULL} - , {"open" , 0ULL, 0, NULL} - , {"open_conf" , 0ULL, 0, NULL} - , {"open_noat" , 0ULL, 0, NULL} - , {"open_dgrd" , 0ULL, 0, NULL} - , {"close" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"fsinfo" , 0ULL, 0, NULL} - , {"renew" , 0ULL, 0, NULL} - , {"setclntid" , 0ULL, 0, NULL} - , {"confirm" , 0ULL, 0, NULL} - , {"lock" , 0ULL, 0, NULL} - , {"lockt" , 0ULL, 0, NULL} - , {"locku" , 0ULL, 0, NULL} - , {"access" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"lookup_root" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"symlink" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"pathconf" , 0ULL, 0, NULL} - , {"statfs" , 0ULL, 0, NULL} - , {"readlink" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"server_caps" , 0ULL, 0, NULL} - , {"delegreturn" , 0ULL, 0, NULL} - , {"getacl" , 0ULL, 0, NULL} - , {"setacl" , 0ULL, 0, NULL} - , {"fs_locations" , 0ULL, 0, NULL} - , {"rel_lkowner" , 0ULL, 0, NULL} - , {"secinfo" , 0ULL, 0, NULL} - , {"fsid_present" , 0ULL, 0, NULL} - , - - /* nfsv4.1 client ops */ - { "exchange_id" , 0ULL, 0, NULL} - , {"create_session" , 0ULL, 0, NULL} - , {"destroy_session" , 0ULL, 0, NULL} - , {"sequence" , 0ULL, 0, NULL} - , {"get_lease_time" , 0ULL, 0, NULL} - , {"reclaim_comp" , 0ULL, 0, NULL} - , {"layoutget" , 0ULL, 0, NULL} - , {"getdevinfo" , 0ULL, 0, NULL} - , {"layoutcommit" , 0ULL, 0, NULL} - , {"layoutreturn" , 0ULL, 0, NULL} - , {"secinfo_no" , 0ULL, 0, NULL} - , {"test_stateid" , 0ULL, 0, NULL} - , {"free_stateid" , 0ULL, 0, NULL} - , {"getdevicelist" , 0ULL, 0, NULL} - , {"bind_conn_to_ses", 0ULL, 0, NULL} - , {"destroy_clientid", 0ULL, 0, NULL} - , - - /* nfsv4.2 client ops */ - { "seek" , 0ULL, 0, NULL} - , {"allocate" , 0ULL, 0, NULL} - , {"deallocate" , 0ULL, 0, NULL} - , {"layoutstats" , 0ULL, 0, NULL} - , {"clone" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - -struct nfsd_procs nfsd4_ops_values[] = { - { "unused_op0" , 0ULL, 0, NULL} - , {"unused_op1" , 0ULL, 0, NULL} - , {"future_op2" , 0ULL, 0, NULL} - , {"access" , 0ULL, 0, NULL} - , {"close" , 0ULL, 0, NULL} - , {"commit" , 0ULL, 0, NULL} - , {"create" , 0ULL, 0, NULL} - , {"delegpurge" , 0ULL, 0, NULL} - , {"delegreturn" , 0ULL, 0, NULL} - , {"getattr" , 0ULL, 0, NULL} - , {"getfh" , 0ULL, 0, NULL} - , {"link" , 0ULL, 0, NULL} - , {"lock" , 0ULL, 0, NULL} - , {"lockt" , 0ULL, 0, NULL} - , {"locku" , 0ULL, 0, NULL} - , {"lookup" , 0ULL, 0, NULL} - , {"lookup_root" , 0ULL, 0, NULL} - , {"nverify" , 0ULL, 0, NULL} - , {"open" , 0ULL, 0, NULL} - , {"openattr" , 0ULL, 0, NULL} - , {"open_confirm" , 0ULL, 0, NULL} - , {"open_downgrade" , 0ULL, 0, NULL} - , {"putfh" , 0ULL, 0, NULL} - , {"putpubfh" , 0ULL, 0, NULL} - , {"putrootfh" , 0ULL, 0, NULL} - , {"read" , 0ULL, 0, NULL} - , {"readdir" , 0ULL, 0, NULL} - , {"readlink" , 0ULL, 0, NULL} - , {"remove" , 0ULL, 0, NULL} - , {"rename" , 0ULL, 0, NULL} - , {"renew" , 0ULL, 0, NULL} - , {"restorefh" , 0ULL, 0, NULL} - , {"savefh" , 0ULL, 0, NULL} - , {"secinfo" , 0ULL, 0, NULL} - , {"setattr" , 0ULL, 0, NULL} - , {"setclientid" , 0ULL, 0, NULL} - , {"setclientid_confirm" , 0ULL, 0, NULL} - , {"verify" , 0ULL, 0, NULL} - , {"write" , 0ULL, 0, NULL} - , {"release_lockowner" , 0ULL, 0, NULL} - , - - /* nfs41 */ - { "backchannel_ctl" , 0ULL, 0, NULL} - , {"bind_conn_to_session", 0ULL, 0, NULL} - , {"exchange_id" , 0ULL, 0, NULL} - , {"create_session" , 0ULL, 0, NULL} - , {"destroy_session" , 0ULL, 0, NULL} - , {"free_stateid" , 0ULL, 0, NULL} - , {"get_dir_delegation" , 0ULL, 0, NULL} - , {"getdeviceinfo" , 0ULL, 0, NULL} - , {"getdevicelist" , 0ULL, 0, NULL} - , {"layoutcommit" , 0ULL, 0, NULL} - , {"layoutget" , 0ULL, 0, NULL} - , {"layoutreturn" , 0ULL, 0, NULL} - , {"secinfo_no_name" , 0ULL, 0, NULL} - , {"sequence" , 0ULL, 0, NULL} - , {"set_ssv" , 0ULL, 0, NULL} - , {"test_stateid" , 0ULL, 0, NULL} - , {"want_delegation" , 0ULL, 0, NULL} - , {"destroy_clientid" , 0ULL, 0, NULL} - , {"reclaim_complete" , 0ULL, 0, NULL} - , - - /* nfs42 */ - { "allocate" , 0ULL, 0, NULL} - , {"copy" , 0ULL, 0, NULL} - , {"copy_notify" , 0ULL, 0, NULL} - , {"deallocate" , 0ULL, 0, NULL} - , {"ioadvise" , 0ULL, 0, NULL} - , {"layouterror" , 0ULL, 0, NULL} - , {"layoutstats" , 0ULL, 0, NULL} - , {"offload_cancel" , 0ULL, 0, NULL} - , {"offload_status" , 0ULL, 0, NULL} - , {"read_plus" , 0ULL, 0, NULL} - , {"seek" , 0ULL, 0, NULL} - , {"write_same" , 0ULL, 0, NULL} - , - - /* termination */ - { "" , 0ULL, 0, NULL} -}; - - -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(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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(unlikely(!ff)) return 1; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - if(unlikely(do_rc == -1)) { - do_rc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read cache", 1); - do_fh = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "file handles", 1); - do_io = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "I/O", 1); - do_th = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "threads", 1); - do_ra = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read ahead", 1); - do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "network", 1); - do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "rpc", 1); - do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v2 procedures", 1); - do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v3 procedures", 1); - do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 procedures", 1); - do_proc4ops = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 operations", 1); - } - - // if they are enabled, reset them to 1 - // later we do them = 2 to avoid doing strcmp() for all lines - if(do_rc) do_rc = 1; - if(do_fh) do_fh = 1; - if(do_io) do_io = 1; - if(do_th) do_th = 1; - if(do_ra) do_ra = 1; - if(do_net) do_net = 1; - if(do_rpc) do_rpc = 1; - if(do_proc2) do_proc2 = 1; - if(do_proc3) do_proc3 = 1; - if(do_proc4) do_proc4 = 1; - if(do_proc4ops) do_proc4ops = 1; - - size_t lines = procfile_lines(ff), l; - - char *type; - unsigned long long rc_hits = 0, rc_misses = 0, rc_nocache = 0; - unsigned long long fh_stale = 0, fh_total_lookups = 0, fh_anonymous_lookups = 0, fh_dir_not_in_dcache = 0, fh_non_dir_not_in_dcache = 0; - unsigned long long io_read = 0, io_write = 0; - unsigned long long th_threads = 0, th_fullcnt = 0, th_hist10 = 0, th_hist20 = 0, th_hist30 = 0, th_hist40 = 0, th_hist50 = 0, th_hist60 = 0, th_hist70 = 0, th_hist80 = 0, th_hist90 = 0, th_hist100 = 0; - unsigned long long ra_size = 0, ra_hist10 = 0, ra_hist20 = 0, ra_hist30 = 0, ra_hist40 = 0, ra_hist50 = 0, ra_hist60 = 0, ra_hist70 = 0, ra_hist80 = 0, ra_hist90 = 0, ra_hist100 = 0, ra_none = 0; - unsigned long long net_count = 0, net_udp_count = 0, net_tcp_count = 0, net_tcp_connections = 0; - unsigned long long rpc_calls = 0, rpc_bad_format = 0, rpc_bad_auth = 0, rpc_bad_client = 0; - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(!words)) continue; - - type = procfile_lineword(ff, l, 0); - - if(do_rc == 1 && strcmp(type, "rc") == 0) { - if(unlikely(words < 4)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 4); - continue; - } - - rc_hits = str2ull(procfile_lineword(ff, l, 1)); - rc_misses = str2ull(procfile_lineword(ff, l, 2)); - rc_nocache = str2ull(procfile_lineword(ff, l, 3)); - - unsigned long long sum = rc_hits + rc_misses + rc_nocache; - if(sum == 0ULL) do_rc = -1; - else do_rc = 2; - } - else if(do_fh == 1 && strcmp(type, "fh") == 0) { - if(unlikely(words < 6)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 6); - continue; - } - - fh_stale = str2ull(procfile_lineword(ff, l, 1)); - fh_total_lookups = str2ull(procfile_lineword(ff, l, 2)); - fh_anonymous_lookups = str2ull(procfile_lineword(ff, l, 3)); - fh_dir_not_in_dcache = str2ull(procfile_lineword(ff, l, 4)); - fh_non_dir_not_in_dcache = str2ull(procfile_lineword(ff, l, 5)); - - unsigned long long sum = fh_stale + fh_total_lookups + fh_anonymous_lookups + fh_dir_not_in_dcache + fh_non_dir_not_in_dcache; - if(sum == 0ULL) do_fh = -1; - else do_fh = 2; - } - else if(do_io == 1 && strcmp(type, "io") == 0) { - if(unlikely(words < 3)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 3); - continue; - } - - io_read = str2ull(procfile_lineword(ff, l, 1)); - io_write = str2ull(procfile_lineword(ff, l, 2)); - - unsigned long long sum = io_read + io_write; - if(sum == 0ULL) do_io = -1; - else do_io = 2; - } - else if(do_th == 1 && strcmp(type, "th") == 0) { - if(unlikely(words < 13)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 13); - continue; - } - - th_threads = str2ull(procfile_lineword(ff, l, 1)); - th_fullcnt = str2ull(procfile_lineword(ff, l, 2)); - th_hist10 = (unsigned long long)(atof(procfile_lineword(ff, l, 3)) * 1000.0); - th_hist20 = (unsigned long long)(atof(procfile_lineword(ff, l, 4)) * 1000.0); - th_hist30 = (unsigned long long)(atof(procfile_lineword(ff, l, 5)) * 1000.0); - th_hist40 = (unsigned long long)(atof(procfile_lineword(ff, l, 6)) * 1000.0); - th_hist50 = (unsigned long long)(atof(procfile_lineword(ff, l, 7)) * 1000.0); - th_hist60 = (unsigned long long)(atof(procfile_lineword(ff, l, 8)) * 1000.0); - th_hist70 = (unsigned long long)(atof(procfile_lineword(ff, l, 9)) * 1000.0); - th_hist80 = (unsigned long long)(atof(procfile_lineword(ff, l, 10)) * 1000.0); - th_hist90 = (unsigned long long)(atof(procfile_lineword(ff, l, 11)) * 1000.0); - th_hist100 = (unsigned long long)(atof(procfile_lineword(ff, l, 12)) * 1000.0); - - // threads histogram has been disabled on recent kernels - // http://permalink.gmane.org/gmane.linux.nfs/24528 - unsigned long long sum = th_hist10 + th_hist20 + th_hist30 + th_hist40 + th_hist50 + th_hist60 + th_hist70 + th_hist80 + th_hist90 + th_hist100; - if(sum == 0ULL) { - if(!th_warning) { - info("Disabling /proc/net/rpc/nfsd threads histogram. It seems unused on this machine. It will be enabled automatically when found with data in it."); - th_warning = 1; - } - do_th = -1; - } - else do_th = 2; - } - else if(do_ra == 1 && strcmp(type, "ra") == 0) { - if(unlikely(words < 13)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 13); - continue; - } - - ra_size = str2ull(procfile_lineword(ff, l, 1)); - ra_hist10 = str2ull(procfile_lineword(ff, l, 2)); - ra_hist20 = str2ull(procfile_lineword(ff, l, 3)); - ra_hist30 = str2ull(procfile_lineword(ff, l, 4)); - ra_hist40 = str2ull(procfile_lineword(ff, l, 5)); - ra_hist50 = str2ull(procfile_lineword(ff, l, 6)); - ra_hist60 = str2ull(procfile_lineword(ff, l, 7)); - ra_hist70 = str2ull(procfile_lineword(ff, l, 8)); - ra_hist80 = str2ull(procfile_lineword(ff, l, 9)); - ra_hist90 = str2ull(procfile_lineword(ff, l, 10)); - ra_hist100 = str2ull(procfile_lineword(ff, l, 11)); - ra_none = str2ull(procfile_lineword(ff, l, 12)); - - unsigned long long sum = ra_hist10 + ra_hist20 + ra_hist30 + ra_hist40 + ra_hist50 + ra_hist60 + ra_hist70 + ra_hist80 + ra_hist90 + ra_hist100 + ra_none; - if(sum == 0ULL) { - if(!ra_warning) { - info("Disabling /proc/net/rpc/nfsd read ahead histogram. It seems unused on this machine. It will be enabled automatically when found with data in it."); - ra_warning = 1; - } - do_ra = -1; - } - else do_ra = 2; - } - else if(do_net == 1 && strcmp(type, "net") == 0) { - if(unlikely(words < 5)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 5); - continue; - } - - net_count = str2ull(procfile_lineword(ff, l, 1)); - net_udp_count = str2ull(procfile_lineword(ff, l, 2)); - net_tcp_count = str2ull(procfile_lineword(ff, l, 3)); - net_tcp_connections = str2ull(procfile_lineword(ff, l, 4)); - - unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections; - if(sum == 0ULL) do_net = -1; - else do_net = 2; - } - else if(do_rpc == 1 && strcmp(type, "rpc") == 0) { - if(unlikely(words < 6)) { - error("%s line of /proc/net/rpc/nfsd has %zu words, expected %d", type, words, 6); - continue; - } - - rpc_calls = str2ull(procfile_lineword(ff, l, 1)); - rpc_bad_format = str2ull(procfile_lineword(ff, l, 2)); - rpc_bad_auth = str2ull(procfile_lineword(ff, l, 3)); - rpc_bad_client = str2ull(procfile_lineword(ff, l, 4)); - - unsigned long long sum = rpc_calls + rpc_bad_format + rpc_bad_auth + rpc_bad_client; - if(sum == 0ULL) do_rpc = -1; - else do_rpc = 2; - } - else if(do_proc2 == 1 && strcmp(type, "proc2") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfsd_proc2_values[i].name[0] ; i++, j++) { - nfsd_proc2_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfsd_proc2_values[i].present = 1; - sum += nfsd_proc2_values[i].value; - } - - if(sum == 0ULL) { - if(!proc2_warning) { - error("Disabling /proc/net/rpc/nfsd v2 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc2_warning = 1; - } - do_proc2 = 0; - } - else do_proc2 = 2; - } - else if(do_proc3 == 1 && strcmp(type, "proc3") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfsd_proc3_values[i].name[0] ; i++, j++) { - nfsd_proc3_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfsd_proc3_values[i].present = 1; - sum += nfsd_proc3_values[i].value; - } - - if(sum == 0ULL) { - if(!proc3_warning) { - info("Disabling /proc/net/rpc/nfsd v3 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc3_warning = 1; - } - do_proc3 = 0; - } - else do_proc3 = 2; - } - else if(do_proc4 == 1 && strcmp(type, "proc4") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfsd_proc4_values[i].name[0] ; i++, j++) { - nfsd_proc4_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfsd_proc4_values[i].present = 1; - sum += nfsd_proc4_values[i].value; - } - - if(sum == 0ULL) { - if(!proc4_warning) { - info("Disabling /proc/net/rpc/nfsd v4 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc4_warning = 1; - } - do_proc4 = 0; - } - else do_proc4 = 2; - } - else if(do_proc4ops == 1 && strcmp(type, "proc4ops") == 0) { - // the first number is the count of numbers present - // so we start for word 2 - - unsigned long long sum = 0; - unsigned int i, j; - for(i = 0, j = 2; j < words && nfsd4_ops_values[i].name[0] ; i++, j++) { - nfsd4_ops_values[i].value = str2ull(procfile_lineword(ff, l, j)); - nfsd4_ops_values[i].present = 1; - sum += nfsd4_ops_values[i].value; - } - - if(sum == 0ULL) { - if(!proc4ops_warning) { - info("Disabling /proc/net/rpc/nfsd v4 operations chart. It seems unused on this machine. It will be enabled automatically when found with data in it."); - proc4ops_warning = 1; - } - do_proc4ops = 0; - } - else do_proc4ops = 2; - } - } - - // -------------------------------------------------------------------- - - if(do_rc == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_hits = NULL, - *rd_misses = NULL, - *rd_nocache = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "readcache" - , NULL - , "cache" - , NULL - , "NFS Server Read Cache" - , "reads/s" - , "proc" - , "net/rpc/nfsd" - , 2100 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_hits = rrddim_add(st, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_misses = rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_nocache = rrddim_add(st, "nocache", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_hits, rc_hits); - rrddim_set_by_pointer(st, rd_misses, rc_misses); - rrddim_set_by_pointer(st, rd_nocache, rc_nocache); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_fh == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_stale = NULL, - *rd_total_lookups = NULL, - *rd_anonymous_lookups = NULL, - *rd_dir_not_in_dcache = NULL, - *rd_non_dir_not_in_dcache = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "filehandles" - , NULL - , "filehandles" - , NULL - , "NFS Server File Handles" - , "handles/s" - , "proc" - , "net/rpc/nfsd" - , 2101 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_stale = rrddim_add(st, "stale", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_total_lookups = rrddim_add(st, "total_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_anonymous_lookups = rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_dir_not_in_dcache = rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_non_dir_not_in_dcache = rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_stale, fh_stale); - rrddim_set_by_pointer(st, rd_total_lookups, fh_total_lookups); - rrddim_set_by_pointer(st, rd_anonymous_lookups, fh_anonymous_lookups); - rrddim_set_by_pointer(st, rd_dir_not_in_dcache, fh_dir_not_in_dcache); - rrddim_set_by_pointer(st, rd_non_dir_not_in_dcache, fh_non_dir_not_in_dcache); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_io == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_read = NULL, - *rd_write = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "io" - , NULL - , "io" - , NULL - , "NFS Server I/O" - , "kilobytes/s" - , "proc" - , "net/rpc/nfsd" - , 2102 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_read = rrddim_add(st, "read", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rd_write = rrddim_add(st, "write", NULL, -1, 1000, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_read, io_read); - rrddim_set_by_pointer(st, rd_write, io_write); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_th == 2) { - { - static RRDSET *st = NULL; - static RRDDIM *rd_threads = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "threads" - , NULL - , "threads" - , NULL - , "NFS Server Threads" - , "threads" - , "proc" - , "net/rpc/nfsd" - , 2103 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_threads = rrddim_add(st, "threads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_threads, th_threads); - rrdset_done(st); - } - - { - static RRDSET *st = NULL; - static RRDDIM *rd_full_count = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "threads_fullcnt" - , NULL - , "threads" - , NULL - , "NFS Server Threads Full Count" - , "ops/s" - , "proc" - , "net/rpc/nfsd" - , 2104 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_full_count = rrddim_add(st, "full_count", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_full_count, th_fullcnt); - rrdset_done(st); - } - - { - static RRDSET *st = NULL; - static RRDDIM *rd_th_hist10 = NULL, - *rd_th_hist20 = NULL, - *rd_th_hist30 = NULL, - *rd_th_hist40 = NULL, - *rd_th_hist50 = NULL, - *rd_th_hist60 = NULL, - *rd_th_hist70 = NULL, - *rd_th_hist80 = NULL, - *rd_th_hist90 = NULL, - *rd_th_hist100 = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "threads_histogram" - , NULL - , "threads" - , NULL - , "NFS Server Threads Usage Histogram" - , "percentage" - , "proc" - , "net/rpc/nfsd" - , 2105 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_th_hist10 = rrddim_add(st, "0%-10%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist20 = rrddim_add(st, "10%-20%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist30 = rrddim_add(st, "20%-30%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist40 = rrddim_add(st, "30%-40%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist50 = rrddim_add(st, "40%-50%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist60 = rrddim_add(st, "50%-60%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist70 = rrddim_add(st, "60%-70%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist80 = rrddim_add(st, "70%-80%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist90 = rrddim_add(st, "80%-90%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rd_th_hist100 = rrddim_add(st, "90%-100%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_th_hist10, th_hist10); - rrddim_set_by_pointer(st, rd_th_hist20, th_hist20); - rrddim_set_by_pointer(st, rd_th_hist30, th_hist30); - rrddim_set_by_pointer(st, rd_th_hist40, th_hist40); - rrddim_set_by_pointer(st, rd_th_hist50, th_hist50); - rrddim_set_by_pointer(st, rd_th_hist60, th_hist60); - rrddim_set_by_pointer(st, rd_th_hist70, th_hist70); - rrddim_set_by_pointer(st, rd_th_hist80, th_hist80); - rrddim_set_by_pointer(st, rd_th_hist90, th_hist90); - rrddim_set_by_pointer(st, rd_th_hist100, th_hist100); - rrdset_done(st); - } - } - - // -------------------------------------------------------------------- - - if(do_ra == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_ra_hist10 = NULL, - *rd_ra_hist20 = NULL, - *rd_ra_hist30 = NULL, - *rd_ra_hist40 = NULL, - *rd_ra_hist50 = NULL, - *rd_ra_hist60 = NULL, - *rd_ra_hist70 = NULL, - *rd_ra_hist80 = NULL, - *rd_ra_hist90 = NULL, - *rd_ra_hist100 = NULL, - *rd_ra_none = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "readahead" - , NULL - , "readahead" - , NULL - , "NFS Server Read Ahead Depth" - , "percentage" - , "proc" - , "net/rpc/nfsd" - , 2105 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_ra_hist10 = rrddim_add(st, "10%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist20 = rrddim_add(st, "20%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist30 = rrddim_add(st, "30%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist40 = rrddim_add(st, "40%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist50 = rrddim_add(st, "50%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist60 = rrddim_add(st, "60%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist70 = rrddim_add(st, "70%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist80 = rrddim_add(st, "80%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist90 = rrddim_add(st, "90%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_hist100 = rrddim_add(st, "100%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_ra_none = rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else rrdset_next(st); - - // ignore ra_size - (void)ra_size; - - rrddim_set_by_pointer(st, rd_ra_hist10, ra_hist10); - rrddim_set_by_pointer(st, rd_ra_hist20, ra_hist20); - rrddim_set_by_pointer(st, rd_ra_hist30, ra_hist30); - rrddim_set_by_pointer(st, rd_ra_hist40, ra_hist40); - rrddim_set_by_pointer(st, rd_ra_hist50, ra_hist50); - rrddim_set_by_pointer(st, rd_ra_hist60, ra_hist60); - rrddim_set_by_pointer(st, rd_ra_hist70, ra_hist70); - rrddim_set_by_pointer(st, rd_ra_hist80, ra_hist80); - rrddim_set_by_pointer(st, rd_ra_hist90, ra_hist90); - rrddim_set_by_pointer(st, rd_ra_hist100,ra_hist100); - rrddim_set_by_pointer(st, rd_ra_none, ra_none); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_net == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_udp = NULL, - *rd_tcp = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "net" - , NULL - , "network" - , NULL - , "NFS Server Network Statistics" - , "packets/s" - , "proc" - , "net/rpc/nfsd" - , 2107 - , update_every - , RRDSET_TYPE_STACKED - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_udp = rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_tcp = rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - // ignore net_count, net_tcp_connections - (void)net_count; - (void)net_tcp_connections; - - rrddim_set_by_pointer(st, rd_udp, net_udp_count); - rrddim_set_by_pointer(st, rd_tcp, net_tcp_count); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_rpc == 2) { - static RRDSET *st = NULL; - static RRDDIM *rd_calls = NULL, - *rd_bad_format = NULL, - *rd_bad_auth = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "rpc" - , NULL - , "rpc" - , NULL - , "NFS Server Remote Procedure Calls Statistics" - , "calls/s" - , "proc" - , "net/rpc/nfsd" - , 2108 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_calls = rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_bad_format = rrddim_add(st, "bad_format", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_bad_auth = rrddim_add(st, "bad_auth", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - // ignore rpc_bad_client - (void)rpc_bad_client; - - rrddim_set_by_pointer(st, rd_calls, rpc_calls); - rrddim_set_by_pointer(st, rd_bad_format, rpc_bad_format); - rrddim_set_by_pointer(st, rd_bad_auth, rpc_bad_auth); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc2 == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "proc2" - , NULL - , "nfsv2rpc" - , NULL - , "NFS v2 Server Remote Procedure Calls" - , "calls/s" - , "proc" - , "net/rpc/nfsd" - , 2109 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfsd_proc2_values[i].present ; i++) { - if(unlikely(!nfsd_proc2_values[i].rd)) - nfsd_proc2_values[i].rd = rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfsd_proc2_values[i].rd, nfsd_proc2_values[i].value); - } - - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc3 == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "proc3" - , NULL - , "nfsv3rpc" - , NULL - , "NFS v3 Server Remote Procedure Calls" - , "calls/s" - , "proc" - , "net/rpc/nfsd" - , 2110 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfsd_proc3_values[i].present ; i++) { - if(unlikely(!nfsd_proc3_values[i].rd)) - nfsd_proc3_values[i].rd = rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfsd_proc3_values[i].rd, nfsd_proc3_values[i].value); - } - - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc4 == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "proc4" - , NULL - , "nfsv4rpc" - , NULL - , "NFS v4 Server Remote Procedure Calls" - , "calls/s" - , "proc" - , "net/rpc/nfsd" - , 2111 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfsd_proc4_values[i].present ; i++) { - if(unlikely(!nfsd_proc4_values[i].rd)) - nfsd_proc4_values[i].rd = rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfsd_proc4_values[i].rd, nfsd_proc4_values[i].value); - } - - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_proc4ops == 2) { - static RRDSET *st = NULL; - if(unlikely(!st)) { - st = rrdset_create_localhost( - "nfsd" - , "proc4ops" - , NULL - , "nfsv2ops" - , NULL - , "NFS v4 Server Operations" - , "operations/s" - , "proc" - , "net/rpc/nfsd" - , 2112 - , update_every - , RRDSET_TYPE_STACKED - ); - } - else rrdset_next(st); - - size_t i; - for(i = 0; nfsd4_ops_values[i].present ; i++) { - if(unlikely(!nfsd4_ops_values[i].rd)) - nfsd4_ops_values[i].rd = rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st, nfsd4_ops_values[i].rd, nfsd4_ops_values[i].value); - } - - rrdset_done(st); - } - - return 0; -} diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c deleted file mode 100644 index 43c010c14..000000000 --- a/src/proc_net_snmp.c +++ /dev/null @@ -1,1020 +0,0 @@ -#include "common.h" - -#define RRD_TYPE_NET_SNMP "ipv4" - -static struct proc_net_snmp { - // kernel_uint_t ip_Forwarding; - kernel_uint_t ip_DefaultTTL; - kernel_uint_t ip_InReceives; - kernel_uint_t ip_InHdrErrors; - kernel_uint_t ip_InAddrErrors; - kernel_uint_t ip_ForwDatagrams; - kernel_uint_t ip_InUnknownProtos; - kernel_uint_t ip_InDiscards; - kernel_uint_t ip_InDelivers; - kernel_uint_t ip_OutRequests; - kernel_uint_t ip_OutDiscards; - kernel_uint_t ip_OutNoRoutes; - kernel_uint_t ip_ReasmTimeout; - kernel_uint_t ip_ReasmReqds; - kernel_uint_t ip_ReasmOKs; - kernel_uint_t ip_ReasmFails; - kernel_uint_t ip_FragOKs; - kernel_uint_t ip_FragFails; - kernel_uint_t ip_FragCreates; - - kernel_uint_t icmp_InMsgs; - kernel_uint_t icmp_OutMsgs; - kernel_uint_t icmp_InErrors; - kernel_uint_t icmp_OutErrors; - kernel_uint_t icmp_InCsumErrors; - - kernel_uint_t icmpmsg_InEchoReps; - kernel_uint_t icmpmsg_OutEchoReps; - kernel_uint_t icmpmsg_InDestUnreachs; - kernel_uint_t icmpmsg_OutDestUnreachs; - kernel_uint_t icmpmsg_InRedirects; - kernel_uint_t icmpmsg_OutRedirects; - kernel_uint_t icmpmsg_InEchos; - kernel_uint_t icmpmsg_OutEchos; - kernel_uint_t icmpmsg_InRouterAdvert; - kernel_uint_t icmpmsg_OutRouterAdvert; - kernel_uint_t icmpmsg_InRouterSelect; - kernel_uint_t icmpmsg_OutRouterSelect; - kernel_uint_t icmpmsg_InTimeExcds; - kernel_uint_t icmpmsg_OutTimeExcds; - kernel_uint_t icmpmsg_InParmProbs; - kernel_uint_t icmpmsg_OutParmProbs; - kernel_uint_t icmpmsg_InTimestamps; - kernel_uint_t icmpmsg_OutTimestamps; - kernel_uint_t icmpmsg_InTimestampReps; - kernel_uint_t icmpmsg_OutTimestampReps; - - //kernel_uint_t tcp_RtoAlgorithm; - //kernel_uint_t tcp_RtoMin; - //kernel_uint_t tcp_RtoMax; - ssize_t tcp_MaxConn; - kernel_uint_t tcp_ActiveOpens; - kernel_uint_t tcp_PassiveOpens; - kernel_uint_t tcp_AttemptFails; - kernel_uint_t tcp_EstabResets; - kernel_uint_t tcp_CurrEstab; - kernel_uint_t tcp_InSegs; - kernel_uint_t tcp_OutSegs; - kernel_uint_t tcp_RetransSegs; - kernel_uint_t tcp_InErrs; - kernel_uint_t tcp_OutRsts; - kernel_uint_t tcp_InCsumErrors; - - kernel_uint_t udp_InDatagrams; - kernel_uint_t udp_NoPorts; - kernel_uint_t udp_InErrors; - kernel_uint_t udp_OutDatagrams; - kernel_uint_t udp_RcvbufErrors; - kernel_uint_t udp_SndbufErrors; - kernel_uint_t udp_InCsumErrors; - kernel_uint_t udp_IgnoredMulti; - - kernel_uint_t udplite_InDatagrams; - kernel_uint_t udplite_NoPorts; - kernel_uint_t udplite_InErrors; - kernel_uint_t udplite_OutDatagrams; - kernel_uint_t udplite_RcvbufErrors; - kernel_uint_t udplite_SndbufErrors; - kernel_uint_t udplite_InCsumErrors; - kernel_uint_t udplite_IgnoredMulti; -} snmp_root = { 0 }; - -int do_proc_net_snmp(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1, - do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcp_opens = -1, - do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1, do_udplite_packets = -1; - static uint32_t hash_ip = 0, hash_icmp = 0, hash_tcp = 0, hash_udp = 0, hash_icmpmsg = 0, hash_udplite = 0; - - static ARL_BASE *arl_ip = NULL, - *arl_icmp = NULL, - *arl_icmpmsg = NULL, - *arl_tcp = NULL, - *arl_udp = NULL, - *arl_udplite = NULL; - - static RRDVAR *tcp_max_connections_var = NULL; - static ssize_t last_max_connections = 0; - - if(unlikely(!arl_ip)) { - do_ip_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1); - do_ip_fragsout = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1); - do_ip_fragsin = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1); - do_ip_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1); - do_tcp_sockets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1); - do_tcp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1); - do_tcp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1); - do_tcp_opens = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP opens", 1); - do_tcp_handshake = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1); - do_udp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1); - do_udp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1); - do_icmp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 ICMP packets", 1); - do_icmpmsg = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 ICMP messages", 1); - do_udplite_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDPLite packets", 1); - - hash_ip = simple_hash("Ip"); - hash_tcp = simple_hash("Tcp"); - hash_udp = simple_hash("Udp"); - hash_icmp = simple_hash("Icmp"); - hash_icmpmsg = simple_hash("IcmpMsg"); - hash_udplite = simple_hash("UdpLite"); - - arl_ip = arl_create("snmp/Ip", arl_callback_str2kernel_uint_t, 60); - // arl_expect(arl_ip, "Forwarding", &snmp_root.ip_Forwarding); - arl_expect(arl_ip, "DefaultTTL", &snmp_root.ip_DefaultTTL); - arl_expect(arl_ip, "InReceives", &snmp_root.ip_InReceives); - arl_expect(arl_ip, "InHdrErrors", &snmp_root.ip_InHdrErrors); - arl_expect(arl_ip, "InAddrErrors", &snmp_root.ip_InAddrErrors); - arl_expect(arl_ip, "ForwDatagrams", &snmp_root.ip_ForwDatagrams); - arl_expect(arl_ip, "InUnknownProtos", &snmp_root.ip_InUnknownProtos); - arl_expect(arl_ip, "InDiscards", &snmp_root.ip_InDiscards); - arl_expect(arl_ip, "InDelivers", &snmp_root.ip_InDelivers); - arl_expect(arl_ip, "OutRequests", &snmp_root.ip_OutRequests); - arl_expect(arl_ip, "OutDiscards", &snmp_root.ip_OutDiscards); - arl_expect(arl_ip, "OutNoRoutes", &snmp_root.ip_OutNoRoutes); - arl_expect(arl_ip, "ReasmTimeout", &snmp_root.ip_ReasmTimeout); - arl_expect(arl_ip, "ReasmReqds", &snmp_root.ip_ReasmReqds); - arl_expect(arl_ip, "ReasmOKs", &snmp_root.ip_ReasmOKs); - arl_expect(arl_ip, "ReasmFails", &snmp_root.ip_ReasmFails); - arl_expect(arl_ip, "FragOKs", &snmp_root.ip_FragOKs); - arl_expect(arl_ip, "FragFails", &snmp_root.ip_FragFails); - arl_expect(arl_ip, "FragCreates", &snmp_root.ip_FragCreates); - - arl_icmp = arl_create("snmp/Icmp", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_icmp, "InMsgs", &snmp_root.icmp_InMsgs); - arl_expect(arl_icmp, "OutMsgs", &snmp_root.icmp_OutMsgs); - arl_expect(arl_icmp, "InErrors", &snmp_root.icmp_InErrors); - arl_expect(arl_icmp, "OutErrors", &snmp_root.icmp_OutErrors); - arl_expect(arl_icmp, "InCsumErrors", &snmp_root.icmp_InCsumErrors); - - arl_icmpmsg = arl_create("snmp/Icmpmsg", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_icmpmsg, "InType0", &snmp_root.icmpmsg_InEchoReps); - arl_expect(arl_icmpmsg, "OutType0", &snmp_root.icmpmsg_OutEchoReps); - arl_expect(arl_icmpmsg, "InType3", &snmp_root.icmpmsg_InDestUnreachs); - arl_expect(arl_icmpmsg, "OutType3", &snmp_root.icmpmsg_OutDestUnreachs); - arl_expect(arl_icmpmsg, "InType5", &snmp_root.icmpmsg_InRedirects); - arl_expect(arl_icmpmsg, "OutType5", &snmp_root.icmpmsg_OutRedirects); - arl_expect(arl_icmpmsg, "InType8", &snmp_root.icmpmsg_InEchos); - arl_expect(arl_icmpmsg, "OutType8", &snmp_root.icmpmsg_OutEchos); - arl_expect(arl_icmpmsg, "InType9", &snmp_root.icmpmsg_InRouterAdvert); - arl_expect(arl_icmpmsg, "OutType9", &snmp_root.icmpmsg_OutRouterAdvert); - arl_expect(arl_icmpmsg, "InType10", &snmp_root.icmpmsg_InRouterSelect); - arl_expect(arl_icmpmsg, "OutType10", &snmp_root.icmpmsg_OutRouterSelect); - arl_expect(arl_icmpmsg, "InType11", &snmp_root.icmpmsg_InTimeExcds); - arl_expect(arl_icmpmsg, "OutType11", &snmp_root.icmpmsg_OutTimeExcds); - arl_expect(arl_icmpmsg, "InType12", &snmp_root.icmpmsg_InParmProbs); - arl_expect(arl_icmpmsg, "OutType12", &snmp_root.icmpmsg_OutParmProbs); - arl_expect(arl_icmpmsg, "InType13", &snmp_root.icmpmsg_InTimestamps); - arl_expect(arl_icmpmsg, "OutType13", &snmp_root.icmpmsg_OutTimestamps); - arl_expect(arl_icmpmsg, "InType14", &snmp_root.icmpmsg_InTimestampReps); - arl_expect(arl_icmpmsg, "OutType14", &snmp_root.icmpmsg_OutTimestampReps); - - arl_tcp = arl_create("snmp/Tcp", arl_callback_str2kernel_uint_t, 60); - // arl_expect(arl_tcp, "RtoAlgorithm", &snmp_root.tcp_RtoAlgorithm); - // arl_expect(arl_tcp, "RtoMin", &snmp_root.tcp_RtoMin); - // arl_expect(arl_tcp, "RtoMax", &snmp_root.tcp_RtoMax); - arl_expect(arl_tcp, "MaxConn", &snmp_root.tcp_MaxConn); - arl_expect(arl_tcp, "ActiveOpens", &snmp_root.tcp_ActiveOpens); - arl_expect(arl_tcp, "PassiveOpens", &snmp_root.tcp_PassiveOpens); - arl_expect(arl_tcp, "AttemptFails", &snmp_root.tcp_AttemptFails); - arl_expect(arl_tcp, "EstabResets", &snmp_root.tcp_EstabResets); - arl_expect(arl_tcp, "CurrEstab", &snmp_root.tcp_CurrEstab); - arl_expect(arl_tcp, "InSegs", &snmp_root.tcp_InSegs); - arl_expect(arl_tcp, "OutSegs", &snmp_root.tcp_OutSegs); - arl_expect(arl_tcp, "RetransSegs", &snmp_root.tcp_RetransSegs); - arl_expect(arl_tcp, "InErrs", &snmp_root.tcp_InErrs); - arl_expect(arl_tcp, "OutRsts", &snmp_root.tcp_OutRsts); - arl_expect(arl_tcp, "InCsumErrors", &snmp_root.tcp_InCsumErrors); - - arl_udp = arl_create("snmp/Udp", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_udp, "InDatagrams", &snmp_root.udp_InDatagrams); - arl_expect(arl_udp, "NoPorts", &snmp_root.udp_NoPorts); - arl_expect(arl_udp, "InErrors", &snmp_root.udp_InErrors); - arl_expect(arl_udp, "OutDatagrams", &snmp_root.udp_OutDatagrams); - arl_expect(arl_udp, "RcvbufErrors", &snmp_root.udp_RcvbufErrors); - arl_expect(arl_udp, "SndbufErrors", &snmp_root.udp_SndbufErrors); - arl_expect(arl_udp, "InCsumErrors", &snmp_root.udp_InCsumErrors); - arl_expect(arl_udp, "IgnoredMulti", &snmp_root.udp_IgnoredMulti); - - arl_udplite = arl_create("snmp/Udplite", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_udplite, "InDatagrams", &snmp_root.udplite_InDatagrams); - arl_expect(arl_udplite, "NoPorts", &snmp_root.udplite_NoPorts); - arl_expect(arl_udplite, "InErrors", &snmp_root.udplite_InErrors); - arl_expect(arl_udplite, "OutDatagrams", &snmp_root.udplite_OutDatagrams); - arl_expect(arl_udplite, "RcvbufErrors", &snmp_root.udplite_RcvbufErrors); - arl_expect(arl_udplite, "SndbufErrors", &snmp_root.udplite_SndbufErrors); - arl_expect(arl_udplite, "InCsumErrors", &snmp_root.udplite_InCsumErrors); - arl_expect(arl_udplite, "IgnoredMulti", &snmp_root.udplite_IgnoredMulti); - - tcp_max_connections_var = rrdvar_custom_host_variable_create(localhost, "tcp_max_connections"); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - size_t words, w; - - for(l = 0; l < lines ;l++) { - char *key = procfile_lineword(ff, l, 0); - uint32_t hash = simple_hash(key); - - if(unlikely(hash == hash_ip && strcmp(key, "Ip") == 0)) { - size_t h = l++; - - if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) { - error("Cannot read Ip line from /proc/net/snmp."); - break; - } - - words = procfile_linewords(ff, l); - if(words < 3) { - error("Cannot read /proc/net/snmp Ip line. Expected 3+ params, read %zu.", words); - continue; - } - - arl_begin(arl_ip); - for(w = 1; w < words ; w++) { - if (unlikely(arl_check(arl_ip, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) - break; - } - - // -------------------------------------------------------------------- - - if(do_ip_packets) { - static RRDSET *st = NULL; - static RRDDIM *rd_InReceives = NULL, - *rd_OutRequests = NULL, - *rd_ForwDatagrams = NULL, - *rd_InDelivers = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "packets" - , NULL - , "packets" - , NULL - , "IPv4 Packets" - , "packets/s" - , "proc" - , "net/snmp" - , 2450 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InReceives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutRequests = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_ForwDatagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InDelivers = rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_OutRequests, (collected_number)snmp_root.ip_OutRequests); - rrddim_set_by_pointer(st, rd_InReceives, (collected_number)snmp_root.ip_InReceives); - rrddim_set_by_pointer(st, rd_ForwDatagrams, (collected_number)snmp_root.ip_ForwDatagrams); - rrddim_set_by_pointer(st, rd_InDelivers, (collected_number)snmp_root.ip_InDelivers); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_fragsout) { - static RRDSET *st = NULL; - static RRDDIM *rd_FragOKs = NULL, - *rd_FragFails = NULL, - *rd_FragCreates = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "fragsout" - , NULL - , "fragments" - , NULL - , "IPv4 Fragments Sent" - , "packets/s" - , "proc" - , "net/snmp" - , 3020 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_FragOKs = rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_FragFails = rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_FragCreates = rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_FragOKs, (collected_number)snmp_root.ip_FragOKs); - rrddim_set_by_pointer(st, rd_FragFails, (collected_number)snmp_root.ip_FragFails); - rrddim_set_by_pointer(st, rd_FragCreates, (collected_number)snmp_root.ip_FragCreates); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_fragsin) { - static RRDSET *st = NULL; - static RRDDIM *rd_ReasmOKs = NULL, - *rd_ReasmFails = NULL, - *rd_ReasmReqds = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "fragsin" - , NULL - , "fragments" - , NULL - , "IPv4 Fragments Reassembly" - , "packets/s" - , "proc" - , "net/snmp" - , 3030 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_ReasmOKs = rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_ReasmFails = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_ReasmReqds = rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_ReasmOKs, (collected_number)snmp_root.ip_ReasmOKs); - rrddim_set_by_pointer(st, rd_ReasmFails, (collected_number)snmp_root.ip_ReasmFails); - rrddim_set_by_pointer(st, rd_ReasmReqds, (collected_number)snmp_root.ip_ReasmReqds); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_errors) { - static RRDSET *st = NULL; - static RRDDIM *rd_InDiscards = NULL, - *rd_OutDiscards = NULL, - *rd_InHdrErrors = NULL, - *rd_OutNoRoutes = NULL, - *rd_InAddrErrors = NULL, - *rd_InUnknownProtos = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "errors" - , NULL - , "errors" - , NULL - , "IPv4 Errors" - , "packets/s" - , "proc" - , "net/snmp" - , 2470 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_InDiscards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutDiscards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - rd_InHdrErrors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutNoRoutes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - rd_InAddrErrors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InUnknownProtos = rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InDiscards, (collected_number)snmp_root.ip_InDiscards); - rrddim_set_by_pointer(st, rd_OutDiscards, (collected_number)snmp_root.ip_OutDiscards); - rrddim_set_by_pointer(st, rd_InHdrErrors, (collected_number)snmp_root.ip_InHdrErrors); - rrddim_set_by_pointer(st, rd_InAddrErrors, (collected_number)snmp_root.ip_InAddrErrors); - rrddim_set_by_pointer(st, rd_InUnknownProtos, (collected_number)snmp_root.ip_InUnknownProtos); - rrddim_set_by_pointer(st, rd_OutNoRoutes, (collected_number)snmp_root.ip_OutNoRoutes); - rrdset_done(st); - } - } - else if(unlikely(hash == hash_icmp && strcmp(key, "Icmp") == 0)) { - size_t h = l++; - - if(strcmp(procfile_lineword(ff, l, 0), "Icmp") != 0) { - error("Cannot read Icmp line from /proc/net/snmp."); - break; - } - - words = procfile_linewords(ff, l); - if(words < 3) { - error("Cannot read /proc/net/snmp Icmp line. Expected 3+ params, read %zu.", words); - continue; - } - - arl_begin(arl_icmp); - for(w = 1; w < words ; w++) { - if (unlikely(arl_check(arl_icmp, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) - break; - } - - // -------------------------------------------------------------------- - - if(do_icmp_packets) { - { - static RRDSET *st_packets = NULL; - static RRDDIM *rd_InMsgs = NULL, - *rd_OutMsgs = NULL; - - if(unlikely(!st_packets)) { - st_packets = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "icmp" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Packets" - , "packets/s" - , "proc" - , "net/snmp" - , 2602 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InMsgs = rrddim_add(st_packets, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutMsgs = rrddim_add(st_packets, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_packets); - - rrddim_set_by_pointer(st_packets, rd_InMsgs, (collected_number)snmp_root.icmp_InMsgs); - rrddim_set_by_pointer(st_packets, rd_OutMsgs, (collected_number)snmp_root.icmp_OutMsgs); - - rrdset_done(st_packets); - } - - { - static RRDSET *st_errors = NULL; - static RRDDIM *rd_InErrors = NULL, - *rd_OutErrors = NULL, - *rd_InCsumErrors = NULL; - - if(unlikely(!st_errors)) { - st_errors = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "icmp_errors" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Errors" - , "packets/s" - , "proc" - , "net/snmp" - , 2603 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InErrors = rrddim_add(st_errors, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutErrors = rrddim_add(st_errors, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st_errors, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_errors); - - rrddim_set_by_pointer(st_errors, rd_InErrors, (collected_number)snmp_root.icmp_InErrors); - rrddim_set_by_pointer(st_errors, rd_OutErrors, (collected_number)snmp_root.icmp_OutErrors); - rrddim_set_by_pointer(st_errors, rd_InCsumErrors, (collected_number)snmp_root.icmp_InCsumErrors); - - rrdset_done(st_errors); - } - } - } - else if(unlikely(hash == hash_icmpmsg && strcmp(key, "IcmpMsg") == 0)) { - size_t h = l++; - - if(strcmp(procfile_lineword(ff, l, 0), "IcmpMsg") != 0) { - error("Cannot read IcmpMsg line from /proc/net/snmp."); - break; - } - - words = procfile_linewords(ff, l); - if(words < 3) { - error("Cannot read /proc/net/snmp IcmpMsg line. Expected 3+ params, read %zu.", words); - continue; - } - - arl_begin(arl_icmpmsg); - for(w = 1; w < words ; w++) { - if (unlikely(arl_check(arl_icmpmsg, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) - break; - } - - // -------------------------------------------------------------------- - - if(do_icmpmsg) { - static RRDSET *st = NULL; - static RRDDIM *rd_InEchoReps = NULL, - *rd_OutEchoReps = NULL, - *rd_InDestUnreachs = NULL, - *rd_OutDestUnreachs = NULL, - *rd_InRedirects = NULL, - *rd_OutRedirects = NULL, - *rd_InEchos = NULL, - *rd_OutEchos = NULL, - *rd_InRouterAdvert = NULL, - *rd_OutRouterAdvert = NULL, - *rd_InRouterSelect = NULL, - *rd_OutRouterSelect = NULL, - *rd_InTimeExcds = NULL, - *rd_OutTimeExcds = NULL, - *rd_InParmProbs = NULL, - *rd_OutParmProbs = NULL, - *rd_InTimestamps = NULL, - *rd_OutTimestamps = NULL, - *rd_InTimestampReps = NULL, - *rd_OutTimestampReps = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "icmpmsg" - , NULL - , "icmp" - , NULL - , "IPv4 ICMP Messages" - , "packets/s" - , "proc" - , "net/snmp" - , 2604 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InEchoReps = rrddim_add(st, "InType0", "InEchoReps", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutEchoReps = rrddim_add(st, "OutType0", "OutEchoReps", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InDestUnreachs = rrddim_add(st, "InType3", "InDestUnreachs", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutDestUnreachs = rrddim_add(st, "OutType3", "OutDestUnreachs", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InRedirects = rrddim_add(st, "InType5", "InRedirects", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutRedirects = rrddim_add(st, "OutType5", "OutRedirects", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InEchos = rrddim_add(st, "InType8", "InEchos", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutEchos = rrddim_add(st, "OutType8", "OutEchos", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InRouterAdvert = rrddim_add(st, "InType9", "InRouterAdvert", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutRouterAdvert = rrddim_add(st, "OutType9", "OutRouterAdvert", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InRouterSelect = rrddim_add(st, "InType10", "InRouterSelect", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutRouterSelect = rrddim_add(st, "OutType10", "OutRouterSelect", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InTimeExcds = rrddim_add(st, "InType11", "InTimeExcds", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutTimeExcds = rrddim_add(st, "OutType11", "OutTimeExcds", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InParmProbs = rrddim_add(st, "InType12", "InParmProbs", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutParmProbs = rrddim_add(st, "OutType12", "OutParmProbs", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InTimestamps = rrddim_add(st, "InType13", "InTimestamps", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutTimestamps = rrddim_add(st, "OutType13", "OutTimestamps", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InTimestampReps = rrddim_add(st, "InType14", "InTimestampReps", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutTimestampReps = rrddim_add(st, "OutType14", "OutTimestampReps", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InEchoReps, (collected_number)snmp_root.icmpmsg_InEchoReps); - rrddim_set_by_pointer(st, rd_OutEchoReps, (collected_number)snmp_root.icmpmsg_OutEchoReps); - rrddim_set_by_pointer(st, rd_InDestUnreachs, (collected_number)snmp_root.icmpmsg_InDestUnreachs); - rrddim_set_by_pointer(st, rd_OutDestUnreachs, (collected_number)snmp_root.icmpmsg_OutDestUnreachs); - rrddim_set_by_pointer(st, rd_InRedirects, (collected_number)snmp_root.icmpmsg_InRedirects); - rrddim_set_by_pointer(st, rd_OutRedirects, (collected_number)snmp_root.icmpmsg_OutRedirects); - rrddim_set_by_pointer(st, rd_InEchos, (collected_number)snmp_root.icmpmsg_InEchos); - rrddim_set_by_pointer(st, rd_OutEchos, (collected_number)snmp_root.icmpmsg_OutEchos); - rrddim_set_by_pointer(st, rd_InRouterAdvert, (collected_number)snmp_root.icmpmsg_InRouterAdvert); - rrddim_set_by_pointer(st, rd_OutRouterAdvert, (collected_number)snmp_root.icmpmsg_OutRouterAdvert); - rrddim_set_by_pointer(st, rd_InRouterSelect, (collected_number)snmp_root.icmpmsg_InRouterSelect); - rrddim_set_by_pointer(st, rd_OutRouterSelect, (collected_number)snmp_root.icmpmsg_OutRouterSelect); - rrddim_set_by_pointer(st, rd_InTimeExcds, (collected_number)snmp_root.icmpmsg_InTimeExcds); - rrddim_set_by_pointer(st, rd_OutTimeExcds, (collected_number)snmp_root.icmpmsg_OutTimeExcds); - rrddim_set_by_pointer(st, rd_InParmProbs, (collected_number)snmp_root.icmpmsg_InParmProbs); - rrddim_set_by_pointer(st, rd_OutParmProbs, (collected_number)snmp_root.icmpmsg_OutParmProbs); - rrddim_set_by_pointer(st, rd_InTimestamps, (collected_number)snmp_root.icmpmsg_InTimestamps); - rrddim_set_by_pointer(st, rd_OutTimestamps, (collected_number)snmp_root.icmpmsg_OutTimestamps); - rrddim_set_by_pointer(st, rd_InTimestampReps, (collected_number)snmp_root.icmpmsg_InTimestampReps); - rrddim_set_by_pointer(st, rd_OutTimestampReps, (collected_number)snmp_root.icmpmsg_OutTimestampReps); - - rrdset_done(st); - } - } - else if(unlikely(hash == hash_tcp && strcmp(key, "Tcp") == 0)) { - size_t h = l++; - - if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) { - error("Cannot read Tcp line from /proc/net/snmp."); - break; - } - - words = procfile_linewords(ff, l); - if(words < 3) { - error("Cannot read /proc/net/snmp Tcp line. Expected 3+ params, read %zu.", words); - continue; - } - - arl_begin(arl_tcp); - for(w = 1; w < words ; w++) { - if (unlikely(arl_check(arl_tcp, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) - break; - } - - // -------------------------------------------------------------------- - - if(snmp_root.tcp_MaxConn != last_max_connections) { - last_max_connections = snmp_root.tcp_MaxConn; - rrdvar_custom_host_variable_set(localhost, tcp_max_connections_var, last_max_connections); - } - - // -------------------------------------------------------------------- - - // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html - if(do_tcp_sockets) { - static RRDSET *st = NULL; - static RRDDIM *rd_CurrEstab = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "tcpsock" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Connections" - , "active connections" - , "proc" - , "net/snmp" - , 2501 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_CurrEstab = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_CurrEstab, (collected_number)snmp_root.tcp_CurrEstab); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_tcp_packets) { - static RRDSET *st = NULL; - static RRDDIM *rd_InSegs = NULL, - *rd_OutSegs = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "tcppackets" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Packets" - , "packets/s" - , "proc" - , "net/snmp" - , 2510 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InSegs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutSegs = rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InSegs, (collected_number)snmp_root.tcp_InSegs); - rrddim_set_by_pointer(st, rd_OutSegs, (collected_number)snmp_root.tcp_OutSegs); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_tcp_errors) { - static RRDSET *st = NULL; - static RRDDIM *rd_InErrs = NULL, - *rd_InCsumErrors = NULL, - *rd_RetransSegs = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "tcperrors" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Errors" - , "packets/s" - , "proc" - , "net/snmp" - , 2525 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_InErrs = rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_RetransSegs = rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InErrs, (collected_number)snmp_root.tcp_InErrs); - rrddim_set_by_pointer(st, rd_InCsumErrors, (collected_number)snmp_root.tcp_InCsumErrors); - rrddim_set_by_pointer(st, rd_RetransSegs, (collected_number)snmp_root.tcp_RetransSegs); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_tcp_opens) { - static RRDSET *st = NULL; - static RRDDIM *rd_ActiveOpens = NULL, - *rd_PassiveOpens = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "tcpopens" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Opens" - , "connections/s" - , "proc" - , "net/snmp" - , 2502 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_ActiveOpens = rrddim_add(st, "ActiveOpens", "active", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_PassiveOpens = rrddim_add(st, "PassiveOpens", "passive", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_ActiveOpens, (collected_number)snmp_root.tcp_ActiveOpens); - rrddim_set_by_pointer(st, rd_PassiveOpens, (collected_number)snmp_root.tcp_PassiveOpens); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_tcp_handshake) { - static RRDSET *st = NULL; - static RRDDIM *rd_EstabResets = NULL, - *rd_OutRsts = NULL, - *rd_AttemptFails = NULL, - *rd_TCPSynRetrans = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "tcphandshake" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Handshake Issues" - , "events/s" - , "proc" - , "net/snmp" - , 2530 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_EstabResets = rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutRsts = rrddim_add(st, "OutRsts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_AttemptFails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_TCPSynRetrans = rrddim_add(st, "TCPSynRetrans", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_EstabResets, (collected_number)snmp_root.tcp_EstabResets); - rrddim_set_by_pointer(st, rd_OutRsts, (collected_number)snmp_root.tcp_OutRsts); - rrddim_set_by_pointer(st, rd_AttemptFails, (collected_number)snmp_root.tcp_AttemptFails); - rrddim_set_by_pointer(st, rd_TCPSynRetrans, tcpext_TCPSynRetrans); - rrdset_done(st); - } - } - else if(unlikely(hash == hash_udp && strcmp(key, "Udp") == 0)) { - size_t h = l++; - - if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) { - error("Cannot read Udp line from /proc/net/snmp."); - break; - } - - words = procfile_linewords(ff, l); - if(words < 3) { - error("Cannot read /proc/net/snmp Udp line. Expected 3+ params, read %zu.", words); - continue; - } - - arl_begin(arl_udp); - for(w = 1; w < words ; w++) { - if (unlikely(arl_check(arl_udp, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) - break; - } - - // -------------------------------------------------------------------- - - // see http://net-snmp.sourceforge.net/docs/mibs/udp.html - if(do_udp_packets) { - static RRDSET *st = NULL; - static RRDDIM *rd_InDatagrams = NULL, - *rd_OutDatagrams = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "udppackets" - , NULL - , "udp" - , NULL - , "IPv4 UDP Packets" - , "packets/s" - , "proc" - , "net/snmp" - , 2602 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udp_InDatagrams); - rrddim_set_by_pointer(st, rd_OutDatagrams, (collected_number)snmp_root.udp_OutDatagrams); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_udp_errors) { - static RRDSET *st = NULL; - static RRDDIM *rd_RcvbufErrors = NULL, - *rd_SndbufErrors = NULL, - *rd_InErrors = NULL, - *rd_NoPorts = NULL, - *rd_InCsumErrors = NULL, - *rd_IgnoredMulti = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "udperrors" - , NULL - , "udp" - , NULL - , "IPv4 UDP Errors" - , "events/s" - , "proc" - , "net/snmp" - , 2701 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_IgnoredMulti = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InErrors, (collected_number)snmp_root.udp_InErrors); - rrddim_set_by_pointer(st, rd_NoPorts, (collected_number)snmp_root.udp_NoPorts); - rrddim_set_by_pointer(st, rd_RcvbufErrors, (collected_number)snmp_root.udp_RcvbufErrors); - rrddim_set_by_pointer(st, rd_SndbufErrors, (collected_number)snmp_root.udp_SndbufErrors); - rrddim_set_by_pointer(st, rd_InCsumErrors, (collected_number)snmp_root.udp_InCsumErrors); - rrddim_set_by_pointer(st, rd_IgnoredMulti, (collected_number)snmp_root.udp_IgnoredMulti); - rrdset_done(st); - } - } - else if(unlikely(hash == hash_udplite && strcmp(key, "UdpLite") == 0)) { - size_t h = l++; - - if(strcmp(procfile_lineword(ff, l, 0), "UdpLite") != 0) { - error("Cannot read UdpLite line from /proc/net/snmp."); - break; - } - - words = procfile_linewords(ff, l); - if(words < 3) { - error("Cannot read /proc/net/snmp UdpLite line. Expected 3+ params, read %zu.", words); - continue; - } - - arl_begin(arl_udplite); - for(w = 1; w < words ; w++) { - if (unlikely(arl_check(arl_udplite, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) - break; - } - - // -------------------------------------------------------------------- - - if(do_udplite_packets) { - { - static RRDSET *st = NULL; - static RRDDIM *rd_InDatagrams = NULL, - *rd_OutDatagrams = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "udplite" - , NULL - , "udplite" - , NULL - , "IPv4 UDPLite Packets" - , "packets/s" - , "proc" - , "net/snmp" - , 2603 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udplite_InDatagrams); - rrddim_set_by_pointer(st, rd_OutDatagrams, (collected_number)snmp_root.udplite_OutDatagrams); - rrdset_done(st); - } - - { - static RRDSET *st = NULL; - static RRDDIM *rd_RcvbufErrors = NULL, - *rd_SndbufErrors = NULL, - *rd_InErrors = NULL, - *rd_NoPorts = NULL, - *rd_InCsumErrors = NULL, - *rd_IgnoredMulti = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP - , "udplite_errors" - , NULL - , "udplite" - , NULL - , "IPv4 UDPLite Errors" - , "packets/s" - , "proc" - , "net/snmp" - , 2604 - , update_every - , RRDSET_TYPE_LINE); - - rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_IgnoredMulti = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_NoPorts, (collected_number)snmp_root.udplite_NoPorts); - rrddim_set_by_pointer(st, rd_InErrors, (collected_number)snmp_root.udplite_InErrors); - rrddim_set_by_pointer(st, rd_InCsumErrors, (collected_number)snmp_root.udplite_InCsumErrors); - rrddim_set_by_pointer(st, rd_RcvbufErrors, (collected_number)snmp_root.udplite_RcvbufErrors); - rrddim_set_by_pointer(st, rd_SndbufErrors, (collected_number)snmp_root.udplite_SndbufErrors); - rrddim_set_by_pointer(st, rd_IgnoredMulti, (collected_number)snmp_root.udplite_IgnoredMulti); - rrdset_done(st); - } - } - } - } - - return 0; -} - diff --git a/src/proc_net_snmp6.c b/src/proc_net_snmp6.c deleted file mode 100644 index bd71b391a..000000000 --- a/src/proc_net_snmp6.c +++ /dev/null @@ -1,1265 +0,0 @@ -#include "common.h" - -#define RRD_TYPE_NET_SNMP6 "ipv6" - -int do_proc_net_snmp6(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - - static int do_ip_packets = -1, - do_ip_fragsout = -1, - do_ip_fragsin = -1, - do_ip_errors = -1, - do_udplite_packets = -1, - do_udplite_errors = -1, - do_udp_packets = -1, - do_udp_errors = -1, - do_bandwidth = -1, - do_mcast = -1, - do_bcast = -1, - do_mcast_p = -1, - do_icmp = -1, - do_icmp_redir = -1, - do_icmp_errors = -1, - do_icmp_echos = -1, - do_icmp_groupmemb = -1, - do_icmp_router = -1, - do_icmp_neighbor = -1, - do_icmp_mldv2 = -1, - do_icmp_types = -1, - do_ect = -1; - - static ARL_BASE *arl_base = NULL; - - static unsigned long long Ip6InReceives = 0ULL; - static unsigned long long Ip6InHdrErrors = 0ULL; - static unsigned long long Ip6InTooBigErrors = 0ULL; - static unsigned long long Ip6InNoRoutes = 0ULL; - static unsigned long long Ip6InAddrErrors = 0ULL; - static unsigned long long Ip6InUnknownProtos = 0ULL; - static unsigned long long Ip6InTruncatedPkts = 0ULL; - static unsigned long long Ip6InDiscards = 0ULL; - static unsigned long long Ip6InDelivers = 0ULL; - static unsigned long long Ip6OutForwDatagrams = 0ULL; - static unsigned long long Ip6OutRequests = 0ULL; - static unsigned long long Ip6OutDiscards = 0ULL; - static unsigned long long Ip6OutNoRoutes = 0ULL; - static unsigned long long Ip6ReasmTimeout = 0ULL; - static unsigned long long Ip6ReasmReqds = 0ULL; - static unsigned long long Ip6ReasmOKs = 0ULL; - static unsigned long long Ip6ReasmFails = 0ULL; - static unsigned long long Ip6FragOKs = 0ULL; - static unsigned long long Ip6FragFails = 0ULL; - static unsigned long long Ip6FragCreates = 0ULL; - static unsigned long long Ip6InMcastPkts = 0ULL; - static unsigned long long Ip6OutMcastPkts = 0ULL; - static unsigned long long Ip6InOctets = 0ULL; - static unsigned long long Ip6OutOctets = 0ULL; - static unsigned long long Ip6InMcastOctets = 0ULL; - static unsigned long long Ip6OutMcastOctets = 0ULL; - static unsigned long long Ip6InBcastOctets = 0ULL; - static unsigned long long Ip6OutBcastOctets = 0ULL; - static unsigned long long Ip6InNoECTPkts = 0ULL; - static unsigned long long Ip6InECT1Pkts = 0ULL; - static unsigned long long Ip6InECT0Pkts = 0ULL; - static unsigned long long Ip6InCEPkts = 0ULL; - static unsigned long long Icmp6InMsgs = 0ULL; - static unsigned long long Icmp6InErrors = 0ULL; - static unsigned long long Icmp6OutMsgs = 0ULL; - static unsigned long long Icmp6OutErrors = 0ULL; - static unsigned long long Icmp6InCsumErrors = 0ULL; - static unsigned long long Icmp6InDestUnreachs = 0ULL; - static unsigned long long Icmp6InPktTooBigs = 0ULL; - static unsigned long long Icmp6InTimeExcds = 0ULL; - static unsigned long long Icmp6InParmProblems = 0ULL; - static unsigned long long Icmp6InEchos = 0ULL; - static unsigned long long Icmp6InEchoReplies = 0ULL; - static unsigned long long Icmp6InGroupMembQueries = 0ULL; - static unsigned long long Icmp6InGroupMembResponses = 0ULL; - static unsigned long long Icmp6InGroupMembReductions = 0ULL; - static unsigned long long Icmp6InRouterSolicits = 0ULL; - static unsigned long long Icmp6InRouterAdvertisements = 0ULL; - static unsigned long long Icmp6InNeighborSolicits = 0ULL; - static unsigned long long Icmp6InNeighborAdvertisements = 0ULL; - static unsigned long long Icmp6InRedirects = 0ULL; - static unsigned long long Icmp6InMLDv2Reports = 0ULL; - static unsigned long long Icmp6OutDestUnreachs = 0ULL; - static unsigned long long Icmp6OutPktTooBigs = 0ULL; - static unsigned long long Icmp6OutTimeExcds = 0ULL; - static unsigned long long Icmp6OutParmProblems = 0ULL; - static unsigned long long Icmp6OutEchos = 0ULL; - static unsigned long long Icmp6OutEchoReplies = 0ULL; - static unsigned long long Icmp6OutGroupMembQueries = 0ULL; - static unsigned long long Icmp6OutGroupMembResponses = 0ULL; - static unsigned long long Icmp6OutGroupMembReductions = 0ULL; - static unsigned long long Icmp6OutRouterSolicits = 0ULL; - static unsigned long long Icmp6OutRouterAdvertisements = 0ULL; - static unsigned long long Icmp6OutNeighborSolicits = 0ULL; - static unsigned long long Icmp6OutNeighborAdvertisements = 0ULL; - static unsigned long long Icmp6OutRedirects = 0ULL; - static unsigned long long Icmp6OutMLDv2Reports = 0ULL; - static unsigned long long Icmp6InType1 = 0ULL; - static unsigned long long Icmp6InType128 = 0ULL; - static unsigned long long Icmp6InType129 = 0ULL; - static unsigned long long Icmp6InType136 = 0ULL; - static unsigned long long Icmp6OutType1 = 0ULL; - static unsigned long long Icmp6OutType128 = 0ULL; - static unsigned long long Icmp6OutType129 = 0ULL; - static unsigned long long Icmp6OutType133 = 0ULL; - static unsigned long long Icmp6OutType135 = 0ULL; - static unsigned long long Icmp6OutType143 = 0ULL; - static unsigned long long Udp6InDatagrams = 0ULL; - static unsigned long long Udp6NoPorts = 0ULL; - static unsigned long long Udp6InErrors = 0ULL; - static unsigned long long Udp6OutDatagrams = 0ULL; - static unsigned long long Udp6RcvbufErrors = 0ULL; - static unsigned long long Udp6SndbufErrors = 0ULL; - static unsigned long long Udp6InCsumErrors = 0ULL; - static unsigned long long Udp6IgnoredMulti = 0ULL; - static unsigned long long UdpLite6InDatagrams = 0ULL; - static unsigned long long UdpLite6NoPorts = 0ULL; - static unsigned long long UdpLite6InErrors = 0ULL; - static unsigned long long UdpLite6OutDatagrams = 0ULL; - static unsigned long long UdpLite6RcvbufErrors = 0ULL; - static unsigned long long UdpLite6SndbufErrors = 0ULL; - 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_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); - arl_expect(arl_base, "Ip6InHdrErrors", &Ip6InHdrErrors); - arl_expect(arl_base, "Ip6InTooBigErrors", &Ip6InTooBigErrors); - arl_expect(arl_base, "Ip6InNoRoutes", &Ip6InNoRoutes); - arl_expect(arl_base, "Ip6InAddrErrors", &Ip6InAddrErrors); - arl_expect(arl_base, "Ip6InUnknownProtos", &Ip6InUnknownProtos); - arl_expect(arl_base, "Ip6InTruncatedPkts", &Ip6InTruncatedPkts); - arl_expect(arl_base, "Ip6InDiscards", &Ip6InDiscards); - arl_expect(arl_base, "Ip6InDelivers", &Ip6InDelivers); - arl_expect(arl_base, "Ip6OutForwDatagrams", &Ip6OutForwDatagrams); - arl_expect(arl_base, "Ip6OutRequests", &Ip6OutRequests); - arl_expect(arl_base, "Ip6OutDiscards", &Ip6OutDiscards); - arl_expect(arl_base, "Ip6OutNoRoutes", &Ip6OutNoRoutes); - arl_expect(arl_base, "Ip6ReasmTimeout", &Ip6ReasmTimeout); - arl_expect(arl_base, "Ip6ReasmReqds", &Ip6ReasmReqds); - arl_expect(arl_base, "Ip6ReasmOKs", &Ip6ReasmOKs); - arl_expect(arl_base, "Ip6ReasmFails", &Ip6ReasmFails); - arl_expect(arl_base, "Ip6FragOKs", &Ip6FragOKs); - arl_expect(arl_base, "Ip6FragFails", &Ip6FragFails); - arl_expect(arl_base, "Ip6FragCreates", &Ip6FragCreates); - arl_expect(arl_base, "Ip6InMcastPkts", &Ip6InMcastPkts); - arl_expect(arl_base, "Ip6OutMcastPkts", &Ip6OutMcastPkts); - arl_expect(arl_base, "Ip6InOctets", &Ip6InOctets); - arl_expect(arl_base, "Ip6OutOctets", &Ip6OutOctets); - arl_expect(arl_base, "Ip6InMcastOctets", &Ip6InMcastOctets); - arl_expect(arl_base, "Ip6OutMcastOctets", &Ip6OutMcastOctets); - arl_expect(arl_base, "Ip6InBcastOctets", &Ip6InBcastOctets); - arl_expect(arl_base, "Ip6OutBcastOctets", &Ip6OutBcastOctets); - arl_expect(arl_base, "Ip6InNoECTPkts", &Ip6InNoECTPkts); - arl_expect(arl_base, "Ip6InECT1Pkts", &Ip6InECT1Pkts); - arl_expect(arl_base, "Ip6InECT0Pkts", &Ip6InECT0Pkts); - arl_expect(arl_base, "Ip6InCEPkts", &Ip6InCEPkts); - arl_expect(arl_base, "Icmp6InMsgs", &Icmp6InMsgs); - arl_expect(arl_base, "Icmp6InErrors", &Icmp6InErrors); - arl_expect(arl_base, "Icmp6OutMsgs", &Icmp6OutMsgs); - arl_expect(arl_base, "Icmp6OutErrors", &Icmp6OutErrors); - arl_expect(arl_base, "Icmp6InCsumErrors", &Icmp6InCsumErrors); - arl_expect(arl_base, "Icmp6InDestUnreachs", &Icmp6InDestUnreachs); - arl_expect(arl_base, "Icmp6InPktTooBigs", &Icmp6InPktTooBigs); - arl_expect(arl_base, "Icmp6InTimeExcds", &Icmp6InTimeExcds); - arl_expect(arl_base, "Icmp6InParmProblems", &Icmp6InParmProblems); - arl_expect(arl_base, "Icmp6InEchos", &Icmp6InEchos); - arl_expect(arl_base, "Icmp6InEchoReplies", &Icmp6InEchoReplies); - arl_expect(arl_base, "Icmp6InGroupMembQueries", &Icmp6InGroupMembQueries); - arl_expect(arl_base, "Icmp6InGroupMembResponses", &Icmp6InGroupMembResponses); - arl_expect(arl_base, "Icmp6InGroupMembReductions", &Icmp6InGroupMembReductions); - arl_expect(arl_base, "Icmp6InRouterSolicits", &Icmp6InRouterSolicits); - arl_expect(arl_base, "Icmp6InRouterAdvertisements", &Icmp6InRouterAdvertisements); - arl_expect(arl_base, "Icmp6InNeighborSolicits", &Icmp6InNeighborSolicits); - arl_expect(arl_base, "Icmp6InNeighborAdvertisements", &Icmp6InNeighborAdvertisements); - arl_expect(arl_base, "Icmp6InRedirects", &Icmp6InRedirects); - arl_expect(arl_base, "Icmp6InMLDv2Reports", &Icmp6InMLDv2Reports); - arl_expect(arl_base, "Icmp6OutDestUnreachs", &Icmp6OutDestUnreachs); - arl_expect(arl_base, "Icmp6OutPktTooBigs", &Icmp6OutPktTooBigs); - arl_expect(arl_base, "Icmp6OutTimeExcds", &Icmp6OutTimeExcds); - arl_expect(arl_base, "Icmp6OutParmProblems", &Icmp6OutParmProblems); - arl_expect(arl_base, "Icmp6OutEchos", &Icmp6OutEchos); - arl_expect(arl_base, "Icmp6OutEchoReplies", &Icmp6OutEchoReplies); - arl_expect(arl_base, "Icmp6OutGroupMembQueries", &Icmp6OutGroupMembQueries); - arl_expect(arl_base, "Icmp6OutGroupMembResponses", &Icmp6OutGroupMembResponses); - arl_expect(arl_base, "Icmp6OutGroupMembReductions", &Icmp6OutGroupMembReductions); - arl_expect(arl_base, "Icmp6OutRouterSolicits", &Icmp6OutRouterSolicits); - arl_expect(arl_base, "Icmp6OutRouterAdvertisements", &Icmp6OutRouterAdvertisements); - arl_expect(arl_base, "Icmp6OutNeighborSolicits", &Icmp6OutNeighborSolicits); - arl_expect(arl_base, "Icmp6OutNeighborAdvertisements", &Icmp6OutNeighborAdvertisements); - arl_expect(arl_base, "Icmp6OutRedirects", &Icmp6OutRedirects); - arl_expect(arl_base, "Icmp6OutMLDv2Reports", &Icmp6OutMLDv2Reports); - arl_expect(arl_base, "Icmp6InType1", &Icmp6InType1); - arl_expect(arl_base, "Icmp6InType128", &Icmp6InType128); - arl_expect(arl_base, "Icmp6InType129", &Icmp6InType129); - arl_expect(arl_base, "Icmp6InType136", &Icmp6InType136); - arl_expect(arl_base, "Icmp6OutType1", &Icmp6OutType1); - arl_expect(arl_base, "Icmp6OutType128", &Icmp6OutType128); - arl_expect(arl_base, "Icmp6OutType129", &Icmp6OutType129); - arl_expect(arl_base, "Icmp6OutType133", &Icmp6OutType133); - arl_expect(arl_base, "Icmp6OutType135", &Icmp6OutType135); - arl_expect(arl_base, "Icmp6OutType143", &Icmp6OutType143); - arl_expect(arl_base, "Udp6InDatagrams", &Udp6InDatagrams); - arl_expect(arl_base, "Udp6NoPorts", &Udp6NoPorts); - arl_expect(arl_base, "Udp6InErrors", &Udp6InErrors); - arl_expect(arl_base, "Udp6OutDatagrams", &Udp6OutDatagrams); - arl_expect(arl_base, "Udp6RcvbufErrors", &Udp6RcvbufErrors); - arl_expect(arl_base, "Udp6SndbufErrors", &Udp6SndbufErrors); - arl_expect(arl_base, "Udp6InCsumErrors", &Udp6InCsumErrors); - arl_expect(arl_base, "Udp6IgnoredMulti", &Udp6IgnoredMulti); - arl_expect(arl_base, "UdpLite6InDatagrams", &UdpLite6InDatagrams); - arl_expect(arl_base, "UdpLite6NoPorts", &UdpLite6NoPorts); - arl_expect(arl_base, "UdpLite6InErrors", &UdpLite6InErrors); - arl_expect(arl_base, "UdpLite6OutDatagrams", &UdpLite6OutDatagrams); - arl_expect(arl_base, "UdpLite6RcvbufErrors", &UdpLite6RcvbufErrors); - arl_expect(arl_base, "UdpLite6SndbufErrors", &UdpLite6SndbufErrors); - arl_expect(arl_base, "UdpLite6InCsumErrors", &UdpLite6InCsumErrors); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - arl_begin(arl_base); - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 2)) { - if(unlikely(words)) error("Cannot read /proc/net/snmp6 line %zu. Expected 2 params, read %zu.", l, words); - continue; - } - - if(unlikely(arl_check(arl_base, - procfile_lineword(ff, l, 0), - procfile_lineword(ff, l, 1)))) break; - } - - // -------------------------------------------------------------------- - - if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (Ip6InOctets || Ip6OutOctets))) { - do_bandwidth = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_received = NULL, - *rd_sent = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "ipv6" - , NULL - , "network" - , NULL - , "IPv6 Bandwidth" - , "kilobits/s" - , "proc" - , "net/snmp6" - , 502 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_received = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_sent = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_received, Ip6InOctets); - rrddim_set_by_pointer(st, rd_sent, Ip6OutOctets); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_packets == CONFIG_BOOLEAN_YES || (do_ip_packets == CONFIG_BOOLEAN_AUTO && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) { - do_ip_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( - RRD_TYPE_NET_SNMP6 - , "packets" - , NULL - , "packets" - , NULL - , "IPv6 Packets" - , "packets/s" - , "proc" - , "net/snmp6" - , 3000 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_received = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_sent = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_forwarded = rrddim_add(st, "OutForwDatagrams", "forwarded", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_delivers = rrddim_add(st, "InDelivers", "delivers", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_received, Ip6InReceives); - rrddim_set_by_pointer(st, rd_sent, Ip6OutRequests); - rrddim_set_by_pointer(st, rd_forwarded, Ip6OutForwDatagrams); - rrddim_set_by_pointer(st, rd_delivers, Ip6InDelivers); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_fragsout == CONFIG_BOOLEAN_YES || (do_ip_fragsout == CONFIG_BOOLEAN_AUTO && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) { - do_ip_fragsout = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_ok = NULL, - *rd_failed = NULL, - *rd_all = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "fragsout" - , NULL - , "fragments6" - , NULL - , "IPv6 Fragments Sent" - , "packets/s" - , "proc" - , "net/snmp6" - , 3011 - , 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_failed = rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_all = rrddim_add(st, "FragCreates", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_ok, Ip6FragOKs); - rrddim_set_by_pointer(st, rd_failed, Ip6FragFails); - rrddim_set_by_pointer(st, rd_all, Ip6FragCreates); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_fragsin == CONFIG_BOOLEAN_YES || (do_ip_fragsin == CONFIG_BOOLEAN_AUTO - && ( - Ip6ReasmOKs - || Ip6ReasmFails - || Ip6ReasmTimeout - || Ip6ReasmReqds - ))) { - do_ip_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_localhost( - RRD_TYPE_NET_SNMP6 - , "fragsin" - , NULL - , "fragments6" - , NULL - , "IPv6 Fragments Reassembly" - , "packets/s" - , "proc" - , "net/snmp6" - , 3012 - , 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_timeout = rrddim_add(st, "ReasmTimeout", "timeout", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_all = rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_ok, Ip6ReasmOKs); - rrddim_set_by_pointer(st, rd_failed, Ip6ReasmFails); - rrddim_set_by_pointer(st, rd_timeout, Ip6ReasmTimeout); - rrddim_set_by_pointer(st, rd_all, Ip6ReasmReqds); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ip_errors == CONFIG_BOOLEAN_YES || (do_ip_errors == CONFIG_BOOLEAN_AUTO - && ( - Ip6InDiscards - || Ip6OutDiscards - || Ip6InHdrErrors - || Ip6InAddrErrors - || Ip6InUnknownProtos - || Ip6InTooBigErrors - || Ip6InTruncatedPkts - || Ip6InNoRoutes - ))) { - do_ip_errors = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InDiscards = NULL, - *rd_OutDiscards = NULL, - *rd_InHdrErrors = NULL, - *rd_InAddrErrors = NULL, - *rd_InUnknownProtos = NULL, - *rd_InTooBigErrors = NULL, - *rd_InTruncatedPkts = NULL, - *rd_InNoRoutes = NULL, - *rd_OutNoRoutes = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "errors" - , NULL - , "errors" - , NULL - , "IPv6 Errors" - , "packets/s" - , "proc" - , "net/snmp6" - , 3002 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_InDiscards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutDiscards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InHdrErrors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InAddrErrors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InUnknownProtos = rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InTooBigErrors = rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InTruncatedPkts = rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InNoRoutes = rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutNoRoutes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InDiscards, Ip6InDiscards); - rrddim_set_by_pointer(st, rd_OutDiscards, Ip6OutDiscards); - rrddim_set_by_pointer(st, rd_InHdrErrors, Ip6InHdrErrors); - rrddim_set_by_pointer(st, rd_InAddrErrors, Ip6InAddrErrors); - rrddim_set_by_pointer(st, rd_InUnknownProtos, Ip6InUnknownProtos); - rrddim_set_by_pointer(st, rd_InTooBigErrors, Ip6InTooBigErrors); - rrddim_set_by_pointer(st, rd_InTruncatedPkts, Ip6InTruncatedPkts); - rrddim_set_by_pointer(st, rd_InNoRoutes, Ip6InNoRoutes); - rrddim_set_by_pointer(st, rd_OutNoRoutes, Ip6OutNoRoutes); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_udp_packets == CONFIG_BOOLEAN_YES || (do_udp_packets == CONFIG_BOOLEAN_AUTO && (Udp6InDatagrams || Udp6OutDatagrams))) { - do_udp_packets = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_received = NULL, - *rd_sent = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "udppackets" - , NULL - , "udp6" - , NULL - , "IPv6 UDP Packets" - , "packets/s" - , "proc" - , "net/snmp6" - , 3601 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_received, Udp6InDatagrams); - rrddim_set_by_pointer(st, rd_sent, Udp6OutDatagrams); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_udp_errors == CONFIG_BOOLEAN_YES || (do_udp_errors == CONFIG_BOOLEAN_AUTO - && ( - Udp6InErrors - || Udp6NoPorts - || Udp6RcvbufErrors - || Udp6SndbufErrors - || Udp6InCsumErrors - || Udp6IgnoredMulti - ))) { - do_udp_errors = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_RcvbufErrors = NULL, - *rd_SndbufErrors = NULL, - *rd_InErrors = NULL, - *rd_NoPorts = NULL, - *rd_InCsumErrors = NULL, - *rd_IgnoredMulti = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "udperrors" - , NULL - , "udp6" - , NULL - , "IPv6 UDP Errors" - , "events/s" - , "proc" - , "net/snmp6" - , 3701 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_IgnoredMulti = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_RcvbufErrors, Udp6RcvbufErrors); - rrddim_set_by_pointer(st, rd_SndbufErrors, Udp6SndbufErrors); - rrddim_set_by_pointer(st, rd_InErrors, Udp6InErrors); - rrddim_set_by_pointer(st, rd_NoPorts, Udp6NoPorts); - rrddim_set_by_pointer(st, rd_InCsumErrors, Udp6InCsumErrors); - rrddim_set_by_pointer(st, rd_IgnoredMulti, Udp6IgnoredMulti); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_udplite_packets == CONFIG_BOOLEAN_YES || (do_udplite_packets == CONFIG_BOOLEAN_AUTO && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) { - do_udplite_packets = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_received = NULL, - *rd_sent = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "udplitepackets" - , NULL - , "udplite6" - , NULL - , "IPv6 UDPlite Packets" - , "packets/s" - , "proc" - , "net/snmp6" - , 3602 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_received, UdpLite6InDatagrams); - rrddim_set_by_pointer(st, rd_sent, UdpLite6OutDatagrams); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_udplite_errors == CONFIG_BOOLEAN_YES || (do_udplite_errors == CONFIG_BOOLEAN_AUTO - && ( - UdpLite6InErrors - || UdpLite6NoPorts - || UdpLite6RcvbufErrors - || UdpLite6SndbufErrors - || Udp6InCsumErrors - || UdpLite6InCsumErrors - ))) { - do_udplite_errors = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_RcvbufErrors = NULL, - *rd_SndbufErrors = NULL, - *rd_InErrors = NULL, - *rd_NoPorts = NULL, - *rd_InCsumErrors = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "udpliteerrors" - , NULL - , "udplite6" - , NULL - , "IPv6 UDP Lite Errors" - , "events/s" - , "proc" - , "net/snmp6" - , 3701 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InErrors, UdpLite6InErrors); - rrddim_set_by_pointer(st, rd_NoPorts, UdpLite6NoPorts); - rrddim_set_by_pointer(st, rd_RcvbufErrors, UdpLite6RcvbufErrors); - rrddim_set_by_pointer(st, rd_SndbufErrors, UdpLite6SndbufErrors); - rrddim_set_by_pointer(st, rd_InCsumErrors, UdpLite6InCsumErrors); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastOctets || Ip6InMcastOctets))) { - do_mcast = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_Ip6InMcastOctets = NULL, - *rd_Ip6OutMcastOctets = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "mcast" - , NULL - , "multicast6" - , NULL - , "IPv6 Multicast Bandwidth" - , "kilobits/s" - , "proc" - , "net/snmp6" - , 9000 - , update_every - , RRDSET_TYPE_AREA - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_Ip6InMcastOctets = rrddim_add(st, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_Ip6OutMcastOctets = rrddim_add(st, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_Ip6InMcastOctets, Ip6InMcastOctets); - rrddim_set_by_pointer(st, rd_Ip6OutMcastOctets, Ip6OutMcastOctets); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (Ip6OutBcastOctets || Ip6InBcastOctets))) { - do_bcast = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_Ip6InBcastOctets = NULL, - *rd_Ip6OutBcastOctets = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "bcast" - , NULL - , "broadcast6" - , NULL - , "IPv6 Broadcast Bandwidth" - , "kilobits/s" - , "proc" - , "net/snmp6" - , 8000 - , update_every - , RRDSET_TYPE_AREA - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_Ip6InBcastOctets = rrddim_add(st, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rd_Ip6OutBcastOctets = rrddim_add(st, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_Ip6InBcastOctets, Ip6InBcastOctets); - rrddim_set_by_pointer(st, rd_Ip6OutBcastOctets, Ip6OutBcastOctets); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastPkts || Ip6InMcastPkts))) { - do_mcast_p = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_Ip6InMcastPkts = NULL, - *rd_Ip6OutMcastPkts = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "mcastpkts" - , NULL - , "multicast6" - , NULL - , "IPv6 Multicast Packets" - , "packets/s" - , "proc" - , "net/snmp6" - , 9500 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_Ip6InMcastPkts = rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_Ip6OutMcastPkts = rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_Ip6InMcastPkts, Ip6InMcastPkts); - rrddim_set_by_pointer(st, rd_Ip6OutMcastPkts, Ip6OutMcastPkts); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp == CONFIG_BOOLEAN_YES || (do_icmp == CONFIG_BOOLEAN_AUTO && (Icmp6InMsgs || Icmp6OutMsgs))) { - do_icmp = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_Icmp6InMsgs = NULL, - *rd_Icmp6OutMsgs = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmp" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP Messages" - , "messages/s" - , "proc" - , "net/snmp6" - , 10000 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_Icmp6InMsgs = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_Icmp6OutMsgs = rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_Icmp6InMsgs, Icmp6InMsgs); - rrddim_set_by_pointer(st, rd_Icmp6OutMsgs, Icmp6OutMsgs); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_redir == CONFIG_BOOLEAN_YES || (do_icmp_redir == CONFIG_BOOLEAN_AUTO && (Icmp6InRedirects || Icmp6OutRedirects))) { - do_icmp_redir = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_Icmp6InRedirects = NULL, - *rd_Icmp6OutRedirects = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmpredir" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP Redirects" - , "redirects/s" - , "proc" - , "net/snmp6" - , 10050 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_Icmp6InRedirects = rrddim_add(st, "InRedirects", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_Icmp6OutRedirects = rrddim_add(st, "OutRedirects", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_Icmp6InRedirects, Icmp6InRedirects); - rrddim_set_by_pointer(st, rd_Icmp6OutRedirects, Icmp6OutRedirects); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_errors == CONFIG_BOOLEAN_YES || (do_icmp_errors == CONFIG_BOOLEAN_AUTO - && ( - Icmp6InErrors - || Icmp6OutErrors - || Icmp6InCsumErrors - || Icmp6InDestUnreachs - || Icmp6InPktTooBigs - || Icmp6InTimeExcds - || Icmp6InParmProblems - || Icmp6OutDestUnreachs - || Icmp6OutPktTooBigs - || Icmp6OutTimeExcds - || Icmp6OutParmProblems - ))) { - do_icmp_errors = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InErrors = NULL, - *rd_OutErrors = NULL, - *rd_InCsumErrors = NULL, - *rd_InDestUnreachs = NULL, - *rd_InPktTooBigs = NULL, - *rd_InTimeExcds = NULL, - *rd_InParmProblems = NULL, - *rd_OutDestUnreachs = NULL, - *rd_OutPktTooBigs = NULL, - *rd_OutTimeExcds = NULL, - *rd_OutParmProblems = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmperrors" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP Errors" - , "errors/s" - , "proc" - , "net/snmp6" - , 10100 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutErrors = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InDestUnreachs = rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InPktTooBigs = rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InTimeExcds = rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InParmProblems = rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutDestUnreachs = rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutPktTooBigs = rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutTimeExcds = rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutParmProblems = rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InErrors, Icmp6InErrors); - rrddim_set_by_pointer(st, rd_OutErrors, Icmp6OutErrors); - rrddim_set_by_pointer(st, rd_InCsumErrors, Icmp6InCsumErrors); - rrddim_set_by_pointer(st, rd_InDestUnreachs, Icmp6InDestUnreachs); - rrddim_set_by_pointer(st, rd_InPktTooBigs, Icmp6InPktTooBigs); - rrddim_set_by_pointer(st, rd_InTimeExcds, Icmp6InTimeExcds); - rrddim_set_by_pointer(st, rd_InParmProblems, Icmp6InParmProblems); - rrddim_set_by_pointer(st, rd_OutDestUnreachs, Icmp6OutDestUnreachs); - rrddim_set_by_pointer(st, rd_OutPktTooBigs, Icmp6OutPktTooBigs); - rrddim_set_by_pointer(st, rd_OutTimeExcds, Icmp6OutTimeExcds); - rrddim_set_by_pointer(st, rd_OutParmProblems, Icmp6OutParmProblems); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_echos == CONFIG_BOOLEAN_YES || (do_icmp_echos == CONFIG_BOOLEAN_AUTO - && ( - Icmp6InEchos - || Icmp6OutEchos - || Icmp6InEchoReplies - || Icmp6OutEchoReplies - ))) { - do_icmp_echos = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InEchos = NULL, - *rd_OutEchos = NULL, - *rd_InEchoReplies = NULL, - *rd_OutEchoReplies = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmpechos" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP Echo" - , "messages/s" - , "proc" - , "net/snmp6" - , 10200 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InEchos = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutEchos = rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InEchoReplies = rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutEchoReplies = rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InEchos, Icmp6InEchos); - rrddim_set_by_pointer(st, rd_OutEchos, Icmp6OutEchos); - rrddim_set_by_pointer(st, rd_InEchoReplies, Icmp6InEchoReplies); - rrddim_set_by_pointer(st, rd_OutEchoReplies, Icmp6OutEchoReplies); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_groupmemb == CONFIG_BOOLEAN_YES || (do_icmp_groupmemb == CONFIG_BOOLEAN_AUTO - && ( - Icmp6InGroupMembQueries - || Icmp6OutGroupMembQueries - || Icmp6InGroupMembResponses - || Icmp6OutGroupMembResponses - || Icmp6InGroupMembReductions - || Icmp6OutGroupMembReductions - ))) { - do_icmp_groupmemb = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InQueries = NULL, - *rd_OutQueries = NULL, - *rd_InResponses = NULL, - *rd_OutResponses = NULL, - *rd_InReductions = NULL, - *rd_OutReductions = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "groupmemb" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP Group Membership" - , "messages/s" - , "proc" - , "net/snmp6" - , 10300 - , update_every - , RRDSET_TYPE_LINE); - - rd_InQueries = rrddim_add(st, "InQueries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutQueries = rrddim_add(st, "OutQueries", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InResponses = rrddim_add(st, "InResponses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutResponses = rrddim_add(st, "OutResponses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InReductions = rrddim_add(st, "InReductions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutReductions = rrddim_add(st, "OutReductions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InQueries, Icmp6InGroupMembQueries); - rrddim_set_by_pointer(st, rd_OutQueries, Icmp6OutGroupMembQueries); - rrddim_set_by_pointer(st, rd_InResponses, Icmp6InGroupMembResponses); - rrddim_set_by_pointer(st, rd_OutResponses, Icmp6OutGroupMembResponses); - rrddim_set_by_pointer(st, rd_InReductions, Icmp6InGroupMembReductions); - rrddim_set_by_pointer(st, rd_OutReductions, Icmp6OutGroupMembReductions); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_router == CONFIG_BOOLEAN_YES || (do_icmp_router == CONFIG_BOOLEAN_AUTO - && ( - Icmp6InRouterSolicits - || Icmp6OutRouterSolicits - || Icmp6InRouterAdvertisements - || Icmp6OutRouterAdvertisements - ))) { - do_icmp_router = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InSolicits = NULL, - *rd_OutSolicits = NULL, - *rd_InAdvertisements = NULL, - *rd_OutAdvertisements = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmprouter" - , NULL - , "icmp6" - , NULL - , "IPv6 Router Messages" - , "messages/s" - , "proc" - , "net/snmp6" - , 10400 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InSolicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutSolicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InAdvertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutAdvertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InSolicits, Icmp6InRouterSolicits); - rrddim_set_by_pointer(st, rd_OutSolicits, Icmp6OutRouterSolicits); - rrddim_set_by_pointer(st, rd_InAdvertisements, Icmp6InRouterAdvertisements); - rrddim_set_by_pointer(st, rd_OutAdvertisements, Icmp6OutRouterAdvertisements); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_neighbor == CONFIG_BOOLEAN_YES || (do_icmp_neighbor == CONFIG_BOOLEAN_AUTO - && ( - Icmp6InNeighborSolicits - || Icmp6OutNeighborSolicits - || Icmp6InNeighborAdvertisements - || Icmp6OutNeighborAdvertisements - ))) { - do_icmp_neighbor = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InSolicits = NULL, - *rd_OutSolicits = NULL, - *rd_InAdvertisements = NULL, - *rd_OutAdvertisements = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmpneighbor" - , NULL - , "icmp6" - , NULL - , "IPv6 Neighbor Messages" - , "messages/s" - , "proc" - , "net/snmp6" - , 10500 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InSolicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutSolicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InAdvertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutAdvertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InSolicits, Icmp6InNeighborSolicits); - rrddim_set_by_pointer(st, rd_OutSolicits, Icmp6OutNeighborSolicits); - rrddim_set_by_pointer(st, rd_InAdvertisements, Icmp6InNeighborAdvertisements); - rrddim_set_by_pointer(st, rd_OutAdvertisements, Icmp6OutNeighborAdvertisements); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_mldv2 == CONFIG_BOOLEAN_YES || (do_icmp_mldv2 == CONFIG_BOOLEAN_AUTO && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) { - do_icmp_mldv2 = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InMLDv2Reports = NULL, - *rd_OutMLDv2Reports = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmpmldv2" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP MLDv2 Reports" - , "reports/s" - , "proc" - , "net/snmp6" - , 10600 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InMLDv2Reports = rrddim_add(st, "InMLDv2Reports", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutMLDv2Reports = rrddim_add(st, "OutMLDv2Reports", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InMLDv2Reports, Icmp6InMLDv2Reports); - rrddim_set_by_pointer(st, rd_OutMLDv2Reports, Icmp6OutMLDv2Reports); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_icmp_types == CONFIG_BOOLEAN_YES || (do_icmp_types == CONFIG_BOOLEAN_AUTO - && ( - Icmp6InType1 - || Icmp6InType128 - || Icmp6InType129 - || Icmp6InType136 - || Icmp6OutType1 - || Icmp6OutType128 - || Icmp6OutType129 - || Icmp6OutType133 - || Icmp6OutType135 - || Icmp6OutType143 - ))) { - do_icmp_types = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InType1 = NULL, - *rd_InType128 = NULL, - *rd_InType129 = NULL, - *rd_InType136 = NULL, - *rd_OutType1 = NULL, - *rd_OutType128 = NULL, - *rd_OutType129 = NULL, - *rd_OutType133 = NULL, - *rd_OutType135 = NULL, - *rd_OutType143 = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "icmptypes" - , NULL - , "icmp6" - , NULL - , "IPv6 ICMP Types" - , "messages/s" - , "proc" - , "net/snmp6" - , 10700 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InType1 = rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InType128 = rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InType129 = rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InType136 = rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutType1 = rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutType128 = rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutType129 = rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutType133 = rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutType135 = rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_OutType143 = rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InType1, Icmp6InType1); - rrddim_set_by_pointer(st, rd_InType128, Icmp6InType128); - rrddim_set_by_pointer(st, rd_InType129, Icmp6InType129); - rrddim_set_by_pointer(st, rd_InType136, Icmp6InType136); - rrddim_set_by_pointer(st, rd_OutType1, Icmp6OutType1); - rrddim_set_by_pointer(st, rd_OutType128, Icmp6OutType128); - rrddim_set_by_pointer(st, rd_OutType129, Icmp6OutType129); - rrddim_set_by_pointer(st, rd_OutType133, Icmp6OutType133); - rrddim_set_by_pointer(st, rd_OutType135, Icmp6OutType135); - rrddim_set_by_pointer(st, rd_OutType143, Icmp6OutType143); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_ect == CONFIG_BOOLEAN_YES || (do_ect == CONFIG_BOOLEAN_AUTO - && ( - Ip6InNoECTPkts - || Ip6InECT1Pkts - || Ip6InECT0Pkts - || Ip6InCEPkts - ))) { - do_ect = CONFIG_BOOLEAN_YES; - static RRDSET *st = NULL; - static RRDDIM *rd_InNoECTPkts = NULL, - *rd_InECT1Pkts = NULL, - *rd_InECT0Pkts = NULL, - *rd_InCEPkts = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - RRD_TYPE_NET_SNMP6 - , "ect" - , NULL - , "packets" - , NULL - , "IPv6 ECT Packets" - , "packets/s" - , "proc" - , "net/snmp6" - , 10800 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_InNoECTPkts = rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InECT1Pkts = rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InECT0Pkts = rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_InCEPkts = rrddim_add(st, "InCEPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_InNoECTPkts, Ip6InNoECTPkts); - rrddim_set_by_pointer(st, rd_InECT1Pkts, Ip6InECT1Pkts); - rrddim_set_by_pointer(st, rd_InECT0Pkts, Ip6InECT0Pkts); - rrddim_set_by_pointer(st, rd_InCEPkts, Ip6InCEPkts); - rrdset_done(st); - } - - return 0; -} - diff --git a/src/proc_net_sockstat.c b/src/proc_net_sockstat.c deleted file mode 100644 index db3070660..000000000 --- a/src/proc_net_sockstat.c +++ /dev/null @@ -1,514 +0,0 @@ -#include "common.h" - -static struct proc_net_sockstat { - kernel_uint_t sockets_used; - - kernel_uint_t tcp_inuse; - kernel_uint_t tcp_orphan; - kernel_uint_t tcp_tw; - kernel_uint_t tcp_alloc; - kernel_uint_t tcp_mem; - - kernel_uint_t udp_inuse; - kernel_uint_t udp_mem; - - kernel_uint_t udplite_inuse; - - kernel_uint_t raw_inuse; - - kernel_uint_t frag_inuse; - kernel_uint_t frag_memory; -} sockstat_root = { 0 }; - - -static int read_tcp_mem(void) { - static char *filename = NULL; - static RRDVAR *tcp_mem_low_threshold = NULL, - *tcp_mem_pressure_threshold = NULL, - *tcp_mem_high_threshold = NULL; - - if(unlikely(!tcp_mem_low_threshold)) { - tcp_mem_low_threshold = rrdvar_custom_host_variable_create(localhost, "tcp_mem_low"); - tcp_mem_pressure_threshold = rrdvar_custom_host_variable_create(localhost, "tcp_mem_pressure"); - tcp_mem_high_threshold = rrdvar_custom_host_variable_create(localhost, "tcp_mem_high"); - } - - if(unlikely(!filename)) { - char buffer[FILENAME_MAX + 1]; - snprintfz(buffer, FILENAME_MAX, "%s/proc/sys/net/ipv4/tcp_mem", netdata_configured_host_prefix); - filename = strdupz(buffer); - } - - char buffer[200 + 1], *start, *end; - if(read_file(filename, buffer, 200) != 0) return 1; - buffer[200] = '\0'; - - unsigned long long low = 0, pressure = 0, high = 0; - - start = buffer; - low = strtoull(start, &end, 10); - - start = end; - pressure = strtoull(start, &end, 10); - - start = end; - high = strtoull(start, &end, 10); - - // fprintf(stderr, "TCP MEM low = %llu, pressure = %llu, high = %llu\n", low, pressure, high); - - rrdvar_custom_host_variable_set(localhost, tcp_mem_low_threshold, low * sysconf(_SC_PAGESIZE) / 1024); - rrdvar_custom_host_variable_set(localhost, tcp_mem_pressure_threshold, pressure * sysconf(_SC_PAGESIZE) / 1024); - rrdvar_custom_host_variable_set(localhost, tcp_mem_high_threshold, high * sysconf(_SC_PAGESIZE) / 1024); - - return 0; -} - -static kernel_uint_t read_tcp_max_orphans(void) { - static char *filename = NULL; - static RRDVAR *tcp_max_orphans_var = NULL; - - if(unlikely(!filename)) { - char buffer[FILENAME_MAX + 1]; - snprintfz(buffer, FILENAME_MAX, "%s/proc/sys/net/ipv4/tcp_max_orphans", netdata_configured_host_prefix); - filename = strdupz(buffer); - } - - unsigned long long tcp_max_orphans = 0; - if(read_single_number_file(filename, &tcp_max_orphans) == 0) { - - if(unlikely(!tcp_max_orphans_var)) - tcp_max_orphans_var = rrdvar_custom_host_variable_create(localhost, "tcp_max_orphans"); - - rrdvar_custom_host_variable_set(localhost, tcp_max_orphans_var, tcp_max_orphans); - return tcp_max_orphans; - } - - return 0; -} - -int do_proc_net_sockstat(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - - static uint32_t hash_sockets = 0, - hash_raw = 0, - hash_frag = 0, - hash_tcp = 0, - hash_udp = 0, - hash_udplite = 0; - - static long long update_constants_every = 60, update_constants_count = 0; - - static ARL_BASE *arl_sockets = NULL; - static ARL_BASE *arl_tcp = NULL; - static ARL_BASE *arl_udp = NULL; - static ARL_BASE *arl_udplite = NULL; - static ARL_BASE *arl_raw = NULL; - static ARL_BASE *arl_frag = NULL; - - static int do_sockets = -1, do_tcp_sockets = -1, do_tcp_mem = -1, do_udp_sockets = -1, do_udp_mem = -1, do_udplite_sockets = -1, do_raw_sockets = -1, do_frag_sockets = -1, do_frag_mem = -1; - - static char *keys[7] = { NULL }; - static uint32_t hashes[7] = { 0 }; - static ARL_BASE *bases[7] = { NULL }; - - if(unlikely(!arl_sockets)) { - do_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 sockets", CONFIG_BOOLEAN_AUTO); - do_tcp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 TCP sockets", CONFIG_BOOLEAN_AUTO); - do_tcp_mem = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 TCP memory", CONFIG_BOOLEAN_AUTO); - do_udp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 UDP sockets", CONFIG_BOOLEAN_AUTO); - do_udp_mem = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 UDP memory", CONFIG_BOOLEAN_AUTO); - do_udplite_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 UDPLITE sockets", CONFIG_BOOLEAN_AUTO); - do_raw_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 RAW sockets", CONFIG_BOOLEAN_AUTO); - do_frag_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 FRAG sockets", CONFIG_BOOLEAN_AUTO); - do_frag_mem = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 FRAG memory", CONFIG_BOOLEAN_AUTO); - - update_constants_every = config_get_number("plugin:proc:/proc/net/sockstat", "update constants every", update_constants_every); - update_constants_count = update_constants_every; - - arl_sockets = arl_create("sockstat/sockets", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_sockets, "used", &sockstat_root.sockets_used); - - arl_tcp = arl_create("sockstat/TCP", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_tcp, "inuse", &sockstat_root.tcp_inuse); - arl_expect(arl_tcp, "orphan", &sockstat_root.tcp_orphan); - arl_expect(arl_tcp, "tw", &sockstat_root.tcp_tw); - arl_expect(arl_tcp, "alloc", &sockstat_root.tcp_alloc); - arl_expect(arl_tcp, "mem", &sockstat_root.tcp_mem); - - arl_udp = arl_create("sockstat/UDP", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_udp, "inuse", &sockstat_root.udp_inuse); - arl_expect(arl_udp, "mem", &sockstat_root.udp_mem); - - arl_udplite = arl_create("sockstat/UDPLITE", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_udplite, "inuse", &sockstat_root.udplite_inuse); - - arl_raw = arl_create("sockstat/RAW", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_raw, "inuse", &sockstat_root.raw_inuse); - - arl_frag = arl_create("sockstat/FRAG", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_frag, "inuse", &sockstat_root.frag_inuse); - arl_expect(arl_frag, "memory", &sockstat_root.frag_memory); - - hash_sockets = simple_hash("sockets"); - hash_tcp = simple_hash("TCP"); - hash_udp = simple_hash("UDP"); - hash_udplite = simple_hash("UDPLITE"); - hash_raw = simple_hash("RAW"); - hash_frag = simple_hash("FRAG"); - - keys[0] = "sockets"; hashes[0] = hash_sockets; bases[0] = arl_sockets; - keys[1] = "TCP"; hashes[1] = hash_tcp; bases[1] = arl_tcp; - keys[2] = "UDP"; hashes[2] = hash_udp; bases[2] = arl_udp; - keys[3] = "UDPLITE"; hashes[3] = hash_udplite; bases[3] = arl_udplite; - keys[4] = "RAW"; hashes[4] = hash_raw; bases[4] = arl_raw; - keys[5] = "FRAG"; hashes[5] = hash_frag; bases[5] = arl_frag; - keys[6] = NULL; // terminator - } - - update_constants_count += update_every; - if(unlikely(update_constants_count > update_constants_every)) { - read_tcp_max_orphans(); - read_tcp_mem(); - update_constants_count = 0; - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sockstat"); - ff = procfile_open(config_get("plugin:proc:/proc/net/sockstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) return 1; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - char *key = procfile_lineword(ff, l, 0); - uint32_t hash = simple_hash(key); - - int k; - for(k = 0; keys[k] ; k++) { - if(unlikely(hash == hashes[k] && strcmp(key, keys[k]) == 0)) { - // fprintf(stderr, "KEY: '%s', l=%zu, w=1, words=%zu\n", key, l, words); - ARL_BASE *arl = bases[k]; - arl_begin(arl); - size_t w = 1; - - while(w + 1 < words) { - char *name = procfile_lineword(ff, l, w); w++; - char *value = procfile_lineword(ff, l, w); w++; - // fprintf(stderr, " > NAME '%s', VALUE '%s', l=%zu, w=%zu, words=%zu\n", name, value, l, w, words); - if(unlikely(arl_check(arl, name, value) != 0)) - break; - } - - break; - } - } - } - - // ------------------------------------------------------------------------ - - if(do_sockets == CONFIG_BOOLEAN_YES || (do_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.sockets_used)) { - do_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_used = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_sockets" - , NULL - , "sockets" - , NULL - , "IPv4 Sockets Used" - , "sockets" - , "proc" - , "net/sockstat" - , 2400 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_used = rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_used, (collected_number)sockstat_root.sockets_used); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_tcp_sockets == CONFIG_BOOLEAN_YES || (do_tcp_sockets == CONFIG_BOOLEAN_AUTO && (sockstat_root.tcp_inuse || sockstat_root.tcp_orphan || sockstat_root.tcp_tw || sockstat_root.tcp_alloc))) { - do_tcp_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL, - *rd_orphan = NULL, - *rd_timewait = NULL, - *rd_alloc = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_tcp_sockets" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Sockets" - , "sockets" - , "proc" - , "net/sockstat" - , 2500 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_alloc = rrddim_add(st, "alloc", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_orphan = rrddim_add(st, "orphan", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_timewait = rrddim_add(st, "timewait", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.tcp_inuse); - rrddim_set_by_pointer(st, rd_orphan, (collected_number)sockstat_root.tcp_orphan); - rrddim_set_by_pointer(st, rd_timewait, (collected_number)sockstat_root.tcp_tw); - rrddim_set_by_pointer(st, rd_alloc, (collected_number)sockstat_root.tcp_alloc); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_tcp_mem == CONFIG_BOOLEAN_YES || (do_tcp_mem == CONFIG_BOOLEAN_AUTO && sockstat_root.tcp_mem)) { - do_tcp_mem = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_mem = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_tcp_mem" - , NULL - , "tcp" - , NULL - , "IPv4 TCP Sockets Memory" - , "KB" - , "proc" - , "net/sockstat" - , 4000 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_mem = rrddim_add(st, "mem", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.tcp_mem); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_udp_sockets == CONFIG_BOOLEAN_YES || (do_udp_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.udp_inuse)) { - do_udp_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_udp_sockets" - , NULL - , "udp" - , NULL - , "IPv4 UDP Sockets" - , "sockets" - , "proc" - , "net/sockstat" - , 2600 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.udp_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_udp_mem == CONFIG_BOOLEAN_YES || (do_udp_mem == CONFIG_BOOLEAN_AUTO && sockstat_root.udp_mem)) { - do_udp_mem = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_mem = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_udp_mem" - , NULL - , "udp" - , NULL - , "IPv4 UDP Sockets Memory" - , "KB" - , "proc" - , "net/sockstat" - , 2603 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_mem = rrddim_add(st, "mem", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.udp_mem); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_udplite_sockets == CONFIG_BOOLEAN_YES || (do_udplite_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.udplite_inuse)) { - do_udplite_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_udplite_sockets" - , NULL - , "udplite" - , NULL - , "IPv4 UDPLITE Sockets" - , "sockets" - , "proc" - , "net/sockstat" - , 2602 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.udplite_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_raw_sockets == CONFIG_BOOLEAN_YES || (do_raw_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.raw_inuse)) { - do_raw_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_raw_sockets" - , NULL - , "raw" - , NULL - , "IPv4 RAW Sockets" - , "sockets" - , "proc" - , "net/sockstat" - , 3010 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.raw_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_frag_sockets == CONFIG_BOOLEAN_YES || (do_frag_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.frag_inuse)) { - do_frag_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_frag_sockets" - , NULL - , "fragments" - , NULL - , "IPv4 FRAG Sockets" - , "fragments" - , "proc" - , "net/sockstat" - , 3010 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.frag_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_frag_mem == CONFIG_BOOLEAN_YES || (do_frag_mem == CONFIG_BOOLEAN_AUTO && sockstat_root.frag_memory)) { - do_frag_mem = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_mem = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv4" - , "sockstat_frag_mem" - , NULL - , "fragments" - , NULL - , "IPv4 FRAG Sockets Memory" - , "KB" - , "proc" - , "net/sockstat" - , 3020 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_mem = rrddim_add(st, "mem", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.frag_memory); - rrdset_done(st); - } - - return 0; -} - diff --git a/src/proc_net_sockstat6.c b/src/proc_net_sockstat6.c deleted file mode 100644 index 97175ccf7..000000000 --- a/src/proc_net_sockstat6.c +++ /dev/null @@ -1,269 +0,0 @@ -#include "common.h" - -static struct proc_net_sockstat6 { - kernel_uint_t tcp6_inuse; - kernel_uint_t udp6_inuse; - kernel_uint_t udplite6_inuse; - kernel_uint_t raw6_inuse; - kernel_uint_t frag6_inuse; -} sockstat6_root = { 0 }; - -int do_proc_net_sockstat6(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - - static uint32_t hash_raw = 0, - hash_frag = 0, - hash_tcp = 0, - hash_udp = 0, - hash_udplite = 0; - - static ARL_BASE *arl_tcp = NULL; - static ARL_BASE *arl_udp = NULL; - static ARL_BASE *arl_udplite = NULL; - static ARL_BASE *arl_raw = NULL; - static ARL_BASE *arl_frag = NULL; - - static int do_tcp_sockets = -1, do_udp_sockets = -1, do_udplite_sockets = -1, do_raw_sockets = -1, do_frag_sockets = -1; - - static char *keys[6] = { NULL }; - static uint32_t hashes[6] = { 0 }; - static ARL_BASE *bases[6] = { NULL }; - - if(unlikely(!arl_tcp)) { - do_tcp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 TCP sockets", CONFIG_BOOLEAN_AUTO); - do_udp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 UDP sockets", CONFIG_BOOLEAN_AUTO); - do_udplite_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 UDPLITE sockets", CONFIG_BOOLEAN_AUTO); - do_raw_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 RAW sockets", CONFIG_BOOLEAN_AUTO); - do_frag_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 FRAG sockets", CONFIG_BOOLEAN_AUTO); - - arl_tcp = arl_create("sockstat6/TCP6", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_tcp, "inuse", &sockstat6_root.tcp6_inuse); - - arl_udp = arl_create("sockstat6/UDP6", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_udp, "inuse", &sockstat6_root.udp6_inuse); - - arl_udplite = arl_create("sockstat6/UDPLITE6", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_udplite, "inuse", &sockstat6_root.udplite6_inuse); - - arl_raw = arl_create("sockstat6/RAW6", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_raw, "inuse", &sockstat6_root.raw6_inuse); - - arl_frag = arl_create("sockstat6/FRAG6", arl_callback_str2kernel_uint_t, 60); - arl_expect(arl_frag, "inuse", &sockstat6_root.frag6_inuse); - - hash_tcp = simple_hash("TCP6"); - hash_udp = simple_hash("UDP6"); - hash_udplite = simple_hash("UDPLITE6"); - hash_raw = simple_hash("RAW6"); - hash_frag = simple_hash("FRAG6"); - - keys[0] = "TCP6"; hashes[0] = hash_tcp; bases[0] = arl_tcp; - keys[1] = "UDP6"; hashes[1] = hash_udp; bases[1] = arl_udp; - keys[2] = "UDPLITE6"; hashes[2] = hash_udplite; bases[2] = arl_udplite; - keys[3] = "RAW6"; hashes[3] = hash_raw; bases[3] = arl_raw; - keys[4] = "FRAG6"; hashes[4] = hash_frag; bases[4] = arl_frag; - keys[5] = NULL; // terminator - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sockstat6"); - ff = procfile_open(config_get("plugin:proc:/proc/net/sockstat6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) return 1; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - char *key = procfile_lineword(ff, l, 0); - uint32_t hash = simple_hash(key); - - int k; - for(k = 0; keys[k] ; k++) { - if(unlikely(hash == hashes[k] && strcmp(key, keys[k]) == 0)) { - // fprintf(stderr, "KEY: '%s', l=%zu, w=1, words=%zu\n", key, l, words); - ARL_BASE *arl = bases[k]; - arl_begin(arl); - size_t w = 1; - - while(w + 1 < words) { - char *name = procfile_lineword(ff, l, w); w++; - char *value = procfile_lineword(ff, l, w); w++; - // fprintf(stderr, " > NAME '%s', VALUE '%s', l=%zu, w=%zu, words=%zu\n", name, value, l, w, words); - if(unlikely(arl_check(arl, name, value) != 0)) - break; - } - - break; - } - } - } - - // ------------------------------------------------------------------------ - - if(do_tcp_sockets == CONFIG_BOOLEAN_YES || (do_tcp_sockets == CONFIG_BOOLEAN_AUTO && (sockstat6_root.tcp6_inuse))) { - do_tcp_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "sockstat6_tcp_sockets" - , NULL - , "tcp6" - , NULL - , "IPv6 TCP Sockets" - , "sockets" - , "proc" - , "net/sockstat6" - , 3599 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.tcp6_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_udp_sockets == CONFIG_BOOLEAN_YES || (do_udp_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.udp6_inuse)) { - do_udp_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "sockstat6_udp_sockets" - , NULL - , "udp6" - , NULL - , "IPv6 UDP Sockets" - , "sockets" - , "proc" - , "net/sockstat6" - , 3600 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.udp6_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_udplite_sockets == CONFIG_BOOLEAN_YES || (do_udplite_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.udplite6_inuse)) { - do_udplite_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "sockstat6_udplite_sockets" - , NULL - , "udplite6" - , NULL - , "IPv6 UDPLITE Sockets" - , "sockets" - , "proc" - , "net/sockstat6" - , 3601 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.udplite6_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_raw_sockets == CONFIG_BOOLEAN_YES || (do_raw_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.raw6_inuse)) { - do_raw_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "sockstat6_raw_sockets" - , NULL - , "raw6" - , NULL - , "IPv6 RAW Sockets" - , "sockets" - , "proc" - , "net/sockstat6" - , 3700 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.raw6_inuse); - rrdset_done(st); - } - - // ------------------------------------------------------------------------ - - if(do_frag_sockets == CONFIG_BOOLEAN_YES || (do_frag_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.frag6_inuse)) { - do_frag_sockets = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - static RRDDIM *rd_inuse = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "ipv6" - , "sockstat6_frag_sockets" - , NULL - , "fragments6" - , NULL - , "IPv6 FRAG Sockets" - , "fragments" - , "proc" - , "net/sockstat6" - , 3010 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.frag6_inuse); - rrdset_done(st); - } - - return 0; -} diff --git a/src/proc_net_softnet_stat.c b/src/proc_net_softnet_stat.c deleted file mode 100644 index f3c117e16..000000000 --- a/src/proc_net_softnet_stat.c +++ /dev/null @@ -1,147 +0,0 @@ -#include "common.h" - -static inline char *softnet_column_name(size_t column) { - switch(column) { - // https://github.com/torvalds/linux/blob/a7fd20d1c476af4563e66865213474a2f9f473a4/net/core/net-procfs.c#L161-L166 - case 0: return "processed"; - case 1: return "dropped"; - case 2: return "squeezed"; - case 9: return "received_rps"; - case 10: return "flow_limit_count"; - default: return NULL; - } -} - -int do_proc_net_softnet_stat(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - static int do_per_core = -1; - static size_t allocated_lines = 0, allocated_columns = 0; - static uint32_t *data = NULL; - - if(unlikely(do_per_core == -1)) do_per_core = config_get_boolean("plugin:proc:/proc/net/softnet_stat", "softnet_stat per core", 1); - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - size_t words = procfile_linewords(ff, 0), w; - - if(unlikely(!lines || !words)) { - error("Cannot read /proc/net/softnet_stat, %zu lines and %zu columns reported.", lines, words); - return 1; - } - - if(unlikely(lines > 200)) lines = 200; - if(unlikely(words > 50)) words = 50; - - if(unlikely(!data || lines > allocated_lines || words > allocated_columns)) { - freez(data); - allocated_lines = lines; - allocated_columns = words; - data = mallocz((allocated_lines + 1) * allocated_columns * sizeof(uint32_t)); - } - - // initialize to zero - memset(data, 0, (allocated_lines + 1) * allocated_columns * sizeof(uint32_t)); - - // parse the values - for(l = 0; l < lines ;l++) { - words = procfile_linewords(ff, l); - if(unlikely(!words)) continue; - - if(unlikely(words > allocated_columns)) - words = allocated_columns; - - for(w = 0; w < words ; w++) { - if(unlikely(softnet_column_name(w))) { - uint32_t t = (uint32_t)strtoul(procfile_lineword(ff, l, w), NULL, 16); - data[w] += t; - data[((l + 1) * allocated_columns) + w] = t; - } - } - } - - if(unlikely(data[(lines * allocated_columns)] == 0)) - lines--; - - RRDSET *st; - - // -------------------------------------------------------------------- - - st = rrdset_find_bytype_localhost("system", "softnet_stat"); - if(unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "softnet_stat" - , NULL - , "softnet_stat" - , "system.softnet_stat" - , "System softnet_stat" - , "events/s" - , "proc" - , "net/softnet_stat" - , 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, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - for(w = 0; w < allocated_columns ;w++) - if(unlikely(softnet_column_name(w))) - rrddim_set(st, softnet_column_name(w), data[w]); - - rrdset_done(st); - - if(do_per_core) { - for(l = 0; l < lines ;l++) { - char id[50+1]; - snprintfz(id, 50, "cpu%zu_softnet_stat", l); - - 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_localhost( - "cpu" - , id - , NULL - , "softnet_stat" - , "cpu.softnet_stat" - , title - , "events/s" - , "proc" - , "net/softnet_stat" - , 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, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - for(w = 0; w < allocated_columns ;w++) - if(unlikely(softnet_column_name(w))) - rrddim_set(st, softnet_column_name(w), data[((l + 1) * allocated_columns) + w]); - - rrdset_done(st); - } - } - - return 0; -} diff --git a/src/proc_net_stat_conntrack.c b/src/proc_net_stat_conntrack.c deleted file mode 100644 index 363fbc199..000000000 --- a/src/proc_net_stat_conntrack.c +++ /dev/null @@ -1,348 +0,0 @@ -#include "common.h" - -#define RRD_TYPE_NET_STAT_NETFILTER "netfilter" -#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack" - -int do_proc_net_stat_conntrack(int update_every, usec_t dt) { - static procfile *ff = NULL; - static int do_sockets = -1, do_new = -1, do_changes = -1, do_expect = -1, do_search = -1, do_errors = -1; - static usec_t get_max_every = 10 * USEC_PER_SEC, usec_since_last_max = 0; - static int read_full = 1; - static char *nf_conntrack_filename, *nf_conntrack_count_filename, *nf_conntrack_max_filename; - static RRDVAR *rrdvar_max = NULL; - - unsigned long long aentries = 0, asearched = 0, afound = 0, anew = 0, ainvalid = 0, aignore = 0, adelete = 0, adelete_list = 0, - ainsert = 0, ainsert_failed = 0, adrop = 0, aearly_drop = 0, aicmp_error = 0, aexpect_new = 0, aexpect_create = 0, aexpect_delete = 0, asearch_restart = 0; - - if(unlikely(do_sockets == -1)) { - char filename[FILENAME_MAX + 1]; - 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", 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; - - read_full = 1; - ff = procfile_open(nf_conntrack_filename, " \t:", PROCFILE_FLAG_DEFAULT); - if(!ff) read_full = 0; - - do_new = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter new connections", read_full); - do_changes = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection changes", read_full); - do_expect = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection expectations", read_full); - do_search = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection searches", read_full); - do_errors = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter errors", read_full); - - do_sockets = 1; - if(!read_full) { - 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)) - do_sockets = 0; - } - - do_sockets = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connections", do_sockets); - - if(!do_sockets && !read_full) - return 1; - - rrdvar_max = rrdvar_custom_host_variable_create(localhost, "netfilter.conntrack.max"); - } - - if(likely(read_full)) { - if(unlikely(!ff)) { - ff = procfile_open(nf_conntrack_filename, " \t:", PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - for(l = 1; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 17)) { - if(unlikely(words)) error("Cannot read /proc/net/stat/nf_conntrack line. Expected 17 params, read %zu.", words); - continue; - } - - unsigned long long tentries = 0, tsearched = 0, tfound = 0, tnew = 0, tinvalid = 0, tignore = 0, tdelete = 0, tdelete_list = 0, tinsert = 0, tinsert_failed = 0, tdrop = 0, tearly_drop = 0, ticmp_error = 0, texpect_new = 0, texpect_create = 0, texpect_delete = 0, tsearch_restart = 0; - - tentries = strtoull(procfile_lineword(ff, l, 0), NULL, 16); - tsearched = strtoull(procfile_lineword(ff, l, 1), NULL, 16); - tfound = strtoull(procfile_lineword(ff, l, 2), NULL, 16); - tnew = strtoull(procfile_lineword(ff, l, 3), NULL, 16); - tinvalid = strtoull(procfile_lineword(ff, l, 4), NULL, 16); - tignore = strtoull(procfile_lineword(ff, l, 5), NULL, 16); - tdelete = strtoull(procfile_lineword(ff, l, 6), NULL, 16); - tdelete_list = strtoull(procfile_lineword(ff, l, 7), NULL, 16); - tinsert = strtoull(procfile_lineword(ff, l, 8), NULL, 16); - tinsert_failed = strtoull(procfile_lineword(ff, l, 9), NULL, 16); - tdrop = strtoull(procfile_lineword(ff, l, 10), NULL, 16); - tearly_drop = strtoull(procfile_lineword(ff, l, 11), NULL, 16); - ticmp_error = strtoull(procfile_lineword(ff, l, 12), NULL, 16); - texpect_new = strtoull(procfile_lineword(ff, l, 13), NULL, 16); - texpect_create = strtoull(procfile_lineword(ff, l, 14), NULL, 16); - texpect_delete = strtoull(procfile_lineword(ff, l, 15), NULL, 16); - tsearch_restart = strtoull(procfile_lineword(ff, l, 16), NULL, 16); - - if(unlikely(!aentries)) aentries = tentries; - - // sum all the cpus together - asearched += tsearched; // conntrack.search - afound += tfound; // conntrack.search - anew += tnew; // conntrack.new - ainvalid += tinvalid; // conntrack.new - aignore += tignore; // conntrack.new - adelete += tdelete; // conntrack.changes - adelete_list += tdelete_list; // conntrack.changes - ainsert += tinsert; // conntrack.changes - ainsert_failed += tinsert_failed; // conntrack.errors - adrop += tdrop; // conntrack.errors - aearly_drop += tearly_drop; // conntrack.errors - aicmp_error += ticmp_error; // conntrack.errors - aexpect_new += texpect_new; // conntrack.expect - aexpect_create += texpect_create; // conntrack.expect - aexpect_delete += texpect_delete; // conntrack.expect - asearch_restart += tsearch_restart; // conntrack.search - } - } - else { - if(unlikely(read_single_number_file(nf_conntrack_count_filename, &aentries))) - return 0; // we return 0, so that we will retry to open it next time - } - - usec_since_last_max += dt; - if(unlikely(rrdvar_max && usec_since_last_max >= get_max_every)) { - usec_since_last_max = 0; - - unsigned long long max; - if(likely(!read_single_number_file(nf_conntrack_max_filename, &max))) - rrdvar_custom_host_variable_set(localhost, rrdvar_max, max); - } - - // -------------------------------------------------------------------- - - if(do_sockets) { - static RRDSET *st = NULL; - static RRDDIM *rd_connections = NULL; - - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/nf_conntrack" - , 3000 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_connections = rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_connections, aentries); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_new) { - static RRDSET *st = NULL; - static RRDDIM - *rd_new = NULL, - *rd_ignore = NULL, - *rd_invalid = NULL; - - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/nf_conntrack" - , 3001 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_new = rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_ignore = rrddim_add(st, "ignore", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_invalid = rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_new, anew); - rrddim_set_by_pointer(st, rd_ignore, aignore); - rrddim_set_by_pointer(st, rd_invalid, ainvalid); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_changes) { - static RRDSET *st = NULL; - static RRDDIM - *rd_inserted = NULL, - *rd_deleted = NULL, - *rd_delete_list = NULL; - - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/nf_conntrack" - , 3002 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_inserted = rrddim_add(st, "inserted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_deleted = rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_delete_list = rrddim_add(st, "delete_list", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_inserted, ainsert); - rrddim_set_by_pointer(st, rd_deleted, adelete); - rrddim_set_by_pointer(st, rd_delete_list, adelete_list); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_expect) { - static RRDSET *st = NULL; - static RRDDIM *rd_created = NULL, - *rd_deleted = NULL, - *rd_new = NULL; - - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/nf_conntrack" - , 3003 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_created = rrddim_add(st, "created", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_deleted = rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_new = rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_created, aexpect_create); - rrddim_set_by_pointer(st, rd_deleted, aexpect_delete); - rrddim_set_by_pointer(st, rd_new, aexpect_new); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_search) { - static RRDSET *st = NULL; - static RRDDIM *rd_searched = NULL, - *rd_restarted = NULL, - *rd_found = NULL; - - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/nf_conntrack" - , 3010 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_searched = rrddim_add(st, "searched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_restarted = rrddim_add(st, "restarted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_found = rrddim_add(st, "found", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_searched, asearched); - rrddim_set_by_pointer(st, rd_restarted, asearch_restart); - rrddim_set_by_pointer(st, rd_found, afound); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if(do_errors) { - static RRDSET *st = NULL; - static RRDDIM *rd_icmp_error = NULL, - *rd_insert_failed = NULL, - *rd_drop = NULL, - *rd_early_drop = NULL; - - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/nf_conntrack" - , 3005 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - - rd_icmp_error = rrddim_add(st, "icmp_error", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_insert_failed = rrddim_add(st, "insert_failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_drop = rrddim_add(st, "drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_early_drop = rrddim_add(st, "early_drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd_icmp_error, aicmp_error); - rrddim_set_by_pointer(st, rd_insert_failed, ainsert_failed); - rrddim_set_by_pointer(st, rd_drop, adrop); - rrddim_set_by_pointer(st, rd_early_drop, aearly_drop); - rrdset_done(st); - } - - return 0; -} diff --git a/src/proc_net_stat_synproxy.c b/src/proc_net_stat_synproxy.c deleted file mode 100644 index 0d6f6ee03..000000000 --- a/src/proc_net_stat_synproxy.c +++ /dev/null @@ -1,181 +0,0 @@ -#include "common.h" - -#define RRD_TYPE_NET_STAT_NETFILTER "netfilter" -#define RRD_TYPE_NET_STAT_SYNPROXY "synproxy" - -int do_proc_net_stat_synproxy(int update_every, usec_t dt) { - (void)dt; - - static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1; - static procfile *ff = NULL; - - if(unlikely(do_entries == -1)) { - 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", 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - // make sure we have 3 lines - size_t lines = procfile_lines(ff), l; - if(unlikely(lines < 2)) { - error("/proc/net/stat/synproxy has %zu lines, expected no less than 2. Disabling it.", lines); - return 1; - } - - unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0; - - // synproxy gives its values per CPU - for(l = 1; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 6)) - continue; - - entries += strtoull(procfile_lineword(ff, l, 0), NULL, 16); - syn_received += strtoull(procfile_lineword(ff, l, 1), NULL, 16); - cookie_invalid += strtoull(procfile_lineword(ff, l, 2), NULL, 16); - cookie_valid += strtoull(procfile_lineword(ff, l, 3), NULL, 16); - cookie_retrans += strtoull(procfile_lineword(ff, l, 4), NULL, 16); - conn_reopened += strtoull(procfile_lineword(ff, l, 5), NULL, 16); - } - - unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened; - - // -------------------------------------------------------------------- - - if((do_entries == CONFIG_BOOLEAN_AUTO && events) || do_entries == CONFIG_BOOLEAN_YES) { - do_entries = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/synproxy" - , 3304 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "entries", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set(st, "entries", entries); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if((do_syns == CONFIG_BOOLEAN_AUTO && events) || do_syns == CONFIG_BOOLEAN_YES) { - do_syns = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/synproxy" - , 3301 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "received", syn_received); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if((do_reopened == CONFIG_BOOLEAN_AUTO && events) || do_reopened == CONFIG_BOOLEAN_YES) { - do_reopened = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/synproxy" - , 3303 - , update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(st, "reopened", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st); - - rrddim_set(st, "reopened", conn_reopened); - rrdset_done(st); - } - - // -------------------------------------------------------------------- - - if((do_cookies == CONFIG_BOOLEAN_AUTO && events) || do_cookies == CONFIG_BOOLEAN_YES) { - do_cookies = CONFIG_BOOLEAN_YES; - - static RRDSET *st = NULL; - if(unlikely(!st)) { - 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" - , "proc" - , "net/stat/synproxy" - , 3302 - , update_every - , RRDSET_TYPE_LINE - ); - - 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); - - rrddim_set(st, "valid", cookie_valid); - rrddim_set(st, "invalid", cookie_invalid); - rrddim_set(st, "retransmits", cookie_retrans); - rrdset_done(st); - } - - return 0; -} diff --git a/src/proc_self_mountinfo.c b/src/proc_self_mountinfo.c deleted file mode 100644 index 4ccdddff1..000000000 --- a/src/proc_self_mountinfo.c +++ /dev/null @@ -1,401 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// taken from gnulib/mountlist.c - -#ifndef ME_REMOTE -/* A file system is "remote" if its Fs_name contains a ':' - or if (it is of type (smbfs or cifs) and its Fs_name starts with '//') - or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */ -# define ME_REMOTE(Fs_name, Fs_type) \ - (strchr (Fs_name, ':') != NULL \ - || ((Fs_name)[0] == '/' \ - && (Fs_name)[1] == '/' \ - && (strcmp (Fs_type, "smbfs") == 0 \ - || strcmp (Fs_type, "cifs") == 0)) \ - || (strcmp("-hosts", Fs_name) == 0)) -#endif - -#define ME_DUMMY_0(Fs_name, Fs_type) \ - (strcmp (Fs_type, "autofs") == 0 \ - || strcmp (Fs_type, "proc") == 0 \ - || strcmp (Fs_type, "subfs") == 0 \ - /* for Linux 2.6/3.x */ \ - || strcmp (Fs_type, "debugfs") == 0 \ - || strcmp (Fs_type, "devpts") == 0 \ - || strcmp (Fs_type, "fusectl") == 0 \ - || strcmp (Fs_type, "mqueue") == 0 \ - || strcmp (Fs_type, "rpc_pipefs") == 0 \ - || strcmp (Fs_type, "sysfs") == 0 \ - /* FreeBSD, Linux 2.4 */ \ - || strcmp (Fs_type, "devfs") == 0 \ - /* for NetBSD 3.0 */ \ - || strcmp (Fs_type, "kernfs") == 0 \ - /* for Irix 6.5 */ \ - || strcmp (Fs_type, "ignore") == 0) - -/* Historically, we have marked as "dummy" any file system of type "none", - but now that programs like du need to know about bind-mounted directories, - we grant an exception to any with "bind" in its list of mount options. - I.e., those are *not* dummy entries. */ -# define ME_DUMMY(Fs_name, Fs_type) \ - (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0) - -// ---------------------------------------------------------------------------- - -// find the mount info with the given major:minor -// in the supplied linked list of mountinfo structures -struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor) { - struct mountinfo *mi; - - for(mi = root; mi ; mi = mi->next) - if(unlikely(mi->major == major && mi->minor == minor)) - return mi; - - return NULL; -} - -// find the mount info with the given filesystem and mount_source -// in the supplied linked list of mountinfo structures -struct mountinfo *mountinfo_find_by_filesystem_mount_source(struct mountinfo *root, const char *filesystem, const char *mount_source) { - struct mountinfo *mi; - uint32_t filesystem_hash = simple_hash(filesystem), mount_source_hash = simple_hash(mount_source); - - for(mi = root; mi ; mi = mi->next) - if(unlikely(mi->filesystem - && mi->mount_source - && mi->filesystem_hash == filesystem_hash - && mi->mount_source_hash == mount_source_hash - && !strcmp(mi->filesystem, filesystem) - && !strcmp(mi->mount_source, mount_source))) - return mi; - - return NULL; -} - -struct mountinfo *mountinfo_find_by_filesystem_super_option(struct mountinfo *root, const char *filesystem, const char *super_options) { - struct mountinfo *mi; - uint32_t filesystem_hash = simple_hash(filesystem); - - size_t solen = strlen(super_options); - - for(mi = root; mi ; mi = mi->next) - if(unlikely(mi->filesystem - && mi->super_options - && mi->filesystem_hash == filesystem_hash - && !strcmp(mi->filesystem, filesystem))) { - - // super_options is a comma separated list - char *s = mi->super_options, *e; - while(*s) { - e = s + 1; - while(*e && *e != ',') e++; - - size_t len = e - s; - if(unlikely(len == solen && !strncmp(s, super_options, len))) - return mi; - - if(*e == ',') s = ++e; - else s = e; - } - } - - return NULL; -} - -static void mountinfo_free(struct mountinfo *mi) { - freez(mi->root); - freez(mi->mount_point); - freez(mi->mount_options); - freez(mi->persistent_id); -/* - if(mi->optional_fields_count) { - int i; - for(i = 0; i < mi->optional_fields_count ; i++) - free(*mi->optional_fields[i]); - } - free(mi->optional_fields); -*/ - freez(mi->filesystem); - freez(mi->mount_source); - freez(mi->super_options); - freez(mi); -} - -// free a linked list of mountinfo structures -void mountinfo_free_all(struct mountinfo *mi) { - while(mi) { - struct mountinfo *t = mi; - mi = mi->next; - - mountinfo_free(t); - } -} - -static char *strdupz_decoding_octal(const char *string) { - char *buffer = strdupz(string); - - char *d = buffer; - const char *s = string; - - while(*s) { - if(unlikely(*s == '\\')) { - s++; - if(likely(isdigit(*s) && isdigit(s[1]) && isdigit(s[2]))) { - char c = *s++ - '0'; - c <<= 3; - c |= *s++ - '0'; - c <<= 3; - c |= *s++ - '0'; - *d++ = c; - } - else *d++ = '_'; - } - else *d++ = *s++; - } - *d = '\0'; - - return buffer; -} - -static inline int is_read_only(const char *s) { - if(!s) return 0; - - size_t len = strlen(s); - if(len < 2) return 0; - if(len == 2) { - if(!strcmp(s, "ro")) return 1; - return 0; - } - if(!strncmp(s, "ro,", 3)) return 1; - if(!strncmp(&s[len - 3], ",ro", 3)) return 1; - if(strstr(s, ",ro,")) return 1; - return 0; -} - -// 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", netdata_configured_host_prefix); - procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) { - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return NULL; - - struct mountinfo *root = NULL, *last = NULL, *mi = NULL; - - unsigned long l, lines = procfile_lines(ff); - for(l = 0; l < lines ;l++) { - if(unlikely(procfile_linewords(ff, l) < 5)) - continue; - - mi = mallocz(sizeof(struct mountinfo)); - - unsigned long w = 0; - mi->id = str2ul(procfile_lineword(ff, l, w)); w++; - mi->parentid = str2ul(procfile_lineword(ff, l, w)); w++; - - char *major = procfile_lineword(ff, l, w), *minor; w++; - for(minor = major; *minor && *minor != ':' ;minor++) ; - - if(unlikely(!*minor)) { - error("Cannot parse major:minor on '%s' at line %lu of '%s'", major, l + 1, filename); - freez(mi); - continue; - } - - *minor = '\0'; - minor++; - - mi->flags = 0; - - mi->major = str2ul(major); - mi->minor = str2ul(minor); - - mi->root = strdupz(procfile_lineword(ff, l, w)); w++; - mi->root_hash = simple_hash(mi->root); - - mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++; - mi->mount_point_hash = simple_hash(mi->mount_point); - - mi->persistent_id = strdupz(mi->mount_point); - netdata_fix_chart_id(mi->persistent_id); - mi->persistent_id_hash = simple_hash(mi->persistent_id); - - mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++; - - if(unlikely(is_read_only(mi->mount_options))) - mi->flags |= MOUNTINFO_READONLY; - - // count the optional fields -/* - unsigned long wo = w; -*/ - mi->optional_fields_count = 0; - char *s = procfile_lineword(ff, l, w); - while(*s && *s != '-') { - w++; - s = procfile_lineword(ff, l, w); - mi->optional_fields_count++; - } - -/* - if(unlikely(mi->optional_fields_count)) { - // we have some optional fields - // read them into a new array of pointers; - - mi->optional_fields = mallocz(mi->optional_fields_count * sizeof(char *)); - - int i; - for(i = 0; i < mi->optional_fields_count ; i++) { - *mi->optional_fields[wo] = strdupz(procfile_lineword(ff, l, w)); - wo++; - } - } - else - mi->optional_fields = NULL; -*/ - - if(likely(*s == '-')) { - w++; - - mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++; - mi->filesystem_hash = simple_hash(mi->filesystem); - - mi->mount_source = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++; - mi->mount_source_hash = simple_hash(mi->mount_source); - - mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++; - - if(unlikely(is_read_only(mi->super_options))) - mi->flags |= MOUNTINFO_READONLY; - - if(unlikely(ME_DUMMY(mi->mount_source, mi->filesystem))) - mi->flags |= MOUNTINFO_IS_DUMMY; - - if(unlikely(ME_REMOTE(mi->mount_source, mi->filesystem))) - mi->flags |= MOUNTINFO_IS_REMOTE; - - // mark as BIND the duplicates (i.e. same filesystem + same source) - if(do_statvfs) { - struct stat buf; - if(unlikely(stat(mi->mount_point, &buf) == -1)) { - mi->st_dev = 0; - mi->flags |= MOUNTINFO_NO_STAT; - } - else { - mi->st_dev = buf.st_dev; - - struct mountinfo *mt; - for(mt = root; mt; mt = mt->next) { - 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 - mi->flags |= MOUNTINFO_IS_SAME_DEV; - } - } - } - } - else { - mi->st_dev = 0; - } - } - else { - mi->filesystem = NULL; - mi->filesystem_hash = 0; - - mi->mount_source = NULL; - mi->mount_source_hash = 0; - - mi->super_options = NULL; - - mi->st_dev = 0; - } - - // check if it has size - 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; - } - else if(unlikely(!buff_statvfs.f_blocks /* || !buff_statvfs.f_files */)) { - mi->flags |= MOUNTINFO_NO_SIZE; - } - } - - // link it - if(unlikely(!root)) - root = mi; - else - last->next = mi; - - last = mi; - mi->next = NULL; - -/* -#ifdef NETDATA_INTERNAL_CHECKS - fprintf(stderr, "MOUNTINFO: %ld %ld %lu:%lu root '%s', persistent id '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'%s%s%s%s%s%s\n", - mi->id, - mi->parentid, - mi->major, - mi->minor, - mi->root, - mi->persistent_id, - (mi->mount_point)?mi->mount_point:"", - (mi->mount_options)?mi->mount_options:"", - (mi->filesystem)?mi->filesystem:"", - (mi->mount_source)?mi->mount_source:"", - (mi->super_options)?mi->super_options:"", - (mi->flags & MOUNTINFO_IS_DUMMY)?" DUMMY":"", - (mi->flags & MOUNTINFO_IS_BIND)?" BIND":"", - (mi->flags & MOUNTINFO_IS_REMOTE)?" REMOTE":"", - (mi->flags & MOUNTINFO_NO_STAT)?" NOSTAT":"", - (mi->flags & MOUNTINFO_NO_SIZE)?" NOSIZE":"", - (mi->flags & MOUNTINFO_IS_SAME_DEV)?" SAMEDEV":"" - ); -#endif -*/ - } - -/* find if the mount options have "bind" in them - { - FILE *fp = setmntent(MOUNTED, "r"); - if (fp != NULL) { - struct mntent mntbuf; - struct mntent *mnt; - char buf[4096 + 1]; - - while ((mnt = getmntent_r(fp, &mntbuf, buf, 4096))) { - char *bind = hasmntopt(mnt, "bind"); - if(unlikely(bind)) { - struct mountinfo *mi; - for(mi = root; mi ; mi = mi->next) { - if(unlikely(strcmp(mnt->mnt_dir, mi->mount_point) == 0)) { - fprintf(stderr, "Mount point '%s' is BIND\n", mi->mount_point); - mi->flags |= MOUNTINFO_IS_BIND; - break; - } - } - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(!mi)) { - error("Mount point '%s' not found in /proc/self/mountinfo", mnt->mnt_dir); - } -#endif - } - } - endmntent(fp); - } - } -*/ - - procfile_close(ff); - return root; -} diff --git a/src/proc_self_mountinfo.h b/src/proc_self_mountinfo.h deleted file mode 100644 index a8d337539..000000000 --- a/src/proc_self_mountinfo.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef NETDATA_PROC_SELF_MOUNTINFO_H -#define NETDATA_PROC_SELF_MOUNTINFO_H 1 - -#define MOUNTINFO_IS_DUMMY 0x00000001 -#define MOUNTINFO_IS_REMOTE 0x00000002 -#define MOUNTINFO_IS_BIND 0x00000004 -#define MOUNTINFO_IS_SAME_DEV 0x00000008 -#define MOUNTINFO_NO_STAT 0x00000010 -#define MOUNTINFO_NO_SIZE 0x00000020 -#define MOUNTINFO_READONLY 0x00000040 - -struct mountinfo { - long id; // mount ID: unique identifier of the mount (may be reused after umount(2)). - long parentid; // parent ID: ID of parent mount (or of self for the top of the mount tree). - unsigned long major; // major:minor: value of st_dev for files on filesystem (see stat(2)). - unsigned long minor; - - char *persistent_id; // a calculated persistent id for the mount point - uint32_t persistent_id_hash; - - char *root; // root: root of the mount within the filesystem. - uint32_t root_hash; - - char *mount_point; // mount point: mount point relative to the process's root. - uint32_t mount_point_hash; - - char *mount_options; // mount options: per-mount options. - - int optional_fields_count; -/* - char ***optional_fields; // optional fields: zero or more fields of the form "tag[:value]". -*/ - char *filesystem; // filesystem type: name of filesystem in the form "type[.subtype]". - uint32_t filesystem_hash; - - char *mount_source; // mount source: filesystem-specific information or "none". - uint32_t mount_source_hash; - - char *super_options; // super options: per-superblock options. - - uint32_t flags; - - dev_t st_dev; // id of device as given by stat() - - struct mountinfo *next; -}; - -extern struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor); -extern struct mountinfo *mountinfo_find_by_filesystem_mount_source(struct mountinfo *root, const char *filesystem, const char *mount_source); -extern struct mountinfo *mountinfo_find_by_filesystem_super_option(struct mountinfo *root, const char *filesystem, const char *super_options); - -extern void mountinfo_free_all(struct mountinfo *mi); -extern struct mountinfo *mountinfo_read(int do_statvfs); - -#endif /* NETDATA_PROC_SELF_MOUNTINFO_H */ \ No newline at end of file diff --git a/src/proc_softirqs.c b/src/proc_softirqs.c deleted file mode 100644 index cd7440b00..000000000 --- a/src/proc_softirqs.c +++ /dev/null @@ -1,249 +0,0 @@ -#include "common.h" - -#define MAX_INTERRUPT_NAME 50 - -struct cpu_interrupt { - unsigned long long value; - RRDDIM *rd; -}; - -struct interrupt { - int used; - char *id; - char name[MAX_INTERRUPT_NAME + 1]; - RRDDIM *rd; - unsigned long long total; - struct cpu_interrupt cpu[]; -}; - -// since each interrupt is variable in size -// we use this to calculate its record size -#define recordsize(cpus) (sizeof(struct interrupt) + ((cpus) * sizeof(struct cpu_interrupt))) - -// given a base, get a pointer to each record -#define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[(line) * recordsize(cpus)]) - -static inline struct interrupt *get_interrupts_array(size_t lines, int cpus) { - static struct interrupt *irrs = NULL; - static size_t allocated = 0; - - if(unlikely(lines != allocated)) { - uint32_t l; - int c; - - irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus)); - - // reset all interrupt RRDDIM pointers as any line could have shifted - for(l = 0; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - irr->rd = NULL; - irr->name[0] = '\0'; - for(c = 0; c < cpus ;c++) - irr->cpu[c].rd = NULL; - } - - allocated = lines; - } - - return irrs; -} - -int do_proc_softirqs(int update_every, usec_t dt) { - (void)dt; - static procfile *ff = NULL; - static int cpus = -1, do_per_core = -1; - struct interrupt *irrs = NULL; - - if(unlikely(do_per_core == -1)) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1); - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - size_t words = procfile_linewords(ff, 0); - - if(unlikely(!lines)) { - error("Cannot read /proc/softirqs, zero lines reported."); - return 1; - } - - // find how many CPUs are there - if(unlikely(cpus == -1)) { - uint32_t w; - cpus = 0; - for(w = 0; w < words ; w++) { - if(likely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)) - cpus++; - } - } - - if(unlikely(!cpus)) { - error("PLUGIN: PROC_SOFTIRQS: Cannot find the number of CPUs in /proc/softirqs"); - return 1; - } - - // allocate the size we need; - irrs = get_interrupts_array(lines, cpus); - irrs[0].used = 0; - - // loop through all lines - for(l = 1; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - irr->used = 0; - irr->total = 0; - - words = procfile_linewords(ff, l); - if(unlikely(!words)) continue; - - irr->id = procfile_lineword(ff, l, 0); - if(unlikely(!irr->id || !irr->id[0])) continue; - - size_t idlen = strlen(irr->id); - if(unlikely(idlen && irr->id[idlen - 1] == ':')) - irr->id[idlen - 1] = '\0'; - - int c; - for(c = 0; c < cpus ;c++) { - if(likely((c + 1) < (int)words)) - irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t)(c + 1))); - else - irr->cpu[c].value = 0; - - irr->total += irr->cpu[c].value; - } - - strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME); - - irr->used = 1; - } - - // -------------------------------------------------------------------- - - static RRDSET *st_system_softirqs = NULL; - if(unlikely(!st_system_softirqs)) - st_system_softirqs = rrdset_create_localhost( - "system" - , "softirqs" - , NULL - , "softirqs" - , NULL - , "System softirqs" - , "softirqs/s" - , "proc" - , "softirqs" - , 950 - , update_every - , RRDSET_TYPE_STACKED - ); - else - rrdset_next(st_system_softirqs); - - for(l = 0; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - - if(unlikely(!irr->used)) continue; - - // some interrupt may have changed without changing the total number of lines - // if the same number of interrupts have been added and removed between two - // calls of this function. - if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) { - irr->rd = rrddim_find(st_system_softirqs, irr->id); - - if(unlikely(!irr->rd)) - irr->rd = rrddim_add(st_system_softirqs, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL); - else - rrddim_set_name(st_system_softirqs, irr->rd, irr->name); - - // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop - if(likely(do_per_core)) { - int c; - for (c = 0; c < cpus ;c++) irr->cpu[c].rd = NULL; - } - } - - rrddim_set_by_pointer(st_system_softirqs, irr->rd, irr->total); - } - - rrdset_done(st_system_softirqs); - - // -------------------------------------------------------------------- - - if(do_per_core) { - static RRDSET **core_st = NULL; - static int old_cpus = 0; - - if(old_cpus < cpus) { - core_st = reallocz(core_st, sizeof(RRDSET *) * cpus); - memset(&core_st[old_cpus], 0, sizeof(RRDSET *) * (cpus - old_cpus)); - old_cpus = cpus; - } - - int c; - - for(c = 0; c < cpus ; c++) { - if(unlikely(!core_st[c])) { - // find if everything is just zero - unsigned long long core_sum = 0; - - for (l = 0; l < lines; l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - if (unlikely(!irr->used)) continue; - core_sum += irr->cpu[c].value; - } - - if (unlikely(core_sum == 0)) continue; // try next core - - char id[50 + 1]; - snprintfz(id, 50, "cpu%d_softirqs", c); - - char title[100 + 1]; - snprintfz(title, 100, "CPU%d softirqs", c); - - core_st[c] = rrdset_create_localhost( - "cpu" - , id - , NULL - , "softirqs" - , "cpu.softirqs" - , title - , "softirqs/s" - , "proc" - , "softirqs" - , 3000 + c - , update_every - , RRDSET_TYPE_STACKED - ); - } - else - rrdset_next(core_st[c]); - - for(l = 0; l < lines ;l++) { - struct interrupt *irr = irrindex(irrs, l, cpus); - - if(unlikely(!irr->used)) continue; - - if(unlikely(!irr->cpu[c].rd)) { - irr->cpu[c].rd = rrddim_find(core_st[c], irr->id); - - if(unlikely(!irr->cpu[c].rd)) - irr->cpu[c].rd = rrddim_add(core_st[c], irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL); - else - rrddim_set_name(core_st[c], irr->cpu[c].rd, irr->name); - } - - rrddim_set_by_pointer(core_st[c], irr->cpu[c].rd, irr->cpu[c].value); - } - - rrdset_done(core_st[c]); - } - } - - return 0; -} diff --git a/src/proc_spl_kstat_zfs.c b/src/proc_spl_kstat_zfs.c deleted file mode 100644 index 9d489d8e4..000000000 --- a/src/proc_spl_kstat_zfs.c +++ /dev/null @@ -1,153 +0,0 @@ -#include "common.h" -#include "zfs_common.h" - -#define ZFS_PROC_ARCSTATS "/proc/spl/kstat/zfs/arcstats" - -extern struct arcstats arcstats; - -int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - static ARL_BASE *arl_base = NULL; - - arcstats.l2exist = -1; - - if(unlikely(!arl_base)) { - arl_base = arl_create("arcstats", NULL, 60); - - arl_expect(arl_base, "hits", &arcstats.hits); - arl_expect(arl_base, "misses", &arcstats.misses); - arl_expect(arl_base, "demand_data_hits", &arcstats.demand_data_hits); - arl_expect(arl_base, "demand_data_misses", &arcstats.demand_data_misses); - arl_expect(arl_base, "demand_metadata_hits", &arcstats.demand_metadata_hits); - arl_expect(arl_base, "demand_metadata_misses", &arcstats.demand_metadata_misses); - arl_expect(arl_base, "prefetch_data_hits", &arcstats.prefetch_data_hits); - arl_expect(arl_base, "prefetch_data_misses", &arcstats.prefetch_data_misses); - arl_expect(arl_base, "prefetch_metadata_hits", &arcstats.prefetch_metadata_hits); - arl_expect(arl_base, "prefetch_metadata_misses", &arcstats.prefetch_metadata_misses); - arl_expect(arl_base, "mru_hits", &arcstats.mru_hits); - arl_expect(arl_base, "mru_ghost_hits", &arcstats.mru_ghost_hits); - arl_expect(arl_base, "mfu_hits", &arcstats.mfu_hits); - arl_expect(arl_base, "mfu_ghost_hits", &arcstats.mfu_ghost_hits); - arl_expect(arl_base, "deleted", &arcstats.deleted); - arl_expect(arl_base, "mutex_miss", &arcstats.mutex_miss); - arl_expect(arl_base, "evict_skip", &arcstats.evict_skip); - arl_expect(arl_base, "evict_not_enough", &arcstats.evict_not_enough); - arl_expect(arl_base, "evict_l2_cached", &arcstats.evict_l2_cached); - arl_expect(arl_base, "evict_l2_eligible", &arcstats.evict_l2_eligible); - arl_expect(arl_base, "evict_l2_ineligible", &arcstats.evict_l2_ineligible); - arl_expect(arl_base, "evict_l2_skip", &arcstats.evict_l2_skip); - arl_expect(arl_base, "hash_elements", &arcstats.hash_elements); - arl_expect(arl_base, "hash_elements_max", &arcstats.hash_elements_max); - arl_expect(arl_base, "hash_collisions", &arcstats.hash_collisions); - arl_expect(arl_base, "hash_chains", &arcstats.hash_chains); - arl_expect(arl_base, "hash_chain_max", &arcstats.hash_chain_max); - arl_expect(arl_base, "p", &arcstats.p); - arl_expect(arl_base, "c", &arcstats.c); - arl_expect(arl_base, "c_min", &arcstats.c_min); - arl_expect(arl_base, "c_max", &arcstats.c_max); - arl_expect(arl_base, "size", &arcstats.size); - arl_expect(arl_base, "hdr_size", &arcstats.hdr_size); - arl_expect(arl_base, "data_size", &arcstats.data_size); - arl_expect(arl_base, "metadata_size", &arcstats.metadata_size); - arl_expect(arl_base, "other_size", &arcstats.other_size); - arl_expect(arl_base, "anon_size", &arcstats.anon_size); - arl_expect(arl_base, "anon_evictable_data", &arcstats.anon_evictable_data); - arl_expect(arl_base, "anon_evictable_metadata", &arcstats.anon_evictable_metadata); - arl_expect(arl_base, "mru_size", &arcstats.mru_size); - arl_expect(arl_base, "mru_evictable_data", &arcstats.mru_evictable_data); - arl_expect(arl_base, "mru_evictable_metadata", &arcstats.mru_evictable_metadata); - arl_expect(arl_base, "mru_ghost_size", &arcstats.mru_ghost_size); - arl_expect(arl_base, "mru_ghost_evictable_data", &arcstats.mru_ghost_evictable_data); - arl_expect(arl_base, "mru_ghost_evictable_metadata", &arcstats.mru_ghost_evictable_metadata); - arl_expect(arl_base, "mfu_size", &arcstats.mfu_size); - arl_expect(arl_base, "mfu_evictable_data", &arcstats.mfu_evictable_data); - arl_expect(arl_base, "mfu_evictable_metadata", &arcstats.mfu_evictable_metadata); - arl_expect(arl_base, "mfu_ghost_size", &arcstats.mfu_ghost_size); - arl_expect(arl_base, "mfu_ghost_evictable_data", &arcstats.mfu_ghost_evictable_data); - arl_expect(arl_base, "mfu_ghost_evictable_metadata", &arcstats.mfu_ghost_evictable_metadata); - arl_expect(arl_base, "l2_hits", &arcstats.l2_hits); - arl_expect(arl_base, "l2_misses", &arcstats.l2_misses); - arl_expect(arl_base, "l2_feeds", &arcstats.l2_feeds); - arl_expect(arl_base, "l2_rw_clash", &arcstats.l2_rw_clash); - arl_expect(arl_base, "l2_read_bytes", &arcstats.l2_read_bytes); - arl_expect(arl_base, "l2_write_bytes", &arcstats.l2_write_bytes); - arl_expect(arl_base, "l2_writes_sent", &arcstats.l2_writes_sent); - arl_expect(arl_base, "l2_writes_done", &arcstats.l2_writes_done); - arl_expect(arl_base, "l2_writes_error", &arcstats.l2_writes_error); - arl_expect(arl_base, "l2_writes_lock_retry", &arcstats.l2_writes_lock_retry); - arl_expect(arl_base, "l2_evict_lock_retry", &arcstats.l2_evict_lock_retry); - arl_expect(arl_base, "l2_evict_reading", &arcstats.l2_evict_reading); - arl_expect(arl_base, "l2_evict_l1cached", &arcstats.l2_evict_l1cached); - arl_expect(arl_base, "l2_free_on_write", &arcstats.l2_free_on_write); - arl_expect(arl_base, "l2_cdata_free_on_write", &arcstats.l2_cdata_free_on_write); - arl_expect(arl_base, "l2_abort_lowmem", &arcstats.l2_abort_lowmem); - arl_expect(arl_base, "l2_cksum_bad", &arcstats.l2_cksum_bad); - arl_expect(arl_base, "l2_io_error", &arcstats.l2_io_error); - arl_expect(arl_base, "l2_size", &arcstats.l2_size); - arl_expect(arl_base, "l2_asize", &arcstats.l2_asize); - arl_expect(arl_base, "l2_hdr_size", &arcstats.l2_hdr_size); - arl_expect(arl_base, "l2_compress_successes", &arcstats.l2_compress_successes); - arl_expect(arl_base, "l2_compress_zeros", &arcstats.l2_compress_zeros); - arl_expect(arl_base, "l2_compress_failures", &arcstats.l2_compress_failures); - arl_expect(arl_base, "memory_throttle_count", &arcstats.memory_throttle_count); - arl_expect(arl_base, "duplicate_buffers", &arcstats.duplicate_buffers); - arl_expect(arl_base, "duplicate_buffers_size", &arcstats.duplicate_buffers_size); - arl_expect(arl_base, "duplicate_reads", &arcstats.duplicate_reads); - arl_expect(arl_base, "memory_direct_count", &arcstats.memory_direct_count); - arl_expect(arl_base, "memory_indirect_count", &arcstats.memory_indirect_count); - arl_expect(arl_base, "arc_no_grow", &arcstats.arc_no_grow); - arl_expect(arl_base, "arc_tempreserve", &arcstats.arc_tempreserve); - arl_expect(arl_base, "arc_loaned_bytes", &arcstats.arc_loaned_bytes); - arl_expect(arl_base, "arc_prune", &arcstats.arc_prune); - arl_expect(arl_base, "arc_meta_used", &arcstats.arc_meta_used); - arl_expect(arl_base, "arc_meta_limit", &arcstats.arc_meta_limit); - arl_expect(arl_base, "arc_meta_max", &arcstats.arc_meta_max); - arl_expect(arl_base, "arc_meta_min", &arcstats.arc_meta_min); - arl_expect(arl_base, "arc_need_free", &arcstats.arc_need_free); - arl_expect(arl_base, "arc_sys_free", &arcstats.arc_sys_free); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, ZFS_PROC_ARCSTATS); - ff = procfile_open(config_get("plugin:proc:" ZFS_PROC_ARCSTATS, "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) - return 1; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) - return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - arl_begin(arl_base); - - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 3)) { - if(unlikely(words)) error("Cannot read " ZFS_PROC_ARCSTATS " line %zu. Expected 3 params, read %zu.", l, words); - continue; - } - - const char *key = procfile_lineword(ff, l, 0); - const char *value = procfile_lineword(ff, l, 2); - - if(unlikely(arcstats.l2exist == -1)) { - if(key[0] == 'l' && key[1] == '2' && key[2] == '_') - arcstats.l2exist = 1; - } - - if(unlikely(arl_check(arl_base, key, value))) break; - } - - if(unlikely(arcstats.l2exist == -1)) - arcstats.l2exist = 0; - - generate_charts_arcstats("proc", update_every); - generate_charts_arc_summary("proc", update_every); - - return 0; -} diff --git a/src/proc_stat.c b/src/proc_stat.c deleted file mode 100644 index d1aefb73e..000000000 --- a/src/proc_stat.c +++ /dev/null @@ -1,557 +0,0 @@ -#include "common.h" - -struct per_core_single_number_file { - char found:1; - const char *filename; - int fd; - collected_number value; - RRDDIM *rd; -}; - -#define CORE_THROTTLE_COUNT_INDEX 0 -#define PACKAGE_THROTTLE_COUNT_INDEX 1 -#define SCALING_CUR_FREQ_INDEX 2 -#define PER_CORE_FILES 3 - -struct cpu_chart { - const char *id; - - RRDSET *st; - RRDDIM *rd_user; - RRDDIM *rd_nice; - RRDDIM *rd_system; - RRDDIM *rd_idle; - RRDDIM *rd_iowait; - RRDDIM *rd_irq; - RRDDIM *rd_softirq; - RRDDIM *rd_steal; - RRDDIM *rd_guest; - RRDDIM *rd_guest_nice; - - struct per_core_single_number_file files[PER_CORE_FILES]; -}; - -static int keep_per_core_fds_open = CONFIG_BOOLEAN_YES; - -static int read_per_core_files(struct cpu_chart *all_cpu_charts, size_t len, size_t index) { - char buf[50 + 1]; - size_t x, files_read = 0, files_nonzero = 0; - - for(x = 0; x < len ; x++) { - struct per_core_single_number_file *f = &all_cpu_charts[x].files[index]; - - f->found = 0; - - if(unlikely(!f->filename)) - continue; - - if(unlikely(f->fd == -1)) { - f->fd = open(f->filename, O_RDONLY); - if (unlikely(f->fd == -1)) { - error("Cannot open file '%s'", f->filename); - continue; - } - } - - ssize_t ret = read(f->fd, buf, 50); - if(unlikely(ret < 0)) { - // cannot read that file - - error("Cannot read file '%s'", f->filename); - close(f->fd); - f->fd = -1; - continue; - } - else { - // successful read - - // terminate the buffer - buf[ret] = '\0'; - - if(unlikely(keep_per_core_fds_open != CONFIG_BOOLEAN_YES)) { - close(f->fd); - f->fd = -1; - } - else if(lseek(f->fd, 0, SEEK_SET) == -1) { - error("Cannot seek in file '%s'", f->filename); - close(f->fd); - f->fd = -1; - } - } - - files_read++; - f->found = 1; - - f->value = str2ll(buf, NULL); - // info("read '%s', parsed as " COLLECTED_NUMBER_FORMAT, buf, f->value); - if(likely(f->value != 0)) - files_nonzero++; - } - - if(files_read == 0) - return -1; - - if(files_nonzero == 0) - return 0; - - return (int)files_nonzero; -} - -static void chart_per_core_files(struct cpu_chart *all_cpu_charts, size_t len, size_t index, RRDSET *st, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm) { - size_t x; - for(x = 0; x < len ; x++) { - struct per_core_single_number_file *f = &all_cpu_charts[x].files[index]; - - if(unlikely(!f->found)) - continue; - - if(unlikely(!f->rd)) - f->rd = rrddim_add(st, all_cpu_charts[x].id, NULL, multiplier, divisor, algorithm); - - rrddim_set_by_pointer(st, f->rd, f->value); - } -} - -int do_proc_stat(int update_every, usec_t dt) { - (void)dt; - - static struct cpu_chart *all_cpu_charts = NULL; - static size_t all_cpu_charts_size = 0; - static procfile *ff = NULL; - static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1, do_core_throttle_count = -1, do_package_throttle_count = -1, do_scaling_cur_freq = -1; - static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked; - static char *core_throttle_count_filename = NULL, *package_throttle_count_filename = NULL, *scaling_cur_freq_filename = NULL; - - if(unlikely(do_cpu == -1)) { - do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", CONFIG_BOOLEAN_YES); - do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", CONFIG_BOOLEAN_YES); - do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", CONFIG_BOOLEAN_YES); - do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", CONFIG_BOOLEAN_YES); - do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", CONFIG_BOOLEAN_YES); - do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", CONFIG_BOOLEAN_YES); - - // give sane defaults based on the number of processors - if(processors > 50) { - // the system has too many processors - keep_per_core_fds_open = CONFIG_BOOLEAN_NO; - do_core_throttle_count = CONFIG_BOOLEAN_NO; - do_package_throttle_count = CONFIG_BOOLEAN_NO; - do_scaling_cur_freq = CONFIG_BOOLEAN_NO; - } - else { - // the system has a reasonable number of processors - keep_per_core_fds_open = CONFIG_BOOLEAN_YES; - do_core_throttle_count = CONFIG_BOOLEAN_AUTO; - do_package_throttle_count = CONFIG_BOOLEAN_NO; - do_scaling_cur_freq = CONFIG_BOOLEAN_NO; - } - - keep_per_core_fds_open = config_get_boolean("plugin:proc:/proc/stat", "keep per core files open", keep_per_core_fds_open); - do_core_throttle_count = config_get_boolean_ondemand("plugin:proc:/proc/stat", "core_throttle_count", do_core_throttle_count); - do_package_throttle_count = config_get_boolean_ondemand("plugin:proc:/proc/stat", "package_throttle_count", do_package_throttle_count); - do_scaling_cur_freq = config_get_boolean_ondemand("plugin:proc:/proc/stat", "scaling_cur_freq", do_scaling_cur_freq); - - hash_intr = simple_hash("intr"); - hash_ctxt = simple_hash("ctxt"); - hash_processes = simple_hash("processes"); - hash_procs_running = simple_hash("procs_running"); - hash_procs_blocked = simple_hash("procs_blocked"); - - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/thermal_throttle/core_throttle_count"); - core_throttle_count_filename = config_get("plugin:proc:/proc/stat", "core_throttle_count filename to monitor", filename); - - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/thermal_throttle/package_throttle_count"); - package_throttle_count_filename = config_get("plugin:proc:/proc/stat", "package_throttle_count filename to monitor", filename); - - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/cpufreq/scaling_cur_freq"); - scaling_cur_freq_filename = config_get("plugin:proc:/proc/stat", "scaling_cur_freq filename to monitor", filename); - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - size_t words; - - unsigned long long processes = 0, running = 0 , blocked = 0; - - for(l = 0; l < lines ;l++) { - char *row_key = procfile_lineword(ff, l, 0); - uint32_t hash = simple_hash(row_key); - - // faster strncmp(row_key, "cpu", 3) == 0 - if(likely(row_key[0] == 'c' && row_key[1] == 'p' && row_key[2] == 'u')) { - words = procfile_linewords(ff, l); - if(unlikely(words < 9)) { - error("Cannot read /proc/stat cpu line. Expected 9 params, read %zu.", words); - continue; - } - - size_t core = (row_key[3] == '\0') ? 0 : str2ul(&row_key[3]) + 1; - - if(likely((core == 0 && do_cpu) || (core > 0 && do_cpu_cores))) { - char *id; - unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0; - - id = row_key; - user = str2ull(procfile_lineword(ff, l, 1)); - nice = str2ull(procfile_lineword(ff, l, 2)); - system = str2ull(procfile_lineword(ff, l, 3)); - idle = str2ull(procfile_lineword(ff, l, 4)); - iowait = str2ull(procfile_lineword(ff, l, 5)); - irq = str2ull(procfile_lineword(ff, l, 6)); - softirq = str2ull(procfile_lineword(ff, l, 7)); - steal = str2ull(procfile_lineword(ff, l, 8)); - - guest = str2ull(procfile_lineword(ff, l, 9)); - user -= guest; - - guest_nice = str2ull(procfile_lineword(ff, l, 10)); - nice -= guest_nice; - - char *title, *type, *context, *family; - long priority; - - if(core >= all_cpu_charts_size) { - size_t old_cpu_charts_size = all_cpu_charts_size; - all_cpu_charts_size = core + 1; - all_cpu_charts = reallocz(all_cpu_charts, sizeof(struct cpu_chart) * all_cpu_charts_size); - memset(&all_cpu_charts[old_cpu_charts_size], 0, sizeof(struct cpu_chart) * (all_cpu_charts_size - old_cpu_charts_size)); - } - struct cpu_chart *cpu_chart = &all_cpu_charts[core]; - - if(unlikely(!cpu_chart->st)) { - cpu_chart->id = strdupz(id); - - if(core == 0) { - title = "Total CPU utilization"; - type = "system"; - context = "system.cpu"; - family = id; - priority = 100; - } - else { - title = "Core utilization"; - type = "cpu"; - context = "cpu.cpu"; - family = "utilization"; - priority = 1000; - - // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq - // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state - - char filename[FILENAME_MAX + 1]; - struct stat stbuf; - - if(do_core_throttle_count != CONFIG_BOOLEAN_NO) { - snprintfz(filename, FILENAME_MAX, core_throttle_count_filename, id); - if (stat(filename, &stbuf) == 0) { - cpu_chart->files[CORE_THROTTLE_COUNT_INDEX].filename = strdupz(filename); - cpu_chart->files[CORE_THROTTLE_COUNT_INDEX].fd = -1; - do_core_throttle_count = CONFIG_BOOLEAN_YES; - } - } - - if(do_package_throttle_count != CONFIG_BOOLEAN_NO) { - snprintfz(filename, FILENAME_MAX, package_throttle_count_filename, id); - if (stat(filename, &stbuf) == 0) { - cpu_chart->files[PACKAGE_THROTTLE_COUNT_INDEX].filename = strdupz(filename); - cpu_chart->files[PACKAGE_THROTTLE_COUNT_INDEX].fd = -1; - do_package_throttle_count = CONFIG_BOOLEAN_YES; - } - } - - if(do_scaling_cur_freq != CONFIG_BOOLEAN_NO) { - snprintfz(filename, FILENAME_MAX, scaling_cur_freq_filename, id); - if (stat(filename, &stbuf) == 0) { - cpu_chart->files[SCALING_CUR_FREQ_INDEX].filename = strdupz(filename); - cpu_chart->files[SCALING_CUR_FREQ_INDEX].fd = -1; - do_scaling_cur_freq = CONFIG_BOOLEAN_YES; - } - } - } - - cpu_chart->st = rrdset_create_localhost( - type - , id - , NULL - , family - , context - , title - , "percentage" - , "proc" - , "stat" - , priority - , update_every - , RRDSET_TYPE_STACKED - ); - - long multiplier = 1; - long divisor = 1; // sysconf(_SC_CLK_TCK); - - cpu_chart->rd_guest_nice = rrddim_add(cpu_chart->st, "guest_nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_guest = rrddim_add(cpu_chart->st, "guest", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_steal = rrddim_add(cpu_chart->st, "steal", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_softirq = rrddim_add(cpu_chart->st, "softirq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_irq = rrddim_add(cpu_chart->st, "irq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_user = rrddim_add(cpu_chart->st, "user", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_system = rrddim_add(cpu_chart->st, "system", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_nice = rrddim_add(cpu_chart->st, "nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_iowait = rrddim_add(cpu_chart->st, "iowait", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - cpu_chart->rd_idle = rrddim_add(cpu_chart->st, "idle", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_hide(cpu_chart->st, "idle"); - } - else rrdset_next(cpu_chart->st); - - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_user, user); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_nice, nice); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_system, system); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_idle, idle); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_iowait, iowait); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_irq, irq); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_softirq, softirq); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_steal, steal); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_guest, guest); - rrddim_set_by_pointer(cpu_chart->st, cpu_chart->rd_guest_nice, guest_nice); - rrdset_done(cpu_chart->st); - } - } - else if(unlikely(hash == hash_intr && strcmp(row_key, "intr") == 0)) { - if(likely(do_interrupts)) { - static RRDSET *st_intr = NULL; - static RRDDIM *rd_interrupts = NULL; - unsigned long long value = str2ull(procfile_lineword(ff, l, 1)); - - if(unlikely(!st_intr)) { - st_intr = rrdset_create_localhost( - "system" - , "intr" - , NULL - , "interrupts" - , NULL - , "CPU Interrupts" - , "interrupts/s" - , "proc" - , "stat" - , 900 - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL); - - rd_interrupts = rrddim_add(st_intr, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_intr); - - rrddim_set_by_pointer(st_intr, rd_interrupts, value); - rrdset_done(st_intr); - } - } - else if(unlikely(hash == hash_ctxt && strcmp(row_key, "ctxt") == 0)) { - if(likely(do_context)) { - static RRDSET *st_ctxt = NULL; - static RRDDIM *rd_switches = NULL; - unsigned long long value = str2ull(procfile_lineword(ff, l, 1)); - - if(unlikely(!st_ctxt)) { - st_ctxt = rrdset_create_localhost( - "system" - , "ctxt" - , NULL - , "processes" - , NULL - , "CPU Context Switches" - , "context switches/s" - , "proc" - , "stat" - , 800 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_switches = rrddim_add(st_ctxt, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_ctxt); - - rrddim_set_by_pointer(st_ctxt, rd_switches, value); - rrdset_done(st_ctxt); - } - } - else if(unlikely(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0)) { - processes = str2ull(procfile_lineword(ff, l, 1)); - } - else if(unlikely(hash == hash_procs_running && !running && strcmp(row_key, "procs_running") == 0)) { - running = str2ull(procfile_lineword(ff, l, 1)); - } - else if(unlikely(hash == hash_procs_blocked && !blocked && strcmp(row_key, "procs_blocked") == 0)) { - blocked = str2ull(procfile_lineword(ff, l, 1)); - } - } - - // -------------------------------------------------------------------- - - if(likely(do_forks)) { - static RRDSET *st_forks = NULL; - static RRDDIM *rd_started = NULL; - - if(unlikely(!st_forks)) { - st_forks = rrdset_create_localhost( - "system" - , "forks" - , NULL - , "processes" - , NULL - , "Started Processes" - , "processes/s" - , "proc" - , "stat" - , 700 - , update_every - , RRDSET_TYPE_LINE - ); - rrdset_flag_set(st_forks, RRDSET_FLAG_DETAIL); - - rd_started = rrddim_add(st_forks, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_forks); - - rrddim_set_by_pointer(st_forks, rd_started, processes); - rrdset_done(st_forks); - } - - // -------------------------------------------------------------------- - - if(likely(do_processes)) { - static RRDSET *st_processes = NULL; - static RRDDIM *rd_running = NULL; - static RRDDIM *rd_blocked = NULL; - - if(unlikely(!st_processes)) { - st_processes = rrdset_create_localhost( - "system" - , "processes" - , NULL - , "processes" - , NULL - , "System Processes" - , "processes" - , "proc" - , "stat" - , 600 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_running = rrddim_add(st_processes, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_blocked = rrddim_add(st_processes, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st_processes); - - rrddim_set_by_pointer(st_processes, rd_running, running); - rrddim_set_by_pointer(st_processes, rd_blocked, blocked); - rrdset_done(st_processes); - } - - if(likely(all_cpu_charts_size > 1)) { - if(likely(do_core_throttle_count != CONFIG_BOOLEAN_NO)) { - int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, CORE_THROTTLE_COUNT_INDEX); - if(likely(r != -1 && (do_core_throttle_count == CONFIG_BOOLEAN_YES || r > 0))) { - do_core_throttle_count = CONFIG_BOOLEAN_YES; - - static RRDSET *st_core_throttle_count = NULL; - - if (unlikely(!st_core_throttle_count)) - st_core_throttle_count = rrdset_create_localhost( - "cpu" - , "core_throttling" - , NULL - , "throttling" - , "cpu.core_throttling" - , "Core Thermal Throttling Events" - , "events/s" - , "proc" - , "stat" - , 5001 - , update_every - , RRDSET_TYPE_LINE - ); - else - rrdset_next(st_core_throttle_count); - - chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, CORE_THROTTLE_COUNT_INDEX, st_core_throttle_count, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrdset_done(st_core_throttle_count); - } - } - - if(likely(do_package_throttle_count != CONFIG_BOOLEAN_NO)) { - int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, PACKAGE_THROTTLE_COUNT_INDEX); - if(likely(r != -1 && (do_package_throttle_count == CONFIG_BOOLEAN_YES || r > 0))) { - do_package_throttle_count = CONFIG_BOOLEAN_YES; - - static RRDSET *st_package_throttle_count = NULL; - - if(unlikely(!st_package_throttle_count)) - st_package_throttle_count = rrdset_create_localhost( - "cpu" - , "package_throttling" - , NULL - , "throttling" - , "cpu.package_throttling" - , "Package Thermal Throttling Events" - , "events/s" - , "proc" - , "stat" - , 5002 - , update_every - , RRDSET_TYPE_LINE - ); - else - rrdset_next(st_package_throttle_count); - - chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, PACKAGE_THROTTLE_COUNT_INDEX, st_package_throttle_count, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrdset_done(st_package_throttle_count); - } - } - - if(likely(do_scaling_cur_freq != CONFIG_BOOLEAN_NO)) { - int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, SCALING_CUR_FREQ_INDEX); - if(likely(r != -1 && (do_scaling_cur_freq == CONFIG_BOOLEAN_YES || r > 0))) { - do_scaling_cur_freq = CONFIG_BOOLEAN_YES; - - static RRDSET *st_scaling_cur_freq = NULL; - - if(unlikely(!st_scaling_cur_freq)) - st_scaling_cur_freq = rrdset_create_localhost( - "cpu" - , "scaling_cur_freq" - , NULL - , "cpufreq" - , "cpu.scaling_cur_freq" - , "Per CPU Core, Current CPU Scaling Frequency" - , "MHz" - , "proc" - , "stat" - , 5003 - , update_every - , RRDSET_TYPE_LINE - ); - else - rrdset_next(st_scaling_cur_freq); - - chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, SCALING_CUR_FREQ_INDEX, st_scaling_cur_freq, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrdset_done(st_scaling_cur_freq); - } - } - } - - return 0; -} diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/src/proc_sys_kernel_random_entropy_avail.c deleted file mode 100644 index ca4d7657c..000000000 --- a/src/proc_sys_kernel_random_entropy_avail.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "common.h" - -int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - unsigned long long entropy = str2ull(procfile_lineword(ff, 0, 0)); - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if(unlikely(!st)) { - st = rrdset_create_localhost( - "system" - , "entropy" - , NULL - , "entropy" - , NULL - , "Available Entropy" - , "entropy" - , "proc" - , "sys/kernel/random/entropy_avail" - , 1000 - , update_every - , RRDSET_TYPE_LINE - ); - - rd = rrddim_add(st, "entropy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(st); - - rrddim_set_by_pointer(st, rd, entropy); - rrdset_done(st); - - return 0; -} diff --git a/src/proc_uptime.c b/src/proc_uptime.c deleted file mode 100644 index 259de4760..000000000 --- a/src/proc_uptime.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "common.h" - -static inline collected_number uptime_from_boottime(void) { -#ifdef CLOCK_BOOTTIME_IS_AVAILABLE - return now_boottime_usec() / 1000; -#else - error("uptime cannot be read from CLOCK_BOOTTIME on this system."); - return 0; -#endif -} - -static procfile *read_proc_uptime_ff = NULL; -static inline collected_number read_proc_uptime(void) { - if(unlikely(!read_proc_uptime_ff)) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/uptime"); - - read_proc_uptime_ff = procfile_open(config_get("plugin:proc:/proc/uptime", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT); - if(unlikely(!read_proc_uptime_ff)) return 0; - } - - read_proc_uptime_ff = procfile_readall(read_proc_uptime_ff); - if(unlikely(!read_proc_uptime_ff)) return 0; - - if(unlikely(procfile_lines(read_proc_uptime_ff) < 1)) { - error("/proc/uptime has no lines."); - return 0; - } - if(unlikely(procfile_linewords(read_proc_uptime_ff, 0) < 1)) { - error("/proc/uptime has less than 1 word in it."); - return 0; - } - - return (collected_number)(strtold(procfile_lineword(read_proc_uptime_ff, 0, 0), NULL) * 1000.0); -} - -int do_proc_uptime(int update_every, usec_t dt) { - (void)dt; - - static int use_boottime = -1; - - if(unlikely(use_boottime == -1)) { - collected_number uptime_boottime = uptime_from_boottime(); - collected_number uptime_proc = read_proc_uptime(); - - long long delta = (long long)uptime_boottime - (long long)uptime_proc; - if(delta < 0) delta = -delta; - - if(delta <= 1000 && uptime_boottime != 0) { - procfile_close(read_proc_uptime_ff); - info("Using now_boottime_usec() for uptime (dt is %lld ms)", delta); - use_boottime = 1; - } - else if(uptime_proc != 0) { - info("Using /proc/uptime for uptime (dt is %lld ms)", delta); - use_boottime = 0; - } - else { - error("Cannot find any way to read uptime on this system."); - return 1; - } - } - - collected_number uptime; - if(use_boottime) - uptime = uptime_from_boottime(); - else - uptime = read_proc_uptime(); - - - // -------------------------------------------------------------------- - - static RRDSET *st = NULL; - static RRDDIM *rd = NULL; - - if(unlikely(!st)) { - - st = rrdset_create_localhost( - "system" - , "uptime" - , NULL - , "uptime" - , NULL - , "System Uptime" - , "seconds" - , "proc" - , "uptime" - , 1000 - , update_every - , RRDSET_TYPE_LINE - ); - - rd = rrddim_add(st, "uptime", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st); - - rrddim_set_by_pointer(st, rd, uptime); - - rrdset_done(st); - - return 0; -} diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c deleted file mode 100644 index 52e88d888..000000000 --- a/src/proc_vmstat.c +++ /dev/null @@ -1,255 +0,0 @@ -#include "common.h" - -int do_proc_vmstat(int update_every, usec_t dt) { - (void)dt; - - static procfile *ff = NULL; - static int do_swapio = -1, do_io = -1, do_pgfaults = -1, do_numa = -1; - static int has_numa = -1; - - static ARL_BASE *arl_base = NULL; - static unsigned long long numa_foreign = 0ULL; - static unsigned long long numa_hint_faults = 0ULL; - static unsigned long long numa_hint_faults_local = 0ULL; - static unsigned long long numa_huge_pte_updates = 0ULL; - static unsigned long long numa_interleave = 0ULL; - static unsigned long long numa_local = 0ULL; - static unsigned long long numa_other = 0ULL; - static unsigned long long numa_pages_migrated = 0ULL; - static unsigned long long numa_pte_updates = 0ULL; - static unsigned long long pgfault = 0ULL; - static unsigned long long pgmajfault = 0ULL; - static unsigned long long pgpgin = 0ULL; - static unsigned long long pgpgout = 0ULL; - static unsigned long long pswpin = 0ULL; - static unsigned long long pswpout = 0ULL; - - if(unlikely(!arl_base)) { - 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_BOOLEAN_AUTO); - - - arl_base = arl_create("vmstat", NULL, 60); - arl_expect(arl_base, "pgfault", &pgfault); - arl_expect(arl_base, "pgmajfault", &pgmajfault); - arl_expect(arl_base, "pgpgin", &pgpgin); - arl_expect(arl_base, "pgpgout", &pgpgout); - arl_expect(arl_base, "pswpin", &pswpin); - arl_expect(arl_base, "pswpout", &pswpout); - - 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); - arl_expect(arl_base, "numa_huge_pte_updates", &numa_huge_pte_updates); - arl_expect(arl_base, "numa_interleave", &numa_interleave); - arl_expect(arl_base, "numa_local", &numa_local); - arl_expect(arl_base, "numa_other", &numa_other); - arl_expect(arl_base, "numa_pages_migrated", &numa_pages_migrated); - arl_expect(arl_base, "numa_pte_updates", &numa_pte_updates); - } - else { - // Do not expect numa metrics when they are not needed. - // By not adding them, the ARL will stop processing the file - // when all the expected metrics are collected. - // Also ARL will not parse their values. - has_numa = 0; - do_numa = CONFIG_BOOLEAN_NO; - } - } - - if(unlikely(!ff)) { - char filename[FILENAME_MAX + 1]; - 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; - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time - - size_t lines = procfile_lines(ff), l; - - arl_begin(arl_base); - for(l = 0; l < lines ;l++) { - size_t words = procfile_linewords(ff, l); - if(unlikely(words < 2)) { - if(unlikely(words)) error("Cannot read /proc/vmstat line %zu. Expected 2 params, read %zu.", l, words); - continue; - } - - if(unlikely(arl_check(arl_base, - procfile_lineword(ff, l, 0), - procfile_lineword(ff, l, 1)))) break; - } - - // -------------------------------------------------------------------- - - if(pswpin || pswpout || do_swapio == CONFIG_BOOLEAN_YES) { - do_swapio = CONFIG_BOOLEAN_YES; - - static RRDSET *st_swapio = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_swapio)) { - st_swapio = rrdset_create_localhost( - "system" - , "swapio" - , NULL - , "swap" - , NULL - , "Swap I/O" - , "kilobytes/s" - , "proc" - , "vmstat" - , 250 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_swapio); - - rrddim_set_by_pointer(st_swapio, rd_in, pswpin); - rrddim_set_by_pointer(st_swapio, rd_out, pswpout); - rrdset_done(st_swapio); - } - - // -------------------------------------------------------------------- - - if(do_io) { - static RRDSET *st_io = NULL; - static RRDDIM *rd_in = NULL, *rd_out = NULL; - - if(unlikely(!st_io)) { - st_io = rrdset_create_localhost( - "system" - , "pgpgio" - , NULL - , "disk" - , NULL - , "Memory Paged from/to disk" - , "kilobytes/s" - , "proc" - , "vmstat" - , 151 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_in = rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_out = rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_io); - - rrddim_set_by_pointer(st_io, rd_in, pgpgin); - rrddim_set_by_pointer(st_io, rd_out, pgpgout); - rrdset_done(st_io); - } - - // -------------------------------------------------------------------- - - if(do_pgfaults) { - static RRDSET *st_pgfaults = NULL; - static RRDDIM *rd_minor = NULL, *rd_major = NULL; - - if(unlikely(!st_pgfaults)) { - st_pgfaults = rrdset_create_localhost( - "mem" - , "pgfaults" - , NULL - , "system" - , NULL - , "Memory Page Faults" - , "page faults/s" - , "proc" - , "vmstat" - , NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL); - - rd_minor = rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_major = rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_pgfaults); - - rrddim_set_by_pointer(st_pgfaults, rd_minor, pgfault); - rrddim_set_by_pointer(st_pgfaults, rd_major, pgmajfault); - rrdset_done(st_pgfaults); - } - - // -------------------------------------------------------------------- - - // Ondemand criteria for NUMA. Since this won't change at run time, we - // check it only once. We check whether the node count is >= 2 because - // single-node systems have uninteresting statistics (since all accesses - // are local). - if(unlikely(has_numa == -1)) - - has_numa = (numa_local || numa_foreign || numa_interleave || numa_other || numa_pte_updates || - numa_huge_pte_updates || numa_hint_faults || numa_hint_faults_local || numa_pages_migrated) ? 1 : 0; - - if(do_numa == CONFIG_BOOLEAN_YES || (do_numa == CONFIG_BOOLEAN_AUTO && has_numa)) { - do_numa = CONFIG_BOOLEAN_YES; - - static RRDSET *st_numa = NULL; - static RRDDIM *rd_local = NULL, *rd_foreign = NULL, *rd_interleave = NULL, *rd_other = NULL, *rd_pte_updates = NULL, *rd_huge_pte_updates = NULL, *rd_hint_faults = NULL, *rd_hint_faults_local = NULL, *rd_pages_migrated = NULL; - - if(unlikely(!st_numa)) { - st_numa = rrdset_create_localhost( - "mem" - , "numa" - , NULL - , "numa" - , NULL - , "NUMA events" - , "events/s" - , "proc" - , "vmstat" - , NETDATA_CHART_PRIO_MEM_NUMA - , update_every - , RRDSET_TYPE_LINE - ); - - rrdset_flag_set(st_numa, RRDSET_FLAG_DETAIL); - - // These depend on CONFIG_NUMA in the kernel. - rd_local = rrddim_add(st_numa, "local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_foreign = rrddim_add(st_numa, "foreign", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_interleave = rrddim_add(st_numa, "interleave", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_other = rrddim_add(st_numa, "other", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - // The following stats depend on CONFIG_NUMA_BALANCING in the - // kernel. - rd_pte_updates = rrddim_add(st_numa, "pte_updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_huge_pte_updates = rrddim_add(st_numa, "huge_pte_updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_hint_faults = rrddim_add(st_numa, "hint_faults", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_hint_faults_local = rrddim_add(st_numa, "hint_faults_local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_pages_migrated = rrddim_add(st_numa, "pages_migrated", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(st_numa); - - rrddim_set_by_pointer(st_numa, rd_local, numa_local); - rrddim_set_by_pointer(st_numa, rd_foreign, numa_foreign); - rrddim_set_by_pointer(st_numa, rd_interleave, numa_interleave); - rrddim_set_by_pointer(st_numa, rd_other, numa_other); - - rrddim_set_by_pointer(st_numa, rd_pte_updates, numa_pte_updates); - rrddim_set_by_pointer(st_numa, rd_huge_pte_updates, numa_huge_pte_updates); - rrddim_set_by_pointer(st_numa, rd_hint_faults, numa_hint_faults); - rrddim_set_by_pointer(st_numa, rd_hint_faults_local, numa_hint_faults_local); - rrddim_set_by_pointer(st_numa, rd_pages_migrated, numa_pages_migrated); - - rrdset_done(st_numa); - } - - return 0; -} - diff --git a/src/procfile.c b/src/procfile.c deleted file mode 100644 index 044f975b5..000000000 --- a/src/procfile.c +++ /dev/null @@ -1,468 +0,0 @@ -#include "common.h" -#include "procfile.h" - -#define PF_PREFIX "PROCFILE" - -#define PFWORDS_INCREASE_STEP 200 -#define PFLINES_INCREASE_STEP 10 -#define PROCFILE_INCREMENT_BUFFER 512 - -int procfile_adaptive_initial_allocation = 0; - -// if adaptive allocation is set, these store the -// max values we have seen so far -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 - -static inline void pfwords_add(procfile *ff, char *str) { - // debug(D_PROCFILE, PF_PREFIX ": adding word No %d: '%s'", fw->len, str); - - pfwords *fw = ff->words; - if(unlikely(fw->len == fw->size)) { - // debug(D_PROCFILE, PF_PREFIX ": expanding words"); - - ff->words = fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *)); - fw->size += PFWORDS_INCREASE_STEP; - } - - fw->words[fw->len++] = str; -} - -NEVERNULL -static inline pfwords *pfwords_new(void) { - // debug(D_PROCFILE, PF_PREFIX ": initializing words"); - - size_t size = (procfile_adaptive_initial_allocation) ? procfile_max_words : PFWORDS_INCREASE_STEP; - - pfwords *new = mallocz(sizeof(pfwords) + size * sizeof(char *)); - new->len = 0; - new->size = size; - return new; -} - -static inline void pfwords_reset(pfwords *fw) { - // debug(D_PROCFILE, PF_PREFIX ": reseting words"); - fw->len = 0; -} - -static inline void pfwords_free(pfwords *fw) { - // debug(D_PROCFILE, PF_PREFIX ": freeing words"); - - freez(fw); -} - - -// ---------------------------------------------------------------------------- -// An array of lines - -NEVERNULL -static inline size_t *pflines_add(procfile *ff) { - // debug(D_PROCFILE, PF_PREFIX ": adding line %d at word %d", fl->len, first_word); - - pflines *fl = ff->lines; - if(unlikely(fl->len == fl->size)) { - // debug(D_PROCFILE, PF_PREFIX ": expanding lines"); - - ff->lines = fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline)); - fl->size += PFLINES_INCREASE_STEP; - } - - ffline *ffl = &fl->lines[fl->len++]; - ffl->words = 0; - ffl->first = ff->words->len; - - return &ffl->words; -} - -NEVERNULL -static inline pflines *pflines_new(void) { - // debug(D_PROCFILE, PF_PREFIX ": initializing lines"); - - size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_words : PFLINES_INCREASE_STEP; - - pflines *new = mallocz(sizeof(pflines) + size * sizeof(ffline)); - new->len = 0; - new->size = size; - return new; -} - -static inline void pflines_reset(pflines *fl) { - // debug(D_PROCFILE, PF_PREFIX ": reseting lines"); - - fl->len = 0; -} - -static inline void pflines_free(pflines *fl) { - // debug(D_PROCFILE, PF_PREFIX ": freeing lines"); - - freez(fl); -} - - -// ---------------------------------------------------------------------------- -// The procfile - -void procfile_close(procfile *ff) { - 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); - - if(likely(ff->fd != -1)) close(ff->fd); - freez(ff); -} - -NOINLINE -static void procfile_parser(procfile *ff) { - // debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename); - - char *s = ff->data // our current position - , *e = &ff->data[ff->len] // the terminating null - , *t = ff->data; // the first character of a word (or quoted / 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 opened = 0; // counts the number of open parenthesis - - size_t *line_words = pflines_add(ff); - - while(s < e) { - PF_CHAR_TYPE ct = separators[(unsigned char)(*s)]; - - // this is faster than a switch() - // read more here: http://lazarenko.me/switch/ - if(likely(ct == PF_CHAR_IS_WORD)) { - s++; - } - else if(likely(ct == PF_CHAR_IS_SEPARATOR)) { - if(!quote && !opened) { - if (s != t) { - // separator, but we have word before it - *s = '\0'; - pfwords_add(ff, t); - (*line_words)++; - t = ++s; - } - else { - // separator at the beginning - // skip it - t = ++s; - } - } - else { - // we are inside a quote or parenthesized string - s++; - } - } - else if(likely(ct == PF_CHAR_IS_NEWLINE)) { - // end of line - - *s = '\0'; - pfwords_add(ff, t); - (*line_words)++; - t = ++s; - - // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words); - - line_words = pflines_add(ff); - } - else if(likely(ct == 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; - - *s = '\0'; - pfwords_add(ff, t); - (*line_words)++; - t = ++s; - } - 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--; - - if(!opened) { - *s = '\0'; - pfwords_add(ff, t); - (*line_words)++; - t = ++s; - } - else - s++; - } - else - s++; - } - else - fatal("Internal Error: procfile_readall() does not handle all the cases."); - } - - if(likely(s > t && t < e)) { - // the last word - if(unlikely(ff->len >= ff->size)) { - // we are going to loose the last byte - s = &ff->data[ff->size - 1]; - } - - *s = '\0'; - pfwords_add(ff, t); - (*line_words)++; - // t = ++s; - } -} - -procfile *procfile_readall(procfile *ff) { - // debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename); - - 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'.", 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 %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' on fd %d", procfile_filename(ff), ff->fd); - procfile_close(ff); - return NULL; - } - - ff->len += r; - } - - // 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'.", procfile_filename(ff)); - procfile_close(ff); - return NULL; - } - - pflines_reset(ff->lines); - pfwords_reset(ff->words); - procfile_parser(ff); - - if(unlikely(procfile_adaptive_initial_allocation)) { - if(unlikely(ff->len > procfile_max_allocation)) procfile_max_allocation = ff->len; - if(unlikely(ff->lines->len > procfile_max_lines)) procfile_max_lines = ff->lines->len; - if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len; - } - - // debug(D_PROCFILE, "File '%s' updated.", ff->filename); - return ff; -} - -NOINLINE -static void procfile_set_separators(procfile *ff, const char *separators) { - static PF_CHAR_TYPE def[256]; - static char initilized = 0; - - if(unlikely(!initilized)) { - // this is thread safe - // 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 - PF_CHAR_TYPE *ffs = ff->separators, *ffd = def, *ffe = &def[256]; - while(ffd != ffe) - *ffs++ = *ffd++; - - // set the separators - if(unlikely(!separators)) - separators = " \t=|"; - - ffs = ff->separators; - const char *s = separators; - 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 = 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 - const char *s = quotes; - 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 = 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 - const char *s = open; - while(*s) - ffs[(int)*s++] = PF_CHAR_IS_OPEN; - - // set the closings - s = close; - while(*s) - ffs[(int)*s++] = PF_CHAR_IS_CLOSE; -} - -procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) { - debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename); - - int fd = open(filename, O_RDONLY, 0666); - if(unlikely(fd == -1)) { - if(unlikely(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot open file '%s'", filename); - return NULL; - } - - // info("PROCFILE: opened '%s' on fd %d", filename, fd); - - 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); - ff->filename[0] = '\0'; - - ff->fd = fd; - ff->size = size; - ff->len = 0; - ff->flags = flags; - - ff->lines = pflines_new(); - ff->words = pfwords_new(); - - procfile_set_separators(ff, separators); - - debug(D_PROCFILE, "File '%s' opened.", filename); - return ff; -} - -procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags) { - if(unlikely(!ff)) return procfile_open(filename, separators, flags); - - if(likely(ff->fd != -1)) { - // info("PROCFILE: closing fd %d", ff->fd); - close(ff->fd); - } - - ff->fd = open(filename, O_RDONLY, 0666); - if(unlikely(ff->fd == -1)) { - procfile_close(ff); - return NULL; - } - - // info("PROCFILE: opened '%s' on fd %d", filename, ff->fd); - - //strncpyz(ff->filename, filename, FILENAME_MAX); - ff->filename[0] = '\0'; - ff->flags = flags; - - // do not do the separators again if NULL is given - if(likely(separators)) procfile_set_separators(ff, separators); - - return ff; -} - -// ---------------------------------------------------------------------------- -// example parsing of procfile data - -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", procfile_filename(ff), ff->lines->len, ff->words->len); - - for(l = 0; likely(l < lines) ;l++) { - size_t words = procfile_linewords(ff, l); - - debug(D_PROCFILE, " line %zu starts at word %zu and has %zu words", l, ff->lines->lines[l].first, ff->lines->lines[l].words); - - size_t w; - for(w = 0; likely(w < words) ;w++) { - s = procfile_lineword(ff, l, w); - debug(D_PROCFILE, " [%zu.%zu] '%s'", l, w, s); - } - } -} diff --git a/src/procfile.h b/src/procfile.h deleted file mode 100644 index 012c6efe1..000000000 --- a/src/procfile.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * procfile is a library for reading kernel files from /proc - * - * The idea is this: - * - * - every file is opened once with procfile_open(). - * - * - to read updated contents, we rewind it (lseek() to 0) and read again - * with procfile_readall(). - * - * - for every file, we use a buffer that is adjusted to fit its entire - * contents in memory, allowing us to read it with a single read() call. - * (this provides atomicity / consistency on the data read from the kernel) - * - * - once the data are read, we update two arrays of pointers: - * - a words array, pointing to each word in the data read - * - a lines array, pointing to the first word for each line - * - * This is highly optimized. Both arrays are automatically adjusted to - * fit all contents and are updated in a single pass on the data: - * - a raspberry Pi can process 5.000+ files / sec. - * - a J1900 celeron processor can process 23.000+ files / sec. -*/ - - -#ifndef NETDATA_PROCFILE_H -#define NETDATA_PROCFILE_H 1 - -// ---------------------------------------------------------------------------- -// An array of words - -typedef struct { - size_t len; // used entries - size_t size; // capacity - char *words[]; // array of pointers -} pfwords; - - -// ---------------------------------------------------------------------------- -// An array of lines - -typedef struct { - size_t words; // how many words this line has - size_t first; // the id of the first word of this line - // in the words array -} ffline; - -typedef struct { - size_t len; // used entries - size_t size; // capacity - ffline lines[]; // array of lines -} pflines; - - -// ---------------------------------------------------------------------------- -// The procfile - -#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]; // 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; - PF_CHAR_TYPE separators[256]; - char data[]; // allocated buffer to keep file contents -} procfile; - -// close the proc file and free all related memory -extern void procfile_close(procfile *ff); - -// (re)read and parse the proc file -extern procfile *procfile_readall(procfile *ff); - -// open a /proc or /sys file -extern procfile *procfile_open(const char *filename, const char *separators, uint32_t flags); - -// re-open a file -// if separators == NULL, the last separators are used -extern procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags); - -// example walk-through a procfile parsed file -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 -extern int procfile_adaptive_initial_allocation; - -// return the number of lines present -#define procfile_lines(ff) ((ff)->lines->len) - -// return the number of words of the Nth line -#define procfile_linewords(ff, line) (((line) < procfile_lines(ff)) ? (ff)->lines->lines[(line)].words : 0) - -// return the Nth word of the file, or empty string -#define procfile_word(ff, word) (((word) < (ff)->words->len) ? (ff)->words->words[(word)] : "") - -// return the first word of the Nth line, or empty string -#define procfile_line(ff, line) (((line) < procfile_lines(ff)) ? procfile_word((ff), (ff)->lines->lines[(line)].first) : "") - -// return the Nth word of the current line -#define procfile_lineword(ff, line, word) (((line) < procfile_lines(ff) && (word) < procfile_linewords((ff), (line))) ? procfile_word((ff), (ff)->lines->lines[(line)].first + (word)) : "") - -#endif /* NETDATA_PROCFILE_H */ diff --git a/src/registry.c b/src/registry.c deleted file mode 100644 index bbc2ef366..000000000 --- a/src/registry.c +++ /dev/null @@ -1,414 +0,0 @@ -#include "common.h" - -#include "registry_internals.h" - -#define REGISTRY_STATUS_OK "ok" -#define REGISTRY_STATUS_FAILED "failed" -#define REGISTRY_STATUS_DISABLED "disabled" - -// ---------------------------------------------------------------------------- -// REGISTRY concurrency locking - -static inline void registry_lock(void) { - netdata_mutex_lock(®istry.lock); -} - -static inline void registry_unlock(void) { - netdata_mutex_unlock(®istry.lock); -} - - -// ---------------------------------------------------------------------------- -// COOKIES - -static void registry_set_cookie(struct web_client *w, const char *guid) { - char edate[100]; - time_t et = now_realtime_sec() + registry.persons_expiration; - struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf); - strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm); - - snprintfz(w->cookie1, NETDATA_WEB_REQUEST_COOKIE_SIZE, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", guid, edate); - - if(registry.registry_domain && registry.registry_domain[0]) - snprintfz(w->cookie2, NETDATA_WEB_REQUEST_COOKIE_SIZE, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", guid, registry.registry_domain, edate); -} - -static inline void registry_set_person_cookie(struct web_client *w, REGISTRY_PERSON *p) { - registry_set_cookie(w, p->guid); -} - - -// ---------------------------------------------------------------------------- -// JSON GENERATION - -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, host->registry_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(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); - - registry_json_footer(w); - return 200; -} - - -// ---------------------------------------------------------------------------- -// CALLBACKS FOR WALKING THROUGH REGISTRY OBJECTS - -// structure used be the callbacks below -struct registry_json_walk_person_urls_callback { - REGISTRY_PERSON *p; - REGISTRY_MACHINE *m; - struct web_client *w; - int count; -}; - -// callback for rendering PERSON_URLs -static int registry_json_person_url_callback(void *entry, void *data) { - REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry; - struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data; - struct web_client *w = c->w; - - if(unlikely(c->count++)) - buffer_strcat(w->response.data, ","); - - buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]", - pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->machine_name); - - return 0; -} - -// callback for rendering MACHINE_URLs -static int registry_json_machine_url_callback(void *entry, void *data) { - REGISTRY_MACHINE_URL *mu = (REGISTRY_MACHINE_URL *)entry; - struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data; - struct web_client *w = c->w; - REGISTRY_MACHINE *m = c->m; - - if(unlikely(c->count++)) - buffer_strcat(w->response.data, ","); - - buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u ]", - m->guid, mu->url->url, mu->last_t, mu->usages); - - return 1; -} - -// ---------------------------------------------------------------------------- - -// structure used be the callbacks below -struct registry_person_url_callback_verify_machine_exists_data { - REGISTRY_MACHINE *m; - int count; -}; - -static inline int registry_person_url_callback_verify_machine_exists(void *entry, void *data) { - struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data; - REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry; - REGISTRY_MACHINE *m = d->m; - - if(pu->machine == m) - d->count++; - - return 0; -} - -// ---------------------------------------------------------------------------- -// public HELLO request - -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); - - registry_json_footer(w); - return 200; -} - -// ---------------------------------------------------------------------------- -//public ACCESS request - -#define REGISTRY_VERIFY_COOKIES_GUID "give-me-back-this-cookie-now--please" - -// the main method for registering an access -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(host, w, "access"); - - // ------------------------------------------------------------------------ - // verify the browser supports cookies - - if(registry.verify_cookies_redirects > 0 && !person_guid[0]) { - buffer_flush(w->response.data); - registry_set_cookie(w, REGISTRY_VERIFY_COOKIES_GUID); - w->response.data->contenttype = CT_APPLICATION_JSON; - buffer_sprintf(w->response.data, "{ \"status\": \"redirect\", \"registry\": \"%s\" }", registry.registry_to_announce); - return 200; - } - - if(unlikely(person_guid[0] && !strcmp(person_guid, REGISTRY_VERIFY_COOKIES_GUID))) - person_guid[0] = '\0'; - - // ------------------------------------------------------------------------ - - registry_lock(); - - REGISTRY_PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when); - if(!p) { - registry_json_header(host, w, "access", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 412; - } - - // set the cookie - registry_set_person_cookie(w, p); - - // generate the response - 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 }; - avl_traverse(&p->person_urls, registry_json_person_url_callback, &c); - buffer_strcat(w->response.data, "\n\t]\n"); - - registry_json_footer(w); - registry_unlock(); - return 200; -} - -// ---------------------------------------------------------------------------- -// public DELETE request - -// the main method for deleting a URL from a person -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(host, w, "delete"); - - registry_lock(); - - REGISTRY_PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when); - if(!p) { - registry_json_header(host, w, "delete", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 412; - } - - // generate the response - registry_json_header(host, w, "delete", REGISTRY_STATUS_OK); - registry_json_footer(w); - registry_unlock(); - return 200; -} - -// ---------------------------------------------------------------------------- -// public SEARCH request - -// the main method for searching the URLs of a netdata -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(host, w, "search"); - - registry_lock(); - - REGISTRY_MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when); - if(!m) { - registry_json_header(host, w, "search", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 404; - } - - 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 }; - dictionary_get_all(m->machine_urls, registry_json_machine_url_callback, &c); - buffer_strcat(w->response.data, "\n\t]\n"); - - registry_json_footer(w); - registry_unlock(); - return 200; -} - -// ---------------------------------------------------------------------------- -// SWITCH REQUEST - -// the main method for switching user identity -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(host, w, "switch"); - - (void)url; - (void)when; - - registry_lock(); - - REGISTRY_PERSON *op = registry_person_find(person_guid); - if(!op) { - registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 430; - } - - REGISTRY_PERSON *np = registry_person_find(new_person_guid); - if(!np) { - registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 431; - } - - REGISTRY_MACHINE *m = registry_machine_find(machine_guid); - if(!m) { - registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 432; - } - - struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 }; - - // 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(host, w, "switch", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 433; - } - - // verify the new person has access to this machine - data.count = 0; - avl_traverse(&np->person_urls, registry_person_url_callback_verify_machine_exists, &data); - if(!data.count) { - registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); - registry_json_footer(w); - registry_unlock(); - return 434; - } - - // set the cookie of the new person - // the user just switched identity - registry_set_person_cookie(w, np); - - // generate the response - 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); - - registry_unlock(); - return 200; -} - -// ---------------------------------------------------------------------------- -// STATISTICS - -void registry_statistics(void) { - if(!registry.enabled) return; - - static RRDSET *sts = NULL, *stc = NULL, *stm = NULL; - - if(unlikely(!sts)) { - sts = rrdset_create_localhost( - "netdata" - , "registry_sessions" - , NULL - , "registry" - , NULL - , "NetData Registry Sessions" - , "session" - , "registry" - , "stats" - , 131000 - , localhost->rrd_update_every - , RRDSET_TYPE_LINE - ); - - rrddim_add(sts, "sessions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(sts); - - rrddim_set(sts, "sessions", registry.usages_count); - rrdset_done(sts); - - // ------------------------------------------------------------------------ - - if(unlikely(!stc)) { - stc = rrdset_create_localhost( - "netdata" - , "registry_entries" - , NULL - , "registry" - , NULL - , "NetData Registry Entries" - , "entries" - , "registry" - , "stats" - , 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); - - rrddim_set(stc, "persons", registry.persons_count); - rrddim_set(stc, "machines", registry.machines_count); - rrddim_set(stc, "urls", registry.urls_count); - rrddim_set(stc, "persons_urls", registry.persons_urls_count); - rrddim_set(stc, "machines_urls", registry.machines_urls_count); - rrdset_done(stc); - - // ------------------------------------------------------------------------ - - if(unlikely(!stm)) { - stm = rrdset_create_localhost( - "netdata" - , "registry_mem" - , NULL - , "registry" - , NULL - , "NetData Registry Memory" - , "KB" - , "registry" - , "stats" - , 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); - - rrddim_set(stm, "persons", registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY)); - rrddim_set(stm, "machines", registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY)); - rrddim_set(stm, "urls", registry.urls_memory); - rrddim_set(stm, "persons_urls", registry.persons_urls_memory); - rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE)); - rrdset_done(stm); -} diff --git a/src/registry.h b/src/registry.h deleted file mode 100644 index 9aa241564..000000000 --- a/src/registry.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * netdata registry - * - * this header file describes the public interface - * to the netdata registry - * - * only these high level functions are exposed - * - */ - -// ---------------------------------------------------------------------------- -// TODO -// -// 1. the default tracking cookie expires in 1 year, but the persons are not -// removed from the db - this means the database only grows - ideally the -// database should be cleaned in registry_db_save() for both on-disk and -// on-memory entries. -// -// Cleanup: -// i. Find all the PERSONs that have expired cookie -// ii. For each of their PERSON_URLs: -// - decrement the linked MACHINE links -// - if the linked MACHINE has no other links, remove the linked MACHINE too -// - remove the PERSON_URL -// -// 2. add protection to prevent abusing the registry by flooding it with -// requests to fill the memory and crash it. -// -// Possible protections: -// - limit the number of URLs per person -// - limit the number of URLs per machine -// - limit the number of persons -// - limit the number of machines -// - [DONE] limit the size of URLs -// - [DONE] limit the size of PERSON_URL names -// - limit the number of requests that add data to the registry, -// per client IP per hour -// -// 3. lower memory requirements -// -// - embed avl structures directly into registry objects, instead of DICTIONARY -// [DONE for PERSON_URLs, PENDING for MACHINE_URLs] -// - store GUIDs in memory as UUID instead of char * -// - do not track persons using the demo machines only -// (i.e. start tracking them only when they access a non-demo machine) -// - [DONE] do not track custom dashboards by default - - -#ifndef NETDATA_REGISTRY_H -#define NETDATA_REGISTRY_H 1 - -#define NETDATA_REGISTRY_COOKIE_NAME "netdata_registry_id" - -// initialize the registry -// should only happen when netdata starts -extern int registry_init(void); - -// free all data held by the registry -// should only happen when netdata exits -extern void registry_free(void); - -// HTTP requests handled by the registry -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 char *registry_get_this_machine_hostname(void); - -extern int regenerate_guid(const char *guid, char *result); - -#endif /* NETDATA_REGISTRY_H */ diff --git a/src/registry_db.c b/src/registry_db.c deleted file mode 100644 index de6c634c3..000000000 --- a/src/registry_db.c +++ /dev/null @@ -1,343 +0,0 @@ -#include "registry_internals.h" - -int registry_db_should_be_saved(void) { - debug(D_REGISTRY, "log entries %llu, max %llu", registry.log_count, registry.save_registry_every_entries); - return registry.log_count > registry.save_registry_every_entries; -} - -// ---------------------------------------------------------------------------- -// INTERNAL FUNCTIONS FOR SAVING REGISTRY OBJECTS - -static int registry_machine_save_url(void *entry, void *file) { - REGISTRY_MACHINE_URL *mu = entry; - FILE *fp = file; - - debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url); - - int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n", - mu->first_t, - mu->last_t, - mu->usages, - mu->flags, - mu->url->url - ); - - // error handling is done at registry_db_save() - - return ret; -} - -static int registry_machine_save(void *entry, void *file) { - REGISTRY_MACHINE *m = entry; - FILE *fp = file; - - debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid); - - int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n", - m->first_t, - m->last_t, - m->usages, - m->guid - ); - - if(ret >= 0) { - int ret2 = dictionary_get_all(m->machine_urls, registry_machine_save_url, fp); - if(ret2 < 0) return ret2; - ret += ret2; - } - - // error handling is done at registry_db_save() - - return ret; -} - -static inline int registry_person_save_url(void *entry, void *file) { - REGISTRY_PERSON_URL *pu = entry; - FILE *fp = file; - - debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url); - - int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\t%s\n", - pu->first_t, - pu->last_t, - pu->usages, - pu->flags, - pu->machine->guid, - pu->machine_name, - pu->url->url - ); - - // error handling is done at registry_db_save() - - return ret; -} - -static inline int registry_person_save(void *entry, void *file) { - REGISTRY_PERSON *p = entry; - FILE *fp = file; - - debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid); - - int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n", - p->first_t, - p->last_t, - p->usages, - p->guid - ); - - if(ret >= 0) { - //int ret2 = dictionary_get_all(p->person_urls, registry_person_save_url, fp); - int ret2 = avl_traverse(&p->person_urls, registry_person_save_url, fp); - if (ret2 < 0) return ret2; - ret += ret2; - } - - // error handling is done at registry_db_save() - - return ret; -} - -// ---------------------------------------------------------------------------- -// SAVE THE REGISTRY DATABASE - -int registry_db_save(void) { - if(unlikely(!registry.enabled)) - return -1; - - if(unlikely(!registry_db_should_be_saved())) - return -2; - - error_log_limit_unlimited(); - - char tmp_filename[FILENAME_MAX + 1]; - char old_filename[FILENAME_MAX + 1]; - - snprintfz(old_filename, FILENAME_MAX, "%s.old", registry.db_filename); - snprintfz(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename); - - debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename); - FILE *fp = fopen(tmp_filename, "w"); - if(!fp) { - error("Registry: Cannot create file: %s", tmp_filename); - error_log_limit_reset(); - return -1; - } - - // dictionary_get_all() has its own locking, so this is safe to do - - debug(D_REGISTRY, "Saving all machines"); - int bytes1 = dictionary_get_all(registry.machines, registry_machine_save, fp); - if(bytes1 < 0) { - error("Registry: Cannot save registry machines - return value %d", bytes1); - fclose(fp); - error_log_limit_reset(); - return bytes1; - } - debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1); - - debug(D_REGISTRY, "Saving all persons"); - int bytes2 = dictionary_get_all(registry.persons, registry_person_save, fp); - if(bytes2 < 0) { - error("Registry: Cannot save registry persons - return value %d", bytes2); - fclose(fp); - error_log_limit_reset(); - return bytes2; - } - debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2); - - // save the totals - fprintf(fp, "T\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\n", - registry.persons_count, - registry.machines_count, - registry.usages_count + 1, // this is required - it is lost on db rotation - registry.urls_count, - registry.persons_urls_count, - registry.machines_urls_count - ); - - fclose(fp); - - errno = 0; - - // remove the .old db - debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename); - if(unlink(old_filename) == -1 && errno != ENOENT) - error("Registry: cannot remove old registry file '%s'", old_filename); - - // rename the db to .old - debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename); - if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT) - error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", registry.db_filename, old_filename); - - else { - // remove the database (it is saved in .old) - debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename); - if (unlink(registry.db_filename) == -1 && errno != ENOENT) - error("Registry: cannot remove old registry file '%s'", registry.db_filename); - - // move the .tmp to make it active - debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename); - if (link(tmp_filename, registry.db_filename) == -1) { - error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, - registry.db_filename); - - // move the .old back - debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename); - if(link(old_filename, registry.db_filename) == -1) - error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename); - } - else { - debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename); - if(unlink(tmp_filename) == -1) - error("Registry: cannot remove tmp registry file '%s'", tmp_filename); - - // it has been moved successfully - // discard the current registry log - registry_log_recreate(); - registry.log_count = 0; - } - } - - // continue operations - error_log_limit_reset(); - - return -1; -} - -// ---------------------------------------------------------------------------- -// LOAD THE REGISTRY DATABASE - -size_t registry_db_load(void) { - char *s, buf[4096 + 1]; - REGISTRY_PERSON *p = NULL; - REGISTRY_MACHINE *m = NULL; - REGISTRY_URL *u = NULL; - size_t line = 0; - - debug(D_REGISTRY, "Registry: loading active db from: '%s'", registry.db_filename); - FILE *fp = fopen(registry.db_filename, "r"); - if(!fp) { - error("Registry: cannot open registry file: '%s'", registry.db_filename); - return 0; - } - - size_t len = 0; - buf[4096] = '\0'; - while((s = fgets_trim_len(buf, 4096, fp, &len))) { - line++; - - debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s); - switch(*s) { - case 'T': // totals - if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) { - error("Registry totals line %zu is wrong (len = %zu).", line, len); - continue; - } - registry.persons_count = strtoull(&s[2], NULL, 16); - registry.machines_count = strtoull(&s[19], NULL, 16); - registry.usages_count = strtoull(&s[36], NULL, 16); - registry.urls_count = strtoull(&s[53], NULL, 16); - registry.persons_urls_count = strtoull(&s[70], NULL, 16); - registry.machines_urls_count = strtoull(&s[87], NULL, 16); - break; - - case 'P': // person - m = NULL; - // verify it is valid - if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) { - error("Registry person line %zu is wrong (len = %zu).", line, len); - continue; - } - - s[1] = s[10] = s[19] = s[28] = '\0'; - p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16)); - p->last_t = (uint32_t)strtoul(&s[11], NULL, 16); - p->usages = (uint32_t)strtoul(&s[20], NULL, 16); - debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages); - break; - - case 'M': // machine - p = NULL; - // verify it is valid - if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) { - error("Registry person line %zu is wrong (len = %zu).", line, len); - continue; - } - - s[1] = s[10] = s[19] = s[28] = '\0'; - m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16)); - m->last_t = (uint32_t)strtoul(&s[11], NULL, 16); - m->usages = (uint32_t)strtoul(&s[20], NULL, 16); - debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages); - break; - - case 'U': // person URL - if(unlikely(!p)) { - error("Registry: ignoring line %zu, no person loaded: %s", line, s); - continue; - } - - // verify it is valid - if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') { - error("Registry person URL line %zu is wrong (len = %zu).", line, len); - continue; - } - - s[1] = s[10] = s[19] = s[28] = s[31] = s[68] = '\0'; - - // skip the name to find the url - char *url = &s[69]; - while(*url && *url != '\t') url++; - if(!*url) { - error("Registry person URL line %zu does not have a url.", line); - continue; - } - *url++ = '\0'; - - // u = registry_url_allocate_nolock(url, strlen(url)); - u = registry_url_get(url, strlen(url)); - - time_t first_t = strtoul(&s[2], NULL, 16); - - m = registry_machine_find(&s[32]); - if(!m) m = registry_machine_allocate(&s[32], first_t); - - REGISTRY_PERSON_URL *pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t); - pu->last_t = (uint32_t)strtoul(&s[11], NULL, 16); - pu->usages = (uint32_t)strtoul(&s[20], NULL, 16); - pu->flags = (uint8_t)strtoul(&s[29], NULL, 16); - debug(D_REGISTRY, "Registry loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, pu->machine_name, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags); - break; - - case 'V': // machine URL - if(unlikely(!m)) { - error("Registry: ignoring line %zu, no machine loaded: %s", line, s); - continue; - } - - // verify it is valid - if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') { - error("Registry person URL line %zu is wrong (len = %zu).", line, len); - continue; - } - - s[1] = s[10] = s[19] = s[28] = s[31] = '\0'; - // u = registry_url_allocate_nolock(&s[32], strlen(&s[32])); - u = registry_url_get(&s[32], strlen(&s[32])); - - REGISTRY_MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16)); - mu->last_t = (uint32_t)strtoul(&s[11], NULL, 16); - mu->usages = (uint32_t)strtoul(&s[20], NULL, 16); - mu->flags = (uint8_t)strtoul(&s[29], NULL, 16); - debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags); - break; - - default: - error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s); - break; - } - } - fclose(fp); - - return line; -} diff --git a/src/registry_init.c b/src/registry_init.c deleted file mode 100644 index 654f66d12..000000000 --- a/src/registry_init.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "registry_internals.h" - -int registry_init(void) { - char filename[FILENAME_MAX + 1]; - - // registry enabled? - 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 - 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(CONFIG_SECTION_REGISTRY, "netdata unique id file", filename); - - snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname); - 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(CONFIG_SECTION_REGISTRY, "registry log file", filename); - - // configuration options - 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", netdata_configured_hostname); - 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(CONFIG_SECTION_REGISTRY, "max URL length", 1024); - if(registry.max_url_length < 10) { - registry.max_url_length = 10; - config_set_number(CONFIG_SECTION_REGISTRY, "max URL length", (long long)registry.max_url_length); - } - - 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(CONFIG_SECTION_REGISTRY, "max URL name length", (long long)registry.max_name_length); - } - - // initialize entries counters - registry.persons_count = 0; - registry.machines_count = 0; - registry.usages_count = 0; - registry.urls_count = 0; - registry.persons_urls_count = 0; - registry.machines_urls_count = 0; - - // initialize memory counters - registry.persons_memory = 0; - registry.machines_memory = 0; - registry.urls_memory = 0; - registry.persons_urls_memory = 0; - registry.machines_urls_memory = 0; - - // initialize locks - netdata_mutex_init(®istry.lock); - - // create dictionaries - registry.persons = dictionary_create(DICTIONARY_FLAGS); - registry.machines = dictionary_create(DICTIONARY_FLAGS); - avl_init(®istry.registry_urls_root_index, registry_url_compare); - - // load the registry database - if(registry.enabled) { - registry_log_open(); - registry_db_load(); - registry_log_load(); - - if(unlikely(registry_db_should_be_saved())) - registry_db_save(); - } - - return 0; -} - -void registry_free(void) { - if(!registry.enabled) return; - - // we need to destroy the dictionaries ourselves - // since the dictionaries use memory we allocated - - while(registry.persons->values_index.root) { - REGISTRY_PERSON *p = ((NAME_VALUE *)registry.persons->values_index.root)->value; - registry_person_del(p); - } - - while(registry.machines->values_index.root) { - REGISTRY_MACHINE *m = ((NAME_VALUE *)registry.machines->values_index.root)->value; - - // fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages); - - while(m->machine_urls->values_index.root) { - REGISTRY_MACHINE_URL *mu = ((NAME_VALUE *)m->machine_urls->values_index.root)->value; - - // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags); - - //debug(D_REGISTRY, "Registry: destroying persons dictionary from url '%s'", mu->url->url); - //dictionary_destroy(mu->persons); - - debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", mu->url->url, m->guid); - dictionary_del(m->machine_urls, mu->url->url); - - debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url); - registry_url_unlink(mu->url); - - debug(D_REGISTRY, "Registry: freeing machine url"); - freez(mu); - } - - debug(D_REGISTRY, "Registry: deleting machine '%s' from machines registry", m->guid); - dictionary_del(registry.machines, m->guid); - - debug(D_REGISTRY, "Registry: destroying URL dictionary of machine '%s'", m->guid); - dictionary_destroy(m->machine_urls); - - debug(D_REGISTRY, "Registry: freeing machine '%s'", m->guid); - freez(m); - } - - // and free the memory of remaining dictionary structures - - debug(D_REGISTRY, "Registry: destroying persons dictionary"); - dictionary_destroy(registry.persons); - - debug(D_REGISTRY, "Registry: destroying machines dictionary"); - dictionary_destroy(registry.machines); -} - diff --git a/src/registry_internals.c b/src/registry_internals.c deleted file mode 100644 index 44b0a1513..000000000 --- a/src/registry_internals.c +++ /dev/null @@ -1,322 +0,0 @@ -#include "registry_internals.h" - -struct registry registry; - -// ---------------------------------------------------------------------------- -// common functions - -// parse a GUID and re-generated to be always lower case -// this is used as a protection against the variations of GUIDs -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); - return -1; - } - else { - uuid_unparse_lower(uuid, result); - -#ifdef NETDATA_INTERNAL_CHECKS - if(strcmp(guid, result) != 0) - info("GUID '%s' and re-generated GUID '%s' differ!", guid, result); -#endif /* NETDATA_INTERNAL_CHECKS */ - } - - return 0; -} - -// make sure the names of the machines / URLs do not contain any tabs -// (which are used as our separator in the database files) -// and are properly trimmed (before and after) -static inline char *registry_fix_machine_name(char *name, size_t *len) { - char *s = name?name:""; - - // skip leading spaces - while(*s && isspace(*s)) s++; - - // make sure all spaces are a SPACE - char *t = s; - while(*t) { - if(unlikely(isspace(*t))) - *t = ' '; - - t++; - } - - // remove trailing spaces - while(--t >= s) { - if(*t == ' ') - *t = '\0'; - else - break; - } - t++; - - if(likely(len)) - *len = (t - s); - - return s; -} - -static inline char *registry_fix_url(char *url, size_t *len) { - size_t l = 0; - char *s = registry_fix_machine_name(url, &l); - - // protection from too big URLs - if(l > registry.max_url_length) { - l = registry.max_url_length; - s[l] = '\0'; - } - - if(len) *len = l; - return s; -} - - -// ---------------------------------------------------------------------------- -// HELPERS - -// verify the person, the machine and the URL exist in our DB -REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_guid, char *url, REGISTRY_PERSON **pp, REGISTRY_MACHINE **mm) { - char pbuf[GUID_LEN + 1], mbuf[GUID_LEN + 1]; - - if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) { - info("Registry Request Verification: invalid request! person: '%s', machine '%s', url '%s'", person_guid?person_guid:"UNSET", machine_guid?machine_guid:"UNSET", url?url:"UNSET"); - return NULL; - } - - // normalize the url - url = registry_fix_url(url, NULL); - - // make sure the person GUID is valid - 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(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; - } - machine_guid = mbuf; - - // make sure the machine exists - REGISTRY_MACHINE *m = registry_machine_find(machine_guid); - if(!m) { - info("Registry Request Verification: machine not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); - return NULL; - } - if(mm) *mm = m; - - // make sure the person exist - REGISTRY_PERSON *p = registry_person_find(person_guid); - if(!p) { - info("Registry Request Verification: person not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); - return NULL; - } - if(pp) *pp = p; - - REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, url); - if(!pu) { - info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); - return NULL; - } - return pu; -} - - -// ---------------------------------------------------------------------------- -// REGISTRY REQUESTS - -REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when) { - debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url); - - REGISTRY_MACHINE *m = registry_machine_get(machine_guid, when); - if(!m) return NULL; - - // make sure the name is valid - size_t namelen; - name = registry_fix_machine_name(name, &namelen); - - size_t urllen; - url = registry_fix_url(url, &urllen); - - REGISTRY_PERSON *p = registry_person_get(person_guid, when); - - REGISTRY_URL *u = registry_url_get(url, urllen); - registry_person_link_to_url(p, m, u, name, namelen, when); - registry_machine_link_to_url(m, u, when); - - registry_log('A', p, m, u, name); - - registry.usages_count++; - - return p; -} - -REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) { - (void) when; - - REGISTRY_PERSON *p = NULL; - REGISTRY_MACHINE *m = NULL; - REGISTRY_PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m); - if(!pu || !p || !m) return NULL; - - // normalize the url - delete_url = registry_fix_url(delete_url, NULL); - - // make sure the user is not deleting the url it uses - if(!strcmp(delete_url, pu->url->url)) { - info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'" - , p->guid, m->guid, pu->url->url, delete_url); - return NULL; - } - - REGISTRY_PERSON_URL *dpu = registry_person_url_index_find(p, delete_url); - if(!dpu) { - info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid - , m->guid, pu->url->url, delete_url); - return NULL; - } - - registry_log('D', p, m, pu->url, dpu->url->url); - registry_person_unlink_from_url(p, dpu); - - return p; -} - - -// a structure to pass to the dictionary_get_all() callback handler -struct machine_request_callback_data { - REGISTRY_MACHINE *find_this_machine; - REGISTRY_PERSON_URL *result; -}; - -// the callback function -// this will be run for every PERSON_URL of this PERSON -static int machine_request_callback(void *entry, void *data) { - REGISTRY_PERSON_URL *mypu = (REGISTRY_PERSON_URL *)entry; - struct machine_request_callback_data *myrdata = (struct machine_request_callback_data *)data; - - if(mypu->machine == myrdata->find_this_machine) { - myrdata->result = mypu; - return -1; // this will also stop the walk through - } - - return 0; // continue -} - -REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) { - (void)when; - - char mbuf[GUID_LEN + 1]; - - REGISTRY_PERSON *p = NULL; - REGISTRY_MACHINE *m = NULL; - REGISTRY_PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m); - if(!pu || !p || !m) return NULL; - - // make sure the machine GUID is valid - 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; - } - request_machine = mbuf; - - // make sure the machine exists - m = registry_machine_find(request_machine); - if(!m) { - info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, machine_guid, pu->url->url, request_machine); - return NULL; - } - - // Verify the user has in the past accessed this machine - // We will walk through the PERSON_URLs to find the machine - // linking to our machine - - // a structure to pass to the dictionary_get_all() callback handler - struct machine_request_callback_data rdata = { m, NULL }; - - // request a walk through on the dictionary - avl_traverse(&p->person_urls, machine_request_callback, &rdata); - - if(rdata.result) - return m; - - return NULL; -} - - -// ---------------------------------------------------------------------------- -// REGISTRY THIS MACHINE UNIQUE ID - -static inline int is_machine_guid_blacklisted(const char *guid) { - // these are machine GUIDs that have been included in distribution packages. - // we blacklist them here, so that the next version of netdata will generate - // new ones. - - if(!strcmp(guid, "8a795b0c-2311-11e6-8563-000c295076a6") - || !strcmp(guid, "4aed1458-1c3e-11e6-a53f-000c290fc8f5") - ) { - error("Blacklisted machine GUID '%s' found.", guid); - return 1; - } - - return 0; -} - -char *registry_get_this_machine_hostname(void) { - return registry.hostname; -} - -char *registry_get_this_machine_guid(void) { - 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); - if(fd != -1) { - char buf[GUID_LEN + 1]; - if(read(fd, buf, GUID_LEN) != GUID_LEN) - error("Failed to read machine GUID from '%s'", registry.machine_guid_filename); - else { - buf[GUID_LEN] = '\0'; - 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); - - guid[0] = '\0'; - } - else if(is_machine_guid_blacklisted(guid)) - guid[0] = '\0'; - } - close(fd); - } - - // generate a new one? - if(!guid[0]) { - uuid_t uuid; - - uuid_generate_time(uuid); - 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, 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", guid, 1); - - return guid; -} diff --git a/src/registry_internals.h b/src/registry_internals.h deleted file mode 100644 index cceaf292b..000000000 --- a/src/registry_internals.h +++ /dev/null @@ -1,86 +0,0 @@ -#include "common.h" - -#ifndef NETDATA_REGISTRY_INTERNALS_H_H -#define NETDATA_REGISTRY_INTERNALS_H_H - -#define REGISTRY_URL_FLAGS_DEFAULT 0x00 -#define REGISTRY_URL_FLAGS_EXPIRED 0x01 - -#define DICTIONARY_FLAGS (DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE | DICTIONARY_FLAG_NAME_LINK_DONT_CLONE | DICTIONARY_FLAG_SINGLE_THREADED) - -// ---------------------------------------------------------------------------- -// COMMON structures - -struct registry { - int enabled; - - // entries counters / statistics - unsigned long long persons_count; - unsigned long long machines_count; - unsigned long long usages_count; - unsigned long long urls_count; - unsigned long long persons_urls_count; - unsigned long long machines_urls_count; - unsigned long long log_count; - - // memory counters / statistics - unsigned long long persons_memory; - unsigned long long machines_memory; - unsigned long long urls_memory; - unsigned long long persons_urls_memory; - unsigned long long machines_urls_memory; - - // configuration - unsigned long long save_registry_every_entries; - char *registry_domain; - char *hostname; - char *registry_to_announce; - time_t persons_expiration; // seconds to expire idle persons - int verify_cookies_redirects; - - size_t max_url_length; - size_t max_name_length; - - // file/path names - char *pathname; - char *db_filename; - char *log_filename; - char *machine_guid_filename; - - // open files - FILE *log_fp; - - // the database - DICTIONARY *persons; // dictionary of REGISTRY_PERSON *, with key the REGISTRY_PERSON.guid - DICTIONARY *machines; // dictionary of REGISTRY_MACHINE *, with key the REGISTRY_MACHINE.guid - - avl_tree registry_urls_root_index; - - netdata_mutex_t lock; -}; - -#include "registry_url.h" -#include "registry_machine.h" -#include "registry_person.h" -#include "registry.h" - -extern struct registry registry; - -// 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); -extern REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when); - -// REGISTRY LOG (in registry_log.c) -extern void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name); -extern int registry_log_open(void); -extern void registry_log_close(void); -extern void registry_log_recreate(void); -extern ssize_t registry_log_load(void); - -// REGISTRY DB (in registry_db.c) -extern int registry_db_save(void); -extern size_t registry_db_load(void); -extern int registry_db_should_be_saved(void); - -#endif //NETDATA_REGISTRY_INTERNALS_H_H diff --git a/src/registry_log.c b/src/registry_log.c deleted file mode 100644 index cca43b09f..000000000 --- a/src/registry_log.c +++ /dev/null @@ -1,133 +0,0 @@ -#include "registry_internals.h" - -void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name) { - if(likely(registry.log_fp)) { - if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n", - action, - p->last_t, - p->guid, - m->guid, - name, - u->url) < 0)) - error("Registry: failed to save log. Registry data may be lost in case of abnormal restart."); - - // we increase the counter even on failures - // so that the registry will be saved periodically - registry.log_count++; - - // this must be outside the log_lock(), or a deadlock will happen. - // registry_db_save() checks the same inside the log_lock, so only - // one thread will save the db - if(unlikely(registry_db_should_be_saved())) - registry_db_save(); - } -} - -int registry_log_open(void) { - if(registry.log_fp) - fclose(registry.log_fp); - - registry.log_fp = fopen(registry.log_filename, "a"); - if(registry.log_fp) { - if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0) - error("Cannot set line buffering on registry log file."); - return 0; - } - - error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename); - return -1; -} - -void registry_log_close(void) { - if(registry.log_fp) { - fclose(registry.log_fp); - registry.log_fp = NULL; - } -} - -void registry_log_recreate(void) { - if(registry.log_fp != NULL) { - registry_log_close(); - - // open it with truncate - registry.log_fp = fopen(registry.log_filename, "w"); - if(registry.log_fp) fclose(registry.log_fp); - else error("Cannot truncate registry log '%s'", registry.log_filename); - - registry.log_fp = NULL; - registry_log_open(); - } -} - -ssize_t registry_log_load(void) { - ssize_t line = -1; - - // closing the log is required here - // otherwise we will append to it the values we read - registry_log_close(); - - debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename); - FILE *fp = fopen(registry.log_filename, "r"); - if(!fp) - error("Registry: cannot open registry file: %s", registry.log_filename); - else { - char *s, buf[4096 + 1]; - line = 0; - size_t len = 0; - - while ((s = fgets_trim_len(buf, 4096, fp, &len))) { - line++; - - switch (s[0]) { - case 'A': // accesses - case 'D': // deletes - - // verify it is valid - if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) { - error("Registry: log line %zd is wrong (len = %zu).", line, len); - continue; - } - s[1] = s[10] = s[47] = s[84] = '\0'; - - // get the variables - time_t when = strtoul(&s[2], NULL, 16); - char *person_guid = &s[11]; - char *machine_guid = &s[48]; - char *name = &s[85]; - - // skip the name to find the url - char *url = name; - while(*url && *url != '\t') url++; - if(!*url) { - error("Registry: log line %zd does not have a url.", line); - continue; - } - *url++ = '\0'; - - // make sure the person exists - // without this, a new person guid will be created - REGISTRY_PERSON *p = registry_person_find(person_guid); - if(!p) p = registry_person_allocate(person_guid, when); - - if(s[0] == 'A') - registry_request_access(p->guid, machine_guid, url, name, when); - else - registry_request_delete(p->guid, machine_guid, url, name, when); - - registry.log_count++; - break; - - default: - error("Registry: ignoring line %zd of filename '%s': %s.", line, registry.log_filename, s); - break; - } - } - - fclose(fp); - } - - // open the log again - registry_log_open(); - - return line; -} diff --git a/src/registry_machine.c b/src/registry_machine.c deleted file mode 100644 index 6dc8200d3..000000000 --- a/src/registry_machine.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "registry_internals.h" - -// ---------------------------------------------------------------------------- -// MACHINE - -REGISTRY_MACHINE *registry_machine_find(const char *machine_guid) { - debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid); - return dictionary_get(registry.machines, machine_guid); -} - -REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when) { - debug(D_REGISTRY, "registry_machine_url_allocate('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(REGISTRY_MACHINE_URL)); - - REGISTRY_MACHINE_URL *mu = mallocz(sizeof(REGISTRY_MACHINE_URL)); - - mu->first_t = mu->last_t = (uint32_t)when; - mu->usages = 1; - mu->url = u; - mu->flags = REGISTRY_URL_FLAGS_DEFAULT; - - registry.machines_urls_memory += sizeof(REGISTRY_MACHINE_URL); - - debug(D_REGISTRY, "registry_machine_url_allocate('%s', '%s'): indexing URL in machine", m->guid, u->url); - dictionary_set(m->machine_urls, u->url, mu, sizeof(REGISTRY_MACHINE_URL)); - - registry_url_link(u); - - return mu; -} - -REGISTRY_MACHINE *registry_machine_allocate(const char *machine_guid, time_t when) { - debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(REGISTRY_MACHINE)); - - REGISTRY_MACHINE *m = mallocz(sizeof(REGISTRY_MACHINE)); - - strncpyz(m->guid, machine_guid, GUID_LEN); - - debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid); - m->machine_urls = dictionary_create(DICTIONARY_FLAGS); - - m->first_t = m->last_t = (uint32_t)when; - m->usages = 0; - - registry.machines_memory += sizeof(REGISTRY_MACHINE); - - registry.machines_count++; - dictionary_set(registry.machines, m->guid, m, sizeof(REGISTRY_MACHINE)); - - return m; -} - -// 1. validate machine GUID -// 2. if it is valid, find it or create it and return it -// 3. if it is not valid, return NULL -REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when) { - REGISTRY_MACHINE *m = NULL; - - if(likely(machine_guid && *machine_guid)) { - // validate it is a GUID - char buf[GUID_LEN + 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; - m = registry_machine_find(machine_guid); - if(!m) m = registry_machine_allocate(machine_guid, when); - } - } - - return m; -} - - -// ---------------------------------------------------------------------------- -// LINKING OF OBJECTS - -REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when) { - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): searching for URL in machine", m->guid, u->url); - - REGISTRY_MACHINE_URL *mu = dictionary_get(m->machine_urls, u->url); - if(!mu) { - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): not found", m->guid, u->url); - mu = registry_machine_url_allocate(m, u, when); - registry.machines_urls_count++; - } - else { - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): found", m->guid, u->url); - mu->usages++; - if(likely(mu->last_t < (uint32_t)when)) mu->last_t = (uint32_t)when; - } - - m->usages++; - if(likely(m->last_t < (uint32_t)when)) m->last_t = (uint32_t)when; - - if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) { - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, u->url); - mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED; - } - - return mu; -} diff --git a/src/registry_machine.h b/src/registry_machine.h deleted file mode 100644 index be824d168..000000000 --- a/src/registry_machine.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef NETDATA_REGISTRY_MACHINE_H -#define NETDATA_REGISTRY_MACHINE_H - -#include "registry_internals.h" - -// ---------------------------------------------------------------------------- -// MACHINE structures - -// For each MACHINE-URL pair we keep this -struct registry_machine_url { - REGISTRY_URL *url; // de-duplicated URL - - uint8_t flags; - - uint32_t first_t; // the first time we saw this - uint32_t last_t; // the last time we saw this - uint32_t usages; // how many times this has been accessed -}; -typedef struct registry_machine_url REGISTRY_MACHINE_URL; - -// A machine -struct registry_machine { - char guid[GUID_LEN + 1]; // the GUID - - uint32_t links; // the number of REGISTRY_PERSON_URL linked to this machine - - DICTIONARY *machine_urls; // MACHINE_URL * - - uint32_t first_t; // the first time we saw this - uint32_t last_t; // the last time we saw this - uint32_t usages; // how many times this has been accessed -}; -typedef struct registry_machine REGISTRY_MACHINE; - -extern REGISTRY_MACHINE *registry_machine_find(const char *machine_guid); -extern REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when); -extern REGISTRY_MACHINE *registry_machine_allocate(const char *machine_guid, time_t when); -extern REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when); -extern REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when); - -#endif //NETDATA_REGISTRY_MACHINE_H diff --git a/src/registry_person.c b/src/registry_person.c deleted file mode 100644 index d8b6cd98a..000000000 --- a/src/registry_person.c +++ /dev/null @@ -1,264 +0,0 @@ -#include "registry_internals.h" - -// ---------------------------------------------------------------------------- -// PERSON_URL INDEX - -int person_url_compare(void *a, void *b) { - register uint32_t hash1 = ((REGISTRY_PERSON_URL *)a)->url->hash; - register uint32_t hash2 = ((REGISTRY_PERSON_URL *)b)->url->hash; - - if(hash1 < hash2) return -1; - else if(hash1 > hash2) return 1; - else return strcmp(((REGISTRY_PERSON_URL *)a)->url->url, ((REGISTRY_PERSON_URL *)b)->url->url); -} - -inline REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, const char *url) { - debug(D_REGISTRY, "Registry: registry_person_url_index_find('%s', '%s')", p->guid, url); - - char buf[sizeof(REGISTRY_URL) + strlen(url)]; - - REGISTRY_URL *u = (REGISTRY_URL *)&buf; - strcpy(u->url, url); - u->hash = simple_hash(u->url); - - REGISTRY_PERSON_URL tpu = { .url = u }; - - REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)avl_search(&p->person_urls, (void *)&tpu); - return pu; -} - -inline REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { - debug(D_REGISTRY, "Registry: registry_person_url_index_add('%s', '%s')", p->guid, pu->url->url); - REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_insert(&(p->person_urls), (avl *)(pu)); - if(tpu != pu) - error("Registry: registry_person_url_index_add('%s', '%s') already exists as '%s'", p->guid, pu->url->url, tpu->url->url); - - return tpu; -} - -inline REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { - debug(D_REGISTRY, "Registry: registry_person_url_index_del('%s', '%s')", p->guid, pu->url->url); - REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_remove(&(p->person_urls), (avl *)(pu)); - if(!tpu) - error("Registry: registry_person_url_index_del('%s', '%s') deleted nothing", p->guid, pu->url->url); - else if(tpu != pu) - error("Registry: registry_person_url_index_del('%s', '%s') deleted wrong URL '%s'", p->guid, pu->url->url, tpu->url->url); - - return tpu; -} - -// ---------------------------------------------------------------------------- -// PERSON_URL - -REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) { - debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen); - - // protection from too big names - if(namelen > registry.max_name_length) - namelen = registry.max_name_length; - - REGISTRY_PERSON_URL *pu = mallocz(sizeof(REGISTRY_PERSON_URL) + namelen); - - // a simple strcpy() should do the job - // but I prefer to be safe, since the caller specified urllen - strncpyz(pu->machine_name, name, namelen); - - pu->machine = m; - pu->first_t = pu->last_t = (uint32_t)when; - pu->usages = 1; - pu->url = u; - pu->flags = REGISTRY_URL_FLAGS_DEFAULT; - m->links++; - - registry.persons_urls_memory += sizeof(REGISTRY_PERSON_URL) + namelen; - - debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url); - REGISTRY_PERSON_URL *tpu = registry_person_url_index_add(p, pu); - if(tpu != pu) { - error("Registry: Attempted to add duplicate person url '%s' with name '%s' to person '%s'", u->url, name, p->guid); - free(pu); - pu = tpu; - } - else - registry_url_link(u); - - return pu; -} - -void registry_person_url_free(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { - debug(D_REGISTRY, "registry_person_url_free('%s', '%s')", p->guid, pu->url->url); - - REGISTRY_PERSON_URL *tpu = registry_person_url_index_del(p, pu); - if(tpu) { - registry_url_unlink(tpu->url); - tpu->machine->links--; - registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(tpu->machine_name); - freez(tpu); - } -} - -// this function is needed to change the name of a PERSON_URL -REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu) { - debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen); - - // keep a backup - REGISTRY_PERSON_URL pu2 = { - .first_t = pu->first_t, - .last_t = pu->last_t, - .usages = pu->usages, - .flags = pu->flags, - .machine = pu->machine, - .machine_name = "" - }; - - // remove the existing one from the index - registry_person_url_free(p, pu); - pu = &pu2; - - // allocate a new one - REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when); - tpu->first_t = pu->first_t; - tpu->last_t = pu->last_t; - tpu->usages = pu->usages; - tpu->flags = pu->flags; - - return tpu; -} - - -// ---------------------------------------------------------------------------- -// PERSON - -REGISTRY_PERSON *registry_person_find(const char *person_guid) { - debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid); - return dictionary_get(registry.persons, person_guid); -} - -REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) { - debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON)); - - REGISTRY_PERSON *p = mallocz(sizeof(REGISTRY_PERSON)); - if(!person_guid) { - for(;;) { - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse_lower(uuid, p->guid); - - debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid); - if (!dictionary_get(registry.persons, p->guid)) { - debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid); - break; - } - else - info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid); - } - } - else - strncpyz(p->guid, person_guid, GUID_LEN); - - debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid); - avl_init(&p->person_urls, person_url_compare); - - p->first_t = p->last_t = (uint32_t)when; - p->usages = 0; - - registry.persons_memory += sizeof(REGISTRY_PERSON); - - registry.persons_count++; - dictionary_set(registry.persons, p->guid, p, sizeof(REGISTRY_PERSON)); - - return p; -} - - -// 1. validate person GUID -// 2. if it is valid, find it -// 3. if it is not valid, create a new one -// 4. return it -REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) { - debug(D_REGISTRY, "Registry: registry_person_get('%s'): creating dictionary of urls", person_guid); - - REGISTRY_PERSON *p = NULL; - - if(person_guid && *person_guid) { - char buf[GUID_LEN + 1]; - // validate it is a GUID - 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; - p = registry_person_find(person_guid); - } - } - - if(!p) p = registry_person_allocate(NULL, when); - - return p; -} - -void registry_person_del(REGISTRY_PERSON *p) { - debug(D_REGISTRY, "Registry: registry_person_del('%s'): creating dictionary of urls", p->guid); - - while(p->person_urls.root) - registry_person_unlink_from_url(p, (REGISTRY_PERSON_URL *)p->person_urls.root); - - debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid); - dictionary_del(registry.persons, p->guid); - - debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid); - freez(p); -} - -// ---------------------------------------------------------------------------- -// LINKING OF OBJECTS - -REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url); - - REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u->url); - if(!pu) { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url); - pu = registry_person_url_allocate(p, m, u, name, namelen, when); - registry.persons_urls_count++; - } - else { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url); - pu->usages++; - if(likely(pu->last_t < (uint32_t)when)) pu->last_t = (uint32_t)when; - - if(pu->machine != m) { - REGISTRY_MACHINE_URL *mu = dictionary_get(pu->machine->machine_urls, u->url); - if(mu) { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.", - p->guid, m->guid, u->url, pu->machine->guid); - mu->flags |= REGISTRY_URL_FLAGS_EXPIRED; - } - else { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.", - p->guid, m->guid, u->url, pu->machine->guid); - } - - pu->machine->links--; - pu->machine = m; - } - - if(strcmp(pu->machine_name, name) != 0) { - // the name of the PERSON_URL has changed ! - pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu); - } - } - - p->usages++; - if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when; - - if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url); - pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED; - } - - return pu; -} - -void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { - registry_person_url_free(p, pu); -} diff --git a/src/registry_person.h b/src/registry_person.h deleted file mode 100644 index 5f6cc2443..000000000 --- a/src/registry_person.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef NETDATA_REGISTRY_PERSON_H -#define NETDATA_REGISTRY_PERSON_H - -#include "registry_internals.h" - -// ---------------------------------------------------------------------------- -// PERSON structures - -// for each PERSON-URL pair we keep this -struct registry_person_url { - avl avl; // binary tree node - - REGISTRY_URL *url; // de-duplicated URL - REGISTRY_MACHINE *machine; // link the MACHINE of this URL - - uint8_t flags; - - uint32_t first_t; // the first time we saw this - uint32_t last_t; // the last time we saw this - uint32_t usages; // how many times this has been accessed - - char machine_name[1]; // the name of the machine, as known by the user - // dynamically allocated to fit properly -}; -typedef struct registry_person_url REGISTRY_PERSON_URL; - -// A person -struct registry_person { - char guid[GUID_LEN + 1]; // the person GUID - - avl_tree person_urls; // dictionary of PERSON_URLs - - uint32_t first_t; // the first time we saw this - uint32_t last_t; // the last time we saw this - uint32_t usages; // how many times this has been accessed - - //uint32_t flags; - //char *email; -}; -typedef struct registry_person REGISTRY_PERSON; - -// PERSON_URL -extern REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, const char *url); -extern REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) NEVERNULL WARNUNUSED; -extern REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) WARNUNUSED; - -extern REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when); -extern REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu); - -// PERSON -extern REGISTRY_PERSON *registry_person_find(const char *person_guid); -extern REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when); -extern REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when); -extern void registry_person_del(REGISTRY_PERSON *p); - -// LINKING PERSON -> PERSON_URL -extern REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when); -extern void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu); - -#endif //NETDATA_REGISTRY_PERSON_H diff --git a/src/registry_url.c b/src/registry_url.c deleted file mode 100644 index 52d36a898..000000000 --- a/src/registry_url.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "registry_internals.h" - -// ---------------------------------------------------------------------------- -// REGISTRY_URL - -int registry_url_compare(void *a, void *b) { - if(((REGISTRY_URL *)a)->hash < ((REGISTRY_URL *)b)->hash) return -1; - else if(((REGISTRY_URL *)a)->hash > ((REGISTRY_URL *)b)->hash) return 1; - else return strcmp(((REGISTRY_URL *)a)->url, ((REGISTRY_URL *)b)->url); -} - -inline REGISTRY_URL *registry_url_index_add(REGISTRY_URL *u) { - return (REGISTRY_URL *)avl_insert(&(registry.registry_urls_root_index), (avl *)(u)); -} - -inline REGISTRY_URL *registry_url_index_del(REGISTRY_URL *u) { - return (REGISTRY_URL *)avl_remove(&(registry.registry_urls_root_index), (avl *)(u)); -} - -REGISTRY_URL *registry_url_get(const char *url, size_t urllen) { - // protection from too big URLs - if(urllen > registry.max_url_length) - urllen = registry.max_url_length; - - debug(D_REGISTRY, "Registry: registry_url_get('%s', %zu)", url, urllen); - - char buf[sizeof(REGISTRY_URL) + urllen]; // no need for +1, 1 is already in REGISTRY_URL - REGISTRY_URL *n = (REGISTRY_URL *)&buf[0]; - n->len = (uint16_t)urllen; - strncpyz(n->url, url, n->len); - n->hash = simple_hash(n->url); - - REGISTRY_URL *u = (REGISTRY_URL *)avl_search(&(registry.registry_urls_root_index), (avl *)n); - if(!u) { - debug(D_REGISTRY, "Registry: registry_url_get('%s', %zu): allocating %zu bytes", url, urllen, sizeof(REGISTRY_URL) + urllen); - u = callocz(1, sizeof(REGISTRY_URL) + urllen); // no need for +1, 1 is already in REGISTRY_URL - - // a simple strcpy() should do the job - // but I prefer to be safe, since the caller specified urllen - u->len = (uint16_t)urllen; - strncpyz(u->url, url, u->len); - u->links = 0; - u->hash = simple_hash(u->url); - - registry.urls_memory += sizeof(REGISTRY_URL) + urllen; // no need for +1, 1 is already in REGISTRY_URL - - debug(D_REGISTRY, "Registry: registry_url_get('%s'): indexing it", url); - n = registry_url_index_add(u); - if(n != u) { - error("INTERNAL ERROR: registry_url_get(): url '%s' already exists in the registry as '%s'", u->url, n->url); - free(u); - u = n; - } - else - registry.urls_count++; - } - - return u; -} - -void registry_url_link(REGISTRY_URL *u) { - u->links++; - debug(D_REGISTRY, "Registry: registry_url_link('%s'): URL has now %u links", u->url, u->links); -} - -void registry_url_unlink(REGISTRY_URL *u) { - u->links--; - if(!u->links) { - debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): No more links for this URL", u->url); - REGISTRY_URL *n = registry_url_index_del(u); - if(!n) { - error("INTERNAL ERROR: registry_url_unlink('%s'): cannot find url in index", u->url); - } - else { - if(n != u) { - error("INTERNAL ERROR: registry_url_unlink('%s'): deleted different url '%s'", u->url, n->url); - } - - registry.urls_memory -= sizeof(REGISTRY_URL) + n->len; // no need for +1, 1 is already in REGISTRY_URL - freez(n); - } - } - else - debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): URL has %u links left", u->url, u->links); -} diff --git a/src/registry_url.h b/src/registry_url.h deleted file mode 100644 index 5ac52f5a5..000000000 --- a/src/registry_url.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef NETDATA_REGISTRY_URL_H -#define NETDATA_REGISTRY_URL_H - -#include "registry_internals.h" - -// ---------------------------------------------------------------------------- -// URL structures -// Save memory by de-duplicating URLs -// so instead of storing URLs all over the place -// we store them here and we keep pointers elsewhere - -struct registry_url { - avl avl; - uint32_t hash; // the index hash - - uint32_t links; // the number of links to this URL - when none is left, we free it - - uint16_t len; // the length of the URL in bytes - char url[1]; // the URL - dynamically allocated to more size -}; -typedef struct registry_url REGISTRY_URL; - -// REGISTRY_URL INDEX -extern int registry_url_compare(void *a, void *b); -extern REGISTRY_URL *registry_url_index_del(REGISTRY_URL *u) WARNUNUSED; -extern REGISTRY_URL *registry_url_index_add(REGISTRY_URL *u) NEVERNULL WARNUNUSED; - -// REGISTRY_URL MANAGEMENT -extern REGISTRY_URL *registry_url_get(const char *url, size_t urllen) NEVERNULL; -extern void registry_url_link(REGISTRY_URL *u); -extern void registry_url_unlink(REGISTRY_URL *u); - -#endif //NETDATA_REGISTRY_URL_H diff --git a/src/rrd.c b/src/rrd.c deleted file mode 100644 index 3be2d8e41..000000000 --- a/src/rrd.c +++ /dev/null @@ -1,148 +0,0 @@ -#define NETDATA_RRD_INTERNALS 1 -#include "common.h" - -// ---------------------------------------------------------------------------- -// globals - -/* -// if not zero it gives the time (in seconds) to remove un-updated dimensions -// DO NOT ENABLE -// if dimensions are removed, the chart generation will have to run again -int rrd_delete_unupdated_dimensions = 0; -*/ - -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; -int gap_when_lost_iterations_above = 1; - - -// ---------------------------------------------------------------------------- -// RRD - memory modes - -inline const char *rrd_memory_mode_name(RRD_MEMORY_MODE id) { - switch(id) { - case RRD_MEMORY_MODE_RAM: - return RRD_MEMORY_MODE_RAM_NAME; - - case RRD_MEMORY_MODE_MAP: - return RRD_MEMORY_MODE_MAP_NAME; - - case RRD_MEMORY_MODE_NONE: - return RRD_MEMORY_MODE_NONE_NAME; - - case RRD_MEMORY_MODE_SAVE: - return RRD_MEMORY_MODE_SAVE_NAME; - - case RRD_MEMORY_MODE_ALLOC: - return RRD_MEMORY_MODE_ALLOC_NAME; - } - - return RRD_MEMORY_MODE_SAVE_NAME; -} - -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; - - else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_ALLOC_NAME))) - return RRD_MEMORY_MODE_ALLOC; - - return RRD_MEMORY_MODE_SAVE; -} - - -// ---------------------------------------------------------------------------- -// RRD - algorithms types - -RRD_ALGORITHM rrd_algorithm_id(const char *name) { - if(strcmp(name, RRD_ALGORITHM_INCREMENTAL_NAME) == 0) - return RRD_ALGORITHM_INCREMENTAL; - - else if(strcmp(name, RRD_ALGORITHM_ABSOLUTE_NAME) == 0) - return RRD_ALGORITHM_ABSOLUTE; - - else if(strcmp(name, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME) == 0) - return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL; - - else if(strcmp(name, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME) == 0) - return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL; - - else - return RRD_ALGORITHM_ABSOLUTE; -} - -const char *rrd_algorithm_name(RRD_ALGORITHM algorithm) { - switch(algorithm) { - case RRD_ALGORITHM_ABSOLUTE: - default: - return RRD_ALGORITHM_ABSOLUTE_NAME; - - case RRD_ALGORITHM_INCREMENTAL: - return RRD_ALGORITHM_INCREMENTAL_NAME; - - case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL: - return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME; - - case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL: - return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME; - } -} - - -// ---------------------------------------------------------------------------- -// RRD - chart types - -inline RRDSET_TYPE 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; -} - -const char *rrdset_type_name(RRDSET_TYPE chart_type) { - switch(chart_type) { - case RRDSET_TYPE_LINE: - default: - return RRDSET_TYPE_LINE_NAME; - - case RRDSET_TYPE_AREA: - return RRDSET_TYPE_AREA_NAME; - - case RRDSET_TYPE_STACKED: - return RRDSET_TYPE_STACKED_NAME; - } -} - - -// ---------------------------------------------------------------------------- -// RRD - cache directory - -char *rrdset_cache_dir(RRDHOST *host, const char *id, const char *config_section) { - char *ret = NULL; - - char b[FILENAME_MAX + 1]; - char n[FILENAME_MAX + 1]; - rrdset_strncpyz_name(b, id, FILENAME_MAX); - - snprintfz(n, FILENAME_MAX, "%s/%s", host->cache_dir, b); - ret = config_get(config_section, "cache directory", n); - - 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); - } - - return ret; -} diff --git a/src/rrd.h b/src/rrd.h deleted file mode 100644 index d17daacd2..000000000 --- a/src/rrd.h +++ /dev/null @@ -1,747 +0,0 @@ -#ifndef NETDATA_RRD_H -#define NETDATA_RRD_H 1 - -#define UPDATE_EVERY 1 -#define UPDATE_EVERY_MAX 3600 - -#define RRD_DEFAULT_HISTORY_ENTRIES 3600 -#define RRD_HISTORY_ENTRIES_MAX (86400*365) - -extern int default_rrd_update_every; -extern int default_rrd_history_entries; -extern int gap_when_lost_iterations_above; - -#define RRD_ID_LENGTH_MAX 200 - -#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" - -typedef struct rrdhost RRDHOST; - -// ---------------------------------------------------------------------------- -// 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" - -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_ALLOC = 4 -} 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_ALLOC_NAME "alloc" - -extern RRD_MEMORY_MODE default_rrd_memory_mode; - -extern const char *rrd_memory_mode_name(RRD_MEMORY_MODE id); -extern RRD_MEMORY_MODE rrd_memory_mode_id(const char *name); - - -// ---------------------------------------------------------------------------- -// algorithms types - -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 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" - -extern RRD_ALGORITHM rrd_algorithm_id(const char *name); -extern const char *rrd_algorithm_name(RRD_ALGORITHM algorithm); - -// ---------------------------------------------------------------------------- -// RRD FAMILY - -struct rrdfamily { - avl avl; - - const char *family; - uint32_t hash_family; - - size_t use_count; - - avl_tree_lock rrdvar_root_index; -}; -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_NONE = 0, - 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; - -#ifdef HAVE_C___ATOMIC -#define rrddim_flag_check(rd, flag) (__atomic_load_n(&((rd)->flags), __ATOMIC_SEQ_CST) & (flag)) -#define rrddim_flag_set(rd, flag) __atomic_or_fetch(&((rd)->flags), (flag), __ATOMIC_SEQ_CST) -#define rrddim_flag_clear(rd, flag) __atomic_and_fetch(&((rd)->flags), ~(flag), __ATOMIC_SEQ_CST) -#else -#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) -#endif - - -// ---------------------------------------------------------------------------- -// RRD DIMENSION - this is a metric - -struct rrddim { - // ------------------------------------------------------------------------ - // binary indexing structures - - avl avl; // the binary index - this has to be first member! - - // ------------------------------------------------------------------------ - // the dimension definition - - 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 - - collected_number multiplier; // the multiplier of the collected values - collected_number divisor; // the divider of the collected values - - uint32_t flags; // configuration flags for the dimension - - // ------------------------------------------------------------------------ - // members for temporary data we need for calculations - - uint32_t hash; // a simple hash of the id, to speed up searching / indexing - // instead of strcmp() every item in the binary index - // we first compare the hashes - - uint32_t hash_name; // a simple hash of the name - - char *cache_filename; // 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]; - - 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 - // THIS IS DIFFERENT FROM THE SAME MEMBER OF RRDSET - - calculated_number calculated_value; // the current calculated value, after applying the algorithm - resets to zero after being used - calculated_number last_calculated_value; // the last calculated value processed - - calculated_number last_stored_value; // the last value as stored in the database (after interpolation) - - collected_number collected_value; // the current value, as collected - resets to 0 after being used - collected_number last_collected_value; // the last value that was collected, after being processed - - // the *_volume members are used to calculate the accuracy of the rounding done by the - // storage number - they are printed to debug.log when debug is enabled for a set. - calculated_number collected_volume; // the sum of all collected values so far - calculated_number stored_volume; // the sum of all stored values so far - - struct rrddim *next; // linking of dimensions within the same data set - struct rrdset *rrdset; - - // ------------------------------------------------------------------------ - // members for checking the data when loading from disk - - long entries; // how many entries this dimension has in ram - // this is the same to the entries of the data set - // we set it here, to check the data when we load it from disk. - - int update_every; // every how many seconds is this updated - - 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 - - struct rrddimvar *variables; - - // ------------------------------------------------------------------------ - // the values stored in this dimension, using our floating point numbers - - storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER -}; -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 - 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_FLAG_BACKEND_SEND = 1 << 4, // if set, this chart should be sent to backends - RRDSET_FLAG_BACKEND_IGNORE = 1 << 5, // if set, this chart should not be sent to backends - RRDSET_FLAG_EXPOSED_UPSTREAM = 1 << 6, // if set, we have sent this chart to netdata master (streaming) - RRDSET_FLAG_STORE_FIRST = 1 << 7, // if set, do not eliminate the first collection during interpolation - RRDSET_FLAG_HETEROGENEOUS = 1 << 8, // if set, the chart is not homogeneous (dimensions in it have multiple algorithms, multipliers or dividers) - RRDSET_FLAG_HOMEGENEOUS_CHECK= 1 << 9, // if set, the chart should be checked to determine if the dimensions as homogeneous - RRDSET_FLAG_HIDDEN = 1 << 10, // if set, do not show this chart on the dashboard, but use it for backends -} RRDSET_FLAGS; - -#ifdef HAVE_C___ATOMIC -#define rrdset_flag_check(st, flag) (__atomic_load_n(&((st)->flags), __ATOMIC_SEQ_CST) & (flag)) -#define rrdset_flag_set(st, flag) __atomic_or_fetch(&((st)->flags), flag, __ATOMIC_SEQ_CST) -#define rrdset_flag_clear(st, flag) __atomic_and_fetch(&((st)->flags), ~flag, __ATOMIC_SEQ_CST) -#else -#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) -#endif - -struct rrdset { - // ------------------------------------------------------------------------ - // binary indexing structures - - avl avl; // the index, with key the id - this has to be first! - avl avlname; // the index, with key the name - - // ------------------------------------------------------------------------ - // the set configuration - - char id[RRD_ID_LENGTH_MAX + 1]; // id of the data set - - 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) - - 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 - char *units; // units of measurement - - char *context; // the template of this data set - uint32_t hash_context; // the hash of the chart's context - - RRDSET_TYPE chart_type; // line, area, stacked - - int update_every; // every how many seconds is this updated? - - long entries; // total number of entries in the data set - - long current_entry; // the entry that is currently being updated - // it goes around in a round-robin fashion - - 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; // the sorting priority of this chart - - - // ------------------------------------------------------------------------ - // members for temporary data we need for calculations - - 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 - - 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 - - time_t last_accessed_time; // the last time this RRDSET has been accessed - time_t upstream_resync_time; // the timestamp up to which we should resync clock upstream - - char *plugin_name; // the name of the plugin that generated this - char *module_name; // the name of the plugin module that generated this - - size_t unused[6]; - - 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 - - uint32_t hash_name; // a simple hash on the name - - usec_t usec_since_last_update; // the time in microseconds since the last collection of data - - struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function) - struct timeval last_collected_time; // when did this data set last collected values - - total_number collected_total; // used internally to calculate percentages - total_number last_collected_total; // used internally to calculate percentages - - RRDFAMILY *rrdfamily; // pointer to RRDFAMILY this chart belongs to - RRDHOST *rrdhost; // pointer to RRDHOST this chart belongs to - - struct rrdset *next; // linking of rrdsets - - // ------------------------------------------------------------------------ - // local variables - - calculated_number green; // green threshold for this chart - calculated_number red; // red threshold for this chart - - avl_tree_lock rrdvar_root_index; // RRDVAR index for this chart - RRDSETVAR *variables; // RRDSETVAR linked list for this chart (one RRDSETVAR, many RRDVARs) - RRDCALC *alarms; // RRDCALC linked list for this chart - - // ------------------------------------------------------------------------ - // members for checking the data when loading from disk - - unsigned long memsize; // how much mem we have allocated for this (without dimensions) - - char magic[sizeof(RRDSET_MAGIC) + 1]; // our magic - - // ------------------------------------------------------------------------ - // the dimensions - - avl_tree_lock dimensions_index; // the root of the dimensions index - RRDDIM *dimensions; // the actual data for every dimension - -}; -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_FLAG_ORPHAN = 1 << 0, // this host is orphan (not receiving data) - RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS = 1 << 1, // delete files of obsolete charts - RRDHOST_FLAG_DELETE_ORPHAN_HOST = 1 << 2, // delete the entire host when orphan - RRDHOST_FLAG_BACKEND_SEND = 1 << 3, // send it to backends - RRDHOST_FLAG_BACKEND_DONT_SEND = 1 << 4, // don't send it to backends -} RRDHOST_FLAGS; - -#ifdef HAVE_C___ATOMIC -#define rrdhost_flag_check(host, flag) (__atomic_load_n(&((host)->flags), __ATOMIC_SEQ_CST) & (flag)) -#define rrdhost_flag_set(host, flag) __atomic_or_fetch(&((host)->flags), flag, __ATOMIC_SEQ_CST) -#define rrdhost_flag_clear(host, flag) __atomic_and_fetch(&((host)->flags), ~flag, __ATOMIC_SEQ_CST) -#else -#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) -#endif - -#ifdef NETDATA_INTERNAL_CHECKS -#define rrdset_debug(st, fmt, args...) do { if(unlikely(debug_flags & D_RRD_STATS && rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) \ - debug_int(__FILE__, __FUNCTION__, __LINE__, "%s: " fmt, st->name, ##args); } while(0) -#else -#define rrdset_debug(st, fmt, args...) debug_dummy() -#endif - - -// ---------------------------------------------------------------------------- -// RRD HOST - -struct rrdhost { - avl avl; // the index of hosts - - // ------------------------------------------------------------------------ - // host information - - char *hostname; // the hostname of this host - uint32_t hash_hostname; // the hostname hash - - char *registry_hostname; // the registry hostname for this host - - char machine_guid[GUID_LEN + 1]; // the unique ID of this host - uint32_t hash_machine_guid; // the hash of the unique ID - - const char *os; // the O/S type of the host - const char *tags; // tags for this host - const char *timezone; // the timezone 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 - - char *program_name; // the program name that collects metrics for this host - char *program_version; // the program version that collects metrics for this host - - // ------------------------------------------------------------------------ - // streaming of data to remote hosts - rrdpush - - int rrdpush_send_enabled:1; // 1 when this host sends metrics to another netdata - char *rrdpush_send_destination; // where to send metrics to - char *rrdpush_send_api_key; // the api key at the receiving netdata - - // the following are state information for the threading - // streaming metrics from this netdata to an upstream netdata - volatile int rrdpush_sender_spawn:1; // 1 when the sender thread has been spawn - netdata_thread_t rrdpush_sender_thread; // the sender thread - - volatile int rrdpush_sender_connected:1; // 1 when the sender is ready to push metrics - int rrdpush_sender_socket; // the fd of the socket to the remote host, or -1 - - volatile int rrdpush_sender_error_shown:1; // 1 when we have logged a communication error - volatile int rrdpush_sender_join:1; // 1 when we have to join the sending thread - - // metrics may be collected asynchronously - // these synchronize all the threads willing the write to our sending buffer - netdata_mutex_t rrdpush_sender_buffer_mutex; // exclusive access to rrdpush_sender_buffer - int rrdpush_sender_pipe[2]; // collector to sender thread signaling - BUFFER *rrdpush_sender_buffer; // collector fills it, sender sends it - - - // ------------------------------------------------------------------------ - // 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; // alarms historical events (event log) - uint32_t health_last_processed_id; // the last processed health id from the log - uint32_t health_max_unique_id; // the max alarm log unique id given for the host - uint32_t health_max_alarm_id; // the max alarm id given for the host - - // templates of alarms - // these are used to create alarms when charts - // 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) - - // ------------------------------------------------------------------------ - // indexes - - 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 rrdvar_root_index; // the host's chart variables index - - struct rrdhost *next; -}; -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 *registry_hostname - , const char *guid - , const char *os - , const char *timezone - , const char *tags - , const char *program_name - , const char *program_version - , 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__) - -#else -#define rrdhost_check_rdlock(host) (void)0 -#define rrdhost_check_wrlock(host) (void)0 -#define rrdset_check_rdlock(st) (void)0 -#define rrdset_check_wrlock(st) (void)0 -#define rrd_check_rdlock() (void)0 -#define rrd_check_wrlock() (void)0 -#endif - -// ---------------------------------------------------------------------------- -// RRDSET functions - -extern int rrdset_set_name(RRDSET *st, const char *name); - -extern RRDSET *rrdset_create_custom(RRDHOST *host - , const char *type - , const char *id - , const char *name - , const char *family - , const char *context - , const char *title - , const char *units - , const char *plugin - , const char *module - , long priority - , int update_every - , RRDSET_TYPE chart_type - , RRD_MEMORY_MODE memory_mode - , long history_entries); - -#define rrdset_create(host, type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type) \ - rrdset_create_custom(host, type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type, (host)->rrd_memory_mode, (host)->rrd_history_entries) - -#define rrdset_create_localhost(type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type) \ - rrdset_create(localhost, type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type) - -extern void rrdhost_free_all(void); -extern void rrdhost_save_all(void); -extern void rrdhost_cleanup_all(void); - -extern void rrdhost_cleanup_orphan_hosts_nolock(RRDHOST *protected); -extern void rrdhost_free(RRDHOST *host); -extern void rrdhost_save_charts(RRDHOST *host); -extern void rrdhost_delete_charts(RRDHOST *host); - -extern int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected, time_t now); - -extern void rrdset_update_heterogeneous_flag(RRDSET *st); - -extern RRDSET *rrdset_find(RRDHOST *host, const char *id); -#define rrdset_find_localhost(id) rrdset_find(localhost, id) - -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_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 void rrdset_done(RRDSET *st); - -extern void rrdset_is_obsolete(RRDSET *st); -extern void rrdset_isnot_obsolete(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_HIDDEN) && !rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE) && (st)->dimensions && (st)->rrd_memory_mode != RRD_MEMORY_MODE_NONE) -#define rrdset_is_available_for_backends(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 )) - -// get the timestamp of the last entry in the round robin database -#define rrdset_last_entry_t(st) ((time_t)(((st)->last_updated.tv_sec))) - -// get the timestamp of first entry in the round robin database -#define rrdset_first_entry_t(st) ((time_t)(rrdset_last_entry_t(st) - rrdset_duration(st))) - -// get the last slot updated in the round robin database -#define rrdset_last_slot(st) ((unsigned long)(((st)->current_entry == 0) ? (st)->entries - 1 : (st)->current_entry - 1)) - -// get the first / oldest slot updated in the round robin database -#define rrdset_first_slot(st) ((unsigned long)( (((st)->counter >= ((unsigned long)(st)->entries)) ? (unsigned long)( ((unsigned long)(st)->current_entry > 0) ? ((unsigned long)(st)->current_entry) : ((unsigned long)(st)->entries) ) - 1 : 0) )) - -// get the slot of the round robin database, for the given timestamp (t) -// it always returns a valid slot, although may not be for the time requested if the time is outside the round robin database -#define rrdset_time2slot(st, t) ( \ - ( (time_t)(t) >= rrdset_last_entry_t(st)) ? ( rrdset_last_slot(st) ) : \ - ( ((time_t)(t) <= rrdset_first_entry_t(st)) ? rrdset_first_slot(st) : \ - ( (rrdset_last_slot(st) >= (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) ? \ - (rrdset_last_slot(st) - (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) : \ - (rrdset_last_slot(st) - (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) + (unsigned long)(st)->entries ) \ - ))) - -// get the timestamp of a specific slot in the round robin database -#define rrdset_slot2time(st, slot) ( rrdset_last_entry_t(st) - \ - ((unsigned long)(st)->update_every * ( \ - ( (unsigned long)(slot) > rrdset_last_slot(st)) ? \ - ( (rrdset_last_slot(st) - (unsigned long)(slot) + (unsigned long)(st)->entries) ) : \ - ( (rrdset_last_slot(st) - (unsigned long)(slot)) )) \ - )) - -// ---------------------------------------------------------------------------- -// RRD DIMENSION functions - -extern RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm, RRD_MEMORY_MODE memory_mode); -#define rrddim_add(st, id, name, multiplier, divisor, algorithm) rrddim_add_custom(st, id, name, multiplier, divisor, algorithm, (st)->rrd_memory_mode) - -extern int rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name); -extern int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm); -extern int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, collected_number multiplier); -extern int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor); - -extern RRDDIM *rrddim_find(RRDSET *st, const char *id); - -extern int rrddim_hide(RRDSET *st, const char *id); -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_charts(RRDHOST *host); - -#endif /* NETDATA_RRD_INTERNALS */ - - -#endif /* NETDATA_RRD_H */ diff --git a/src/rrd2json.c b/src/rrd2json.c deleted file mode 100644 index 24b3da340..000000000 --- a/src/rrd2json.c +++ /dev/null @@ -1,2059 +0,0 @@ -#include "common.h" - -void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used) -{ - rrdset_rdlock(st); - - 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 (%s)\",\n" - "\t\t\t\"priority\": %ld,\n" - "\t\t\t\"plugin\": \"%s\",\n" - "\t\t\t\"module\": \"%s\",\n" - "\t\t\t\"enabled\": %s,\n" - "\t\t\t\"units\": \"%s\",\n" - "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n" - "\t\t\t\"chart_type\": \"%s\",\n" - "\t\t\t\"duration\": %ld,\n" - "\t\t\t\"first_entry\": %ld,\n" - "\t\t\t\"last_entry\": %ld,\n" - "\t\t\t\"update_every\": %d,\n" - "\t\t\t\"dimensions\": {\n" - , st->id - , st->name - , st->type - , st->family - , st->context - , st->title, st->name - , st->priority - , st->plugin_name?st->plugin_name:"" - , st->module_name?st->module_name:"" - , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?"true":"false" - , st->units - , st->name - , rrdset_type_name(st->chart_type) - , st->entries * st->update_every - , rrdset_first_entry_t(st) - , rrdset_last_entry_t(st) - , st->update_every - ); - - unsigned long memory = st->memsize; - - size_t dimensions = 0; - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) continue; - - memory += rd->memsize; - - buffer_sprintf( - wb - , "%s" - "\t\t\t\t\"%s\": { \"name\": \"%s\" }" - , dimensions ? ",\n" : "" - , rd->id - , rd->name - ); - - dimensions++; - } - - if(dimensions_count) *dimensions_count += dimensions; - if(memory_used) *memory_used += memory; - - buffer_strcat(wb, "\n\t\t\t},\n\t\t\t\"green\": "); - buffer_rrd_value(wb, st->green); - buffer_strcat(wb, ",\n\t\t\t\"red\": "); - buffer_rrd_value(wb, st->red); - - buffer_strcat(wb, ",\n\t\t\t\"alarms\": {\n"); - size_t alarms = 0; - RRDCALC *rc; - for(rc = st->alarms; rc ; rc = rc->rrdset_next) { - - buffer_sprintf( - wb - , "%s" - "\t\t\t\t\"%s\": {\n" - "\t\t\t\t\t\"id\": %u,\n" - "\t\t\t\t\t\"status\": \"%s\",\n" - "\t\t\t\t\t\"units\": \"%s\",\n" - "\t\t\t\t\t\"update_every\": %d\n" - "\t\t\t\t}" - , (alarms) ? ",\n" : "" - , rc->name - , rc->id - , rrdcalc_status2string(rc->status) - , rc->units - , rc->update_every - ); - - alarms++; - } - - buffer_sprintf(wb, - "\n\t\t\t}\n\t\t}" - ); - - 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(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\"timezone\": \"%s\"" - ",\n\t\"update_every\": %d" - ",\n\t\"history\": %ld" - ",\n\t\"custom_info\": \"%s\"" - ",\n\t\"charts\": {" - , host->hostname - , host->program_version - , host->os - , host->timezone - , host->rrd_update_every - , host->rrd_history_entries - , custom_dashboard_info_js_filename - ); - - 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 = host->alarms; rc ; rc = rc->next) { - if(rc->rrdset) - alarms++; - } - 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\t\"hosts_count\": %zu" - ",\n\t\"hosts\": [" - , c - , dimensions - , alarms - , memory - , rrd_hosts_available - ); - - if(unlikely(rrd_hosts_available > 1)) { - rrd_rdlock(); - - size_t found = 0; - RRDHOST *h; - rrdhost_foreach_read(h) { - if(!rrdhost_should_be_removed(h, host, now)) { - buffer_sprintf(wb - , "%s\n\t\t{" - "\n\t\t\t\"hostname\": \"%s\"" - "\n\t\t}" - , (found > 0) ? "," : "" - , h->hostname - ); - - found++; - } - } - - 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"); -} - -// ---------------------------------------------------------------------------- -// BASH -// /api/v1/allmetrics?format=bash - -static inline size_t shell_name_copy(char *d, const char *s, size_t usable) { - size_t n; - - for(n = 0; *s && n < usable ; d++, s++, n++) { - register char c = *s; - - if(unlikely(!isalnum(c))) *d = '_'; - else *d = (char)toupper(c); - } - *d = '\0'; - - return n; -} - -#define SHELL_ELEMENT_MAX 100 - -void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) { - rrdhost_rdlock(host); - - // for each chart - RRDSET *st; - rrdset_foreach_read(st, host) { - calculated_number total = 0.0; - char chart[SHELL_ELEMENT_MAX + 1]; - shell_name_copy(chart, st->name?st->name:st->id, SHELL_ELEMENT_MAX); - - buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name); - if(rrdset_is_available_for_viewers(st)) { - rrdset_rdlock(st); - - // for each dimension - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - if(rd->collections_counter) { - char dimension[SHELL_ELEMENT_MAX + 1]; - shell_name_copy(dimension, rd->name?rd->name:rd->id, SHELL_ELEMENT_MAX); - - calculated_number n = rd->last_stored_value; - - if(isnan(n) || isinf(n)) - buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, st->units); - else { - if(rd->multiplier < 0 || rd->divisor < 0) n = -n; - n = calculated_number_round(n); - if(!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) total += n; - buffer_sprintf(wb, "NETDATA_%s_%s=\"" CALCULATED_NUMBER_FORMAT_ZERO "\" # %s\n", chart, dimension, n, st->units); - } - } - } - - total = calculated_number_round(total); - buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"" CALCULATED_NUMBER_FORMAT_ZERO "\" # %s\n", chart, total, st->units); - rrdset_unlock(st); - } - } - - buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n"); - - RRDCALC *rc; - for(rc = host->alarms; rc ;rc = rc->next) { - if(!rc->rrdset) continue; - - char chart[SHELL_ELEMENT_MAX + 1]; - shell_name_copy(chart, rc->rrdset->name?rc->rrdset->name:rc->rrdset->id, SHELL_ELEMENT_MAX); - - char alarm[SHELL_ELEMENT_MAX + 1]; - shell_name_copy(alarm, rc->name, SHELL_ELEMENT_MAX); - - calculated_number n = rc->value; - - if(isnan(n) || isinf(n)) - buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rc->units); - else { - n = calculated_number_round(n); - buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"" CALCULATED_NUMBER_FORMAT_ZERO "\" # %s\n", chart, alarm, n, rc->units); - } - - buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status)); - } - - rrdhost_unlock(host); -} - -// ---------------------------------------------------------------------------- - -void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) { - rrdhost_rdlock(host); - - buffer_strcat(wb, "{"); - - size_t chart_counter = 0; - size_t dimension_counter = 0; - - // 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) - ); - - chart_counter++; - dimension_counter = 0; - - // 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 - ); - - if(isnan(rd->last_stored_value)) - buffer_strcat(wb, "null"); - else - buffer_sprintf(wb, CALCULATED_NUMBER_FORMAT, rd->last_stored_value); - - buffer_strcat(wb, "\n\t\t\t}"); - - dimension_counter++; - } - } - - buffer_strcat(wb, "\n\t\t}\n\t}"); - rrdset_unlock(st); - } - } - - buffer_strcat(wb, "\n}"); - rrdhost_unlock(host); -} - -// ---------------------------------------------------------------------------- - -// RRDR dimension options -#define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null) -#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 -#define RRDR_RESULT_OPTION_RELATIVE 0x00000002 - -typedef struct rrdresult { - RRDSET *st; // the chart this result refers to - - uint32_t result_options; // RRDR_RESULT_OPTION_* - - int d; // the number of dimensions - long n; // the number of values in the arrays - long rows; // the number of rows used - - uint8_t *od; // the options for the dimensions - - time_t *t; // array of n timestamps - calculated_number *v; // array n x d values - uint8_t *o; // array n x d options - - long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows ) - - long group; // how many collected values were grouped for each row - int update_every; // what is the suggested update frequency in seconds - - calculated_number min; - calculated_number max; - - time_t before; - time_t after; - - int has_st_lock; // if st is read locked by us -} RRDR; - -#define rrdr_rows(r) ((r)->rows) - -/* -static void rrdr_dump(RRDR *r) -{ - long c, i; - RRDDIM *d; - - fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name); - - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) { - fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n" - , d->id - , d->name - , (r->od[c] & RRDR_EMPTY)?"EMPTY ":"" - , (r->od[c] & RRDR_RESET)?"RESET ":"" - , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":"" - , (r->od[c] & RRDR_NONZERO)?"NONZERO ":"" - ); - } - - if(r->rows <= 0) { - fprintf(stderr, "RRDR does not have any values in it.\n"); - return; - } - - fprintf(stderr, "RRDR includes %d values in it:\n", r->rows); - - // for each line in the array - for(i = 0; i < r->rows ;i++) { - calculated_number *cn = &r->v[ i * r->d ]; - uint8_t *co = &r->o[ i * r->d ]; - - // print the id and the timestamp of the line - fprintf(stderr, "%ld %ld ", i + 1, r->t[i]); - - // for each dimension - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue; - - if(co[c] & RRDR_EMPTY) - fprintf(stderr, "null "); - else - fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s " - , cn[c] - , (co[c] & RRDR_EMPTY)?"E":" " - , (co[c] & RRDR_RESET)?"R":" " - , (co[c] & RRDR_HIDDEN)?"H":" " - , (co[c] & RRDR_NONZERO)?"N":" " - ); - } - - fprintf(stderr, "\n"); - } -} -*/ - -void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) { - rrdset_check_rdlock(r->st); - - if(unlikely(!dims || !*dims || (dims[0] == '*' && dims[1] == '\0'))) return; - - int match_ids = 0, match_names = 0; - - if(unlikely(options & RRDR_OPTION_MATCH_IDS)) - match_ids = 1; - if(unlikely(options & RRDR_OPTION_MATCH_NAMES)) - match_names = 1; - - if(likely(!match_ids && !match_names)) - match_ids = match_names = 1; - - SIMPLE_PATTERN *pattern = simple_pattern_create(dims, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT); - - RRDDIM *d; - long c, dims_selected = 0, dims_not_hidden_not_zero = 0; - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) { - if( (match_ids && simple_pattern_matches(pattern, d->id)) - || (match_names && simple_pattern_matches(pattern, d->name)) - ) { - r->od[c] |= RRDR_SELECTED; - if(unlikely(r->od[c] & RRDR_HIDDEN)) 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 - // unless option non_zero is set - if(unlikely(!(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++; - } - else { - r->od[c] |= RRDR_HIDDEN; - if(unlikely(r->od[c] & RRDR_SELECTED)) r->od[c] &= ~RRDR_SELECTED; - } - } - simple_pattern_free(pattern); - - // 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) -{ - switch(format) { - case DATASOURCE_JSON: - buffer_strcat(wb, DATASOURCE_FORMAT_JSON); - break; - - case DATASOURCE_DATATABLE_JSON: - buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON); - break; - - case DATASOURCE_DATATABLE_JSONP: - buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP); - break; - - case DATASOURCE_JSONP: - buffer_strcat(wb, DATASOURCE_FORMAT_JSONP); - break; - - case DATASOURCE_SSV: - buffer_strcat(wb, DATASOURCE_FORMAT_SSV); - break; - - case DATASOURCE_CSV: - buffer_strcat(wb, DATASOURCE_FORMAT_CSV); - break; - - case DATASOURCE_TSV: - buffer_strcat(wb, DATASOURCE_FORMAT_TSV); - break; - - case DATASOURCE_HTML: - buffer_strcat(wb, DATASOURCE_FORMAT_HTML); - break; - - case DATASOURCE_JS_ARRAY: - buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY); - break; - - case DATASOURCE_SSV_COMMA: - buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA); - break; - - default: - buffer_strcat(wb, "unknown"); - break; - } -} - -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) { - long i; - - // commented due to #1514 - - //if(dims && *dims) { - // the caller wants specific dimensions - // disable NONZERO option - // to make sure we don't accidentally prevent - // the specific dimensions from being returned - // i = 0; - //} - //else { - // find how many dimensions are not zero - long c; - RRDDIM *rd; - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue; - i++; - } - //} - - // if with nonzero we get i = 0 (no dimensions will be returned) - // disable nonzero to show all dimensions - if(!i) options &= ~RRDR_OPTION_NONZERO; - } - - return options; -} - -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; - - //info("JSONWRAPPER(): %s: BEGIN", r->st->id); - char kq[2] = "", // key quote - sq[2] = ""; // string quote - - if( options & RRDR_OPTION_GOOGLE_JSON ) { - kq[0] = '\0'; - sq[0] = '\''; - } - else { - kq[0] = '"'; - sq[0] = '"'; - } - - buffer_sprintf(wb, "{\n" - " %sapi%s: 1,\n" - " %sid%s: %s%s%s,\n" - " %sname%s: %s%s%s,\n" - " %sview_update_every%s: %d,\n" - " %supdate_every%s: %d,\n" - " %sfirst_entry%s: %u,\n" - " %slast_entry%s: %u,\n" - " %sbefore%s: %u,\n" - " %safter%s: %u,\n" - " %sdimension_names%s: [" - , kq, kq - , kq, kq, sq, r->st->id, sq - , kq, kq, sq, r->st->name, sq - , kq, kq, r->update_every - , kq, kq, r->st->update_every - , kq, kq, (uint32_t)rrdset_first_entry_t(r->st) - , kq, kq, (uint32_t)rrdset_last_entry_t(r->st) - , kq, kq, (uint32_t)r->before - , kq, kq, (uint32_t)r->after - , kq, kq); - - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - if(i) buffer_strcat(wb, ", "); - buffer_strcat(wb, sq); - buffer_strcat(wb, rd->name); - buffer_strcat(wb, sq); - i++; - } - if(!i) { -#ifdef NETDATA_INTERNAL_CHECKS - error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options); -#endif - rows = 0; - buffer_strcat(wb, sq); - buffer_strcat(wb, "no data"); - buffer_strcat(wb, sq); - } - - buffer_sprintf(wb, "],\n" - " %sdimension_ids%s: [" - , kq, kq); - - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - if(i) buffer_strcat(wb, ", "); - buffer_strcat(wb, sq); - buffer_strcat(wb, rd->id); - buffer_strcat(wb, sq); - i++; - } - if(!i) { - rows = 0; - buffer_strcat(wb, sq); - buffer_strcat(wb, "no data"); - buffer_strcat(wb, sq); - } - - buffer_sprintf(wb, "],\n" - " %slatest_values%s: [" - , kq, kq); - - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - if(i) buffer_strcat(wb, ", "); - i++; - - storage_number n = rd->values[rrdset_last_slot(r->st)]; - - if(!does_storage_number_exist(n)) - buffer_strcat(wb, "null"); - else - buffer_rrd_value(wb, unpack_storage_number(n)); - } - if(!i) { - rows = 0; - buffer_strcat(wb, "null"); - } - - buffer_sprintf(wb, "],\n" - " %sview_latest_values%s: [" - , kq, kq); - - i = 0; - if(rows) { - calculated_number total = 1; - - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - total = 0; - for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - calculated_number *cn = &r->v[ (0) * r->d ]; - calculated_number n = cn[c]; - - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - total += n; - } - // prevent a division by zero - if(total == 0) total = 1; - } - - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - if(i) buffer_strcat(wb, ", "); - i++; - - calculated_number *cn = &r->v[ (0) * r->d ]; - uint8_t *co = &r->o[ (0) * r->d ]; - calculated_number n = cn[c]; - - if(co[c] & RRDR_EMPTY) { - if(options & RRDR_OPTION_NULL2ZERO) - buffer_strcat(wb, "0"); - else - buffer_strcat(wb, "null"); - } - else { - if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) - n = n * 100 / total; - - buffer_rrd_value(wb, n); - } - } - } - if(!i) { - rows = 0; - buffer_strcat(wb, "null"); - } - - buffer_sprintf(wb, "],\n" - " %sdimensions%s: %ld,\n" - " %spoints%s: %ld,\n" - " %sformat%s: %s" - , kq, kq, i - , kq, kq, rows - , kq, kq, sq - ); - - rrdr_buffer_print_format(wb, format); - - buffer_sprintf(wb, "%s,\n" - " %sresult%s: " - , sq - , kq, kq - ); - - if(string_value) buffer_strcat(wb, sq); - //info("JSONWRAPPER(): %s: END", r->st->id); -} - -void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) -{ - (void)format; - - char kq[2] = "", // key quote - sq[2] = ""; // string quote - - if( options & RRDR_OPTION_GOOGLE_JSON ) { - kq[0] = '\0'; - sq[0] = '\''; - } - else { - kq[0] = '"'; - sq[0] = '"'; - } - - if(string_value) buffer_strcat(wb, sq); - - buffer_sprintf(wb, ",\n %smin%s: ", kq, kq); - buffer_rrd_value(wb, r->min); - buffer_sprintf(wb, ",\n %smax%s: ", kq, kq); - buffer_rrd_value(wb, r->max); - buffer_strcat(wb, "\n}\n"); -} - -#define JSON_DATES_JS 1 -#define JSON_DATES_TIMESTAMP 2 - -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 - sq[2] = "", // string quote - pre_label[101] = "", // before each label - post_label[101] = "", // after each label - pre_date[101] = "", // the beginning of line, to the date - post_date[101] = "", // closing the date - pre_value[101] = "", // before each value - post_value[101] = "", // after each value - post_line[101] = "", // at the end of each row - normal_annotation[201] = "", // default row annotation - overflow_annotation[201] = "", // overflow row annotation - data_begin[101] = "", // between labels and values - finish[101] = ""; // at the end of everything - - if(datatable) { - dates = JSON_DATES_JS; - if( options & RRDR_OPTION_GOOGLE_JSON ) { - kq[0] = '\0'; - sq[0] = '\''; - } - else { - kq[0] = '"'; - sq[0] = '"'; - } - row_annotations = 1; - snprintfz(pre_date, 100, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq); - snprintfz(post_date, 100, "%s}", sq); - snprintfz(pre_label, 100, ",\n {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq); - snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq); - snprintfz(pre_value, 100, ",{%sv%s:", kq, kq); - strcpy(post_value, "}"); - strcpy(post_line, "]}"); - snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq); - strcpy(finish, "\n ]\n}"); - - 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); - snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq); - - 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); - - // remove the valueobjects flag - // google wants its own keys - if(options & RRDR_OPTION_OBJECTSROWS) - options &= ~RRDR_OPTION_OBJECTSROWS; - } - else { - kq[0] = '"'; - sq[0] = '"'; - 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 - strcpy(pre_date, " [ "); - strcpy(pre_label, ", \""); - strcpy(post_label, "\""); - strcpy(pre_value, ", "); - if( options & RRDR_OPTION_OBJECTSROWS ) - strcpy(post_line, "}"); - else - strcpy(post_line, "]"); - snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq); - strcpy(finish, "\n ]\n}"); - - buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq); - buffer_sprintf(wb, "%stime%s", sq, sq); - } - - // ------------------------------------------------------------------------- - // print the JSON header - - long c, i; - RRDDIM *rd; - - // print the header lines - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - buffer_strcat(wb, pre_label); - buffer_strcat(wb, rd->name); - buffer_strcat(wb, post_label); - i++; - } - if(!i) { - buffer_strcat(wb, pre_label); - buffer_strcat(wb, "no data"); - buffer_strcat(wb, post_label); - } - - // print the begin of row data - buffer_strcat(wb, data_begin); - - // if all dimensions are hidden, print a null - if(!i) { - buffer_strcat(wb, finish); - return; - } - - long start = 0, end = rrdr_rows(r), step = 1; - if((options & RRDR_OPTION_REVERSED)) { - start = rrdr_rows(r) - 1; - end = -1; - step = -1; - } - - // for each line in the array - calculated_number total = 1; - for(i = start; i != end ;i += step) { - calculated_number *cn = &r->v[ i * r->d ]; - uint8_t *co = &r->o[ i * r->d ]; - - time_t now = r->t[i]; - - if(dates == JSON_DATES_JS) { - // generate the local date time - struct tm tmbuf, *tm = localtime_r(&now, &tmbuf); - if(!tm) { error("localtime_r() failed."); continue; } - - if(likely(i != start)) buffer_strcat(wb, ",\n"); - buffer_strcat(wb, pre_date); - - if( options & RRDR_OPTION_OBJECTSROWS ) - buffer_sprintf(wb, "%stime%s: ", kq, kq); - - if(dates_with_new) - buffer_strcat(wb, "new "); - - 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); - - if(row_annotations) { - // google supports one annotation per row - int annotation_found = 0; - for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) { - if(co[c] & RRDR_RESET) { - buffer_strcat(wb, overflow_annotation); - annotation_found = 1; - break; - } - } - if(!annotation_found) - buffer_strcat(wb, normal_annotation); - } - } - else { - // print the timestamp of the line - if(likely(i != start)) buffer_strcat(wb, ",\n"); - buffer_strcat(wb, pre_date); - - if( options & RRDR_OPTION_OBJECTSROWS ) - buffer_sprintf(wb, "%stime%s: ", kq, kq); - - buffer_rrd_value(wb, (calculated_number)r->t[i]); - // in ms - if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000"); - - buffer_strcat(wb, post_date); - } - - int set_min_max = 0; - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - total = 0; - for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - calculated_number n = cn[c]; - - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - total += n; - } - // prevent a division by zero - if(total == 0) total = 1; - set_min_max = 1; - } - - // for each dimension - for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - calculated_number n = cn[c]; - - buffer_strcat(wb, pre_value); - - if( options & RRDR_OPTION_OBJECTSROWS ) - buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq); - - if(co[c] & RRDR_EMPTY) { - if(options & RRDR_OPTION_NULL2ZERO) - buffer_strcat(wb, "0"); - else - buffer_strcat(wb, "null"); - } - else { - if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - n = n * 100 / total; - - if(unlikely(set_min_max)) { - r->min = r->max = n; - set_min_max = 0; - } - - if(n < r->min) r->min = n; - if(n > r->max) r->max = n; - } - - buffer_rrd_value(wb, n); - } - - buffer_strcat(wb, post_value); - } - - buffer_strcat(wb, post_line); - } - - buffer_strcat(wb, finish); - //info("RRD2JSON(): %s: END", r->st->id); -} - -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; - - // print the csv header - for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - if(!i) { - buffer_strcat(wb, startline); - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\""); - buffer_strcat(wb, "time"); - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\""); - } - buffer_strcat(wb, separator); - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\""); - buffer_strcat(wb, d->name); - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\""); - i++; - } - buffer_strcat(wb, endline); - - if(!i) { - // no dimensions present - return; - } - - long start = 0, end = rrdr_rows(r), step = 1; - if((options & RRDR_OPTION_REVERSED)) { - start = rrdr_rows(r) - 1; - end = -1; - step = -1; - } - - // for each line in the array - calculated_number total = 1; - for(i = start; i != end ;i += step) { - calculated_number *cn = &r->v[ i * r->d ]; - uint8_t *co = &r->o[ i * r->d ]; - - buffer_strcat(wb, betweenlines); - buffer_strcat(wb, startline); - - time_t now = r->t[i]; - - if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) { - // print the timestamp of the line - buffer_rrd_value(wb, (calculated_number)now); - // in ms - if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000"); - } - else { - // generate the local date time - struct tm tmbuf, *tm = localtime_r(&now, &tmbuf); - if(!tm) { error("localtime() failed."); continue; } - buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - } - - int set_min_max = 0; - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - total = 0; - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) { - calculated_number n = cn[c]; - - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - total += n; - } - // prevent a division by zero - if(total == 0) total = 1; - set_min_max = 1; - } - - // for each dimension - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - buffer_strcat(wb, separator); - - calculated_number n = cn[c]; - - if(co[c] & RRDR_EMPTY) { - if(options & RRDR_OPTION_NULL2ZERO) - buffer_strcat(wb, "0"); - else - buffer_strcat(wb, "null"); - } - else { - if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - n = n * 100 / total; - - if(unlikely(set_min_max)) { - r->min = r->max = n; - set_min_max = 0; - } - - if(n < r->min) r->min = n; - if(n > r->max) r->max = n; - } - - buffer_rrd_value(wb, n); - } - } - - buffer_strcat(wb, endline); - } - //info("RRD2CSV(): %s: END", r->st->id); -} - -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; - - calculated_number *cn = &r->v[ i * r->d ]; - uint8_t *co = &r->o[ i * r->d ]; - - calculated_number sum = 0, min = 0, max = 0, v; - int all_null = 1, init = 1; - - calculated_number total = 1; - int set_min_max = 0; - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - total = 0; - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) { - calculated_number n = cn[c]; - - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - total += n; - } - // prevent a division by zero - if(total == 0) total = 1; - set_min_max = 1; - } - - // for each dimension - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) { - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue; - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue; - - calculated_number n = cn[c]; - - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0)) - n = -n; - - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) { - n = n * 100 / total; - - if(unlikely(set_min_max)) { - r->min = r->max = n; - set_min_max = 0; - } - - if(n < r->min) r->min = n; - if(n > r->max) r->max = n; - } - - if(unlikely(init)) { - if(n > 0) { - min = 0; - max = n; - } - else { - min = n; - max = 0; - } - init = 0; - } - - if(likely(!(co[c] & RRDR_EMPTY))) { - all_null = 0; - sum += n; - } - - if(n < min) min = n; - if(n > max) max = n; - } - - if(unlikely(all_null)) { - if(likely(all_values_are_null)) - *all_values_are_null = 1; - return 0; - } - else { - if(likely(all_values_are_null)) - *all_values_are_null = 0; - } - - if(options & RRDR_OPTION_MIN2MAX) - v = max - min; - else - v = sum; - - return v; -} - -static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix) -{ - //info("RRD2SSV(): %s: BEGIN", r->st->id); - long i; - - buffer_strcat(wb, prefix); - long start = 0, end = rrdr_rows(r), step = 1; - if((options & RRDR_OPTION_REVERSED)) { - start = rrdr_rows(r) - 1; - end = -1; - step = -1; - } - - // for each line in the array - for(i = start; i != end ;i += step) { - int all_values_are_null = 0; - calculated_number v = rrdr2value(r, i, options, &all_values_are_null); - - if(likely(i != start)) { - if(r->min > v) r->min = v; - if(r->max < v) r->max = v; - } - else { - r->min = v; - r->max = v; - } - - if(likely(i != start)) - buffer_strcat(wb, separator); - - if(all_values_are_null) { - if(options & RRDR_OPTION_NULL2ZERO) - buffer_strcat(wb, "0"); - else - buffer_strcat(wb, "null"); - } - else - buffer_rrd_value(wb, v); - } - buffer_strcat(wb, suffix); - //info("RRD2SSV(): %s: END", r->st->id); -} - -inline static calculated_number *rrdr_line_values(RRDR *r) -{ - return &r->v[ r->c * r->d ]; -} - -inline static uint8_t *rrdr_line_options(RRDR *r) -{ - return &r->o[ r->c * r->d ]; -} - -inline static int rrdr_line_init(RRDR *r, time_t t) -{ - r->c++; - - if(unlikely(r->c >= r->n)) { - error("requested to step above RRDR size for chart %s", r->st->name); - r->c = r->n - 1; - } - - // save the time - r->t[r->c] = t; - - return 1; -} - -inline static void rrdr_lock_rrdset(RRDR *r) { - if(unlikely(!r)) { - error("NULL value given!"); - return; - } - - rrdset_rdlock(r->st); - r->has_st_lock = 1; -} - -inline static void rrdr_unlock_rrdset(RRDR *r) { - if(unlikely(!r)) { - error("NULL value given!"); - return; - } - - if(likely(r->has_st_lock)) { - rrdset_unlock(r->st); - r->has_st_lock = 0; - } -} - -inline static void rrdr_free(RRDR *r) -{ - if(unlikely(!r)) { - error("NULL value given!"); - return; - } - - rrdr_unlock_rrdset(r); - freez(r->t); - freez(r->v); - freez(r->o); - freez(r->od); - freez(r); -} - -static inline void rrdr_done(RRDR *r) -{ - r->rows = r->c + 1; - r->c = 0; -} - -static RRDR *rrdr_create(RRDSET *st, long n) -{ - if(unlikely(!st)) { - error("NULL value given!"); - return NULL; - } - - RRDR *r = callocz(1, sizeof(RRDR)); - r->st = st; - - rrdr_lock_rrdset(r); - - RRDDIM *rd; - rrddim_foreach_read(rd, st) r->d++; - - r->n = n; - - r->t = mallocz(n * sizeof(time_t)); - r->v = mallocz(n * r->d * sizeof(calculated_number)); - r->o = mallocz(n * r->d * sizeof(uint8_t)); - r->od = mallocz(r->d * sizeof(uint8_t)); - - // set the hidden flag on hidden dimensions - int c; - for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) { - if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN))) - r->od[c] = RRDR_HIDDEN; - else - r->od[c] = 0; - } - - r->c = -1; - r->group = 1; - r->update_every = 1; - - return r; -} - -RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, long group_time, int aligned) -{ -#ifdef NETDATA_INTERNAL_CHECKS - int debug = rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?1:0; -#endif - int absolute_period_requested = -1; - - time_t first_entry_t = rrdset_first_entry_t(st); - time_t last_entry_t = rrdset_last_entry_t(st); - - if(before == 0 && after == 0) { - // dump the all the data - before = last_entry_t; - after = first_entry_t; - absolute_period_requested = 0; - } - - // allow relative for before (smaller than API_RELATIVE_TIME_MAX) - if(((before < 0)?-before:before) <= API_RELATIVE_TIME_MAX) { - if(abs(before) % st->update_every) { - // make sure it is multiple of st->update_every - if(before < 0) before = before - st->update_every - before % st->update_every; - else before = before + st->update_every - before % st->update_every; - } - if(before > 0) before = first_entry_t + before; - else before = last_entry_t + before; - absolute_period_requested = 0; - } - - // allow relative for after (smaller than API_RELATIVE_TIME_MAX) - if(((after < 0)?-after:after) <= API_RELATIVE_TIME_MAX) { - if(after == 0) after = -st->update_every; - if(abs(after) % st->update_every) { - // make sure it is multiple of st->update_every - if(after < 0) after = after - st->update_every - after % st->update_every; - else after = after + st->update_every - after % st->update_every; - } - after = before + after; - absolute_period_requested = 0; - } - - if(absolute_period_requested == -1) - absolute_period_requested = 1; - - // make sure they are within our timeframe - if(before > last_entry_t) before = last_entry_t; - if(before < first_entry_t) before = first_entry_t; - - if(after > last_entry_t) after = last_entry_t; - if(after < first_entry_t) after = first_entry_t; - - // check if they are upside down - if(after > before) { - time_t tmp = before; - before = after; - after = tmp; - } - - // the duration of the chart - time_t duration = before - after; - long available_points = duration / st->update_every; - - if(duration <= 0 || available_points <= 0) - return rrdr_create(st, 1); - - // check the number of wanted points in the result - if(unlikely(points < 0)) points = -points; - if(unlikely(points > available_points)) points = available_points; - if(unlikely(points == 0)) points = available_points; - - // calculate the desired grouping of source data points - long group = available_points / points; - if(unlikely(group <= 0)) group = 1; - if(unlikely(available_points % points > points / 2)) group++; // rounding to the closest integer - - // group_time enforces a certain grouping multiple - calculated_number group_sum_divisor = 1.0; - long group_points = 1; - if(unlikely(group_time > st->update_every)) { - if (unlikely(group_time > duration)) { - // group_time is above the available duration - - #ifdef NETDATA_INTERNAL_CHECKS - info("INTERNAL CHECK: %s: requested gtime %ld secs, is greater than the desired duration %ld secs", st->id, group_time, duration); - #endif - - group = points; // use all the points - } - else { - // the points we should group to satisfy gtime - group_points = group_time / st->update_every; - if(unlikely(group_time % group_points)) { - #ifdef NETDATA_INTERNAL_CHECKS - info("INTERNAL CHECK: %s: requested gtime %ld secs, is not a multiple of the chart's data collection frequency %d secs", st->id, group_time, st->update_every); - #endif - - group_points++; - } - - // adapt group according to group_points - if(unlikely(group < group_points)) group = group_points; // do not allow grouping below the desired one - if(unlikely(group % group_points)) group += group_points - (group % group_points); // make sure group is multiple of group_points - - //group_sum_divisor = group / group_points; - group_sum_divisor = (calculated_number)(group * st->update_every) / (calculated_number)group_time; - } - } - - time_t after_new = after - (after % ( ((aligned)?group:1) * st->update_every )); - time_t before_new = before - (before % ( ((aligned)?group:1) * st->update_every )); - long points_new = (before_new - after_new) / st->update_every / group; - - // find the starting and ending slots in our round robin db - long start_at_slot = rrdset_time2slot(st, before_new), - stop_at_slot = rrdset_time2slot(st, after_new); - -#ifdef NETDATA_INTERNAL_CHECKS - if(after_new < first_entry_t) - error("INTERNAL CHECK: after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t); - - if(after_new > last_entry_t) - error("INTERNAL CHECK: after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t); - - if(before_new < first_entry_t) - error("INTERNAL CHECK: before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t); - - if(before_new > last_entry_t) - error("INTERNAL CHECK: before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t); - - if(start_at_slot < 0 || start_at_slot >= st->entries) - error("INTERNAL CHECK: start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1); - - if(stop_at_slot < 0 || stop_at_slot >= st->entries) - error("INTERNAL CHECK: stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1); - - if(points_new > (before_new - after_new) / group / st->update_every + 1) - error("INTERNAL CHECK: points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1); - - if(group < group_points) - error("INTERNAL CHECK: group %ld is less than the desired group points %ld", group, group_points); - - if(group > group_points && group % group_points) - error("INTERNAL CHECK: group %ld is not a multiple of the desired group points %ld", group, group_points); -#endif - - //info("RRD2RRDR(): %s: wanted %ld points, got %ld - group=%ld, wanted duration=%u, got %u - wanted %ld - %ld, got %ld - %ld", st->id, points, points_new, group, before - after, before_new - after_new, after, before, after_new, before_new); - - after = after_new; - before = before_new; - duration = before - after; - points = points_new; - - // Now we have: - // before = the end time of the calculation - // after = the start time of the calculation - // duration = the duration of the calculation - // group = the number of source points to aggregate / group together - // method = the method of grouping source points - // points = the number of points to generate - - - // ------------------------------------------------------------------------- - // initialize our result set - - RRDR *r = rrdr_create(st, points); - if(unlikely(!r)) { -#ifdef NETDATA_INTERNAL_CHECKS - error("INTERNAL CHECK: Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points); -#endif - return NULL; - } - - if(unlikely(!r->d)) { -#ifdef NETDATA_INTERNAL_CHECKS - error("INTERNAL CHECK: Returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points); -#endif - return r; - } - - if(unlikely(absolute_period_requested == 1)) - r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE; - else - r->result_options |= RRDR_RESULT_OPTION_RELATIVE; - - // find how many dimensions we have - long dimensions = r->d; - - - // ------------------------------------------------------------------------- - // checks for debugging -#ifdef NETDATA_INTERNAL_CHECKS - if(debug) debug(D_RRD_STATS, "INFO %s first_t: %u, last_t: %u, all_duration: %u, after: %u, before: %u, duration: %u, points: %ld, group: %ld, group_points: %ld" - , st->id - , (uint32_t)first_entry_t - , (uint32_t)last_entry_t - , (uint32_t)(last_entry_t - first_entry_t) - , (uint32_t)after - , (uint32_t)before - , (uint32_t)duration - , points - , group - , group_points - ); -#endif - - // ------------------------------------------------------------------------- - // temp arrays for keeping values per dimension - - calculated_number last_values[dimensions]; // keep the last value of each dimension - calculated_number group_values[dimensions]; // keep sums when grouping - long group_counts[dimensions]; // keep the number of values added to group_values - uint8_t group_options[dimensions]; - uint8_t found_non_zero[dimensions]; - - - // 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; - group_counts[c] = 0; - group_options[c] = 0; - found_non_zero[c] = 0; - } - - - // ------------------------------------------------------------------------- - // the main loop - - time_t now = rrdset_slot2time(st, start_at_slot), - dt = st->update_every, - group_start_t = 0; - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(debug)) debug(D_RRD_STATS, "BEGIN %s after_t: %u (stop_at_t: %ld), before_t: %u (start_at_t: %ld), start_t(now): %u, current_entry: %ld, entries: %ld" - , st->id - , (uint32_t)after - , stop_at_slot - , (uint32_t)before - , start_at_slot - , (uint32_t)now - , st->current_entry - , st->entries - ); -#endif - - r->group = group; - r->update_every = (int)group * st->update_every; - r->before = now; - r->after = now; - - //info("RRD2RRDR(): %s: STARTING", st->id); - - long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0; - for(; !stop_now ; now -= dt, slot--, counter++) { - if(unlikely(slot < 0)) slot = st->entries - 1; - if(unlikely(slot == stop_at_slot)) stop_now = counter; - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s" - , st->id - , slot - , counter - , group_count + 1 - , added - , now - , (group_count + 1 == group)?"PRINT":" - " - , (now >= after && now <= before)?"RANGE":" - " - ); -#endif - - // make sure we return data in the proper time range - if(unlikely(now > before)) continue; - if(unlikely(now < after)) break; - - if(unlikely(group_count == 0)) group_start_t = now; - group_count++; - - if(unlikely(group_count == group)) { - if(unlikely(added >= points)) break; - add_this = 1; - } - - // do the calculations - for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) { - storage_number n = rd->values[slot]; - if(unlikely(!does_storage_number_exist(n))) continue; - - group_counts[c]++; - - calculated_number value = unpack_storage_number(n); - if(likely(value != 0.0)) { - group_options[c] |= RRDR_NONZERO; - found_non_zero[c] = 1; - } - - if(unlikely(did_storage_number_reset(n))) - group_options[c] |= RRDR_RESET; - - switch(group_method) { - case GROUP_MIN: - if(unlikely(isnan(group_values[c])) || - calculated_number_fabs(value) < calculated_number_fabs(group_values[c])) - group_values[c] = value; - break; - - case GROUP_MAX: - if(unlikely(isnan(group_values[c])) || - calculated_number_fabs(value) > calculated_number_fabs(group_values[c])) - group_values[c] = value; - break; - - default: - case GROUP_SUM: - case GROUP_AVERAGE: - case GROUP_UNDEFINED: - group_values[c] += value; - break; - - case GROUP_INCREMENTAL_SUM: - if(unlikely(slot == start_at_slot)) - last_values[c] = value; - - group_values[c] += last_values[c] - value; - last_values[c] = value; - break; - } - } - - // added it - if(unlikely(add_this)) { - if(unlikely(!rrdr_line_init(r, group_start_t))) break; - - r->after = now; - - calculated_number *cn = rrdr_line_values(r); - uint8_t *co = rrdr_line_options(r); - - for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) { - - // update the dimension options - if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO; - - // store the specific point options - co[c] = group_options[c]; - - // store the value - if(unlikely(group_counts[c] == 0)) { - cn[c] = 0.0; - co[c] |= RRDR_EMPTY; - group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0; - } - else { - switch(group_method) { - case GROUP_MIN: - case GROUP_MAX: - if(unlikely(isnan(group_values[c]))) - cn[c] = 0; - else { - cn[c] = group_values[c]; - group_values[c] = NAN; - } - break; - - case GROUP_SUM: - case GROUP_INCREMENTAL_SUM: - cn[c] = group_values[c]; - group_values[c] = 0; - break; - - default: - case GROUP_AVERAGE: - case GROUP_UNDEFINED: - if(unlikely(group_points != 1)) - cn[c] = group_values[c] / group_sum_divisor; - else - cn[c] = group_values[c] / group_counts[c]; - - group_values[c] = 0; - break; - } - - if(cn[c] < r->min) r->min = cn[c]; - if(cn[c] > r->max) r->max = cn[c]; - } - - // reset for the next loop - group_counts[c] = 0; - group_options[c] = 0; - } - - added++; - group_count = 0; - add_this = 0; - } - } - - rrdr_done(r); - //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r)); - //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r)); - return r; -} - -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 - , long group_time - , uint32_t options - , time_t *db_after - , time_t *db_before - , int *value_is_null -) { - RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, !(options & RRDR_OPTION_NOT_ALIGNED)); - if(!r) { - if(value_is_null) *value_is_null = 1; - return 500; - } - - if(rrdr_rows(r) == 0) { - rrdr_free(r); - - if(db_after) *db_after = 0; - if(db_before) *db_before = 0; - if(value_is_null) *value_is_null = 1; - - return 400; - } - - if(wb) { - if (r->result_options & RRDR_RESULT_OPTION_RELATIVE) - buffer_no_cacheable(wb); - else if (r->result_options & RRDR_RESULT_OPTION_ABSOLUTE) - buffer_cacheable(wb); - } - - options = rrdr_check_options(r, options, dimensions); - - if(dimensions) - rrdr_disable_not_selected_dimensions(r, options, dimensions); - - if(db_after) *db_after = r->after; - if(db_before) *db_before = r->before; - - long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0; - *n = rrdr2value(r, i, options, value_is_null); - - rrdr_free(r); - return 200; -} - -int rrdset2anything_api_v1( - RRDSET *st - , BUFFER *wb - , BUFFER *dimensions - , uint32_t format - , long points - , long long after - , long long before - , int group_method - , long group_time - , uint32_t options - , time_t *latest_timestamp -) { - st->last_accessed_time = now_realtime_sec(); - - RRDR *r = rrd2rrdr(st, points, after, before, group_method, group_time, !(options & RRDR_OPTION_NOT_ALIGNED)); - if(!r) { - buffer_strcat(wb, "Cannot generate output with these parameters on this chart."); - return 500; - } - - if(r->result_options & RRDR_RESULT_OPTION_RELATIVE) - buffer_no_cacheable(wb); - else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE) - buffer_cacheable(wb); - - options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL); - - if(dimensions) - rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions)); - - if(latest_timestamp && rrdr_rows(r) > 0) - *latest_timestamp = r->before; - - switch(format) { - case DATASOURCE_SSV: - if(options & RRDR_OPTION_JSON_WRAP) { - wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1); - rrdr2ssv(r, wb, options, "", " ", ""); - rrdr_json_wrapper_end(r, wb, format, options, 1); - } - else { - wb->contenttype = CT_TEXT_PLAIN; - rrdr2ssv(r, wb, options, "", " ", ""); - } - break; - - case DATASOURCE_SSV_COMMA: - if(options & RRDR_OPTION_JSON_WRAP) { - wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1); - rrdr2ssv(r, wb, options, "", ",", ""); - rrdr_json_wrapper_end(r, wb, format, options, 1); - } - else { - wb->contenttype = CT_TEXT_PLAIN; - rrdr2ssv(r, wb, options, "", ",", ""); - } - break; - - case DATASOURCE_JS_ARRAY: - if(options & RRDR_OPTION_JSON_WRAP) { - wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 0); - rrdr2ssv(r, wb, options, "[", ",", "]"); - rrdr_json_wrapper_end(r, wb, format, options, 0); - } - else { - wb->contenttype = CT_APPLICATION_JSON; - rrdr2ssv(r, wb, options, "[", ",", "]"); - } - break; - - case DATASOURCE_CSV: - if(options & RRDR_OPTION_JSON_WRAP) { - wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1); - rrdr2csv(r, wb, options, "", ",", "\\n", ""); - rrdr_json_wrapper_end(r, wb, format, options, 1); - } - else { - wb->contenttype = CT_TEXT_PLAIN; - rrdr2csv(r, wb, options, "", ",", "\r\n", ""); - } - break; - - case DATASOURCE_CSV_JSON_ARRAY: - wb->contenttype = CT_APPLICATION_JSON; - if(options & RRDR_OPTION_JSON_WRAP) { - rrdr_json_wrapper_begin(r, wb, format, options, 0); - buffer_strcat(wb, "[\n"); - rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n"); - buffer_strcat(wb, "\n]"); - rrdr_json_wrapper_end(r, wb, format, options, 0); - } - else { - wb->contenttype = CT_TEXT_PLAIN; - buffer_strcat(wb, "[\n"); - rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n"); - buffer_strcat(wb, "\n]"); - } - break; - - case DATASOURCE_TSV: - if(options & RRDR_OPTION_JSON_WRAP) { - wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1); - rrdr2csv(r, wb, options, "", "\t", "\\n", ""); - rrdr_json_wrapper_end(r, wb, format, options, 1); - } - else { - wb->contenttype = CT_TEXT_PLAIN; - rrdr2csv(r, wb, options, "", "\t", "\r\n", ""); - } - break; - - case DATASOURCE_HTML: - if(options & RRDR_OPTION_JSON_WRAP) { - wb->contenttype = CT_APPLICATION_JSON; - rrdr_json_wrapper_begin(r, wb, format, options, 1); - buffer_strcat(wb, "\\n
\\n\\n"); - rrdr2csv(r, wb, options, "\\n", ""); - buffer_strcat(wb, "
", "", "
\\n
\\n\\n"); - rrdr_json_wrapper_end(r, wb, format, options, 1); - } - else { - wb->contenttype = CT_TEXT_HTML; - buffer_strcat(wb, "\n
\n\n"); - rrdr2csv(r, wb, options, "\n", ""); - buffer_strcat(wb, "
", "", "
\n
\n\n"); - } - break; - - case DATASOURCE_DATATABLE_JSONP: - wb->contenttype = CT_APPLICATION_X_JAVASCRIPT; - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0); - - rrdr2json(r, wb, options, 1); - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_end(r, wb, format, options, 0); - break; - - case DATASOURCE_DATATABLE_JSON: - wb->contenttype = CT_APPLICATION_JSON; - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0); - - rrdr2json(r, wb, options, 1); - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_end(r, wb, format, options, 0); - break; - - case DATASOURCE_JSONP: - wb->contenttype = CT_APPLICATION_X_JAVASCRIPT; - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0); - - rrdr2json(r, wb, options, 0); - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_end(r, wb, format, options, 0); - break; - - case DATASOURCE_JSON: - default: - wb->contenttype = CT_APPLICATION_JSON; - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_begin(r, wb, format, options, 0); - - rrdr2json(r, wb, options, 0); - - if(options & RRDR_OPTION_JSON_WRAP) - rrdr_json_wrapper_end(r, wb, format, options, 0); - break; - } - - rrdr_free(r); - return 200; -} diff --git a/src/rrd2json.h b/src/rrd2json.h deleted file mode 100644 index b41c814ec..000000000 --- a/src/rrd2json.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef NETDATA_RRD2JSON_H -#define NETDATA_RRD2JSON_H 1 - -#define HOSTNAME_MAX 1024 - -#define API_RELATIVE_TIME_MAX (3 * 365 * 86400) - -// type of JSON generations -#define DATASOURCE_INVALID (-1) -#define DATASOURCE_JSON 0 -#define DATASOURCE_DATATABLE_JSON 1 -#define DATASOURCE_DATATABLE_JSONP 2 -#define DATASOURCE_SSV 3 -#define DATASOURCE_CSV 4 -#define DATASOURCE_JSONP 5 -#define DATASOURCE_TSV 6 -#define DATASOURCE_HTML 7 -#define DATASOURCE_JS_ARRAY 8 -#define DATASOURCE_SSV_COMMA 9 -#define DATASOURCE_CSV_JSON_ARRAY 10 - -#define DATASOURCE_FORMAT_JSON "json" -#define DATASOURCE_FORMAT_DATATABLE_JSON "datatable" -#define DATASOURCE_FORMAT_DATATABLE_JSONP "datasource" -#define DATASOURCE_FORMAT_JSONP "jsonp" -#define DATASOURCE_FORMAT_SSV "ssv" -#define DATASOURCE_FORMAT_CSV "csv" -#define DATASOURCE_FORMAT_TSV "tsv" -#define DATASOURCE_FORMAT_HTML "html" -#define DATASOURCE_FORMAT_JS_ARRAY "array" -#define DATASOURCE_FORMAT_SSV_COMMA "ssvcomma" -#define DATASOURCE_FORMAT_CSV_JSON_ARRAY "csvjsonarray" - -#define ALLMETRICS_FORMAT_SHELL "shell" -#define ALLMETRICS_FORMAT_PROMETHEUS "prometheus" -#define ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS "prometheus_all_hosts" -#define ALLMETRICS_FORMAT_JSON "json" - -#define ALLMETRICS_SHELL 1 -#define ALLMETRICS_PROMETHEUS 2 -#define ALLMETRICS_JSON 3 -#define ALLMETRICS_PROMETHEUS_ALL_HOSTS 4 - -#define GROUP_UNDEFINED 0 -#define GROUP_AVERAGE 1 -#define GROUP_MIN 2 -#define GROUP_MAX 3 -#define GROUP_SUM 4 -#define GROUP_INCREMENTAL_SUM 5 - -#define RRDR_OPTION_NONZERO 0x00000001 // don't output dimensions will just zero values -#define RRDR_OPTION_REVERSED 0x00000002 // output the rows in reverse order (oldest to newest) -#define RRDR_OPTION_ABSOLUTE 0x00000004 // values positive, for DATASOURCE_SSV before summing -#define RRDR_OPTION_MIN2MAX 0x00000008 // when adding dimensions, use max - min, instead of sum -#define RRDR_OPTION_SECONDS 0x00000010 // output seconds, instead of dates -#define RRDR_OPTION_MILLISECONDS 0x00000020 // output milliseconds, instead of dates -#define RRDR_OPTION_NULL2ZERO 0x00000040 // do not show nulls, convert them to zeros -#define RRDR_OPTION_OBJECTSROWS 0x00000080 // each row of values should be an object, not an array -#define RRDR_OPTION_GOOGLE_JSON 0x00000100 // comply with google JSON/JSONP specs -#define RRDR_OPTION_JSON_WRAP 0x00000200 // wrap the response in a JSON header with info about the result -#define RRDR_OPTION_LABEL_QUOTES 0x00000400 // in CSV output, wrap header labels in double quotes -#define RRDR_OPTION_PERCENTAGE 0x00000800 // give values as percentage of total -#define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes -#define RRDR_OPTION_DISPLAY_ABS 0x00002000 // for badges, display the absolute value, but calculate colors with sign -#define RRDR_OPTION_MATCH_IDS 0x00004000 // when filtering dimensions, match only IDs -#define RRDR_OPTION_MATCH_NAMES 0x00008000 // when filtering dimensions, match only names - -extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb); -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 int rrdset2anything_api_v1(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points - , long long after, long long before, int group_method, long group_time, 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, long group_time, uint32_t options - , time_t *db_after, time_t *db_before, int *value_is_null); - -#endif /* NETDATA_RRD2JSON_H */ diff --git a/src/rrd2json_api_old.c b/src/rrd2json_api_old.c deleted file mode 100644 index 003b8626d..000000000 --- a/src/rrd2json_api_old.c +++ /dev/null @@ -1,487 +0,0 @@ -#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 (%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->name - , 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 deleted file mode 100644 index f8c63814f..000000000 --- a/src/rrd2json_api_old.h +++ /dev/null @@ -1,14 +0,0 @@ -#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 deleted file mode 100644 index 4e41539e2..000000000 --- a/src/rrdcalc.c +++ /dev/null @@ -1,424 +0,0 @@ -#define NETDATA_HEALTH_INTERNALS -#include "common.h" - -// ---------------------------------------------------------------------------- -// RRDCALC management - -inline const char *rrdcalc_status2string(RRDCALC_STATUS 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) { - RRDHOST *host = st->rrdhost; - - debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->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 " CALCULATED_NUMBER_FORMAT_AUTO " to " CALCULATED_NUMBER_FORMAT_AUTO ".", 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 " CALCULATED_NUMBER_FORMAT_AUTO " to " CALCULATED_NUMBER_FORMAT_AUTO ".", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red); - st->red = rc->red; - } - - rc->local = rrdvar_create_and_index("local", &st->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value); - rc->family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_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", &host->rrdvar_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", &host->rrdvar_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( - 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, - 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) { - RRDHOST *host = st->rrdhost; - // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id); - - RRDCALC *rc; - for(rc = host->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; - } - - RRDHOST *host = st->rrdhost; - - { - time_t now = now_realtime_sec(); - 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, - RRDCALC_STATUS_REMOVED, - rc->source, - rc->units, - rc->info, - 0, - 0 - ); - } - - 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(host, &st->rrdvar_root_index, rc->local); - rc->local = NULL; - - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rc->family); - rc->family = NULL; - - rrdvar_free(host, &host->rrdvar_root_index, rc->hostid); - rc->hostid = NULL; - - rrdvar_free(host, &host->rrdvar_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); - info("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 " CALCULATED_NUMBER_FORMAT_AUTO ", red " CALCULATED_NUMBER_FORMAT_AUTO ", 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(RRDCALC *rc) { - if(unlikely(!rc)) return; - - 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); -} - -void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc) { - if(unlikely(!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); - } - - rrdcalc_free(rc); -} diff --git a/src/rrdcalctemplate.c b/src/rrdcalctemplate.c deleted file mode 100644 index 75a7002b3..000000000 --- a/src/rrdcalctemplate.c +++ /dev/null @@ -1,69 +0,0 @@ -#define NETDATA_HEALTH_INTERNALS -#include "common.h" - -// ---------------------------------------------------------------------------- -// RRDCALCTEMPLATE management - -void rrdcalctemplate_link_matching(RRDSET *st) { - RRDHOST *host = st->rrdhost; - RRDCALCTEMPLATE *rt; - - for(rt = host->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(host, rt, st->id); - if(unlikely(!rc)) - info("Health tried to create alarm from template '%s' on chart '%s' of host '%s', but it failed", rt->name, st->id, host->hostname); - -#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(RRDCALCTEMPLATE *rt) { - if(unlikely(!rt)) return; - - 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); -} - -inline void rrdcalctemplate_unlink_and_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); - } - - rrdcalctemplate_free(rt); -} - - diff --git a/src/rrddim.c b/src/rrddim.c deleted file mode 100644 index a54c6452f..000000000 --- a/src/rrddim.c +++ /dev/null @@ -1,387 +0,0 @@ -#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 int rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name) { - if(unlikely(!name || !*name || !strcmp(rd->name, name))) - return 0; - - 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); - rd->exposed = 0; - return 1; -} - -inline int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm) { - if(unlikely(rd->algorithm == algorithm)) - return 0; - - debug(D_RRD_CALLS, "Updating algorithm of dimension '%s/%s' from %s to %s", st->id, rd->name, rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm)); - rd->algorithm = algorithm; - rd->exposed = 0; - rrdset_flag_set(st, RRDSET_FLAG_HOMEGENEOUS_CHECK); - return 1; -} - -inline int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, collected_number multiplier) { - if(unlikely(rd->multiplier == multiplier)) - return 0; - - debug(D_RRD_CALLS, "Updating multiplier of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, st->id, rd->name, rd->multiplier, multiplier); - rd->multiplier = multiplier; - rd->exposed = 0; - rrdset_flag_set(st, RRDSET_FLAG_HOMEGENEOUS_CHECK); - return 1; -} - -inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor) { - if(unlikely(rd->divisor == divisor)) - return 0; - - debug(D_RRD_CALLS, "Updating divisor of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, st->id, rd->name, rd->divisor, divisor); - rd->divisor = divisor; - rd->exposed = 0; - rrdset_flag_set(st, RRDSET_FLAG_HOMEGENEOUS_CHECK); - return 1; -} - -// ---------------------------------------------------------------------------- -// RRDDIM create a dimension - -RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm, RRD_MEMORY_MODE memory_mode) { - 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:""); - - rrddim_set_name(st, rd, name); - rrddim_set_algorithm(st, rd, algorithm); - rrddim_set_multiplier(st, rd, multiplier); - rrddim_set_divisor(st, rd, divisor); - - return rd; - } - - RRDHOST *host = st->rrdhost; - 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(memory_mode == RRD_MEMORY_MODE_SAVE || memory_mode == RRD_MEMORY_MODE_MAP || memory_mode == RRD_MEMORY_MODE_RAM) { - rd = (RRDDIM *)mymmap( - (memory_mode == RRD_MEMORY_MODE_RAM)?NULL:fullfilename - , size - , ((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; - rd->exposed = 0; - - struct timeval now; - now_realtime_timeval(&now); - - if(memory_mode == RRD_MEMORY_MODE_RAM) { - memset(rd, 0, size); - } - else { - int reset = 0; - - if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) { - info("Initializing file %s.", fullfilename); - memset(rd, 0, size); - reset = 1; - } - else if(rd->memsize != size) { - error("File %s does not have the desired size, expected %lu but found %lu. Clearing it.", fullfilename, size, rd->memsize); - memset(rd, 0, size); - reset = 1; - } - else if(rd->update_every != st->update_every) { - error("File %s does not have the same update frequency, expected %d but found %d. Clearing it.", fullfilename, st->update_every, rd->update_every); - memset(rd, 0, size); - reset = 1; - } - else if(dt_usec(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * USEC_PER_SEC)) { - info("File %s is too old (last collected %llu seconds ago, but the database is %ld seconds). Clearing it.", fullfilename, dt_usec(&now, &rd->last_collected_time) / USEC_PER_SEC, rd->entries * rd->update_every); - memset(rd, 0, size); - reset = 1; - } - - if(!reset) { - if(rd->algorithm != algorithm) { - info("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)); - } - - if(rd->multiplier != multiplier) { - info("File %s does not have the expected multiplier (expected " COLLECTED_NUMBER_FORMAT ", found " COLLECTED_NUMBER_FORMAT "). Previous values may be wrong.", fullfilename, multiplier, rd->multiplier); - } - - if(rd->divisor != divisor) { - info("File %s does not have the expected divisor (expected " COLLECTED_NUMBER_FORMAT ", found " COLLECTED_NUMBER_FORMAT "). Previous values may be wrong.", fullfilename, divisor, rd->divisor); - } - } - } - - // make sure we have the right memory mode - // even if we cleared the memory - rd->rrd_memory_mode = 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 = (memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_ALLOC; - } - - 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; - - if(rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST)) - rd->collections_counter = 1; - else - 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] = SN_EMPTY_SLOT; // 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; - - if(td->algorithm != rd->algorithm || abs(td->multiplier) != abs(rd->multiplier) || abs(td->divisor) != abs(rd->divisor)) { - if(!rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS)) { - #ifdef NETDATA_INTERNAL_CHECKS - info("Dimension '%s' added on chart '%s' of host '%s' is not homogeneous to other dimensions already present (algorithm is '%s' vs '%s', multiplier is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ", divisor is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ").", - rd->name, - st->name, - host->hostname, - rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(td->algorithm), - rd->multiplier, td->multiplier, - rd->divisor, td->divisor - ); - #endif - rrdset_flag_set(st, RRDSET_FLAG_HETEROGENEOUS); - } - } - - for(; td->next; td = td->next) ; - td->next = rd; - } - - if(host->health_enabled) { - rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, RRDVAR_OPTION_DEFAULT); - rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, RRDVAR_OPTION_DEFAULT); - rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, RRDVAR_OPTION_DEFAULT); - } - - 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: - case RRD_MEMORY_MODE_MAP: - case RRD_MEMORY_MODE_RAM: - 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_ALLOC: - case RRD_MEMORY_MODE_NONE: - 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); - - RRDHOST *host = st->rrdhost; - - RRDDIM *rd = rrddim_find(st, id); - if(unlikely(!rd)) { - error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, st->name, st->id, host->hostname); - 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); - - RRDHOST *host = st->rrdhost; - RRDDIM *rd = rrddim_find(st, id); - if(unlikely(!rd)) { - error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, st->name, st->id, host->hostname); - 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) { - RRDHOST *host = st->rrdhost; - RRDDIM *rd = rrddim_find(st, id); - if(unlikely(!rd)) { - error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, st->name, st->id, host->hostname); - return 0; - } - - return rrddim_set_by_pointer(st, rd, value); -} diff --git a/src/rrddimvar.c b/src/rrddimvar.c deleted file mode 100644 index 28a3e7fa6..000000000 --- a/src/rrddimvar.c +++ /dev/null @@ -1,212 +0,0 @@ -#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; - RRDHOST *host = st->rrdhost; - - // CHART VARIABLES FOR THIS DIMENSION - - rrdvar_free(host, &st->rrdvar_root_index, rs->var_local_id); - rs->var_local_id = NULL; - - rrdvar_free(host, &st->rrdvar_root_index, rs->var_local_name); - rs->var_local_name = NULL; - - // FAMILY VARIABLES FOR THIS DIMENSION - - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_id); - rs->var_family_id = NULL; - - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_name); - rs->var_family_name = NULL; - - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_contextid); - rs->var_family_contextid = NULL; - - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_contextname); - rs->var_family_contextname = NULL; - - // HOST VARIABLES FOR THIS DIMENSION - - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartidid); - rs->var_host_chartidid = NULL; - - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartidname); - rs->var_host_chartidname = NULL; - - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartnameid); - rs->var_host_chartnameid = NULL; - - rrdvar_free(host, &host->rrdvar_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; - RRDHOST *host = st->rrdhost; - - 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->rrdvar_root_index, rs->key_id, rs->type, rs->value); - rs->var_local_name = rrdvar_create_and_index("local", &st->rrdvar_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->rrdvar_root_index, rs->key_id, rs->type, rs->value); - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_name, rs->type, rs->value); - rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_contextid, rs->type, rs->value); - rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_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", &host->rrdvar_root_index, rs->key_fullidid, rs->type, rs->value); - rs->var_host_chartidname = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullidname, rs->type, rs->value); - rs->var_host_chartnameid = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullnameid, rs->type, rs->value); - rs->var_host_chartnamename = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullnamename, rs->type, rs->value); -} - -RRDDIMVAR *rrddimvar_create(RRDDIM *rd, RRDVAR_TYPE type, const char *prefix, const char *suffix, void *value, RRDVAR_OPTIONS 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 deleted file mode 100644 index 905ae480b..000000000 --- a/src/rrdfamily.c +++ /dev/null @@ -1,59 +0,0 @@ -#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->rrdvar_root_index, rrdvar_compare); - - RRDFAMILY *ret = rrdfamily_index_add(host, rc); - if(ret != rc) - error("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) - error("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE"); - else { - debug(D_RRD_CALLS, "RRDFAMILY: Cleaning up remaining family variables for host '%s', family '%s'", host->hostname, rc->family); - rrdvar_free_remaining_variables(host, &rc->rrdvar_root_index); - - freez((void *) rc->family); - freez(rc); - } - } -} - diff --git a/src/rrdhost.c b/src/rrdhost.c deleted file mode 100644 index e62e61ae8..000000000 --- a/src/rrdhost.c +++ /dev/null @@ -1,735 +0,0 @@ -#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_tags(RRDHOST *host, const char *tags) { - if(host->tags && tags && !strcmp(host->tags, tags)) - return; - - void *old = (void *)host->tags; - host->tags = (tags && *tags)?strdupz(tags):NULL; - freez(old); -} - -static inline void rrdhost_init_hostname(RRDHOST *host, const char *hostname) { - if(host->hostname && hostname && !strcmp(host->hostname, hostname)) - return; - - void *old = host->hostname; - host->hostname = strdupz(hostname?hostname:"localhost"); - host->hash_hostname = simple_hash(host->hostname); - freez(old); -} - -static inline void rrdhost_init_os(RRDHOST *host, const char *os) { - if(host->os && os && !strcmp(host->os, os)) - return; - - void *old = (void *)host->os; - host->os = strdupz(os?os:"unknown"); - freez(old); -} - -static inline void rrdhost_init_timezone(RRDHOST *host, const char *timezone) { - if(host->timezone && timezone && !strcmp(host->timezone, timezone)) - return; - - void *old = (void *)host->timezone; - host->timezone = strdupz((timezone && *timezone)?timezone:"unknown"); - freez(old); -} - -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 *registry_hostname, - const char *guid, - const char *os, - const char *timezone, - const char *tags, - const char *program_name, - const char *program_version, - 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_send_enabled = (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key); - host->rrdpush_send_destination = (host->rrdpush_send_enabled)?strdupz(rrdpush_destination):NULL; - host->rrdpush_send_api_key = (host->rrdpush_send_enabled)?strdupz(rrdpush_api_key):NULL; - - host->rrdpush_sender_pipe[0] = -1; - host->rrdpush_sender_pipe[1] = -1; - host->rrdpush_sender_socket = -1; - - netdata_mutex_init(&host->rrdpush_sender_buffer_mutex); - netdata_rwlock_init(&host->rrdhost_rwlock); - - rrdhost_init_hostname(host, hostname); - rrdhost_init_machine_guid(host, guid); - rrdhost_init_os(host, os); - rrdhost_init_timezone(host, timezone); - rrdhost_init_tags(host, tags); - - host->program_name = strdupz((program_name && *program_name)?program_name:"unknown"); - host->program_version = strdupz((program_version && *program_version)?program_version:"unknown"); - host->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname); - - 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->rrdvar_root_index), rrdvar_compare); - - if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete obsolete charts files", 1)) - rrdhost_flag_set(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS); - - if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete orphan hosts files", 1) && !is_localhost) - rrdhost_flag_set(host, RRDHOST_FLAG_DELETE_ORPHAN_HOST); - - - // ------------------------------------------------------------------------ - // 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' (at registry as '%s') with guid '%s' initialized" - ", os '%s'" - ", timezone '%s'" - ", tags '%s'" - ", program_name '%s'" - ", program_version '%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->registry_hostname - , host->machine_guid - , host->os - , host->timezone - , (host->tags)?host->tags:"" - , host->program_name - , host->program_version - , host->rrd_update_every - , rrd_memory_mode_name(host->rrd_memory_mode) - , host->rrd_history_entries - , host->rrdpush_send_enabled?"enabled":"disabled" - , host->rrdpush_send_destination?host->rrdpush_send_destination:"" - , host->rrdpush_send_api_key?host->rrdpush_send_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 *registry_hostname - , const char *guid - , const char *os - , const char *timezone - , const char *tags - , const char *program_name - , const char *program_version - , 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 - , registry_hostname - , guid - , os - , timezone - , tags - , program_name - , program_version - , 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) != 0) { - info("Host '%s' has been renamed to '%s'. If this is not intentional it may mean multiple hosts are using the same machine_guid.", host->hostname, hostname); - char *t = host->hostname; - host->hostname = strdupz(hostname); - host->hash_hostname = simple_hash(host->hostname); - freez(t); - } - - if(strcmp(host->program_name, program_name) != 0) { - info("Host '%s' switched program name from '%s' to '%s'", host->hostname, host->program_name, program_name); - char *t = host->program_name; - host->program_name = strdupz(program_name); - freez(t); - } - - if(strcmp(host->program_version, program_version) != 0) { - info("Host '%s' switched program version from '%s' to '%s'", host->hostname, host->program_version, program_version); - char *t = host->program_version; - host->program_version = strdupz(program_version); - 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. Restart netdata here to apply the new settings.", 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. Restart netdata here to apply the new settings.", 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'. Restart netdata here to apply the new settings.", host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode)); - - // update host tags - rrdhost_init_tags(host, tags); - } - - rrdhost_cleanup_orphan_hosts_nolock(host); - - rrd_unlock(); - - return host; -} - -inline int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected, time_t now) { - if(host != protected - && host != localhost - && rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN) - && !host->connected_senders - && host->senders_disconnected_time - && host->senders_disconnected_time + rrdhost_free_orphan_time < now) - return 1; - - return 0; -} - -void rrdhost_cleanup_orphan_hosts_nolock(RRDHOST *protected) { - time_t now = now_realtime_sec(); - - RRDHOST *host; - -restart_after_removal: - rrdhost_foreach_write(host) { - if(rrdhost_should_be_removed(host, protected, now)) { - info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", host->hostname, host->machine_guid); - - if(rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_ORPHAN_HOST)) - rrdhost_delete_charts(host); - else - rrdhost_save_charts(host); - - rrdhost_free(host); - goto restart_after_removal; - } - } -} - -// ---------------------------------------------------------------------------- -// 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); - gap_when_lost_iterations_above = (int)config_get_number(CONFIG_SECTION_GLOBAL, "gap when lost iterations above", gap_when_lost_iterations_above); - if(gap_when_lost_iterations_above < 1) - gap_when_lost_iterations_above = 1; - - 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_hostname() - , registry_get_this_machine_guid() - , os_type - , netdata_configured_timezone - , config_get(CONFIG_SECTION_BACKEND, "host tags", "") - , program_name - , program_version - , 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_unlink_and_free(host, host->alarms); - - while(host->templates) - rrdcalctemplate_unlink_and_free(host, host->templates); - - debug(D_RRD_CALLS, "RRDHOST: Cleaning up remaining host variables for host '%s'", host->hostname); - rrdvar_free_remaining_variables(host, &host->rrdvar_root_index); - - 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((void *)host->tags); - freez((void *)host->os); - freez((void *)host->timezone); - freez(host->program_version); - freez(host->program_name); - freez(host->cache_dir); - freez(host->varlib_dir); - freez(host->rrdpush_send_api_key); - freez(host->rrdpush_send_destination); - freez(host->health_default_exec); - freez(host->health_default_recipient); - freez(host->health_log_filename); - freez(host->hostname); - freez(host->registry_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 host files - -void rrdhost_save_charts(RRDHOST *host) { - if(!host) return; - - info("Saving/Closing 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 host files - -void rrdhost_delete_charts(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); - } - - recursively_delete_dir(host->cache_dir, "left over host"); - - rrdhost_unlock(host); -} - -// ---------------------------------------------------------------------------- -// RRDHOST - cleanup host files - -void rrdhost_cleanup_charts(RRDHOST *host) { - if(!host) return; - - info("Cleaning up database of host '%s'...", host->hostname); - - RRDSET *st; - uint32_t rrdhost_delete_obsolete_charts = rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS); - - // 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); - - if(rrdhost_delete_obsolete_charts && rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)) - rrdset_delete(st); - else - rrdset_save(st); - - rrdset_unlock(st); - } - - rrdhost_unlock(host); -} - - -// ---------------------------------------------------------------------------- -// RRDHOST - save all hosts to disk - -void rrdhost_save_all(void) { - info("Saving database [%zu hosts(s)]...", rrd_hosts_available); - - rrd_rdlock(); - - RRDHOST *host; - rrdhost_foreach_read(host) - rrdhost_save_charts(host); - - rrd_unlock(); -} - -// ---------------------------------------------------------------------------- -// RRDHOST - save or delete all hosts from disk - -void rrdhost_cleanup_all(void) { - info("Cleaning up database [%zu hosts(s)]...", rrd_hosts_available); - - rrd_rdlock(); - - RRDHOST *host; - rrdhost_foreach_read(host) { - if(host != localhost && rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS) && !host->connected_senders) - rrdhost_delete_charts(host); - else - rrdhost_cleanup_charts(host); - } - - rrd_unlock(); -} - - -// ---------------------------------------------------------------------------- -// RRDHOST - save or delete all the host charts from disk - -void rrdhost_cleanup_obsolete_charts(RRDHOST *host) { - time_t now = now_realtime_sec(); - - RRDSET *st; - - uint32_t rrdhost_delete_obsolete_charts = rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS); - -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_delete_obsolete_charts) - 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 deleted file mode 100644 index 8f71c6d4c..000000000 --- a/src/rrdpush.c +++ /dev/null @@ -1,1160 +0,0 @@ -#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..." - -typedef enum { - RRDPUSH_MULTIPLE_CONNECTIONS_ALLOW, - RRDPUSH_MULTIPLE_CONNECTIONS_DENY_NEW -} RRDPUSH_MULTIPLE_CONNECTIONS_STRATEGY; - -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 -unsigned int remote_clock_resync_iterations = 60; - -#define rrdpush_buffer_lock(host) netdata_mutex_lock(&((host)->rrdpush_sender_buffer_mutex)) -#define rrdpush_buffer_unlock(host) netdata_mutex_unlock(&((host)->rrdpush_sender_buffer_mutex)) - -// checks if the current chart definition has been sent -static inline int need_to_send_chart_definition(RRDSET *st) { - rrdset_check_rdlock(st); - - if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_EXPOSED_UPSTREAM)))) - return 1; - - RRDDIM *rd; - rrddim_foreach_read(rd, st) - if(unlikely(!rd->exposed)) - return 1; - - return 0; -} - -// sends the current chart definition -static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) { - RRDHOST *host = st->rrdhost; - - rrdset_flag_set(st, RRDSET_FLAG_EXPOSED_UPSTREAM); - - // send the chart - buffer_sprintf( - host->rrdpush_sender_buffer - , "CHART \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %ld %d \"%s %s %s %s\" \"%s\" \"%s\"\n" - , st->id - , st->name - , st->title - , st->units - , st->family - , st->context - , rrdset_type_name(st->chart_type) - , st->priority - , st->update_every - , rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)?"obsolete":"" - , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?"detail":"" - , rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST)?"store_first":"" - , rrdset_flag_check(st, RRDSET_FLAG_HIDDEN)?"hidden":"" - , (st->plugin_name)?st->plugin_name:"" - , (st->module_name)?st->module_name:"" - ); - - // send the dimensions - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - buffer_sprintf( - host->rrdpush_sender_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; - } - - // send the chart local custom variables - RRDSETVAR *rs; - for(rs = st->variables; rs ;rs = rs->next) { - if(unlikely(rs->options && RRDVAR_OPTION_ALLOCATED)) { - calculated_number *value = (calculated_number *) rs->value; - - buffer_sprintf( - host->rrdpush_sender_buffer - , "VARIABLE CHART %s = " CALCULATED_NUMBER_FORMAT "\n" - , rs->variable - , *value - ); - } - } - - st->upstream_resync_time = st->last_collected_time.tv_sec + (remote_clock_resync_iterations * st->update_every); -} - -// sends the current chart dimensions -static inline void rrdpush_send_chart_metrics_nolock(RRDSET *st) { - RRDHOST *host = st->rrdhost; - buffer_sprintf(host->rrdpush_sender_buffer, "BEGIN \"%s\" %llu\n", st->id, (st->upstream_resync_time > st->last_collected_time.tv_sec)?st->usec_since_last_update:0); - - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - if(rd->updated && rd->exposed) - buffer_sprintf(host->rrdpush_sender_buffer - , "SET \"%s\" = " COLLECTED_NUMBER_FORMAT "\n" - , rd->id - , rd->collected_value - ); - } - - buffer_strcat(host->rrdpush_sender_buffer, "END\n"); -} - -static void rrdpush_sender_thread_spawn(RRDHOST *host); - -void rrdset_push_chart_definition(RRDSET *st) { - RRDHOST *host = st->rrdhost; - - rrdset_rdlock(st); - rrdpush_buffer_lock(host); - rrdpush_send_chart_definition_nolock(st); - rrdpush_buffer_unlock(host); - rrdset_unlock(st); -} - -void rrdset_done_push(RRDSET *st) { - RRDHOST *host = st->rrdhost; - - if(unlikely(!rrdset_flag_check(st, RRDSET_FLAG_ENABLED))) - return; - - rrdpush_buffer_lock(host); - - if(unlikely(host->rrdpush_send_enabled && !host->rrdpush_sender_spawn)) - rrdpush_sender_thread_spawn(host); - - if(unlikely(!host->rrdpush_sender_buffer || !host->rrdpush_sender_connected)) { - if(unlikely(!host->rrdpush_sender_error_shown)) - error("STREAM %s [send]: not ready - discarding collected metrics.", host->hostname); - - host->rrdpush_sender_error_shown = 1; - - rrdpush_buffer_unlock(host); - return; - } - else if(unlikely(host->rrdpush_sender_error_shown)) { - info("STREAM %s [send]: sending metrics...", host->hostname); - host->rrdpush_sender_error_shown = 0; - } - - if(need_to_send_chart_definition(st)) - rrdpush_send_chart_definition_nolock(st); - - rrdpush_send_chart_metrics_nolock(st); - - // signal the sender there are more data - if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1 && write(host->rrdpush_sender_pipe[PIPE_WRITE], " ", 1) == -1) - error("STREAM %s [send]: cannot write to internal pipe", host->hostname); - - rrdpush_buffer_unlock(host); -} - -// ---------------------------------------------------------------------------- -// rrdpush sender thread - -static inline void rrdpush_sender_add_host_variable_to_buffer_nolock(RRDHOST *host, RRDVAR *rv) { - calculated_number *value = (calculated_number *)rv->value; - - buffer_sprintf( - host->rrdpush_sender_buffer - , "VARIABLE HOST %s = " CALCULATED_NUMBER_FORMAT "\n" - , rv->name - , *value - ); - - debug(D_STREAM, "RRDVAR pushed HOST VARIABLE %s = " CALCULATED_NUMBER_FORMAT, rv->name, *value); -} - -void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv) { - if(host->rrdpush_send_enabled && host->rrdpush_sender_spawn && host->rrdpush_sender_connected) { - rrdpush_buffer_lock(host); - rrdpush_sender_add_host_variable_to_buffer_nolock(host, rv); - rrdpush_buffer_unlock(host); - } -} - -static int rrdpush_sender_thread_custom_host_variables_callback(void *rrdvar_ptr, void *host_ptr) { - RRDVAR *rv = (RRDVAR *)rrdvar_ptr; - RRDHOST *host = (RRDHOST *)host_ptr; - - if(unlikely(rv->type == RRDVAR_TYPE_CALCULATED_ALLOCATED)) { - rrdpush_sender_add_host_variable_to_buffer_nolock(host, rv); - - // return 1, so that the traversal will return the number of variables sent - return 1; - } - - // returning a negative number will break the traversal - return 0; -} - -static void rrdpush_sender_thread_send_custom_host_variables(RRDHOST *host) { - int ret = rrdvar_callback_for_all_host_variables(host, rrdpush_sender_thread_custom_host_variables_callback, host); - debug(D_STREAM, "RRDVAR sent %d VARIABLES", ret); -} - -// 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) { - rrdset_flag_clear(st, RRDSET_FLAG_EXPOSED_UPSTREAM); - - st->upstream_resync_time = 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_buffer_lock(host); - - if(buffer_strlen(host->rrdpush_sender_buffer)) - error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", host->hostname, buffer_strlen(host->rrdpush_sender_buffer)); - - buffer_flush(host->rrdpush_sender_buffer); - - rrdpush_sender_thread_reset_all_charts(host); - rrdpush_sender_thread_send_custom_host_variables(host); - - rrdpush_buffer_unlock(host); -} - -void rrdpush_sender_thread_stop(RRDHOST *host) { - rrdpush_buffer_lock(host); - rrdhost_wrlock(host); - - netdata_thread_t thr = 0; - - if(host->rrdpush_sender_spawn) { - info("STREAM %s [send]: signaling sending thread to stop...", host->hostname); - - // signal the thread that we want to join it - host->rrdpush_sender_join = 1; - - // copy the thread id, so that we will be waiting for the right one - // even if a new one has been spawn - thr = host->rrdpush_sender_thread; - - // signal it to cancel - netdata_thread_cancel(host->rrdpush_sender_thread); - } - - rrdhost_unlock(host); - rrdpush_buffer_unlock(host); - - if(thr != 0) { - info("STREAM %s [send]: waiting for the sending thread to stop...", host->hostname); - void *result; - netdata_thread_join(thr, &result); - info("STREAM %s [send]: sending thread has exited.", host->hostname); - } -} - -static inline void rrdpush_sender_thread_close_socket(RRDHOST *host) { - host->rrdpush_sender_connected = 0; - - if(host->rrdpush_sender_socket != -1) { - close(host->rrdpush_sender_socket); - host->rrdpush_sender_socket = -1; - } -} - -static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_port, int timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) { - struct timeval tv = { - .tv_sec = timeout, - .tv_usec = 0 - }; - - // make sure the socket is closed - rrdpush_sender_thread_close_socket(host); - - debug(D_STREAM, "STREAM: Attempting to connect..."); - info("STREAM %s [send to %s]: connecting...", host->hostname, host->rrdpush_send_destination); - - host->rrdpush_sender_socket = connect_to_one_of( - host->rrdpush_send_destination - , default_port - , &tv - , reconnects_counter - , connected_to - , connected_to_size - ); - - if(unlikely(host->rrdpush_sender_socket == -1)) { - error("STREAM %s [send to %s]: failed to connect", host->hostname, host->rrdpush_send_destination); - return 0; - } - - info("STREAM %s [send to %s]: initializing communication...", host->hostname, connected_to); - - #define HTTP_HEADER_SIZE 8192 - char http[HTTP_HEADER_SIZE + 1]; - snprintfz(http, HTTP_HEADER_SIZE, - "STREAM key=%s&hostname=%s®istry_hostname=%s&machine_guid=%s&update_every=%d&os=%s&timezone=%s&tags=%s HTTP/1.1\r\n" - "User-Agent: %s/%s\r\n" - "Accept: */*\r\n\r\n" - , host->rrdpush_send_api_key - , host->hostname - , host->registry_hostname - , host->machine_guid - , default_rrd_update_every - , host->os - , host->timezone - , (host->tags)?host->tags:"" - , host->program_name - , host->program_version - ); - - if(send_timeout(host->rrdpush_sender_socket, http, strlen(http), 0, timeout) == -1) { - error("STREAM %s [send to %s]: failed to send HTTP header to remote netdata.", host->hostname, connected_to); - rrdpush_sender_thread_close_socket(host); - return 0; - } - - info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, connected_to); - - if(recv_timeout(host->rrdpush_sender_socket, http, HTTP_HEADER_SIZE, 0, timeout) == -1) { - error("STREAM %s [send to %s]: remote netdata does not respond.", host->hostname, connected_to); - rrdpush_sender_thread_close_socket(host); - return 0; - } - - if(strncmp(http, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT)) != 0) { - error("STREAM %s [send to %s]: server is not replying properly (is it a netdata?).", host->hostname, connected_to); - rrdpush_sender_thread_close_socket(host); - return 0; - } - - info("STREAM %s [send to %s]: established communication - ready to send metrics...", host->hostname, connected_to); - - if(sock_setnonblock(host->rrdpush_sender_socket) < 0) - error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", host->hostname, connected_to); - - if(sock_enlarge_out(host->rrdpush_sender_socket) < 0) - error("STREAM %s [send to %s]: cannot enlarge the socket buffer.", host->hostname, connected_to); - - debug(D_STREAM, "STREAM: Connected on fd %d...", host->rrdpush_sender_socket); - - return 1; -} - -static void rrdpush_sender_thread_cleanup_callback(void *ptr) { - RRDHOST *host = (RRDHOST *)ptr; - - rrdpush_buffer_lock(host); - rrdhost_wrlock(host); - - info("STREAM %s [send]: sending thread cleans up...", host->hostname); - - rrdpush_sender_thread_close_socket(host); - - // close the pipe - if(host->rrdpush_sender_pipe[PIPE_READ] != -1) { - close(host->rrdpush_sender_pipe[PIPE_READ]); - host->rrdpush_sender_pipe[PIPE_READ] = -1; - } - - if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1) { - close(host->rrdpush_sender_pipe[PIPE_WRITE]); - host->rrdpush_sender_pipe[PIPE_WRITE] = -1; - } - - buffer_free(host->rrdpush_sender_buffer); - host->rrdpush_sender_buffer = NULL; - - if(!host->rrdpush_sender_join) { - info("STREAM %s [send]: sending thread detaches itself.", host->hostname); - netdata_thread_detach(netdata_thread_self()); - } - - host->rrdpush_sender_spawn = 0; - - info("STREAM %s [send]: sending thread now exits.", host->hostname); - - rrdhost_unlock(host); - rrdpush_buffer_unlock(host); -} - -void *rrdpush_sender_thread(void *ptr) { - RRDHOST *host = (RRDHOST *)ptr; - - if(!host->rrdpush_send_enabled || !host->rrdpush_send_destination || !*host->rrdpush_send_destination || !host->rrdpush_send_api_key || !*host->rrdpush_send_api_key) { - error("STREAM %s [send]: thread created (task id %d), but host has streaming disabled.", host->hostname, gettid()); - return NULL; - } - - info("STREAM %s [send]: thread created (task id %d)", host->hostname, gettid()); - - 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] = ""; - - // initialize rrdpush globals - host->rrdpush_sender_buffer = buffer_create(1); - host->rrdpush_sender_connected = 0; - if(pipe(host->rrdpush_sender_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_bytes_on_this_connection = 0; - - - time_t last_sent_t = 0; - struct pollfd fds[2], *ifd, *ofd; - nfds_t fdmax; - - ifd = &fds[0]; - ofd = &fds[1]; - - size_t not_connected_loops = 0; - - netdata_thread_cleanup_push(rrdpush_sender_thread_cleanup_callback, host); - - for(; host->rrdpush_send_enabled && !netdata_exit ;) { - // check for outstanding cancellation requests - netdata_thread_testcancel(); - - // if we don't have socket open, lets wait a bit - if(unlikely(host->rrdpush_sender_socket == -1)) { - if(not_connected_loops == 0 && sent_bytes_on_this_connection > 0) { - // fast re-connection on first disconnect - sleep_usec(USEC_PER_MS * 500); // milliseconds - } - else { - // slow re-connection on repeating errors - sleep_usec(USEC_PER_SEC * reconnect_delay); // seconds - } - - if(rrdpush_sender_thread_connect_to_master(host, default_port, timeout, &reconnects_counter, connected_to, CONNECTED_TO_SIZE)) { - last_sent_t = now_monotonic_sec(); - - // reset the buffer, to properly send charts and metrics - rrdpush_sender_thread_data_flush(host); - - // make sure the next reconnection will be immediate - not_connected_loops = 0; - - // reset the bytes we have sent for this session - sent_bytes_on_this_connection = 0; - - // let the data collection threads know we are ready - host->rrdpush_sender_connected = 1; - } - else { - // increase the failed connections counter - not_connected_loops++; - - // reset the number of bytes sent - sent_bytes_on_this_connection = 0; - } - - // loop through - continue; - } - else if(unlikely(now_monotonic_sec() - last_sent_t > timeout)) { - error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, timeout, sent_bytes_on_this_connection); - rrdpush_sender_thread_close_socket(host); - } - - ifd->fd = host->rrdpush_sender_pipe[PIPE_READ]; - ifd->events = POLLIN; - ifd->revents = 0; - - ofd->fd = host->rrdpush_sender_socket; - ofd->revents = 0; - if(ofd->fd != -1 && begin < buffer_strlen(host->rrdpush_sender_buffer)) { - debug(D_STREAM, "STREAM: Requesting data output on streaming socket %d...", ofd->fd); - ofd->events = POLLOUT; - fdmax = 2; - } - else { - debug(D_STREAM, "STREAM: Not requesting data output on streaming socket %d (nothing to send now)...", ofd->fd); - ofd->events = 0; - fdmax = 1; - } - - debug(D_STREAM, "STREAM: Waiting for poll() events (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_sender_buffer)); - if(unlikely(netdata_exit)) break; - int retval = poll(fds, fdmax, 1000); - if(unlikely(netdata_exit)) break; - - if(unlikely(retval == -1)) { - debug(D_STREAM, "STREAM: poll() failed (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_sender_buffer)); - - if(errno == EAGAIN || errno == EINTR) { - debug(D_STREAM, "STREAM: poll() failed with EAGAIN or EINTR..."); - } - else { - error("STREAM %s [send to %s]: failed to poll(). Closing socket.", host->hostname, connected_to); - rrdpush_sender_thread_close_socket(host); - } - - continue; - } - else if(likely(retval)) { - if (ifd->revents & POLLIN || ifd->revents & POLLPRI) { - debug(D_STREAM, "STREAM: Data added to send buffer (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_sender_buffer)); - - char buffer[1000 + 1]; - if (read(host->rrdpush_sender_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) { - if (begin < buffer_strlen(host->rrdpush_sender_buffer)) { - debug(D_STREAM, "STREAM: Sending data (current buffer length %zu bytes, begin = %zu)...", buffer_strlen(host->rrdpush_sender_buffer), begin); - - // BEGIN RRDPUSH LOCKED SESSION - - // during this session, data collectors - // will not be able to append data to our buffer - // but the socket is in non-blocking mode - // so, we will not block at send() - - netdata_thread_disable_cancelability(); - - debug(D_STREAM, "STREAM: Getting exclusive lock on host..."); - rrdpush_buffer_lock(host); - - debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_sender_buffer)); - ssize_t ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT); - if (unlikely(ret == -1)) { - if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { - debug(D_STREAM, "STREAM: Send failed - closing socket..."); - error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_bytes_on_this_connection); - rrdpush_sender_thread_close_socket(host); - } - else { - debug(D_STREAM, "STREAM: Send failed - will retry..."); - } - } - else if (likely(ret > 0)) { - // DEBUG - dump the string to see it - //char c = host->rrdpush_sender_buffer->buffer[begin + ret]; - //host->rrdpush_sender_buffer->buffer[begin + ret] = '\0'; - //debug(D_STREAM, "STREAM: sent from %zu to %zd:\n%s\n", begin, ret, &host->rrdpush_sender_buffer->buffer[begin]); - //host->rrdpush_sender_buffer->buffer[begin + ret] = c; - - sent_bytes_on_this_connection += ret; - sent_bytes += ret; - begin += ret; - - if (begin == buffer_strlen(host->rrdpush_sender_buffer)) { - // we send it all - - debug(D_STREAM, "STREAM: Sent %zd bytes (the whole buffer)...", ret); - buffer_flush(host->rrdpush_sender_buffer); - begin = 0; - } - else { - debug(D_STREAM, "STREAM: Sent %zd bytes (part of the data buffer)...", ret); - } - - last_sent_t = now_monotonic_sec(); - } - else { - debug(D_STREAM, "STREAM: send() returned %zd - closing the socket...", ret); - error("STREAM %s [send to %s]: failed to send metrics (send() returned %zd) - closing connection - we have sent %zu bytes on this connection.", - host->hostname, connected_to, ret, sent_bytes_on_this_connection); - rrdpush_sender_thread_close_socket(host); - } - - debug(D_STREAM, "STREAM: Releasing exclusive lock on host..."); - rrdpush_buffer_unlock(host); - - netdata_thread_enable_cancelability(); - - // END RRDPUSH LOCKED SESSION - } - else { - debug(D_STREAM, "STREAM: we have sent the entire buffer, but we received POLLOUT..."); - } - } - - if(host->rrdpush_sender_socket != -1) { - char *error = NULL; - - if (unlikely(ofd->revents & POLLERR)) - error = "socket reports errors (POLLERR)"; - - else if (unlikely(ofd->revents & POLLHUP)) - error = "connection closed by remote end (POLLHUP)"; - - else if (unlikely(ofd->revents & POLLNVAL)) - error = "connection is invalid (POLLNVAL)"; - - if(unlikely(error)) { - debug(D_STREAM, "STREAM: %s - closing socket...", error); - error("STREAM %s [send to %s]: %s - reopening socket - we have sent %zu bytes on this connection.", host->hostname, connected_to, error, sent_bytes_on_this_connection); - rrdpush_sender_thread_close_socket(host); - } - } - } - else { - debug(D_STREAM, "STREAM: poll() timed out."); - } - - // protection from overflow - if(buffer_strlen(host->rrdpush_sender_buffer) > max_size) { - debug(D_STREAM, "STREAM: Buffer is too big (%zu bytes), bigger than the max (%zu) - flushing it...", buffer_strlen(host->rrdpush_sender_buffer), 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_sender_buffer->len, host->rrdpush_sender_buffer->len - begin, sent_bytes, sent_bytes_on_this_connection); - rrdpush_sender_thread_close_socket(host); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - - -// ---------------------------------------------------------------------------- -// rrdpush receiver thread - -static void log_stream_connection(const char *client_ip, const char *client_port, const char *api_key, const char *machine_guid, const char *host, const char *msg) { - log_access("STREAM: %d '[%s]:%s' '%s' host '%s' api key '%s' machine guid '%s'", gettid(), client_ip, client_port, msg, host, api_key, machine_guid); -} - -static RRDPUSH_MULTIPLE_CONNECTIONS_STRATEGY get_multiple_connections_strategy(struct config *c, const char *section, const char *name, RRDPUSH_MULTIPLE_CONNECTIONS_STRATEGY def) { - char *value; - switch(def) { - default: - case RRDPUSH_MULTIPLE_CONNECTIONS_ALLOW: - value = "allow"; - break; - - case RRDPUSH_MULTIPLE_CONNECTIONS_DENY_NEW: - value = "deny"; - break; - } - - value = appconfig_get(c, section, name, value); - - RRDPUSH_MULTIPLE_CONNECTIONS_STRATEGY ret = def; - - if(strcasecmp(value, "allow") == 0 || strcasecmp(value, "permit") == 0 || strcasecmp(value, "accept") == 0) - ret = RRDPUSH_MULTIPLE_CONNECTIONS_ALLOW; - - else if(strcasecmp(value, "deny") == 0 || strcasecmp(value, "reject") == 0 || strcasecmp(value, "block") == 0) - ret = RRDPUSH_MULTIPLE_CONNECTIONS_DENY_NEW; - - else - error("Invalid stream config value at section [%s], setting '%s', value '%s'", section, name, value); - - return ret; -} - -static int rrdpush_receive(int fd - , const char *key - , const char *hostname - , const char *registry_hostname - , const char *machine_guid - , const char *os - , const char *timezone - , const char *tags - , const char *program_name - , const char *program_version - , 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; - RRDPUSH_MULTIPLE_CONNECTIONS_STRATEGY rrdpush_multiple_connections_strategy = RRDPUSH_MULTIPLE_CONNECTIONS_ALLOW; - - 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); - - rrdpush_multiple_connections_strategy = get_multiple_connections_strategy(&stream_config, key, "multiple connections", rrdpush_multiple_connections_strategy); - rrdpush_multiple_connections_strategy = get_multiple_connections_strategy(&stream_config, machine_guid, "multiple connections", rrdpush_multiple_connections_strategy); - - tags = appconfig_set_default(&stream_config, machine_guid, "host tags", (tags)?tags:""); - if(tags && !*tags) tags = NULL; - - if(!strcmp(machine_guid, "localhost")) - host = localhost; - else - host = rrdhost_find_or_create( - hostname - , registry_hostname - , machine_guid - , os - , timezone - , tags - , program_name - , program_version - , 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); - log_stream_connection(client_ip, client_port, key, machine_guid, hostname, "FAILED - CANNOT ACQUIRE HOST"); - 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, tags '%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") - , host->tags?host->tags:"" - ); -#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)) { - log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "FAILED - CANNOT REPLY"); - 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(sock_delnonblock(fd) < 0) - 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) { - log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "FAILED - SOCKET ERROR"); - 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); - if(host->connected_senders > 0) { - switch(rrdpush_multiple_connections_strategy) { - case RRDPUSH_MULTIPLE_CONNECTIONS_ALLOW: - info("STREAM %s [receive from [%s]:%s]: multiple streaming connections for the same host detected. If multiple netdata are pushing metrics for the same charts, at the same time, the result is unexpected.", host->hostname, client_ip, client_port); - break; - - case RRDPUSH_MULTIPLE_CONNECTIONS_DENY_NEW: - rrdhost_unlock(host); - log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "REJECTED - ALREADY CONNECTED"); - info("STREAM %s [receive from [%s]:%s]: multiple streaming connections for the same host detected. Rejecting new connection.", host->hostname, client_ip, client_port); - fclose(fp); - return 0; - } - } - - rrdhost_flag_clear(host, RRDHOST_FLAG_ORPHAN); - host->connected_senders++; - host->senders_disconnected_time = 0; - if(health_enabled != CONFIG_BOOLEAN_NO) { - if(alarms_delay > 0) { - host->health_delay_up_to = now_realtime_sec() + alarms_delay; - info("Postponing health checks for %ld seconds, on host '%s', because it was just connected." - , alarms_delay - , host->hostname - ); - } - } - rrdhost_unlock(host); - - // call the plugins.d processor to receive the metrics - info("STREAM %s [receive from [%s]:%s]: receiving metrics...", host->hostname, client_ip, client_port); - log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "CONNECTED"); - - size_t count = pluginsd_process(host, &cd, fp, 1); - - log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "DISCONNECTED"); - error("STREAM %s [receive from [%s]:%s]: disconnected (completed %zu updates).", host->hostname, client_ip, client_port, count); - - rrdhost_wrlock(host); - host->senders_disconnected_time = now_realtime_sec(); - host->connected_senders--; - if(!host->connected_senders) { - rrdhost_flag_set(host, RRDHOST_FLAG_ORPHAN); - if(health_enabled == CONFIG_BOOLEAN_AUTO) - host->health_enabled = 0; - } - rrdhost_unlock(host); - - if(host->connected_senders == 0) - rrdpush_sender_thread_stop(host); - - // cleanup - fclose(fp); - - return (int)count; -} - -struct rrdpush_thread { - int fd; - char *key; - char *hostname; - char *registry_hostname; - char *machine_guid; - char *os; - char *timezone; - char *tags; - char *client_ip; - char *client_port; - char *program_name; - char *program_version; - int update_every; -}; - -static void rrdpush_receiver_thread_cleanup(void *ptr) { - static __thread int executed = 0; - if(!executed) { - executed = 1; - struct rrdpush_thread *rpt = (struct rrdpush_thread *) ptr; - - 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->registry_hostname); - freez(rpt->machine_guid); - freez(rpt->os); - freez(rpt->timezone); - freez(rpt->tags); - freez(rpt->client_ip); - freez(rpt->client_port); - freez(rpt->program_name); - freez(rpt->program_version); - freez(rpt); - } -} - -static void *rrdpush_receiver_thread(void *ptr) { - netdata_thread_cleanup_push(rrdpush_receiver_thread_cleanup, ptr); - - struct rrdpush_thread *rpt = (struct rrdpush_thread *)ptr; - 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->registry_hostname - , rpt->machine_guid - , rpt->os - , rpt->timezone - , rpt->tags - , rpt->program_name - , rpt->program_version - , rpt->update_every - , rpt->client_ip - , rpt->client_port - ); - - netdata_thread_cleanup_pop(1); - return NULL; -} - -static void rrdpush_sender_thread_spawn(RRDHOST *host) { - rrdhost_wrlock(host); - - if(!host->rrdpush_sender_spawn) { - char tag[NETDATA_THREAD_TAG_MAX + 1]; - snprintfz(tag, NETDATA_THREAD_TAG_MAX, "STREAM_SENDER[%s]", host->hostname); - - if(netdata_thread_create(&host->rrdpush_sender_thread, tag, NETDATA_THREAD_OPTION_JOINABLE, rrdpush_sender_thread, (void *) host)) - error("STREAM %s [send]: failed to create new thread for client.", host->hostname); - else - host->rrdpush_sender_spawn = 1; - } - - rrdhost_unlock(host); -} - -int rrdpush_receiver_permission_denied(struct web_client *w) { - // we always respond with the same message and error code - // to prevent an attacker from gaining info about the error - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "You are not permitted to access this. Check the logs for more info."); - return 401; -} - -int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url) { - (void)host; - - info("clients wants to STREAM metrics."); - - char *key = NULL, *hostname = NULL, *registry_hostname = NULL, *machine_guid = NULL, *os = "unknown", *timezone = "unknown", *tags = NULL; - 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, "registry_hostname")) - registry_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; - else if(!strcmp(name, "timezone")) - timezone = value; - else if(!strcmp(name, "tags")) - tags = value; - else - info("STREAM [receive from [%s]:%s]: request has parameter '%s' = '%s', which is not used.", w->client_ip, w->client_port, key, value); - } - - if(!key || !*key) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO KEY"); - error("STREAM [receive from [%s]:%s]: request without an API key. Forbidding access.", w->client_ip, w->client_port); - return rrdpush_receiver_permission_denied(w); - } - - if(!hostname || !*hostname) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO HOSTNAME"); - error("STREAM [receive from [%s]:%s]: request without a hostname. Forbidding access.", w->client_ip, w->client_port); - return rrdpush_receiver_permission_denied(w); - } - - if(!machine_guid || !*machine_guid) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO MACHINE GUID"); - error("STREAM [receive from [%s]:%s]: request without a machine GUID. Forbidding access.", w->client_ip, w->client_port); - return rrdpush_receiver_permission_denied(w); - } - - if(regenerate_guid(key, buf) == -1) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - INVALID KEY"); - error("STREAM [receive from [%s]:%s]: API key '%s' is not valid GUID (use the command uuidgen to generate one). Forbidding access.", w->client_ip, w->client_port, key); - return rrdpush_receiver_permission_denied(w); - } - - if(regenerate_guid(machine_guid, buf) == -1) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - INVALID MACHINE GUID"); - error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not GUID. Forbidding access.", w->client_ip, w->client_port, machine_guid); - return rrdpush_receiver_permission_denied(w); - } - - if(!appconfig_get_boolean(&stream_config, key, "enabled", 0)) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - KEY NOT ENABLED"); - error("STREAM [receive from [%s]:%s]: API key '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, key); - return rrdpush_receiver_permission_denied(w); - } - - { - SIMPLE_PATTERN *key_allow_from = simple_pattern_create(appconfig_get(&stream_config, key, "allow from", "*"), NULL, SIMPLE_PATTERN_EXACT); - if(key_allow_from) { - if(!simple_pattern_matches(key_allow_from, w->client_ip)) { - simple_pattern_free(key_allow_from); - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname) ? hostname : "-", "ACCESS DENIED - KEY NOT ALLOWED FROM THIS IP"); - error("STREAM [receive from [%s]:%s]: API key '%s' is not permitted from this IP. Forbidding access.", w->client_ip, w->client_port, key); - return rrdpush_receiver_permission_denied(w); - } - simple_pattern_free(key_allow_from); - } - } - - if(!appconfig_get_boolean(&stream_config, machine_guid, "enabled", 1)) { - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - MACHINE GUID NOT ENABLED"); - error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid); - return rrdpush_receiver_permission_denied(w); - } - - { - SIMPLE_PATTERN *machine_allow_from = simple_pattern_create(appconfig_get(&stream_config, machine_guid, "allow from", "*"), NULL, SIMPLE_PATTERN_EXACT); - if(machine_allow_from) { - if(!simple_pattern_matches(machine_allow_from, w->client_ip)) { - simple_pattern_free(machine_allow_from); - log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname) ? hostname : "-", "ACCESS DENIED - MACHINE GUID NOT ALLOWED FROM THIS IP"); - error("STREAM [receive from [%s]:%s]: Machine GUID '%s' is not permitted from this IP. Forbidding access.", w->client_ip, w->client_port, machine_guid); - return rrdpush_receiver_permission_denied(w); - } - simple_pattern_free(machine_allow_from); - } - } - - struct rrdpush_thread *rpt = callocz(1, sizeof(struct rrdpush_thread)); - rpt->fd = w->ifd; - rpt->key = strdupz(key); - rpt->hostname = strdupz(hostname); - rpt->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname); - rpt->machine_guid = strdupz(machine_guid); - rpt->os = strdupz(os); - rpt->timezone = strdupz(timezone); - rpt->tags = (tags)?strdupz(tags):NULL; - rpt->client_ip = strdupz(w->client_ip); - rpt->client_port = strdupz(w->client_port); - rpt->update_every = update_every; - - if(w->user_agent && w->user_agent[0]) { - char *t = strchr(w->user_agent, '/'); - if(t && *t) { - *t = '\0'; - t++; - } - - rpt->program_name = strdupz(w->user_agent); - if(t && *t) rpt->program_version = strdupz(t); - } - - netdata_thread_t thread; - - debug(D_SYSTEM, "starting STREAM receive thread."); - - char tag[FILENAME_MAX + 1]; - snprintfz(tag, FILENAME_MAX, "STREAM_RECEIVER[%s,[%s]:%s]", rpt->hostname, w->client_ip, w->client_port); - - if(netdata_thread_create(&thread, tag, NETDATA_THREAD_OPTION_DEFAULT, rrdpush_receiver_thread, (void *)rpt)) - error("Failed to create new STREAM receive thread for client."); - - // prevent the caller from closing the streaming socket - if(web_server_mode == WEB_SERVER_MODE_STATIC_THREADED) { - web_client_flag_set(w, WEB_CLIENT_FLAG_DONT_CLOSE_SOCKET); - } - else { - 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 deleted file mode 100644 index bf3d9435c..000000000 --- a/src/rrdpush.h +++ /dev/null @@ -1,19 +0,0 @@ -#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 unsigned int remote_clock_resync_iterations; - -extern int rrdpush_init(); -extern void rrdset_done_push(RRDSET *st); -extern void rrdset_push_chart_definition(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); - -extern void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv); - -#endif //NETDATA_RRDPUSH_H diff --git a/src/rrdset.c b/src/rrdset.c deleted file mode 100644 index bbd0ae728..000000000 --- a/src/rrdset.c +++ /dev/null @@ -1,1544 +0,0 @@ -#define NETDATA_RRD_INTERNALS 1 -#include "common.h" - -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) != 0) - 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; -} - -int rrdset_set_name(RRDSET *st, const char *name) { - if(unlikely(st->name && !strcmp(st->name, name))) - return 1; - - RRDHOST *host = st->rrdhost; - - debug(D_RRD_CALLS, "rrdset_set_name() old: '%s', new: '%s'", st->name?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(rrdset_index_find_name(host, b, 0)) { - error("RRDSET: chart name '%s' on host '%s' already exists.", b, host->hostname); - return 0; - } - - if(st->name) { - rrdset_index_del_name(host, 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(host, st) != st)) - error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name); - - return 1; -} - -inline void rrdset_is_obsolete(RRDSET *st) { - RRDHOST *host = st->rrdhost; - - if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))) { - rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE); - rrdset_flag_clear(st, RRDSET_FLAG_EXPOSED_UPSTREAM); - - // the chart will not get more updates (data collection) - // so, we have to push its definition now - if(unlikely(host->rrdpush_send_enabled)) - rrdset_push_chart_definition(st); - } -} - -inline void rrdset_isnot_obsolete(RRDSET *st) { - if(unlikely((rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))) { - rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE); - rrdset_flag_clear(st, RRDSET_FLAG_EXPOSED_UPSTREAM); - - // the chart will be pushed upstream automatically - // due to data collection - } -} - -inline void rrdset_update_heterogeneous_flag(RRDSET *st) { - RRDHOST *host = st->rrdhost; - RRDDIM *rd; - - rrdset_flag_clear(st, RRDSET_FLAG_HOMEGENEOUS_CHECK); - - RRD_ALGORITHM algorithm = st->dimensions->algorithm; - collected_number multiplier = abs(st->dimensions->multiplier); - collected_number divisor = abs(st->dimensions->divisor); - - rrddim_foreach_read(rd, st) { - if(algorithm != rd->algorithm || multiplier != abs(rd->multiplier) || divisor != abs(rd->divisor)) { - if(!rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS)) { - #ifdef NETDATA_INTERNAL_CHECKS - info("Dimension '%s' added on chart '%s' of host '%s' is not homogeneous to other dimensions already present (algorithm is '%s' vs '%s', multiplier is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ", divisor is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ").", - rd->name, - st->name, - host->hostname, - rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm), - rd->multiplier, multiplier, - rd->divisor, divisor - ); - #endif - rrdset_flag_set(st, RRDSET_FLAG_HETEROGENEOUS); - } - return; - } - } - - rrdset_flag_clear(st, RRDSET_FLAG_HETEROGENEOUS); -} - -// ---------------------------------------------------------------------------- -// 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_ALLOC)) - 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(RRDSET *st) { - st->last_collected_time.tv_sec -= st->last_collected_time.tv_sec % st->update_every; - - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST))) - st->last_collected_time.tv_usec = 0; - else - st->last_collected_time.tv_usec = 500000; -} - -static inline void last_updated_time_align(RRDSET *st) { - st->last_updated.tv_sec -= st->last_updated.tv_sec % st->update_every; - st->last_updated.tv_usec = 0; -} - -// ---------------------------------------------------------------------------- -// RRDSET - free a chart - -void rrdset_free(RRDSET *st) { - if(unlikely(!st)) return; - - RRDHOST *host = st->rrdhost; - - rrdhost_check_wrlock(host); // 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(host, st) != st)) - error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id); - - rrdset_index_del_name(host, 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(host, st->rrdfamily); - - debug(D_RRD_CALLS, "RRDSET: Cleaning up remaining chart variables for host '%s', chart '%s'", host->hostname, st->id); - rrdvar_free_remaining_variables(host, &st->rrdvar_root_index); - - // ------------------------------------------------------------------------ - // unlink it from the host - - if(st == host->rrdset_root) { - host->rrdset_root = st->next; - } - else { - // find the previous one - RRDSET *s; - for(s = host->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, host->hostname); - } - - rrdset_unlock(st); - - // ------------------------------------------------------------------------ - // free it - - netdata_rwlock_destroy(&st->rrdset_rwlock); - - // free directly allocated members - freez(st->config_section); - freez(st->plugin_name); - freez(st->module_name); - - switch(st->rrd_memory_mode) { - case RRD_MEMORY_MODE_SAVE: - case RRD_MEMORY_MODE_MAP: - case RRD_MEMORY_MODE_RAM: - debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name); - munmap(st, st->memsize); - break; - - case RRD_MEMORY_MODE_ALLOC: - case RRD_MEMORY_MODE_NONE: - freez(st); - break; - } -} - -void rrdset_save(RRDSET *st) { - 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); - memory_file_save(st->cache_filename, st, st->memsize); - } - - RRDDIM *rd; - 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); - memory_file_save(rd->cache_filename, rd, rd->memsize); - } - } -} - -void rrdset_delete(RRDSET *st) { - RRDDIM *rd; - - rrdset_check_rdlock(st); - - info("Deleting chart '%s' ('%s') from disk...", st->id, st->name); - - if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) { - info("Deleting chart header file '%s'.", st->cache_filename); - if(unlikely(unlink(st->cache_filename) == -1)) - error("Cannot delete chart header file '%s'", st->cache_filename); - } - - rrddim_foreach_read(rd, st) { - if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || rd->rrd_memory_mode == RRD_MEMORY_MODE_MAP)) { - info("Deleting dimension file '%s'.", rd->cache_filename); - if(unlikely(unlink(rd->cache_filename) == -1)) - error("Cannot delete dimension file '%s'", rd->cache_filename); - } - } - - recursively_delete_dir(st->cache_dir, "left-over chart"); -} - -// ---------------------------------------------------------------------------- -// 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_isnot_obsolete(st); - debug(D_RRD_CALLS, "RRDSET '%s', already exists.", fullid); - return st; - } - - return NULL; -} - -RRDSET *rrdset_create_custom( - RRDHOST *host - , const char *type - , const char *id - , const char *name - , const char *family - , const char *context - , const char *title - , const char *units - , const char *plugin - , const char *module - , long priority - , int update_every - , RRDSET_TYPE chart_type - , RRD_MEMORY_MODE memory_mode - , long history_entries -) { - if(!type || !type[0]) { - fatal("Cannot create rrd stats without a type: id '%s', name '%s', family '%s', context '%s', title '%s', units '%s', plugin '%s', module '%s'." - , (id && *id)?id:"" - , (name && *name)?name:"" - , (family && *family)?family:"" - , (context && *context)?context:"" - , (title && *title)?title:"" - , (units && *units)?units:"" - , (plugin && *plugin)?plugin:"" - , (module && *module)?module:"" - ); - return NULL; - } - - if(!id || !id[0]) { - fatal("Cannot create rrd stats without an id: type '%s', name '%s', family '%s', context '%s', title '%s', units '%s', plugin '%s', module '%s'." - , type - , (name && *name)?name:"" - , (family && *family)?family:"" - , (context && *context)?context:"" - , (title && *title)?title:"" - , (units && *units)?units:"" - , (plugin && *plugin)?plugin:"" - , (module && *module)?module:"" - ); - 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", history_entries); - long entries = align_entries_to_pagesize(memory_mode, rentries); - if(entries != rentries) entries = config_set_number(config_section, "history", entries); - - if(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(memory_mode == RRD_MEMORY_MODE_SAVE || memory_mode == RRD_MEMORY_MODE_MAP || memory_mode == RRD_MEMORY_MODE_RAM) { - st = (RRDSET *) mymmap( - (memory_mode == RRD_MEMORY_MODE_RAM)?NULL:fullfilename - , size - , ((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->rrdvar_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->config_section = NULL; - st->type = NULL; - st->family = NULL; - st->title = NULL; - st->units = NULL; - st->context = NULL; - st->cache_dir = NULL; - st->plugin_name = NULL; - st->module_name = NULL; - st->dimensions = NULL; - st->rrdfamily = NULL; - st->rrdhost = NULL; - st->next = NULL; - st->variables = NULL; - st->alarms = NULL; - st->flags = 0x00000000; - - if(memory_mode == RRD_MEMORY_MODE_RAM) { - memset(st, 0, size); - } - else { - if(strcmp(st->magic, RRDSET_MAGIC) != 0) { - info("Initializing file %s.", fullfilename); - memset(st, 0, size); - } - else if(strcmp(st->id, fullid) != 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) { - error("File %s does not have the desired size. Clearing it.", fullfilename); - memset(st, 0, size); - } - else if(st->update_every != update_every) { - 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) { - error("File %s is too old. Clearing it.", fullfilename); - memset(st, 0, size); - } - else if(st->last_updated.tv_sec > now + update_every) { - 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) { - st->update_every = update_every; - last_updated_time_align(st); - } - } - - // make sure we have the right memory mode - // even if we cleared the memory - st->rrd_memory_mode = memory_mode; - } - } - - if(unlikely(!st)) { - st = callocz(1, size); - st->rrd_memory_mode = (memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_ALLOC; - } - - st->plugin_name = plugin?strdup(plugin):NULL; - st->module_name = module?strdup(module):NULL; - - 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); - json_fix_string(st->family); - - st->units = config_get(st->config_section, "units", units?units:""); - json_fix_string(st->units); - - st->context = config_get(st->config_section, "context", context?context:st->id); - json_fix_string(st->context); - st->hash_context = simple_hash(st->context); - - st->priority = config_get_number(st->config_section, "priority", priority); - 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); - rrdset_flag_clear(st, RRDSET_FLAG_EXPOSED_UPSTREAM); - - // 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) (gap_when_lost_iterations_above + 2); - - st->last_accessed_time = 0; - st->upstream_resync_time = 0; - - avl_init_lock(&st->dimensions_index, rrddim_compare); - avl_init_lock(&st->rrdvar_root_index, rrdvar_compare); - - netdata_rwlock_init(&st->rrdset_rwlock); - - if(name && *name && rrdset_set_name(st, name)) - // we did set the name - ; - else - // could not use the name, use the id - rrdset_set_name(st, id); - - st->title = config_get(st->config_section, "title", title); - json_fix_string(st->title); - - 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, RRDVAR_OPTION_DEFAULT); - rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, RRDVAR_OPTION_DEFAULT); - rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, RRDVAR_OPTION_DEFAULT); - rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, RRDVAR_OPTION_DEFAULT); - rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, RRDVAR_OPTION_DEFAULT); - } - - 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_charts(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 || !microseconds)) { - // call the full next_usec() function - rrdset_next_usec(st, microseconds); - return; - } - - 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 - 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 - info("RRD database for chart '%s' on host '%s' is %0.5" LONG_DOUBLE_MODIFIER " secs in the future (counter #%zu, update #%zu). Adjusting it to current time.", st->id, st->rrdhost->hostname, (LONG_DOUBLE)-since_last_usec / USEC_PER_SEC, st->counter, st->counter_done); - - 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); - - st->last_updated.tv_sec = now.tv_sec - st->update_every; - st->last_updated.tv_usec = now.tv_usec; - last_updated_time_align(st); - - microseconds = st->update_every * USEC_PER_SEC; - } - else if(unlikely((usec_t)since_last_usec > (usec_t)(st->update_every * 10 * USEC_PER_SEC))) { - // oops! the database is too far behind - info("RRD database for chart '%s' on host '%s' is %0.5" LONG_DOUBLE_MODIFIER " secs in the past (counter #%zu, update #%zu). Adjusting it to current time.", st->id, st->rrdhost->hostname, (LONG_DOUBLE)since_last_usec / USEC_PER_SEC, st->counter, st->counter_done); - - microseconds = (usec_t)since_last_usec; - } - } - - #ifdef NETDATA_INTERNAL_CHECKS - debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds); - rrdset_debug(st, "NEXT: %llu microseconds", microseconds); - #endif - - st->usec_since_last_update = microseconds; -} - - -// ---------------------------------------------------------------------------- -// RRDSET - process the collected values for all dimensions of a chart - -static inline usec_t rrdset_init_last_collected_time(RRDSET *st) { - now_realtime_timeval(&st->last_collected_time); - last_collected_time_align(st); - - usec_t last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "initialized last collected time to %0.3" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE)last_collect_ut / USEC_PER_SEC); - #endif - - return last_collect_ut; -} - -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); - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "updated last collected time to %0.3" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE)last_collect_ut / USEC_PER_SEC); - #endif - - return last_collect_ut; -} - -static inline usec_t 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; - - if(rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST)) - st->last_updated.tv_sec -= st->update_every; - - last_updated_time_align(st); - - usec_t last_updated_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "initialized last updated time to %0.3" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE)last_updated_ut / USEC_PER_SEC); - #endif - - return last_updated_ut; -} - -static inline void rrdset_done_push_exclusive(RRDSET *st) { -// usec_t update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds -// -// if(unlikely(st->usec_since_last_update > update_every_ut * remote_clock_resync_iterations)) { -// error("Chart '%s' was last collected %llu usec before. Resetting it.", st->id, st->usec_since_last_update); -// rrdset_reset(st); -// st->usec_since_last_update = update_every_ut; -// } - - 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); -} - - -static inline size_t rrdset_done_interpolate( - RRDSET *st - , usec_t update_every_ut - , usec_t last_stored_ut - , usec_t next_store_ut - , usec_t last_collect_ut - , usec_t now_collect_ut - , char store_this_entry - , uint32_t storage_flags -) { - RRDDIM *rd; - - size_t stored_entries = 0; // the number of entries we have stored in the db, during this call to rrdset_done() - - usec_t first_ut = last_stored_ut, last_ut = 0; - ssize_t iterations = (ssize_t)((now_collect_ut - last_stored_ut) / (update_every_ut)); - if((now_collect_ut % (update_every_ut)) == 0) iterations++; - - size_t counter = st->counter; - long current_entry = st->current_entry; - - 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("INTERNAL CHECK: %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); } - rrdset_debug(st, "last_stored_ut = %0.3" LONG_DOUBLE_MODIFIER " (last updated time)", (LONG_DOUBLE)last_stored_ut/USEC_PER_SEC); - rrdset_debug(st, "next_store_ut = %0.3" LONG_DOUBLE_MODIFIER " (next interpolation point)", (LONG_DOUBLE)next_store_ut/USEC_PER_SEC); - #endif - - last_ut = next_store_ut; - - 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) - ); - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC2 INC " - CALCULATED_NUMBER_FORMAT " = " - CALCULATED_NUMBER_FORMAT - " * (%llu - %llu)" - " / (%llu - %llu)" - , rd->name - , new_value - , rd->calculated_value - , next_store_ut, last_collect_ut - , now_collect_ut, last_collect_ut - ); - #endif - - 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)) { - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: COLLECTION POINT IS SHORT " CALCULATED_NUMBER_FORMAT " - EXTRAPOLATING", - rd->name - , (calculated_number)(next_store_ut - last_stored_ut) - ); - #endif - - new_value = new_value * (calculated_number)(st->update_every * USEC_PER_SEC) / (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 - ); - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC2 DEF " - CALCULATED_NUMBER_FORMAT " = (((" - "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")" - " * %llu" - " / %llu) + " CALCULATED_NUMBER_FORMAT - , 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 - ); - #endif - } - break; - } - - if(unlikely(!store_this_entry)) { - rd->values[current_entry] = SN_EMPTY_SLOT; //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[current_entry] = pack_storage_number(new_value, storage_flags ); - rd->last_stored_value = new_value; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: STORE[%ld] " - CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT - , rd->name - , current_entry - , unpack_storage_number(rd->values[current_entry]), new_value - ); - #endif - - } - else { - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING " - , rd->name - , current_entry - ); - #endif - - rd->values[current_entry] = SN_EMPTY_SLOT; // pack_storage_number(0, SN_NOT_EXISTS); - rd->last_stored_value = NAN; - } - - stored_entries++; - - #ifdef NETDATA_INTERNAL_CHECKS - 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[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 - , current_entry - , t2 - , get_storage_number_flags(rd->values[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 - , current_entry - , rd->stored_volume - , rd->collected_volume - , accuracy - , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : "" - ); - } - #endif - } - // reset the storage flags for the next point, if any; - storage_flags = SN_EXISTS; - - counter++; - current_entry = ((current_entry + 1) >= st->entries) ? 0 : current_entry + 1; - last_stored_ut = next_store_ut; - } - - st->counter = counter; - st->current_entry = current_entry; - - if(likely(last_ut)) { - st->last_updated.tv_sec = (time_t) (last_ut / USEC_PER_SEC); - st->last_updated.tv_usec = 0; - } - - return stored_entries; -} - -static inline void rrdset_done_fill_the_gap(RRDSET *st) { - usec_t update_every_ut = st->update_every * USEC_PER_SEC; - usec_t now_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec; - - long c = 0, entries = st->entries; - RRDDIM *rd; - rrddim_foreach_read(rd, st) { - usec_t next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC; - long current_entry = st->current_entry; - - for(c = 0; c < entries && next_store_ut <= now_collect_ut ; next_store_ut += update_every_ut, c++) { - rd->values[current_entry] = SN_EMPTY_SLOT; - current_entry = ((current_entry + 1) >= entries) ? 0 : current_entry + 1; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING (FILLED THE GAP)", rd->name, current_entry); - #endif - } - } - - if(c > 0) { - c--; - st->last_updated.tv_sec += c * st->update_every; - - st->current_entry += c; - if(st->current_entry >= st->entries) - st->current_entry -= st->entries; - } -} - -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_send_enabled)) - rrdset_done_push_exclusive(st); - - return; - } - - debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name); - - RRDDIM *rd; - - 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 - - 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 - - netdata_thread_disable_cancelability(); - - // a read lock is OK here - rrdset_rdlock(st); - - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))) { - error("Chart '%s' has the OBSOLETE flag set, but it is collected.", st->id); - rrdset_isnot_obsolete(st); - } - - // check if the chart has a long time to be updated - if(unlikely(st->usec_since_last_update > st->entries * update_every_ut)) { - info("host '%s', chart %s: took too long to be updated (counter #%zu, update #%zu, %0.3" LONG_DOUBLE_MODIFIER " secs). Resetting it.", st->rrdhost->hostname, st->name, st->counter, st->counter_done, (LONG_DOUBLE)st->usec_since_last_update / USEC_PER_SEC); - rrdset_reset(st); - st->usec_since_last_update = update_every_ut; - store_this_entry = 0; - first_entry = 1; - } - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "microseconds since last update: %llu", st->usec_since_last_update); - #endif - - // set last_collected_time - if(unlikely(!st->last_collected_time.tv_sec)) { - // it is the first entry - // set the last_collected_time to now - last_collect_ut = rrdset_init_last_collected_time(st) - update_every_ut; - - // the first entry should not be stored - store_this_entry = 0; - first_entry = 1; - } - 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; - } - - // 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 - now_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec; - last_stored_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec; - next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC; - - if(unlikely(!st->counter_done)) { - // if we have not collected metrics this session (st->counter_done == 0) - // and we have collected metrics for this chart in the past (st->counter != 0) - // fill the gap (the chart has been just loaded from disk) - if(unlikely(st->counter)) { - rrdset_done_fill_the_gap(st); - last_stored_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec; - next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC; - } - - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST))) { - store_this_entry = 1; - last_collect_ut = next_store_ut - update_every_ut; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "Fixed first entry."); - #endif - } - else { - store_this_entry = 0; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "Will not store the next entry."); - #endif - } - } - st->counter_done++; - - if(unlikely(st->rrdhost->rrdpush_send_enabled)) - rrdset_done_push(st); - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "last_collect_ut = %0.3" LONG_DOUBLE_MODIFIER " (last collection time)", (LONG_DOUBLE)last_collect_ut/USEC_PER_SEC); - rrdset_debug(st, "now_collect_ut = %0.3" LONG_DOUBLE_MODIFIER " (current collection time)", (LONG_DOUBLE)now_collect_ut/USEC_PER_SEC); - rrdset_debug(st, "last_stored_ut = %0.3" LONG_DOUBLE_MODIFIER " (last updated time)", (LONG_DOUBLE)last_stored_ut/USEC_PER_SEC); - rrdset_debug(st, "next_store_ut = %0.3" LONG_DOUBLE_MODIFIER " (next interpolation point)", (LONG_DOUBLE)next_store_ut/USEC_PER_SEC); - #endif - - // 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; - } - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: START " - " last_collected_value = " COLLECTED_NUMBER_FORMAT - " collected_value = " COLLECTED_NUMBER_FORMAT - " last_calculated_value = " CALCULATED_NUMBER_FORMAT - " calculated_value = " CALCULATED_NUMBER_FORMAT - , rd->name - , rd->last_collected_value - , rd->collected_value - , rd->last_calculated_value - , rd->calculated_value - ); - #endif - - switch(rd->algorithm) { - case RRD_ALGORITHM_ABSOLUTE: - rd->calculated_value = (calculated_number)rd->collected_value - * (calculated_number)rd->multiplier - / (calculated_number)rd->divisor; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC ABS/ABS-NO-IN " - CALCULATED_NUMBER_FORMAT " = " - COLLECTED_NUMBER_FORMAT - " * " CALCULATED_NUMBER_FORMAT - " / " CALCULATED_NUMBER_FORMAT - , rd->name - , rd->calculated_value - , rd->collected_value - , (calculated_number)rd->multiplier - , (calculated_number)rd->divisor - ); - #endif - - 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; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC PCENT-ROW " - CALCULATED_NUMBER_FORMAT " = 100" - " * " COLLECTED_NUMBER_FORMAT - " / " COLLECTED_NUMBER_FORMAT - , rd->name - , rd->calculated_value - , rd->collected_value - , st->collected_total - ); - #endif - - 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; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC INC PRE " - CALCULATED_NUMBER_FORMAT " = (" - COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT - ")" - " * " CALCULATED_NUMBER_FORMAT - " / " CALCULATED_NUMBER_FORMAT - , rd->name - , rd->calculated_value - , rd->collected_value, rd->last_collected_value - , (calculated_number)rd->multiplier - , (calculated_number)rd->divisor - ); - #endif - - 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); - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC PCENT-DIFF " - CALCULATED_NUMBER_FORMAT " = 100" - " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")" - " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")" - , rd->name - , rd->calculated_value - , rd->collected_value, rd->last_collected_value - , st->collected_total, st->last_collected_total - ); - #endif - - break; - - default: - // make the default zero, to make sure - // it gets noticed when we add new types - rd->calculated_value = 0; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: CALC " - CALCULATED_NUMBER_FORMAT " = 0" - , rd->name - , rd->calculated_value - ); - #endif - - break; - } - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: PHASE2 " - " last_collected_value = " COLLECTED_NUMBER_FORMAT - " collected_value = " COLLECTED_NUMBER_FORMAT - " last_calculated_value = " CALCULATED_NUMBER_FORMAT - " calculated_value = " CALCULATED_NUMBER_FORMAT - , rd->name - , rd->last_collected_value - , rd->collected_value - , rd->last_calculated_value - , rd->calculated_value - ); - #endif - - } - - // at this point we have all the calculated values ready - // it is now time to interpolate values on a second boundary - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(now_collect_ut < next_store_ut)) { - // this is collected in the same interpolation point - rrdset_debug(st, "THIS IS IN THE SAME INTERPOLATION POINT"); - info("INTERNAL CHECK: host '%s', chart '%s' is collected in the same interpolation point: short by %llu microseconds", st->rrdhost->hostname, st->name, next_store_ut - now_collect_ut); - } -#endif - - rrdset_done_interpolate(st - , update_every_ut - , last_stored_ut - , next_store_ut - , last_collect_ut - , now_collect_ut - , store_this_entry - , storage_flags - ); - - st->last_collected_total = st->collected_total; - - rrddim_foreach_read(rd, st) { - if(unlikely(!rd->updated)) - continue; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", rd->name, rd->last_collected_value, rd->collected_value); - #endif - - rd->last_collected_value = rd->collected_value; - - switch(rd->algorithm) { - case RRD_ALGORITHM_INCREMENTAL: - if(unlikely(!first_entry)) { - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", rd->name, rd->last_calculated_value + rd->calculated_value, rd->calculated_value); - #endif - - rd->last_calculated_value += rd->calculated_value; - } - else { - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "THIS IS THE FIRST POINT"); - #endif - } - break; - - case RRD_ALGORITHM_ABSOLUTE: - case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL: - case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL: - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", rd->name, rd->last_calculated_value, rd->calculated_value); - #endif - - rd->last_calculated_value = rd->calculated_value; - break; - } - - rd->calculated_value = 0; - rd->collected_value = 0; - rd->updated = 0; - - #ifdef NETDATA_INTERNAL_CHECKS - rrdset_debug(st, "%s: END " - " last_collected_value = " COLLECTED_NUMBER_FORMAT - " collected_value = " COLLECTED_NUMBER_FORMAT - " last_calculated_value = " CALCULATED_NUMBER_FORMAT - " calculated_value = " CALCULATED_NUMBER_FORMAT - , rd->name - , rd->last_collected_value - , rd->collected_value - , rd->last_calculated_value - , rd->calculated_value - ); - #endif - - } - - // 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); - - netdata_thread_enable_cancelability(); -} diff --git a/src/rrdsetvar.c b/src/rrdsetvar.c deleted file mode 100644 index aec57efa9..000000000 --- a/src/rrdsetvar.c +++ /dev/null @@ -1,183 +0,0 @@ -#define NETDATA_HEALTH_INTERNALS -#include "common.h" - -// ---------------------------------------------------------------------------- -// RRDSETVAR management -// CHART VARIABLES - -static inline void rrdsetvar_free_variables(RRDSETVAR *rs) { - RRDSET *st = rs->rrdset; - RRDHOST *host = st->rrdhost; - - // ------------------------------------------------------------------------ - // CHART - rrdvar_free(host, &st->rrdvar_root_index, rs->var_local); - rs->var_local = NULL; - - // ------------------------------------------------------------------------ - // FAMILY - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family); - rs->var_family = NULL; - - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_name); - rs->var_family_name = NULL; - - // ------------------------------------------------------------------------ - // HOST - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host); - rs->var_host = NULL; - - rrdvar_free(host, &host->rrdvar_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) { - RRDSET *st = rs->rrdset; - RRDHOST *host = st->rrdhost; - - // ------------------------------------------------------------------------ - // free the old ones (if any) - - rrdsetvar_free_variables(rs); - - // ------------------------------------------------------------------------ - // 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->rrdvar_root_index, rs->variable, rs->type, rs->value); - - // ------------------------------------------------------------------------ - // FAMILY - rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_fullid, rs->type, rs->value); - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_fullname, rs->type, rs->value); - - // ------------------------------------------------------------------------ - // HOST - rs->var_host = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullid, rs->type, rs->value); - rs->var_host_name = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullname, rs->type, rs->value); -} - -RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, RRDVAR_TYPE type, void *value, RRDVAR_OPTIONS 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->hash = simple_hash(rs->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; - for(rs = st->variables; rs ; rs = 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); - - if(rs->options & RRDVAR_OPTION_ALLOCATED) - freez(rs->value); - - freez(rs); -} - -// -------------------------------------------------------------------------------------------------------------------- -// custom chart variables - -RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name) { - RRDHOST *host = st->rrdhost; - - char *n = strdupz(name); - rrdvar_fix_name(n); - uint32_t hash = simple_hash(n); - - rrdset_wrlock(st); - - // find it - RRDSETVAR *rs; - for(rs = st->variables; rs ; rs = rs->next) { - if(hash == rs->hash && strcmp(n, rs->variable) == 0) { - rrdset_unlock(st); - if(rs->options & RRDVAR_OPTION_ALLOCATED) { - free(n); - return rs; - } - else { - error("RRDSETVAR: custom variable '%s' on chart '%s' of host '%s', conflicts with an internal chart variable", n, st->id, host->hostname); - free(n); - return NULL; - } - } - } - - // not found, allocate one - - calculated_number *v = mallocz(sizeof(calculated_number)); - *v = NAN; - - rs = rrdsetvar_create(st, n, RRDVAR_TYPE_CALCULATED, v, RRDVAR_OPTION_ALLOCATED); - rrdset_unlock(st); - - free(n); - return rs; -} - -void rrdsetvar_custom_chart_variable_set(RRDSETVAR *rs, calculated_number value) { - if(unlikely(!(rs->options & RRDVAR_OPTION_ALLOCATED))) { - error("RRDSETVAR: requested to set variable '%s' of chart '%s' on host '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rs->variable, rs->rrdset->id, rs->rrdset->rrdhost->hostname, value); - } - else { - calculated_number *v = rs->value; - if(*v != value) { - *v = value; - - // mark the chart to be sent upstream - rrdset_flag_clear(rs->rrdset, RRDSET_FLAG_EXPOSED_UPSTREAM); - } - } -} diff --git a/src/rrdvar.c b/src/rrdvar.c deleted file mode 100644 index 6936c36f1..000000000 --- a/src/rrdvar.c +++ /dev/null @@ -1,275 +0,0 @@ -#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("RRDVAR: Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname); - } - - if(rv->type == RRDVAR_TYPE_CALCULATED_ALLOCATED) - freez(rv->value); - - freez(rv->name); - freez(rv); -} - -inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, RRDVAR_TYPE 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); - freez(rv); - freez(variable); - 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; -} - -void rrdvar_free_remaining_variables(RRDHOST *host, avl_tree_lock *tree_lock) { - // FIXME: this is not bullet proof - avl should support some means to destroy it - // with a callback for each item already in the index - - RRDVAR *rv, *last = NULL; - while((rv = (RRDVAR *)tree_lock->avl_tree.root)) { - if(unlikely(rv == last)) { - error("RRDVAR: INTERNAL ERROR: Cannot cleanup tree of RRDVARs"); - break; - } - last = rv; - rrdvar_free(host, tree_lock, rv); - } -} - -// ---------------------------------------------------------------------------- -// CUSTOM HOST VARIABLES - -inline int rrdvar_callback_for_all_host_variables(RRDHOST *host, int (*callback)(void *rrdvar, void *data), void *data) { - return avl_traverse_lock(&host->rrdvar_root_index, callback, data); -} - -static RRDVAR *rrdvar_custom_variable_create(const char *scope, avl_tree_lock *tree_lock, const char *name) { - calculated_number *v = callocz(1, sizeof(calculated_number)); - *v = NAN; - - RRDVAR *rv = rrdvar_create_and_index(scope, tree_lock, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v); - if(unlikely(!rv)) { - free(v); - debug(D_VARIABLES, "Requested variable '%s' already exists - possibly 2 plugins are 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(tree_lock, variable, hash); - - freez(variable); - } - - return rv; -} - -RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) { - return rrdvar_custom_variable_create("host", &host->rrdvar_root_index, name); -} - -void rrdvar_custom_host_variable_set(RRDHOST *host, 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; - if(*v != value) { - *v = value; - - // if the host is streaming, send this variable upstream immediately - rrdpush_sender_send_this_host_variable_now(host, rv); - } - } -} - -// ---------------------------------------------------------------------------- -// 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 %u 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; - if(!st) return 0; - - RRDHOST *host = st->rrdhost; - RRDVAR *rv; - - rv = rrdvar_index_find(&st->rrdvar_root_index, variable, hash); - if(rv) { - *result = rrdvar2number(rv); - return 1; - } - - rv = rrdvar_index_find(&st->rrdfamily->rrdvar_root_index, variable, hash); - if(rv) { - *result = rrdvar2number(rv); - return 1; - } - - rv = rrdvar_index_find(&host->rrdvar_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.5" LONG_DOUBLE_MODIFIER, helper->counter?",":"", rv->name, (LONG_DOUBLE)value); - - helper->counter++; - - return 0; -} - -void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) { - RRDHOST *host = st->rrdhost; - - 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->rrdvar_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->rrdvar_root_index, single_variable2json, (void *)&helper); - buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", host->hostname); - helper.counter = 0; - avl_traverse_lock(&host->rrdvar_root_index, single_variable2json, (void *)&helper); - buffer_strcat(buf, "\n\t}\n}\n"); -} - diff --git a/src/signals.c b/src/signals.c deleted file mode 100644 index 331e80358..000000000 --- a/src/signals.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "common.h" - -typedef enum signal_action { - NETDATA_SIGNAL_END_OF_LIST, - NETDATA_SIGNAL_IGNORE, - NETDATA_SIGNAL_EXIT_CLEANLY, - NETDATA_SIGNAL_SAVE_DATABASE, - NETDATA_SIGNAL_LOG_ROTATE, - NETDATA_SIGNAL_RELOAD_HEALTH, - NETDATA_SIGNAL_FATAL, -} SIGNAL_ACTION; - -static struct { - int signo; // the signal - const char *name; // the name of the signal - size_t count; // the number of signals received - SIGNAL_ACTION action; // the action to take -} signals_waiting[] = { - { SIGPIPE, "SIGPIPE", 0, NETDATA_SIGNAL_IGNORE }, - { SIGINT , "SIGINT", 0, NETDATA_SIGNAL_EXIT_CLEANLY }, - { SIGQUIT, "SIGQUIT", 0, NETDATA_SIGNAL_EXIT_CLEANLY }, - { SIGTERM, "SIGTERM", 0, NETDATA_SIGNAL_EXIT_CLEANLY }, - { SIGHUP, "SIGHUP", 0, NETDATA_SIGNAL_LOG_ROTATE }, - { SIGUSR1, "SIGUSR1", 0, NETDATA_SIGNAL_SAVE_DATABASE }, - { SIGUSR2, "SIGUSR2", 0, NETDATA_SIGNAL_RELOAD_HEALTH }, - { SIGBUS, "SIGBUS", 0, NETDATA_SIGNAL_FATAL }, - - // terminator - { 0, "NONE", 0, NETDATA_SIGNAL_END_OF_LIST } -}; - -static void signal_handler(int signo) { - // find the entry in the list - int i; - for(i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST ; i++) { - if(unlikely(signals_waiting[i].signo == signo)) { - signals_waiting[i].count++; - - if(signals_waiting[i].action == NETDATA_SIGNAL_FATAL) { - char buffer[200 + 1]; - snprintfz(buffer, 200, "\nSIGNAL HANLDER: received: %s. Oops! This is bad!\n", signals_waiting[i].name); - if(write(STDERR_FILENO, buffer, strlen(buffer)) == -1) { - // nothing to do - we cannot write but there is no way to complaint about it - ; - } - } - - return; - } - } -} - -void signals_block(void) { - sigset_t sigset; - sigfillset(&sigset); - - if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1) - error("SIGNAL: Could not block signals for threads"); -} - -void signals_unblock(void) { - sigset_t sigset; - sigfillset(&sigset); - - if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) { - error("SIGNAL: Could not unblock signals for threads"); - } -} - -void signals_init(void) { - // Catch signals which we want to use - struct sigaction sa; - sa.sa_flags = 0; - - // ignore all signals while we run in a signal handler - sigfillset(&sa.sa_mask); - - int i; - for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) { - if(signals_waiting[i].action == NETDATA_SIGNAL_IGNORE) - sa.sa_handler = SIG_IGN; - else - sa.sa_handler = signal_handler; - - if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1) - error("SIGNAL: Failed to change signal handler for: %s", signals_waiting[i].name); - } -} - -void signals_reset(void) { - struct sigaction sa; - sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_DFL; - sa.sa_flags = 0; - - int i; - for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) { - if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1) - error("SIGNAL: Failed to reset signal handler for: %s", signals_waiting[i].name); - } -} - -void signals_handle(void) { - while(1) { - - // pause() causes the calling process (or thread) to sleep until a signal - // is delivered that either terminates the process or causes the invocation - // of a signal-catching function. - if(pause() == -1 && errno == EINTR) { - - // loop once, but keep looping while signals are coming in - // this is needed because a few operations may take some time - // so we need to check for new signals before pausing again - int found = 1; - while(found) { - found = 0; - - // execute the actions of the signals - int i; - for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) { - if (signals_waiting[i].count) { - found = 1; - signals_waiting[i].count = 0; - const char *name = signals_waiting[i].name; - - switch (signals_waiting[i].action) { - case NETDATA_SIGNAL_RELOAD_HEALTH: - error_log_limit_unlimited(); - info("SIGNAL: Received %s. Reloading HEALTH configuration...", name); - health_reload(); - error_log_limit_reset(); - break; - - case NETDATA_SIGNAL_SAVE_DATABASE: - error_log_limit_unlimited(); - info("SIGNAL: Received %s. Saving databases...", name); - rrdhost_save_all(); - info("Databases saved."); - error_log_limit_reset(); - break; - - case NETDATA_SIGNAL_LOG_ROTATE: - error_log_limit_unlimited(); - info("SIGNAL: Received %s. Reopening all log files...", name); - reopen_all_log_files(); - error_log_limit_reset(); - break; - - case NETDATA_SIGNAL_EXIT_CLEANLY: - info("SIGNAL: Received %s. Cleaning up to exit...", name); - netdata_cleanup_and_exit(0); - exit(0); - - case NETDATA_SIGNAL_FATAL: - fatal("SIGNAL: Received %s. netdata now exits.", name); - - default: - info("SIGNAL: Received %s. No signal handler configured. Ignoring it.", name); - break; - } - } - } - } - } - else - error("SIGNAL: pause() returned but it was not interrupted by a signal."); - } -} diff --git a/src/signals.h b/src/signals.h deleted file mode 100644 index 2fdd36552..000000000 --- a/src/signals.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NETDATA_SIGNALS_H -#define NETDATA_SIGNALS_H - -extern void signals_init(void); -extern void signals_block(void); -extern void signals_unblock(void); -extern void signals_reset(void); -extern void signals_handle(void) NORETURN; - -#endif //NETDATA_SIGNALS_H diff --git a/src/simple_pattern.c b/src/simple_pattern.c deleted file mode 100644 index 747b5150a..000000000 --- a/src/simple_pattern.c +++ /dev/null @@ -1,260 +0,0 @@ -#include "common.h" - -struct simple_pattern { - const char *match; - size_t len; - - SIMPLE_PREFIX_MODE mode; - char negative; - - struct simple_pattern *child; - - struct simple_pattern *next; -}; - -static inline struct simple_pattern *parse_pattern(char *str, SIMPLE_PREFIX_MODE default_mode) { - // fprintf(stderr, "PARSING PATTERN: '%s'\n", str); - - SIMPLE_PREFIX_MODE mode; - struct simple_pattern *child = NULL; - - char *s = str, *c = str; - - // skip asterisks in front - while(*c == '*') c++; - - // find the next asterisk - while(*c && *c != '*') c++; - - // do we have an asterisk in the middle? - if(*c == '*' && c[1] != '\0') { - // yes, we have - child = parse_pattern(c, default_mode); - c[1] = '\0'; - } - - // check what this one matches - - size_t len = strlen(s); - if(len >= 2 && *s == '*' && s[len - 1] == '*') { - s[len - 1] = '\0'; - s++; - mode = SIMPLE_PATTERN_SUBSTRING; - } - else if(len >= 1 && *s == '*') { - s++; - mode = SIMPLE_PATTERN_SUFFIX; - } - else if(len >= 1 && s[len - 1] == '*') { - s[len - 1] = '\0'; - mode = SIMPLE_PATTERN_PREFIX; - } - else - mode = default_mode; - - // allocate the structure - struct simple_pattern *m = callocz(1, sizeof(struct simple_pattern)); - if(*s) { - m->match = strdupz(s); - m->len = strlen(m->match); - m->mode = mode; - } - else { - m->mode = SIMPLE_PATTERN_SUBSTRING; - } - - m->child = child; - - return m; -} - -SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators, SIMPLE_PREFIX_MODE default_mode) { - struct simple_pattern *root = NULL, *last = NULL; - - if(unlikely(!list || !*list)) return root; - - int isseparator[256] = { - [' '] = 1 // space - , ['\t'] = 1 // tab - , ['\r'] = 1 // carriage return - , ['\n'] = 1 // new line - , ['\f'] = 1 // form feed - , ['\v'] = 1 // vertical tab - }; - - if (unlikely(separators && *separators)) { - memset(&isseparator[0], 0, sizeof(isseparator)); - while(*separators) isseparator[(unsigned char)*separators++] = 1; - } - - char *buf = mallocz(strlen(list) + 1); - const char *s = list; - - while(s && *s) { - buf[0] = '\0'; - char *c = buf; - - char negative = 0; - - // skip all spaces - while(isseparator[(unsigned char)*s]) - s++; - - if(*s == '!') { - negative = 1; - s++; - } - - // empty string - if(unlikely(!*s)) - break; - - // find the next space - char escape = 0; - while(*s) { - if(*s == '\\' && !escape) { - escape = 1; - s++; - } - else { - if (isseparator[(unsigned char)*s] && !escape) { - s++; - break; - } - - *c++ = *s++; - escape = 0; - } - } - - // terminate our string - *c = '\0'; - - // if we matched the empty string, skip it - if(unlikely(!*buf)) - continue; - - // fprintf(stderr, "FOUND PATTERN: '%s'\n", buf); - struct simple_pattern *m = parse_pattern(buf, default_mode); - m->negative = negative; - - // link it at the end - if(unlikely(!root)) - root = last = m; - else { - last->next = m; - last = m; - } - } - - freez(buf); - return (SIMPLE_PATTERN *)root; -} - -static inline char *add_wildcarded(const char *matched, size_t matched_size, char *wildcarded, size_t *wildcarded_size) { - //if(matched_size) { - // char buf[matched_size + 1]; - // strncpyz(buf, matched, matched_size); - // fprintf(stderr, "ADD WILDCARDED '%s' of length %zu\n", buf, matched_size); - //} - - if(unlikely(wildcarded && *wildcarded_size && matched && *matched && matched_size)) { - size_t wss = *wildcarded_size - 1; - size_t len = (matched_size < wss)?matched_size:wss; - if(likely(len)) { - strncpyz(wildcarded, matched, len); - - *wildcarded_size -= len; - return &wildcarded[len]; - } - } - - return wildcarded; -} - -static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len, char *wildcarded, size_t *wildcarded_size) { - char *s; - - if(m->len <= len) { - switch(m->mode) { - case SIMPLE_PATTERN_SUBSTRING: - if(!m->len) return 1; - if((s = strstr(str, m->match))) { - wildcarded = add_wildcarded(str, s - str, wildcarded, wildcarded_size); - if(!m->child) { - wildcarded = add_wildcarded(&s[m->len], len - (&s[m->len] - str), wildcarded, wildcarded_size); - return 1; - } - return match_pattern(m->child, &s[m->len], len - (s - str) - m->len, wildcarded, wildcarded_size); - } - break; - - case SIMPLE_PATTERN_PREFIX: - if(unlikely(strncmp(str, m->match, m->len) == 0)) { - if(!m->child) { - wildcarded = add_wildcarded(&str[m->len], len - m->len, wildcarded, wildcarded_size); - return 1; - } - return match_pattern(m->child, &str[m->len], len - m->len, wildcarded, wildcarded_size); - } - break; - - case SIMPLE_PATTERN_SUFFIX: - if(unlikely(strcmp(&str[len - m->len], m->match) == 0)) { - wildcarded = add_wildcarded(str, len - m->len, wildcarded, wildcarded_size); - if(!m->child) return 1; - return 0; - } - break; - - case SIMPLE_PATTERN_EXACT: - default: - if(unlikely(strcmp(str, m->match) == 0)) { - if(!m->child) return 1; - return 0; - } - break; - } - } - - return 0; -} - -int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size) { - struct simple_pattern *m, *root = (struct simple_pattern *)list; - - if(unlikely(!root || !str || !*str)) return 0; - - size_t len = strlen(str); - for(m = root; m ; m = m->next) { - char *ws = wildcarded; - size_t wss = wildcarded_size; - if(unlikely(ws)) *ws = '\0'; - - if (match_pattern(m, str, len, ws, &wss)) { - - //if(ws && wss) - // fprintf(stderr, "FINAL WILDCARDED '%s' of length %zu\n", ws, strlen(ws)); - - if (m->negative) return 0; - return 1; - } - } - - return 0; -} - -static inline void free_pattern(struct simple_pattern *m) { - if(!m) return; - - free_pattern(m->child); - free_pattern(m->next); - freez((void *)m->match); - freez(m); -} - -void simple_pattern_free(SIMPLE_PATTERN *list) { - if(!list) return; - - free_pattern(((struct simple_pattern *)list)); -} diff --git a/src/simple_pattern.h b/src/simple_pattern.h deleted file mode 100644 index d0b75af7e..000000000 --- a/src/simple_pattern.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef NETDATA_SIMPLE_PATTERN_H -#define NETDATA_SIMPLE_PATTERN_H - -typedef enum { - SIMPLE_PATTERN_EXACT, - SIMPLE_PATTERN_PREFIX, - SIMPLE_PATTERN_SUFFIX, - SIMPLE_PATTERN_SUBSTRING -} SIMPLE_PREFIX_MODE; - -typedef void SIMPLE_PATTERN; - -// create a simple_pattern from the string given -// default_mode is used in cases where EXACT matches, without an asterisk, -// should be considered PREFIX matches. -extern SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators, SIMPLE_PREFIX_MODE default_mode); - -// test if string str is matched from the pattern and fill 'wildcarded' with the parts matched by '*' -extern int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size); - -// test if string str is matched from the pattern -#define simple_pattern_matches(list, str) simple_pattern_matches_extract(list, str, NULL, 0) - -// free a simple_pattern that was created with simple_pattern_create() -// list can be NULL, in which case, this does nothing. -extern void simple_pattern_free(SIMPLE_PATTERN *list); - -#endif //NETDATA_SIMPLE_PATTERN_H diff --git a/src/socket.c b/src/socket.c deleted file mode 100644 index 8bede73fd..000000000 --- a/src/socket.c +++ /dev/null @@ -1,1518 +0,0 @@ -#include "common.h" - -// -------------------------------------------------------------------------------------------------------------------- -// various library calls - -#ifdef __gnu_linux__ -#define LARGE_SOCK_SIZE 33554431 // don't ask why - I found it at brubeck source - I guess it is just a large number -#else -#define LARGE_SOCK_SIZE 4096 -#endif - -int sock_setnonblock(int fd) { - int flags; - - flags = fcntl(fd, F_GETFL); - flags |= O_NONBLOCK; - - int ret = fcntl(fd, F_SETFL, flags); - if(ret < 0) - error("Failed to set O_NONBLOCK on socket %d", fd); - - return ret; -} - -int sock_delnonblock(int fd) { - int flags; - - flags = fcntl(fd, F_GETFL); - flags &= ~O_NONBLOCK; - - int ret = fcntl(fd, F_SETFL, flags); - if(ret < 0) - error("Failed to remove O_NONBLOCK on socket %d", fd); - - return ret; -} - -int sock_setreuse(int fd, int reuse) { - int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - - if(ret == -1) - error("Failed to set SO_REUSEADDR on socket %d", fd); - - return ret; -} - -int sock_setreuse_port(int fd, int reuse) { - int ret = -1; - -#ifdef SO_REUSEPORT - ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)); - if(ret == -1 && errno != ENOPROTOOPT) - error("failed to set SO_REUSEPORT on socket %d", fd); -#endif - - return ret; -} - -int sock_enlarge_in(int fd) { - int ret, bs = LARGE_SOCK_SIZE; - - ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bs, sizeof(bs)); - - if(ret == -1) - error("Failed to set SO_RCVBUF on socket %d", fd); - - return ret; -} - -int sock_enlarge_out(int fd) { - int ret, bs = LARGE_SOCK_SIZE; - ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bs, sizeof(bs)); - - if(ret == -1) - error("Failed to set SO_SNDBUF on socket %d", fd); - - return ret; -} - - -// -------------------------------------------------------------------------------------------------------------------- - -char *strdup_client_description(int family, const char *protocol, const char *ip, int port) { - char buffer[100 + 1]; - - switch(family) { - case AF_INET: - snprintfz(buffer, 100, "%s:%s:%d", protocol, ip, port); - break; - - case AF_INET6: - default: - snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port); - break; - - case AF_UNIX: - snprintfz(buffer, 100, "%s:%s", protocol, ip); - break; - } - - return strdupz(buffer); -} - -// -------------------------------------------------------------------------------------------------------------------- -// listening sockets - -int create_listen_socket_unix(const char *path, int listen_backlog) { - int sock; - - debug(D_LISTENER, "LISTENER: UNIX creating new listening socket on path '%s'", path); - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if(sock < 0) { - error("LISTENER: UNIX socket() on path '%s' failed.", path); - return -1; - } - - sock_setnonblock(sock); - sock_enlarge_in(sock); - - struct sockaddr_un name; - memset(&name, 0, sizeof(struct sockaddr_un)); - name.sun_family = AF_UNIX; - strncpy(name.sun_path, path, sizeof(name.sun_path)-1); - - errno = 0; - if (unlink(path) == -1 && errno != ENOENT) - error("LISTENER: failed to remove existing (probably obsolete or left-over) file on UNIX socket path '%s'.", path); - - if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) { - close(sock); - error("LISTENER: UNIX bind() on path '%s' failed.", path); - return -1; - } - - // we have to chmod this to 0777 so that the client will be able - // to read from and write to this socket. - if(chmod(path, 0777) == -1) - error("LISTENER: failed to chmod() socket file '%s'.", path); - - if(listen(sock, listen_backlog) < 0) { - close(sock); - error("LISTENER: UNIX listen() on path '%s' failed.", path); - return -1; - } - - debug(D_LISTENER, "LISTENER: Listening on UNIX path '%s'", path); - return sock; -} - -int create_listen_socket4(int socktype, const char *ip, int port, int listen_backlog) { - int sock; - - debug(D_LISTENER, "LISTENER: IPv4 creating new listening socket on ip '%s' port %d, socktype %d", ip, port, socktype); - - sock = socket(AF_INET, socktype, 0); - if(sock < 0) { - error("LISTENER: IPv4 socket() on ip '%s' port %d, socktype %d failed.", ip, port, socktype); - return -1; - } - - sock_setreuse(sock, 1); - sock_setreuse_port(sock, 1); - sock_setnonblock(sock); - sock_enlarge_in(sock); - - struct sockaddr_in name; - memset(&name, 0, sizeof(struct sockaddr_in)); - name.sin_family = AF_INET; - name.sin_port = htons (port); - - int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr); - if(ret != 1) { - error("LISTENER: Failed to convert IP '%s' to a valid IPv4 address.", ip); - close(sock); - return -1; - } - - if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) { - close(sock); - error("LISTENER: IPv4 bind() on ip '%s' port %d, socktype %d failed.", ip, port, socktype); - return -1; - } - - if(socktype == SOCK_STREAM && listen(sock, listen_backlog) < 0) { - close(sock); - error("LISTENER: IPv4 listen() on ip '%s' port %d, socktype %d failed.", ip, port, socktype); - return -1; - } - - debug(D_LISTENER, "LISTENER: Listening on IPv4 ip '%s' port %d, socktype %d", ip, port, socktype); - return sock; -} - -int create_listen_socket6(int socktype, uint32_t scope_id, const char *ip, int port, int listen_backlog) { - int sock; - int ipv6only = 1; - - debug(D_LISTENER, "LISTENER: IPv6 creating new listening socket on ip '%s' port %d, socktype %d", ip, port, socktype); - - sock = socket(AF_INET6, socktype, 0); - if (sock < 0) { - error("LISTENER: IPv6 socket() on ip '%s' port %d, socktype %d, failed.", ip, port, socktype); - return -1; - } - - sock_setreuse(sock, 1); - sock_setreuse_port(sock, 1); - sock_setnonblock(sock); - sock_enlarge_in(sock); - - /* IPv6 only */ - if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&ipv6only, sizeof(ipv6only)) != 0) - error("LISTENER: Cannot set IPV6_V6ONLY on ip '%s' port %d, socktype %d.", ip, port, socktype); - - struct sockaddr_in6 name; - memset(&name, 0, sizeof(struct sockaddr_in6)); - name.sin6_family = AF_INET6; - name.sin6_port = htons ((uint16_t) port); - name.sin6_scope_id = scope_id; - - int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr); - if(ret != 1) { - error("LISTENER: Failed to convert IP '%s' to a valid IPv6 address.", ip); - close(sock); - return -1; - } - - name.sin6_scope_id = scope_id; - - if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) { - close(sock); - error("LISTENER: IPv6 bind() on ip '%s' port %d, socktype %d failed.", ip, port, socktype); - return -1; - } - - if (socktype == SOCK_STREAM && listen(sock, listen_backlog) < 0) { - close(sock); - error("LISTENER: IPv6 listen() on ip '%s' port %d, socktype %d failed.", ip, port, socktype); - return -1; - } - - debug(D_LISTENER, "LISTENER: Listening on IPv6 ip '%s' port %d, socktype %d", ip, port, socktype); - return sock; -} - -static inline int listen_sockets_add(LISTEN_SOCKETS *sockets, int fd, int family, int socktype, const char *protocol, const char *ip, int port) { - if(sockets->opened >= MAX_LISTEN_FDS) { - error("LISTENER: Too many listening sockets. Failed to add listening %s socket at ip '%s' port %d, protocol %s, socktype %d", protocol, ip, port, protocol, socktype); - close(fd); - return -1; - } - - sockets->fds[sockets->opened] = fd; - sockets->fds_types[sockets->opened] = socktype; - sockets->fds_families[sockets->opened] = family; - sockets->fds_names[sockets->opened] = strdup_client_description(family, protocol, ip, port); - - sockets->opened++; - return 0; -} - -int listen_sockets_check_is_member(LISTEN_SOCKETS *sockets, int fd) { - size_t i; - for(i = 0; i < sockets->opened ;i++) - if(sockets->fds[i] == fd) return 1; - - return 0; -} - -static inline void listen_sockets_init(LISTEN_SOCKETS *sockets) { - size_t i; - for(i = 0; i < MAX_LISTEN_FDS ;i++) { - sockets->fds[i] = -1; - sockets->fds_names[i] = NULL; - sockets->fds_types[i] = -1; - } - - sockets->opened = 0; - sockets->failed = 0; -} - -void listen_sockets_close(LISTEN_SOCKETS *sockets) { - size_t i; - for(i = 0; i < sockets->opened ;i++) { - close(sockets->fds[i]); - sockets->fds[i] = -1; - - freez(sockets->fds_names[i]); - sockets->fds_names[i] = NULL; - - sockets->fds_types[i] = -1; - } - - sockets->opened = 0; - sockets->failed = 0; -} - -static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) { - int added = 0; - struct addrinfo hints; - struct addrinfo *result = NULL, *rp = NULL; - - char buffer[strlen(definition) + 1]; - strcpy(buffer, definition); - - char buffer2[10 + 1]; - snprintfz(buffer2, 10, "%d", default_port); - - char *ip = buffer, *port = buffer2, *interface = "";; - - int protocol = IPPROTO_TCP, socktype = SOCK_STREAM; - const char *protocol_str = "tcp"; - - if(strncmp(ip, "tcp:", 4) == 0) { - ip += 4; - protocol = IPPROTO_TCP; - socktype = SOCK_STREAM; - protocol_str = "tcp"; - } - else if(strncmp(ip, "udp:", 4) == 0) { - ip += 4; - protocol = IPPROTO_UDP; - socktype = SOCK_DGRAM; - protocol_str = "udp"; - } - else if(strncmp(ip, "unix:", 5) == 0) { - char *path = ip + 5; - socktype = SOCK_STREAM; - protocol_str = "unix"; - - int fd = create_listen_socket_unix(path, listen_backlog); - if (fd == -1) { - error("LISTENER: Cannot create unix socket '%s'", path); - sockets->failed++; - } - else { - listen_sockets_add(sockets, fd, AF_UNIX, socktype, protocol_str, path, 0); - added++; - } - return added; - } - - char *e = ip; - if(*e == '[') { - e = ++ip; - while(*e && *e != ']') e++; - if(*e == ']') { - *e = '\0'; - e++; - } - } - else { - while(*e && *e != ':' && *e != '%') e++; - } - - if(*e == '%') { - *e = '\0'; - e++; - interface = e; - while(*e && *e != ':') e++; - } - - if(*e == ':') { - port = e + 1; - *e = '\0'; - } - - uint32_t scope_id = 0; - if(*interface) { - scope_id = if_nametoindex(interface); - if(!scope_id) - error("LISTENER: Cannot find a network interface named '%s'. Continuing with limiting the network interface", interface); - } - - if(!*ip || *ip == '*' || !strcmp(ip, "any") || !strcmp(ip, "all")) - ip = NULL; - - if(!*port) - port = buffer2; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = socktype; - hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ - hints.ai_protocol = protocol; - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - int r = getaddrinfo(ip, port, &hints, &result); - if (r != 0) { - error("LISTENER: getaddrinfo('%s', '%s'): %s\n", ip, port, gai_strerror(r)); - return -1; - } - - for (rp = result; rp != NULL; rp = rp->ai_next) { - int fd = -1; - int family = -1; - - char rip[INET_ADDRSTRLEN + INET6_ADDRSTRLEN] = "INVALID"; - int rport = default_port; - - family = rp->ai_addr->sa_family; - switch (family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *) rp->ai_addr; - inet_ntop(AF_INET, &sin->sin_addr, rip, INET_ADDRSTRLEN); - rport = ntohs(sin->sin_port); - // info("Attempting to listen on IPv4 '%s' ('%s'), port %d ('%s'), socktype %d", rip, ip, rport, port, socktype); - fd = create_listen_socket4(socktype, rip, rport, listen_backlog); - break; - } - - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) rp->ai_addr; - inet_ntop(AF_INET6, &sin6->sin6_addr, rip, INET6_ADDRSTRLEN); - rport = ntohs(sin6->sin6_port); - // info("Attempting to listen on IPv6 '%s' ('%s'), port %d ('%s'), socktype %d", rip, ip, rport, port, socktype); - fd = create_listen_socket6(socktype, scope_id, rip, rport, listen_backlog); - break; - } - - default: - debug(D_LISTENER, "LISTENER: Unknown socket family %d", family); - break; - } - - if (fd == -1) { - error("LISTENER: Cannot bind to ip '%s', port %d", rip, rport); - sockets->failed++; - } - else { - listen_sockets_add(sockets, fd, family, socktype, protocol_str, rip, rport); - added++; - } - } - - freeaddrinfo(result); - - return added; -} - -int listen_sockets_setup(LISTEN_SOCKETS *sockets) { - listen_sockets_init(sockets); - - sockets->backlog = (int) config_get_number(sockets->config_section, "listen backlog", sockets->backlog); - - int old_port = sockets->default_port; - sockets->default_port = (int) config_get_number(sockets->config_section, "default port", sockets->default_port); - if(sockets->default_port < 1 || sockets->default_port > 65535) { - error("LISTENER: Invalid listen port %d given. Defaulting to %d.", sockets->default_port, old_port); - sockets->default_port = (int) config_set_number(sockets->config_section, "default port", old_port); - } - debug(D_OPTIONS, "LISTENER: Default listen port set to %d.", sockets->default_port); - - char *s = config_get(sockets->config_section, "bind to", sockets->default_bind_to); - while(*s) { - 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); - bind_to_this(sockets, buf, sockets->default_port, sockets->backlog); - - s = e; - } - - if(sockets->failed) { - size_t i; - for(i = 0; i < sockets->opened ;i++) - info("LISTENER: Listen socket %s opened successfully.", sockets->fds_names[i]); - } - - return (int)sockets->opened; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// connect to another host/port - -// connect_to_this_unix() -// path the path of the unix socket -// timeout the timeout for establishing a connection - -static inline int connect_to_unix(const char *path, struct timeval *timeout) { - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd == -1) { - error("Failed to create UNIX socket() for '%s'", path); - return -1; - } - - if(timeout) { - if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0) - error("Failed to set timeout on UNIX socket '%s'", path); - } - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1); - - if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { - error("Cannot connect to UNIX socket on path '%s'.", path); - close(fd); - return -1; - } - - debug(D_CONNECT_TO, "Connected to UNIX socket on path '%s'.", path); - - return fd; -} - -// connect_to_this_ip46() -// protocol IPPROTO_TCP, IPPROTO_UDP -// socktype SOCK_STREAM, SOCK_DGRAM -// host the destination hostname or IP address (IPv4 or IPv6) to connect to -// if it resolves to many IPs, all are tried (IPv4 and IPv6) -// scope_id the if_index id of the interface to use for connecting (0 = any) -// (used only under IPv6) -// service the service name or port to connect to -// timeout the timeout for establishing a connection - -static inline int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) { - struct addrinfo hints; - struct addrinfo *ai_head = NULL, *ai = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = socktype; - hints.ai_protocol = protocol; - - int ai_err = getaddrinfo(host, service, &hints, &ai_head); - if (ai_err != 0) { - error("Cannot resolve host '%s', port '%s': %s", host, service, gai_strerror(ai_err)); - return -1; - } - - int fd = -1; - for (ai = ai_head; ai != NULL && fd == -1; ai = ai->ai_next) { - - if (ai->ai_family == PF_INET6) { - struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6 *) ai->ai_addr; - if(pSadrIn6->sin6_scope_id == 0) { - pSadrIn6->sin6_scope_id = scope_id; - } - } - - char hostBfr[NI_MAXHOST + 1]; - char servBfr[NI_MAXSERV + 1]; - - getnameinfo(ai->ai_addr, - ai->ai_addrlen, - hostBfr, - sizeof(hostBfr), - servBfr, - sizeof(servBfr), - NI_NUMERICHOST | NI_NUMERICSERV); - - debug(D_CONNECT_TO, "Address info: host = '%s', service = '%s', ai_flags = 0x%02X, ai_family = %d (PF_INET = %d, PF_INET6 = %d), ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d), ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d), ai_addrlen = %lu (sockaddr_in = %lu, sockaddr_in6 = %lu)", - hostBfr, - servBfr, - (unsigned int)ai->ai_flags, - ai->ai_family, - PF_INET, - PF_INET6, - ai->ai_socktype, - SOCK_STREAM, - SOCK_DGRAM, - ai->ai_protocol, - IPPROTO_TCP, - IPPROTO_UDP, - (unsigned long)ai->ai_addrlen, - (unsigned long)sizeof(struct sockaddr_in), - (unsigned long)sizeof(struct sockaddr_in6)); - - switch (ai->ai_addr->sa_family) { - case PF_INET: { - struct sockaddr_in *pSadrIn = (struct sockaddr_in *)ai->ai_addr; - debug(D_CONNECT_TO, "ai_addr = sin_family: %d (AF_INET = %d, AF_INET6 = %d), sin_addr: '%s', sin_port: '%s'", - pSadrIn->sin_family, - AF_INET, - AF_INET6, - hostBfr, - servBfr); - break; - } - - case PF_INET6: { - struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6 *) ai->ai_addr; - debug(D_CONNECT_TO,"ai_addr = sin6_family: %d (AF_INET = %d, AF_INET6 = %d), sin6_addr: '%s', sin6_port: '%s', sin6_flowinfo: %u, sin6_scope_id: %u", - pSadrIn6->sin6_family, - AF_INET, - AF_INET6, - hostBfr, - servBfr, - pSadrIn6->sin6_flowinfo, - pSadrIn6->sin6_scope_id); - break; - } - - default: { - debug(D_CONNECT_TO, "Unknown protocol family %d.", ai->ai_family); - continue; - } - } - - fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if(fd != -1) { - 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); - } - - errno = 0; - if(connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) { - if(errno == EALREADY || errno == EINPROGRESS) { - info("Waiting for connection to ip %s port %s to be established", hostBfr, servBfr); - - fd_set fds; - FD_ZERO(&fds); - FD_SET(0, &fds); - int rc = select (1, NULL, &fds, NULL, timeout); - - if(rc > 0 && FD_ISSET(fd, &fds)) { - info("connect() to ip %s port %s completed successfully", hostBfr, servBfr); - } - else if(rc == -1) { - error("Failed to connect to '%s', port '%s'. select() returned %d", hostBfr, servBfr, rc); - close(fd); - fd = -1; - } - else { - error("Timed out while connecting to '%s', port '%s'. select() returned %d", hostBfr, servBfr, rc); - close(fd); - fd = -1; - } - } - else { - error("Failed to connect to '%s', port '%s'", hostBfr, servBfr); - close(fd); - fd = -1; - } - } - - if(fd != -1) - debug(D_CONNECT_TO, "Connected to '%s' on port '%s'.", hostBfr, servBfr); - } - } - - freeaddrinfo(ai_head); - - return fd; -} - -// connect_to_this() -// -// definition format: -// -// [PROTOCOL:]IP[%INTERFACE][:PORT] -// -// PROTOCOL = tcp or udp -// IP = IPv4 or IPv6 IP or hostname, optionally enclosed in [] (required for IPv6) -// INTERFACE = for IPv6 only, the network interface to use -// PORT = port number or service name - -int connect_to_this(const char *definition, int default_port, struct timeval *timeout) { - char buffer[strlen(definition) + 1]; - strcpy(buffer, definition); - - char default_service[10 + 1]; - snprintfz(default_service, 10, "%d", default_port); - - char *host = buffer, *service = default_service, *interface = ""; - int protocol = IPPROTO_TCP, socktype = SOCK_STREAM; - uint32_t scope_id = 0; - - if(strncmp(host, "tcp:", 4) == 0) { - host += 4; - protocol = IPPROTO_TCP; - socktype = SOCK_STREAM; - } - else if(strncmp(host, "udp:", 4) == 0) { - host += 4; - protocol = IPPROTO_UDP; - socktype = SOCK_DGRAM; - } - else if(strncmp(host, "unix:", 5) == 0) { - char *path = host + 5; - return connect_to_unix(path, timeout); - } - - char *e = host; - if(*e == '[') { - e = ++host; - while(*e && *e != ']') e++; - if(*e == ']') { - *e = '\0'; - e++; - } - } - else { - while(*e && *e != ':' && *e != '%') e++; - } - - if(*e == '%') { - *e = '\0'; - e++; - interface = e; - while(*e && *e != ':') e++; - } - - if(*e == ':') { - *e = '\0'; - e++; - service = e; - } - - debug(D_CONNECT_TO, "Attempting connection to host = '%s', service = '%s', interface = '%s', protocol = %d (tcp = %d, udp = %d)", host, service, interface, protocol, IPPROTO_TCP, IPPROTO_UDP); - - if(!*host) { - error("Definition '%s' does not specify a host.", definition); - return -1; - } - - if(*interface) { - scope_id = if_nametoindex(interface); - if(!scope_id) - error("Cannot find a network interface named '%s'. Continuing with limiting the network interface", interface); - } - - if(!*service) - service = default_service; - - - return connect_to_this_ip46(protocol, socktype, host, scope_id, service, timeout); -} - -int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) { - 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_this(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; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// helpers to send/receive data in one call, in blocking mode, with a timeout - -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); -} - - -// -------------------------------------------------------------------------------------------------------------------- -// accept4() replacement for systems that do not have one - -#ifndef HAVE_ACCEPT4 -int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) { - int fd = accept(sock, addr, addrlen); - int newflags = 0; - - if (fd < 0) return fd; - - if (flags & SOCK_NONBLOCK) { - newflags |= O_NONBLOCK; - flags &= ~SOCK_NONBLOCK; - } - -#ifdef SOCK_CLOEXEC -#ifdef O_CLOEXEC - if (flags & SOCK_CLOEXEC) { - newflags |= O_CLOEXEC; - flags &= ~SOCK_CLOEXEC; - } -#endif -#endif - - if (flags) { - close(fd); - errno = EINVAL; - return -1; - } - - if (fcntl(fd, F_SETFL, newflags) < 0) { - int saved_errno = errno; - close(fd); - errno = saved_errno; - return -1; - } - - return fd; -} -#endif - - -// -------------------------------------------------------------------------------------------------------------------- -// accept_socket() - accept a socket and store client IP and port - -int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize, SIMPLE_PATTERN *access_list) { - struct sockaddr_storage sadr; - socklen_t addrlen = sizeof(sadr); - - int nfd = accept4(fd, (struct sockaddr *)&sadr, &addrlen, flags); - if (likely(nfd >= 0)) { - if (getnameinfo((struct sockaddr *)&sadr, addrlen, client_ip, (socklen_t)ipsize, client_port, (socklen_t)portsize, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - error("LISTENER: cannot getnameinfo() on received client connection."); - strncpyz(client_ip, "UNKNOWN", ipsize - 1); - strncpyz(client_port, "UNKNOWN", portsize - 1); - } - - client_ip[ipsize - 1] = '\0'; - client_port[portsize - 1] = '\0'; - - switch (((struct sockaddr *)&sadr)->sa_family) { - case AF_UNIX: - debug(D_LISTENER, "New UNIX domain web client from %s on socket %d.", client_ip, fd); - // set the port - certain versions of libc return garbage on unix sockets - strncpy(client_port, "UNIX", portsize); - client_port[portsize - 1] = '\0'; - break; - - case AF_INET: - debug(D_LISTENER, "New IPv4 web client from %s port %s on socket %d.", client_ip, client_port, fd); - break; - - case AF_INET6: - if (strncmp(client_ip, "::ffff:", 7) == 0) { - memmove(client_ip, &client_ip[7], strlen(&client_ip[7]) + 1); - debug(D_LISTENER, "New IPv4 web client from %s port %s on socket %d.", client_ip, client_port, fd); - } - else - debug(D_LISTENER, "New IPv6 web client from %s port %s on socket %d.", client_ip, client_port, fd); - break; - - default: - debug(D_LISTENER, "New UNKNOWN web client from %s port %s on socket %d.", client_ip, client_port, fd); - break; - } - - if(access_list) { - if(!strcmp(client_ip, "127.0.0.1") || !strcmp(client_ip, "::1")) { - strncpy(client_ip, "localhost", ipsize); - client_ip[ipsize - 1] = '\0'; - } - - if(unlikely(!simple_pattern_matches(access_list, client_ip))) { - errno = 0; - debug(D_LISTENER, "Permission denied for client '%s', port '%s'", client_ip, client_port); - error("DENIED ACCESS to client '%s'", client_ip); - close(nfd); - nfd = -1; - errno = EPERM; - } - } - } -#ifdef HAVE_ACCEPT4 - else if(errno == ENOSYS) - error("netdata has been compiled with the assumption that the system has the accept4() call, but it is not here. Recompile netdata like this: ./configure --disable-accept4 ..."); -#endif - - return nfd; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// poll() based listener -// this should be the fastest possible listener for up to 100 sockets -// above 100, an epoll() interface is needed on Linux - -#define POLL_FDS_INCREASE_STEP 10 - -inline POLLINFO *poll_add_fd(POLLJOB *p - , int fd - , int socktype - , uint32_t flags - , const char *client_ip - , const char *client_port - , void *(*add_callback)(POLLINFO *pi, short int *events, void *data) - , void (*del_callback)(POLLINFO *pi) - , int (*rcv_callback)(POLLINFO *pi, short int *events) - , int (*snd_callback)(POLLINFO *pi, short int *events) - , void *data -) { - debug(D_POLLFD, "POLLFD: ADD: request to add fd %d, slots = %zu, used = %zu, min = %zu, max = %zu, next free = %zd", fd, p->slots, p->used, p->min, p->max, p->first_free?(ssize_t)p->first_free->slot:(ssize_t)-1); - - if(unlikely(fd < 0)) return NULL; - - //if(p->limit && p->used >= p->limit) { - // info("Max sockets limit reached (%zu sockets), dropping connection", p->used); - // close(fd); - // return NULL; - //} - - if(unlikely(!p->first_free)) { - size_t new_slots = p->slots + POLL_FDS_INCREASE_STEP; - debug(D_POLLFD, "POLLFD: ADD: increasing size (current = %zu, new = %zu, used = %zu, min = %zu, max = %zu)", p->slots, new_slots, p->used, p->min, p->max); - - p->fds = reallocz(p->fds, sizeof(struct pollfd) * new_slots); - p->inf = reallocz(p->inf, sizeof(POLLINFO) * new_slots); - - // reset all the newly added slots - ssize_t i; - for(i = new_slots - 1; i >= (ssize_t)p->slots ; i--) { - debug(D_POLLFD, "POLLFD: ADD: resetting new slot %zd", i); - p->fds[i].fd = -1; - p->fds[i].events = 0; - p->fds[i].revents = 0; - - p->inf[i].p = p; - p->inf[i].slot = (size_t)i; - p->inf[i].flags = 0; - p->inf[i].socktype = -1; - p->inf[i].client_ip = NULL; - p->inf[i].client_port = NULL; - p->inf[i].del_callback = p->del_callback; - p->inf[i].rcv_callback = p->rcv_callback; - p->inf[i].snd_callback = p->snd_callback; - p->inf[i].data = NULL; - - // link them so that the first free will be earlier in the array - // (we loop decrementing i) - p->inf[i].next = p->first_free; - p->first_free = &p->inf[i]; - } - - p->slots = new_slots; - } - - POLLINFO *pi = p->first_free; - p->first_free = p->first_free->next; - - debug(D_POLLFD, "POLLFD: ADD: selected slot %zu, next free is %zd", pi->slot, p->first_free?(ssize_t)p->first_free->slot:(ssize_t)-1); - - struct pollfd *pf = &p->fds[pi->slot]; - pf->fd = fd; - pf->events = POLLIN; - pf->revents = 0; - - pi->fd = fd; - pi->p = p; - pi->socktype = socktype; - pi->flags = flags; - pi->next = NULL; - pi->client_ip = strdupz(client_ip); - pi->client_port = strdupz(client_port); - - pi->del_callback = del_callback; - pi->rcv_callback = rcv_callback; - pi->snd_callback = snd_callback; - - pi->connected_t = now_boottime_sec(); - pi->last_received_t = 0; - pi->last_sent_t = 0; - pi->last_sent_t = 0; - pi->recv_count = 0; - pi->send_count = 0; - - netdata_thread_disable_cancelability(); - p->used++; - if(unlikely(pi->slot > p->max)) - p->max = pi->slot; - - if(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET) { - pi->data = add_callback(pi, &pf->events, data); - } - - if(pi->flags & POLLINFO_FLAG_SERVER_SOCKET) { - p->min = pi->slot; - } - netdata_thread_enable_cancelability(); - - debug(D_POLLFD, "POLLFD: ADD: completed, slots = %zu, used = %zu, min = %zu, max = %zu, next free = %zd", p->slots, p->used, p->min, p->max, p->first_free?(ssize_t)p->first_free->slot:(ssize_t)-1); - - return pi; -} - -inline void poll_close_fd(POLLINFO *pi) { - POLLJOB *p = pi->p; - - struct pollfd *pf = &p->fds[pi->slot]; - debug(D_POLLFD, "POLLFD: DEL: request to clear slot %zu (fd %d), old next free was %zd", pi->slot, pf->fd, p->first_free?(ssize_t)p->first_free->slot:(ssize_t)-1); - - if(unlikely(pf->fd == -1)) return; - - netdata_thread_disable_cancelability(); - - if(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET) { - pi->del_callback(pi); - - if(likely(!(pi->flags & POLLINFO_FLAG_DONT_CLOSE))) { - if(close(pf->fd) == -1) - error("Failed to close() poll_events() socket %d", pf->fd); - } - } - - pf->fd = -1; - pf->events = 0; - pf->revents = 0; - - pi->fd = -1; - pi->socktype = -1; - pi->flags = 0; - pi->data = NULL; - - pi->del_callback = NULL; - pi->rcv_callback = NULL; - pi->snd_callback = NULL; - - freez(pi->client_ip); - pi->client_ip = NULL; - - freez(pi->client_port); - pi->client_port = NULL; - - pi->next = p->first_free; - p->first_free = pi; - - p->used--; - if(unlikely(p->max == pi->slot)) { - p->max = p->min; - ssize_t i; - for(i = (ssize_t)pi->slot; i > (ssize_t)p->min ;i--) { - if (unlikely(p->fds[i].fd != -1)) { - p->max = (size_t)i; - break; - } - } - } - netdata_thread_enable_cancelability(); - - debug(D_POLLFD, "POLLFD: DEL: completed, slots = %zu, used = %zu, min = %zu, max = %zu, next free = %zd", p->slots, p->used, p->min, p->max, p->first_free?(ssize_t)p->first_free->slot:(ssize_t)-1); -} - -void *poll_default_add_callback(POLLINFO *pi, short int *events, void *data) { - (void)pi; - (void)events; - (void)data; - - // error("POLLFD: internal error: poll_default_add_callback() called"); - - return NULL; -} - -void poll_default_del_callback(POLLINFO *pi) { - if(pi->data) - error("POLLFD: internal error: del_callback_default() called with data pointer - possible memory leak"); -} - -int poll_default_rcv_callback(POLLINFO *pi, short int *events) { - *events |= POLLIN; - - char buffer[1024 + 1]; - - ssize_t rc; - do { - rc = recv(pi->fd, buffer, 1024, MSG_DONTWAIT); - if (rc < 0) { - // read failed - if (errno != EWOULDBLOCK && errno != EAGAIN) { - error("POLLFD: poll_default_rcv_callback(): recv() failed with %zd.", rc); - return -1; - } - } else if (rc) { - // data received - info("POLLFD: internal error: poll_default_rcv_callback() is discarding %zd bytes received on socket %d", rc, pi->fd); - } - } while (rc != -1); - - return 0; -} - -int poll_default_snd_callback(POLLINFO *pi, short int *events) { - *events &= ~POLLOUT; - - info("POLLFD: internal error: poll_default_snd_callback(): nothing to send on socket %d", pi->fd); - return 0; -} - -void poll_default_tmr_callback(void *timer_data) { - (void)timer_data; -} - -static void poll_events_cleanup(void *data) { - POLLJOB *p = (POLLJOB *)data; - - size_t i; - for(i = 0 ; i <= p->max ; i++) { - POLLINFO *pi = &p->inf[i]; - poll_close_fd(pi); - } - - freez(p->fds); - freez(p->inf); -} - -static void poll_events_process(POLLJOB *p, POLLINFO *pi, struct pollfd *pf, short int revents, time_t now) { - short int events = pf->events; - int fd = pf->fd; - pf->revents = 0; - size_t i = pi->slot; - - if(unlikely(fd == -1)) { - debug(D_POLLFD, "POLLFD: LISTENER: ignoring slot %zu, it does not have an fd", i); - return; - } - - debug(D_POLLFD, "POLLFD: LISTENER: processing events for slot %zu (events = %d, revents = %d)", i, events, revents); - - if(revents & POLLIN || revents & POLLPRI) { - // receiving data - - pi->last_received_t = now; - pi->recv_count++; - - if(likely(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET)) { - // read data from client TCP socket - debug(D_POLLFD, "POLLFD: LISTENER: reading data from TCP client slot %zu (fd %d)", i, fd); - - pf->events = 0; - if (pi->rcv_callback(pi, &pf->events) == -1) { - poll_close_fd(&p->inf[i]); - return; - } - pf = &p->fds[i]; - pi = &p->inf[i]; - -#ifdef NETDATA_INTERNAL_CHECKS - // this is common - it is used for web server file copies - if(unlikely(!(pf->events & (POLLIN|POLLOUT)))) { - error("POLLFD: LISTENER: after reading, client slot %zu (fd %d) from '%s:%s' was left without expecting input or output. ", i, fd, pi->client_ip?pi->client_ip:"", pi->client_port?pi->client_port:""); - //poll_close_fd(pi); - //return; - } -#endif - } - else if(likely(pi->flags & POLLINFO_FLAG_SERVER_SOCKET)) { - // new connection - // debug(D_POLLFD, "POLLFD: LISTENER: accepting connections from slot %zu (fd %d)", i, fd); - - switch(pi->socktype) { - case SOCK_STREAM: { - // a TCP socket - // we accept the connection - - int nfd; - do { - char client_ip[NI_MAXHOST + 1]; - char client_port[NI_MAXSERV + 1]; - - debug(D_POLLFD, "POLLFD: LISTENER: calling accept4() slot %zu (fd %d)", i, fd); - nfd = accept_socket(fd, SOCK_NONBLOCK, client_ip, NI_MAXHOST + 1, client_port, NI_MAXSERV + 1, p->access_list); - if (unlikely(nfd < 0)) { - // accept failed - - debug(D_POLLFD, "POLLFD: LISTENER: accept4() slot %zu (fd %d) failed.", i, fd); - - if(unlikely(errno == EMFILE)) { - error("POLLFD: LISTENER: too many open files - sleeping for 1ms - used by this thread %zu, max for this thread %zu", p->used, p->limit); - usleep(1000); // 10ms - } - else if(unlikely(errno != EWOULDBLOCK && errno != EAGAIN)) - error("POLLFD: LISTENER: accept() failed."); - - break; - } - else { - // accept ok - // info("POLLFD: LISTENER: client '[%s]:%s' connected to '%s' on fd %d", client_ip, client_port, sockets->fds_names[i], nfd); - poll_add_fd(p - , nfd - , SOCK_STREAM - , POLLINFO_FLAG_CLIENT_SOCKET - , client_ip - , client_port - , p->add_callback - , p->del_callback - , p->rcv_callback - , p->snd_callback - , NULL - ); - - // it may have reallocated them, so refresh our pointers - pf = &p->fds[i]; - pi = &p->inf[i]; - } - } while (nfd >= 0 && (!p->limit || p->used < p->limit)); - break; - } - - case SOCK_DGRAM: { - // a UDP socket - // we read data from the server socket - - debug(D_POLLFD, "POLLFD: LISTENER: reading data from UDP slot %zu (fd %d)", i, fd); - - // FIXME: access_list is not applied to UDP - - pf->events = 0; - pi->rcv_callback(pi, &pf->events); - break; - } - - default: { - error("POLLFD: LISTENER: Unknown socktype %d on slot %zu", pi->socktype, pi->slot); - break; - } - } - } - } - - if(unlikely(revents & POLLOUT)) { - // sending data - debug(D_POLLFD, "POLLFD: LISTENER: sending data to socket on slot %zu (fd %d)", i, fd); - - pi->last_sent_t = now; - pi->send_count++; - - pf->events = 0; - if (pi->snd_callback(pi, &pf->events) == -1) { - poll_close_fd(&p->inf[i]); - return; - } - pf = &p->fds[i]; - pi = &p->inf[i]; - -#ifdef NETDATA_INTERNAL_CHECKS - // this is common - it is used for streaming - if(unlikely(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET && !(pf->events & (POLLIN|POLLOUT)))) { - error("POLLFD: LISTENER: after sending, client slot %zu (fd %d) from '%s:%s' was left without expecting input or output. ", i, fd, pi->client_ip?pi->client_ip:"", pi->client_port?pi->client_port:""); - //poll_close_fd(pi); - //return; - } -#endif - } - - if(unlikely(revents & POLLERR)) { - error("POLLFD: LISTENER: processing POLLERR events for slot %zu fd %d (events = %d, revents = %d)", i, events, revents, fd); - pf->events = 0; - poll_close_fd(pi); - return; - } - - if(unlikely(revents & POLLHUP)) { - error("POLLFD: LISTENER: processing POLLHUP events for slot %zu fd %d (events = %d, revents = %d)", i, events, revents, fd); - pf->events = 0; - poll_close_fd(pi); - return; - } - - if(unlikely(revents & POLLNVAL)) { - error("POLLFD: LISTENER: processing POLLNVAL events for slot %zu fd %d (events = %d, revents = %d)", i, events, revents, fd); - pf->events = 0; - poll_close_fd(pi); - return; - } -} - -void poll_events(LISTEN_SOCKETS *sockets - , void *(*add_callback)(POLLINFO *pi, short int *events, void *data) - , void (*del_callback)(POLLINFO *pi) - , int (*rcv_callback)(POLLINFO *pi, short int *events) - , int (*snd_callback)(POLLINFO *pi, short int *events) - , void (*tmr_callback)(void *timer_data) - , SIMPLE_PATTERN *access_list - , void *data - , time_t tcp_request_timeout_seconds - , time_t tcp_idle_timeout_seconds - , time_t timer_milliseconds - , void *timer_data - , size_t max_tcp_sockets -) { - if(!sockets || !sockets->opened) { - error("POLLFD: internal error: no listening sockets are opened"); - return; - } - - if(timer_milliseconds <= 0) timer_milliseconds = 0; - - int retval; - - POLLJOB p = { - .slots = 0, - .used = 0, - .max = 0, - .limit = max_tcp_sockets, - .fds = NULL, - .inf = NULL, - .first_free = NULL, - - .complete_request_timeout = tcp_request_timeout_seconds, - .idle_timeout = tcp_idle_timeout_seconds, - .checks_every = (tcp_idle_timeout_seconds / 3) + 1, - - .access_list = access_list, - - .timer_milliseconds = timer_milliseconds, - .timer_data = timer_data, - - .add_callback = add_callback?add_callback:poll_default_add_callback, - .del_callback = del_callback?del_callback:poll_default_del_callback, - .rcv_callback = rcv_callback?rcv_callback:poll_default_rcv_callback, - .snd_callback = snd_callback?snd_callback:poll_default_snd_callback, - .tmr_callback = tmr_callback?tmr_callback:poll_default_tmr_callback - }; - - size_t i; - for(i = 0; i < sockets->opened ;i++) { - - POLLINFO *pi = poll_add_fd(&p - , sockets->fds[i] - , sockets->fds_types[i] - , POLLINFO_FLAG_SERVER_SOCKET - , (sockets->fds_names[i])?sockets->fds_names[i]:"UNKNOWN" - , "" - , p.add_callback - , p.del_callback - , p.rcv_callback - , p.snd_callback - , NULL - ); - - pi->data = data; - info("POLLFD: LISTENER: listening on '%s'", (sockets->fds_names[i])?sockets->fds_names[i]:"UNKNOWN"); - } - - int listen_sockets_active = 1; - - int timeout_ms = 1000; // in milliseconds - time_t last_check = now_boottime_sec(); - - usec_t timer_usec = timer_milliseconds * USEC_PER_MS; - usec_t now_usec = 0, next_timer_usec = 0, last_timer_usec = 0; - if(unlikely(timer_usec)) { - now_usec = now_boottime_usec(); - next_timer_usec = now_usec - (now_usec % timer_usec) + timer_usec; - } - - netdata_thread_cleanup_push(poll_events_cleanup, &p); - - while(!netdata_exit) { - if(unlikely(timer_usec)) { - now_usec = now_boottime_usec(); - - if(unlikely(timer_usec && now_usec >= next_timer_usec)) { - debug(D_POLLFD, "Calling timer callback after %zu usec", (size_t)(now_usec - last_timer_usec)); - last_timer_usec = now_usec; - p.tmr_callback(p.timer_data); - now_usec = now_boottime_usec(); - next_timer_usec = now_usec - (now_usec % timer_usec) + timer_usec; - } - - usec_t dt_usec = next_timer_usec - now_usec; - if(dt_usec > 1000 * USEC_PER_MS) - timeout_ms = 1000; - else - timeout_ms = (int)(dt_usec / USEC_PER_MS); - } - - // enable or disable the TCP listening sockets, based on the current number of sockets used and the limit set - if((listen_sockets_active && (p.limit && p.used >= p.limit)) || (!listen_sockets_active && (!p.limit || p.used < p.limit))) { - listen_sockets_active = !listen_sockets_active; - info("%s listening sockets (used TCP sockets %zu, max allowed for this worker %zu)", (listen_sockets_active)?"ENABLING":"DISABLING", p.used, p.limit); - for (i = 0; i <= p.max; i++) { - if(p.inf[i].flags & POLLINFO_FLAG_SERVER_SOCKET && p.inf[i].socktype == SOCK_STREAM) { - p.fds[i].events = (short int) ((listen_sockets_active) ? POLLIN : 0); - } - } - } - - debug(D_POLLFD, "POLLFD: LISTENER: Waiting on %zu sockets for %zu ms...", p.max + 1, (size_t)timeout_ms); - retval = poll(p.fds, p.max + 1, timeout_ms); - time_t now = now_boottime_sec(); - - if(unlikely(retval == -1)) { - error("POLLFD: LISTENER: poll() failed while waiting on %zu sockets.", p.max + 1); - break; - } - else if(unlikely(!retval)) { - debug(D_POLLFD, "POLLFD: LISTENER: poll() timeout."); - } - else { - for (i = 0; i <= p.max; i++) { - struct pollfd *pf = &p.fds[i]; - short int revents = pf->revents; - if (unlikely(revents)) - poll_events_process(&p, &p.inf[i], pf, revents, now); - } - } - - if(unlikely(p.checks_every > 0 && now - last_check > p.checks_every)) { - last_check = now; - - // security checks - for(i = 0; i <= p.max; i++) { - POLLINFO *pi = &p.inf[i]; - - if(likely(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET)) { - if (unlikely(pi->send_count == 0 && p.complete_request_timeout > 0 && (now - pi->connected_t) >= p.complete_request_timeout)) { - info("POLLFD: LISTENER: client slot %zu (fd %d) from '%s:%s' has not sent a complete request in %zu seconds - closing it. " - , i - , pi->fd - , pi->client_ip ? pi->client_ip : "" - , pi->client_port ? pi->client_port : "" - , (size_t) p.complete_request_timeout - ); - poll_close_fd(pi); - } - else if(unlikely(pi->recv_count && p.idle_timeout > 0 && now - ((pi->last_received_t > pi->last_sent_t) ? pi->last_received_t : pi->last_sent_t) >= p.idle_timeout )) { - info("POLLFD: LISTENER: client slot %zu (fd %d) from '%s:%s' is idle for more than %zu seconds - closing it. " - , i - , pi->fd - , pi->client_ip ? pi->client_ip : "" - , pi->client_port ? pi->client_port : "" - , (size_t) p.idle_timeout - ); - poll_close_fd(pi); - } - } - } - } - } - - netdata_thread_cleanup_pop(1); - debug(D_POLLFD, "POLLFD: LISTENER: cleanup completed"); -} diff --git a/src/socket.h b/src/socket.h deleted file mode 100644 index 7b3e726ec..000000000 --- a/src/socket.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef NETDATA_SOCKET_H -#define NETDATA_SOCKET_H - -#ifndef MAX_LISTEN_FDS -#define MAX_LISTEN_FDS 50 -#endif - -typedef struct listen_sockets { - const char *config_section; // the netdata configuration section to read settings from - const char *default_bind_to; // the default bind to configuration string - int default_port; // the default port to use - int backlog; // the default listen backlog to use - - size_t opened; // the number of sockets opened - size_t failed; // the number of sockets attempted to open, but failed - int fds[MAX_LISTEN_FDS]; // the open sockets - char *fds_names[MAX_LISTEN_FDS]; // descriptions for the open sockets - int fds_types[MAX_LISTEN_FDS]; // the socktype for the open sockets (SOCK_STREAM, SOCK_DGRAM) - int fds_families[MAX_LISTEN_FDS]; // the family of the open sockets (AF_UNIX, AF_INET, AF_INET6) -} LISTEN_SOCKETS; - -extern char *strdup_client_description(int family, const char *protocol, const char *ip, int port); - -extern int listen_sockets_setup(LISTEN_SOCKETS *sockets); -extern void listen_sockets_close(LISTEN_SOCKETS *sockets); - -extern int connect_to_this(const char *definition, int default_port, struct timeval *timeout); -extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size); - -extern ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout); -extern ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout); - -extern int sock_setnonblock(int fd); -extern int sock_delnonblock(int fd); -extern int sock_setreuse(int fd, int reuse); -extern int sock_setreuse_port(int fd, int reuse); -extern int sock_enlarge_in(int fd); -extern int sock_enlarge_out(int fd); - -extern int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize, SIMPLE_PATTERN *access_list); - -#ifndef HAVE_ACCEPT4 -extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags); - -#ifndef SOCK_NONBLOCK -#define SOCK_NONBLOCK 00004000 -#endif /* #ifndef SOCK_NONBLOCK */ - -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 02000000 -#endif /* #ifndef SOCK_CLOEXEC */ - -#endif /* #ifndef HAVE_ACCEPT4 */ - - -// ---------------------------------------------------------------------------- -// poll() based listener - -#define POLLINFO_FLAG_SERVER_SOCKET 0x00000001 -#define POLLINFO_FLAG_CLIENT_SOCKET 0x00000002 -#define POLLINFO_FLAG_DONT_CLOSE 0x00000004 - -typedef struct poll POLLJOB; - -typedef struct pollinfo { - POLLJOB *p; // the parent - size_t slot; // the slot id - - int fd; // the file descriptor - int socktype; // the client socket type - char *client_ip; // the connected client IP - char *client_port; // the connected client port - - time_t connected_t; // the time the socket connected - time_t last_received_t; // the time the socket last received data - time_t last_sent_t; // the time the socket last sent data - - size_t recv_count; // the number of times the socket was ready for inbound traffic - size_t send_count; // the number of times the socket was ready for outbound traffic - - uint32_t flags; // internal flags - - // callbacks for this socket - void (*del_callback)(struct pollinfo *pi); - int (*rcv_callback)(struct pollinfo *pi, short int *events); - int (*snd_callback)(struct pollinfo *pi, short int *events); - - // the user data - void *data; - - // linking of free pollinfo structures - // for quickly finding the next available - // this is like a stack, it grows and shrinks - // (with gaps - lower empty slots are preferred) - struct pollinfo *next; -} POLLINFO; - -struct poll { - size_t slots; - size_t used; - size_t min; - size_t max; - - size_t limit; - - time_t complete_request_timeout; - time_t idle_timeout; - time_t checks_every; - - time_t timer_milliseconds; - void *timer_data; - - struct pollfd *fds; - struct pollinfo *inf; - struct pollinfo *first_free; - - SIMPLE_PATTERN *access_list; - - void *(*add_callback)(POLLINFO *pi, short int *events, void *data); - void (*del_callback)(POLLINFO *pi); - int (*rcv_callback)(POLLINFO *pi, short int *events); - int (*snd_callback)(POLLINFO *pi, short int *events); - void (*tmr_callback)(void *timer_data); -}; - -#define pollinfo_from_slot(p, slot) (&((p)->inf[(slot)])) - -extern int poll_default_snd_callback(POLLINFO *pi, short int *events); -extern int poll_default_rcv_callback(POLLINFO *pi, short int *events); -extern void poll_default_del_callback(POLLINFO *pi); -extern void *poll_default_add_callback(POLLINFO *pi, short int *events, void *data); - -extern POLLINFO *poll_add_fd(POLLJOB *p - , int fd - , int socktype - , uint32_t flags - , const char *client_ip - , const char *client_port - , void *(*add_callback)(POLLINFO *pi, short int *events, void *data) - , void (*del_callback)(POLLINFO *pi) - , int (*rcv_callback)(POLLINFO *pi, short int *events) - , int (*snd_callback)(POLLINFO *pi, short int *events) - , void *data -); -extern void poll_close_fd(POLLINFO *pi); - -extern void poll_events(LISTEN_SOCKETS *sockets - , void *(*add_callback)(POLLINFO *pi, short int *events, void *data) - , void (*del_callback)(POLLINFO *pi) - , int (*rcv_callback)(POLLINFO *pi, short int *events) - , int (*snd_callback)(POLLINFO *pi, short int *events) - , void (*tmr_callback)(void *timer_data) - , SIMPLE_PATTERN *access_list - , void *data - , time_t tcp_request_timeout_seconds - , time_t tcp_idle_timeout_seconds - , time_t timer_milliseconds - , void *timer_data - , size_t max_tcp_sockets -); - -#endif //NETDATA_SOCKET_H diff --git a/src/statistical.c b/src/statistical.c deleted file mode 100644 index d4b33fd5a..000000000 --- a/src/statistical.c +++ /dev/null @@ -1,459 +0,0 @@ -#include "common.h" - -// -------------------------------------------------------------------------------------------------------------------- - -inline LONG_DOUBLE sum_and_count(const LONG_DOUBLE *series, size_t entries, size_t *count) { - if(unlikely(entries == 0)) { - if(likely(count)) - *count = 0; - - return NAN; - } - - if(unlikely(entries == 1)) { - if(likely(count)) - *count = (isnan(series[0])?0:1); - - return series[0]; - } - - size_t i, c = 0; - LONG_DOUBLE sum = 0; - - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - c++; - sum += value; - } - - if(likely(count)) - *count = c; - - if(unlikely(c == 0)) - return NAN; - - return sum; -} - -inline LONG_DOUBLE sum(const LONG_DOUBLE *series, size_t entries) { - return sum_and_count(series, entries, NULL); -} - -inline LONG_DOUBLE average(const LONG_DOUBLE *series, size_t entries) { - size_t count = 0; - LONG_DOUBLE sum = sum_and_count(series, entries, &count); - - if(unlikely(count == 0)) - return NAN; - - return sum / (LONG_DOUBLE)count; -} - -// -------------------------------------------------------------------------------------------------------------------- - -LONG_DOUBLE moving_average(const LONG_DOUBLE *series, size_t entries, size_t period) { - if(unlikely(period <= 0)) - return 0.0; - - size_t i, count; - LONG_DOUBLE sum = 0, avg = 0; - LONG_DOUBLE p[period]; - - for(count = 0; count < period ; count++) - p[count] = 0.0; - - for(i = 0, count = 0; i < entries; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - - if(unlikely(count < period)) { - sum += value; - avg = (count == period - 1) ? sum / (LONG_DOUBLE)period : 0; - } - else { - sum = sum - p[count % period] + value; - avg = sum / (LONG_DOUBLE)period; - } - - p[count % period] = value; - count++; - } - - return avg; -} - -// -------------------------------------------------------------------------------------------------------------------- - -static int qsort_compare(const void *a, const void *b) { - LONG_DOUBLE *p1 = (LONG_DOUBLE *)a, *p2 = (LONG_DOUBLE *)b; - LONG_DOUBLE n1 = *p1, n2 = *p2; - - if(unlikely(isnan(n1) || isnan(n2))) { - if(isnan(n1) && !isnan(n2)) return -1; - if(!isnan(n1) && isnan(n2)) return 1; - return 0; - } - if(unlikely(isinf(n1) || isinf(n2))) { - if(!isinf(n1) && isinf(n2)) return -1; - if(isinf(n1) && !isinf(n2)) return 1; - return 0; - } - - if(unlikely(n1 < n2)) return -1; - if(unlikely(n1 > n2)) return 1; - return 0; -} - -inline void sort_series(LONG_DOUBLE *series, size_t entries) { - qsort(series, entries, sizeof(LONG_DOUBLE), qsort_compare); -} - -inline LONG_DOUBLE *copy_series(const LONG_DOUBLE *series, size_t entries) { - LONG_DOUBLE *copy = mallocz(sizeof(LONG_DOUBLE) * entries); - memcpy(copy, series, sizeof(LONG_DOUBLE) * entries); - return copy; -} - -LONG_DOUBLE median_on_sorted_series(const LONG_DOUBLE *series, size_t entries) { - if(unlikely(entries == 0)) - return NAN; - - if(unlikely(entries == 1)) - return series[0]; - - if(unlikely(entries == 2)) - return (series[0] + series[1]) / 2; - - LONG_DOUBLE avg; - if(entries % 2 == 0) { - size_t m = entries / 2; - avg = (series[m] + series[m + 1]) / 2; - } - else { - avg = series[entries / 2]; - } - - return avg; -} - -LONG_DOUBLE median(const LONG_DOUBLE *series, size_t entries) { - if(unlikely(entries == 0)) - return NAN; - - if(unlikely(entries == 1)) - return series[0]; - - if(unlikely(entries == 2)) - return (series[0] + series[1]) / 2; - - LONG_DOUBLE *copy = copy_series(series, entries); - sort_series(copy, entries); - - LONG_DOUBLE avg = median_on_sorted_series(copy, entries); - - freez(copy); - return avg; -} - -// -------------------------------------------------------------------------------------------------------------------- - -LONG_DOUBLE moving_median(const LONG_DOUBLE *series, size_t entries, size_t period) { - if(entries <= period) - return median(series, entries); - - LONG_DOUBLE *data = copy_series(series, entries); - - size_t i; - for(i = period; i < entries; i++) { - data[i - period] = median(&series[i - period], period); - } - - LONG_DOUBLE avg = median(data, entries - period); - freez(data); - return avg; -} - -// -------------------------------------------------------------------------------------------------------------------- - -// http://stackoverflow.com/a/15150143/4525767 -LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries) { - LONG_DOUBLE median = 0.0f; - LONG_DOUBLE average = 0.0f; - size_t i; - - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - - average += ( value - average ) * 0.1f; // rough running average. - median += copysignl( average * 0.01, value - median ); - } - - return median; -} - -// -------------------------------------------------------------------------------------------------------------------- - -LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries) { - if(unlikely(entries < 1)) - return NAN; - - if(unlikely(entries == 1)) - return series[0]; - - size_t i, count = 0; - LONG_DOUBLE sum = 0; - - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - - count++; - sum += value; - } - - if(unlikely(count == 0)) - return NAN; - - if(unlikely(count == 1)) - return sum; - - LONG_DOUBLE average = sum / (LONG_DOUBLE)count; - - for(i = 0, count = 0, sum = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - - count++; - sum += powl(value - average, 2); - } - - if(unlikely(count == 0)) - return NAN; - - if(unlikely(count == 1)) - return average; - - LONG_DOUBLE variance = sum / (LONG_DOUBLE)(count - 1); // remove -1 to have a population stddev - - LONG_DOUBLE stddev = sqrtl(variance); - return stddev; -} - -// -------------------------------------------------------------------------------------------------------------------- - -LONG_DOUBLE single_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha) { - size_t i, count = 0; - LONG_DOUBLE level = 0, sum = 0; - - if(unlikely(isnan(alpha))) - alpha = 0.3; - - for(i = 0; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - count++; - - sum += value; - - LONG_DOUBLE last_level = level; - level = alpha * value + (1.0 - alpha) * last_level; - } - - return level; -} - -// -------------------------------------------------------------------------------------------------------------------- - -// http://grisha.org/blog/2016/02/16/triple-exponential-smoothing-forecasting-part-ii/ -LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE *forecast) { - size_t i, count = 0; - LONG_DOUBLE level = series[0], trend, sum; - - if(unlikely(isnan(alpha))) - alpha = 0.3; - - if(unlikely(isnan(beta))) - beta = 0.05; - - if(likely(entries > 1)) - trend = series[1] - series[0]; - else - trend = 0; - - sum = series[0]; - - for(i = 1; i < entries ; i++) { - LONG_DOUBLE value = series[i]; - if(unlikely(isnan(value) || isinf(value))) continue; - count++; - - sum += value; - - LONG_DOUBLE last_level = level; - - level = alpha * value + (1.0 - alpha) * (level + trend); - trend = beta * (level - last_level) + (1.0 - beta) * trend; - } - - if(forecast) - *forecast = level + trend; - - return level; -} - -// -------------------------------------------------------------------------------------------------------------------- - -/* - * Based on th R implementation - * - * a: level component - * b: trend component - * s: seasonal component - * - * Additive: - * - * Yhat[t+h] = a[t] + h * b[t] + s[t + 1 + (h - 1) mod p], - * a[t] = α (Y[t] - s[t-p]) + (1-α) (a[t-1] + b[t-1]) - * b[t] = β (a[t] - a[t-1]) + (1-β) b[t-1] - * s[t] = γ (Y[t] - a[t]) + (1-γ) s[t-p] - * - * Multiplicative: - * - * Yhat[t+h] = (a[t] + h * b[t]) * s[t + 1 + (h - 1) mod p], - * a[t] = α (Y[t] / s[t-p]) + (1-α) (a[t-1] + b[t-1]) - * b[t] = β (a[t] - a[t-1]) + (1-β) b[t-1] - * s[t] = γ (Y[t] / a[t]) + (1-γ) s[t-p] - */ -static int __HoltWinters( - const LONG_DOUBLE *series, - int entries, // start_time + h - - LONG_DOUBLE alpha, // alpha parameter of Holt-Winters Filter. - LONG_DOUBLE beta, // beta parameter of Holt-Winters Filter. If set to 0, the function will do exponential smoothing. - LONG_DOUBLE gamma, // gamma parameter used for the seasonal component. If set to 0, an non-seasonal model is fitted. - - const int *seasonal, - const int *period, - const LONG_DOUBLE *a, // Start value for level (a[0]). - const LONG_DOUBLE *b, // Start value for trend (b[0]). - LONG_DOUBLE *s, // Vector of start values for the seasonal component (s_1[0] ... s_p[0]) - - /* return values */ - LONG_DOUBLE *SSE, // The final sum of squared errors achieved in optimizing - LONG_DOUBLE *level, // Estimated values for the level component (size entries - t + 2) - LONG_DOUBLE *trend, // Estimated values for the trend component (size entries - t + 2) - LONG_DOUBLE *season // Estimated values for the seasonal component (size entries - t + 2) -) -{ - if(unlikely(entries < 4)) - return 0; - - int start_time = 2; - - LONG_DOUBLE res = 0, xhat = 0, stmp = 0; - int i, i0, s0; - - /* copy start values to the beginning of the vectors */ - level[0] = *a; - if(beta > 0) trend[0] = *b; - if(gamma > 0) memcpy(season, s, *period * sizeof(LONG_DOUBLE)); - - for(i = start_time - 1; i < entries; i++) { - /* indices for period i */ - i0 = i - start_time + 2; - s0 = i0 + *period - 1; - - /* forecast *for* period i */ - xhat = level[i0 - 1] + (beta > 0 ? trend[i0 - 1] : 0); - stmp = gamma > 0 ? season[s0 - *period] : (*seasonal != 1); - if (*seasonal == 1) - xhat += stmp; - else - xhat *= stmp; - - /* Sum of Squared Errors */ - res = series[i] - xhat; - *SSE += res * res; - - /* estimate of level *in* period i */ - if (*seasonal == 1) - level[i0] = alpha * (series[i] - stmp) - + (1 - alpha) * (level[i0 - 1] + trend[i0 - 1]); - else - level[i0] = alpha * (series[i] / stmp) - + (1 - alpha) * (level[i0 - 1] + trend[i0 - 1]); - - /* estimate of trend *in* period i */ - if (beta > 0) - trend[i0] = beta * (level[i0] - level[i0 - 1]) - + (1 - beta) * trend[i0 - 1]; - - /* estimate of seasonal component *in* period i */ - if (gamma > 0) { - if (*seasonal == 1) - season[s0] = gamma * (series[i] - level[i0]) - + (1 - gamma) * stmp; - else - season[s0] = gamma * (series[i] / level[i0]) - + (1 - gamma) * stmp; - } - } - - return 1; -} - -LONG_DOUBLE holtwinters(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE gamma, LONG_DOUBLE *forecast) { - if(unlikely(isnan(alpha))) - alpha = 0.3; - - if(unlikely(isnan(beta))) - beta = 0.05; - - if(unlikely(isnan(gamma))) - gamma = 0; - - int seasonal = 0; - int period = 0; - LONG_DOUBLE a0 = series[0]; - LONG_DOUBLE b0 = 0; - LONG_DOUBLE s[] = {}; - - LONG_DOUBLE errors = 0.0; - size_t nb_computations = entries; - LONG_DOUBLE *estimated_level = callocz(nb_computations, sizeof(LONG_DOUBLE)); - LONG_DOUBLE *estimated_trend = callocz(nb_computations, sizeof(LONG_DOUBLE)); - LONG_DOUBLE *estimated_season = callocz(nb_computations, sizeof(LONG_DOUBLE)); - - int ret = __HoltWinters( - series, - (int)entries, - alpha, - beta, - gamma, - &seasonal, - &period, - &a0, - &b0, - s, - &errors, - estimated_level, - estimated_trend, - estimated_season - ); - - LONG_DOUBLE value = estimated_level[nb_computations - 1]; - - if(forecast) - *forecast = 0.0; - - freez(estimated_level); - freez(estimated_trend); - freez(estimated_season); - - if(!ret) - return 0.0; - - return value; -} diff --git a/src/statistical.h b/src/statistical.h deleted file mode 100644 index 675389021..000000000 --- a/src/statistical.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef NETDATA_STATISTICAL_H -#define NETDATA_STATISTICAL_H - -extern LONG_DOUBLE average(const LONG_DOUBLE *series, size_t entries); -extern LONG_DOUBLE moving_average(const LONG_DOUBLE *series, size_t entries, size_t period); -extern LONG_DOUBLE median(const LONG_DOUBLE *series, size_t entries); -extern LONG_DOUBLE moving_median(const LONG_DOUBLE *series, size_t entries, size_t period); -extern LONG_DOUBLE running_median_estimate(const LONG_DOUBLE *series, size_t entries); -extern LONG_DOUBLE standard_deviation(const LONG_DOUBLE *series, size_t entries); -extern LONG_DOUBLE single_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha); -extern LONG_DOUBLE double_exponential_smoothing(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE *forecast); -extern LONG_DOUBLE holtwinters(const LONG_DOUBLE *series, size_t entries, LONG_DOUBLE alpha, LONG_DOUBLE beta, LONG_DOUBLE gamma, LONG_DOUBLE *forecast); -extern LONG_DOUBLE sum_and_count(const LONG_DOUBLE *series, size_t entries, size_t *count); -extern LONG_DOUBLE sum(const LONG_DOUBLE *series, size_t entries); -extern LONG_DOUBLE median_on_sorted_series(const LONG_DOUBLE *series, size_t entries); -extern LONG_DOUBLE *copy_series(const LONG_DOUBLE *series, size_t entries); -extern void sort_series(LONG_DOUBLE *series, size_t entries); - -#endif //NETDATA_STATISTICAL_H diff --git a/src/statsd.c b/src/statsd.c deleted file mode 100644 index 44ebd8894..000000000 --- a/src/statsd.c +++ /dev/null @@ -1,2499 +0,0 @@ -#include "common.h" - -#define STATSD_CHART_PREFIX "statsd" -#define STATSD_CHART_PRIORITY 90000 - -// -------------------------------------------------------------------------------------- - -// #define STATSD_MULTITHREADED 1 - -#ifdef STATSD_MULTITHREADED -// DO NOT ENABLE MULTITHREADING - IT IS NOT WELL TESTED -#define STATSD_AVL_TREE avl_tree_lock -#define STATSD_AVL_INSERT avl_insert_lock -#define STATSD_AVL_SEARCH avl_search_lock -#define STATSD_AVL_INDEX_INIT { .avl_tree = { NULL, statsd_metric_compare }, .rwlock = AVL_LOCK_INITIALIZER } -#define STATSD_FIRST_PTR_MUTEX netdata_mutex_t first_mutex -#define STATSD_FIRST_PTR_MUTEX_INIT .first_mutex = NETDATA_MUTEX_INITIALIZER -#define STATSD_FIRST_PTR_MUTEX_LOCK(index) netdata_mutex_lock(&((index)->first_mutex)) -#define STATSD_FIRST_PTR_MUTEX_UNLOCK(index) netdata_mutex_unlock(&((index)->first_mutex)) -#define STATSD_DICTIONARY_OPTIONS DICTIONARY_FLAG_DEFAULT -#else -#define STATSD_AVL_TREE avl_tree -#define STATSD_AVL_INSERT avl_insert -#define STATSD_AVL_SEARCH avl_search -#define STATSD_AVL_INDEX_INIT { .root = NULL, .compar = statsd_metric_compare } -#define STATSD_FIRST_PTR_MUTEX -#define STATSD_FIRST_PTR_MUTEX_INIT -#define STATSD_FIRST_PTR_MUTEX_LOCK(index) -#define STATSD_FIRST_PTR_MUTEX_UNLOCK(index) -#define STATSD_DICTIONARY_OPTIONS DICTIONARY_FLAG_SINGLE_THREADED -#endif - -#define STATSD_DECIMAL_DETAIL 1000 // floating point values get multiplied by this, with the same divisor - -// -------------------------------------------------------------------------------------------------------------------- -// data specific to each metric type - -typedef struct statsd_metric_gauge { - LONG_DOUBLE value; -} STATSD_METRIC_GAUGE; - -typedef struct statsd_metric_counter { // counter and meter - long long value; -} STATSD_METRIC_COUNTER; - -typedef struct statsd_histogram_extensions { - netdata_mutex_t mutex; - - // average is stored in metric->last - collected_number last_min; - collected_number last_max; - collected_number last_percentile; - collected_number last_median; - collected_number last_stddev; - collected_number last_sum; - - int zeroed; - - RRDDIM *rd_min; - RRDDIM *rd_max; - RRDDIM *rd_percentile; - RRDDIM *rd_median; - RRDDIM *rd_stddev; - RRDDIM *rd_sum; - - size_t size; - size_t used; - LONG_DOUBLE *values; // dynamic array of values collected -} STATSD_METRIC_HISTOGRAM_EXTENSIONS; - -typedef struct statsd_metric_histogram { // histogram and timer - STATSD_METRIC_HISTOGRAM_EXTENSIONS *ext; -} STATSD_METRIC_HISTOGRAM; - -typedef struct statsd_metric_set { - DICTIONARY *dict; - size_t unique; -} STATSD_METRIC_SET; - - -// -------------------------------------------------------------------------------------------------------------------- -// this is a metric - for all types of metrics - -typedef enum statsd_metric_options { - STATSD_METRIC_OPTION_NONE = 0x00000000, // no options set - STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED = 0x00000001, // do not update the chart dimension, when this metric is not collected - STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED = 0x00000002, // render a private chart for this metric - STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED = 0x00000004, // the metric has been checked if it should get private chart or not - STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT = 0x00000008, // show the count of events for this private chart - STATSD_METRIC_OPTION_CHECKED_IN_APPS = 0x00000010, // set when this metric has been checked agains apps -} STATS_METRIC_OPTIONS; - -typedef enum statsd_metric_type { - STATSD_METRIC_TYPE_GAUGE, - STATSD_METRIC_TYPE_COUNTER, - STATSD_METRIC_TYPE_METER, - STATSD_METRIC_TYPE_TIMER, - STATSD_METRIC_TYPE_HISTOGRAM, - STATSD_METRIC_TYPE_SET -} STATSD_METRIC_TYPE; - - -typedef struct statsd_metric { - avl avl; // indexing - - const char *name; // the name of the metric - uint32_t hash; // hash of the name - - STATSD_METRIC_TYPE type; - - // metadata about data collection - collected_number events; // the number of times this metric has been collected (never resets) - size_t count; // the number of times this metric has been collected since the last flush - - // the actual collected data - union { - STATSD_METRIC_GAUGE gauge; - STATSD_METRIC_COUNTER counter; - STATSD_METRIC_HISTOGRAM histogram; - STATSD_METRIC_SET set; - }; - - // chart related members - STATS_METRIC_OPTIONS options; // STATSD_METRIC_OPTION_* (bitfield) - char reset; // set to 1 to reset this metric to zero - collected_number last; // the last value sent to netdata - RRDSET *st; // the chart of this metric - RRDDIM *rd_value; // the dimension of this metric value - RRDDIM *rd_count; // the dimension for the number of events received - - // linking, used for walking through all metrics - struct statsd_metric *next; -} STATSD_METRIC; - - -// -------------------------------------------------------------------------------------------------------------------- -// each type of metric has its own index - -typedef struct statsd_index { - char *name; // the name of the index of metrics - size_t events; // the number of events processed for this index - size_t metrics; // the number of metrics in this index - - STATSD_AVL_TREE index; // the AVL tree - - STATSD_METRIC *first; // the linked list of metrics (new metrics are added in front) - STATSD_FIRST_PTR_MUTEX; // when mutli-threading is enabled, a lock to protect the linked list - - STATS_METRIC_OPTIONS default_options; // default options for all metrics in this index -} STATSD_INDEX; - -static int statsd_metric_compare(void* a, void* b); - -// -------------------------------------------------------------------------------------------------------------------- -// synthetic charts - -typedef enum statsd_app_chart_dimension_value_type { - STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS, - STATSD_APP_CHART_DIM_VALUE_TYPE_LAST, - STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE, - STATSD_APP_CHART_DIM_VALUE_TYPE_SUM, - STATSD_APP_CHART_DIM_VALUE_TYPE_MIN, - STATSD_APP_CHART_DIM_VALUE_TYPE_MAX, - STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE, - STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN, - STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV -} STATSD_APP_CHART_DIM_VALUE_TYPE; - -typedef struct statsd_app_chart_dimension { - const char *name; // the name of this dimension - const char *metric; // the source metric name of this dimension - uint32_t metric_hash; // hash for fast string comparisons - - SIMPLE_PATTERN *metric_pattern; // set when the 'metric' is a simple pattern - - collected_number multiplier; // the multipler of the dimension - collected_number divisor; // the divisor of the dimension - RRDDIM_FLAGS flags; // the RRDDIM flags for this dimension - - STATSD_APP_CHART_DIM_VALUE_TYPE value_type; // which value to use of the source metric - - RRDDIM *rd; // a pointer to the RRDDIM that has been created for this dimension - collected_number *value_ptr; // a pointer to the source metric value - RRD_ALGORITHM algorithm; // the algorithm of this dimension - - struct statsd_app_chart_dimension *next; // the next dimension for this chart -} STATSD_APP_CHART_DIM; - -typedef struct statsd_app_chart { - const char *source; - const char *id; - const char *name; - const char *title; - const char *family; - const char *context; - const char *units; - long priority; - RRDSET_TYPE chart_type; - STATSD_APP_CHART_DIM *dimensions; - size_t dimensions_count; - size_t dimensions_linked_count; - - RRDSET *st; - struct statsd_app_chart *next; -} STATSD_APP_CHART; - -typedef struct statsd_app { - const char *name; - SIMPLE_PATTERN *metrics; - STATS_METRIC_OPTIONS default_options; - RRD_MEMORY_MODE rrd_memory_mode; - DICTIONARY *dict; - long rrd_history_entries; - - const char *source; - STATSD_APP_CHART *charts; - struct statsd_app *next; -} STATSD_APP; - -// -------------------------------------------------------------------------------------------------------------------- -// global statsd data - -struct collection_thread_status { - int status; - size_t max_sockets; - - netdata_thread_t thread; - struct rusage rusage; - RRDSET *st_cpu; - RRDDIM *rd_user; - RRDDIM *rd_system; -}; - -static struct statsd { - STATSD_INDEX gauges; - STATSD_INDEX counters; - STATSD_INDEX timers; - STATSD_INDEX histograms; - STATSD_INDEX meters; - STATSD_INDEX sets; - size_t unknown_types; - size_t socket_errors; - size_t tcp_socket_connects; - size_t tcp_socket_disconnects; - size_t tcp_socket_connected; - size_t tcp_socket_reads; - size_t tcp_packets_received; - size_t tcp_bytes_read; - size_t udp_socket_reads; - size_t udp_packets_received; - size_t udp_bytes_read; - - int enabled; - int update_every; - SIMPLE_PATTERN *charts_for; - - size_t tcp_idle_timeout; - size_t decimal_detail; - size_t private_charts; - size_t max_private_charts; - size_t max_private_charts_hard; - RRD_MEMORY_MODE private_charts_memory_mode; - long private_charts_rrd_history_entries; - int private_charts_hidden; - - STATSD_APP *apps; - size_t recvmmsg_size; - size_t histogram_increase_step; - double histogram_percentile; - char *histogram_percentile_str; - - int threads; - struct collection_thread_status *collection_threads_status; - - LISTEN_SOCKETS sockets; -} statsd = { - .enabled = 1, - .max_private_charts = 200, - .max_private_charts_hard = 1000, - .private_charts_hidden = 0, - .recvmmsg_size = 10, - .decimal_detail = STATSD_DECIMAL_DETAIL, - - .gauges = { - .name = "gauge", - .events = 0, - .metrics = 0, - .index = STATSD_AVL_INDEX_INIT, - .default_options = STATSD_METRIC_OPTION_NONE, - .first = NULL, - STATSD_FIRST_PTR_MUTEX_INIT - }, - .counters = { - .name = "counter", - .events = 0, - .metrics = 0, - .index = STATSD_AVL_INDEX_INIT, - .default_options = STATSD_METRIC_OPTION_NONE, - .first = NULL, - STATSD_FIRST_PTR_MUTEX_INIT - }, - .timers = { - .name = "timer", - .events = 0, - .metrics = 0, - .index = STATSD_AVL_INDEX_INIT, - .default_options = STATSD_METRIC_OPTION_NONE, - .first = NULL, - STATSD_FIRST_PTR_MUTEX_INIT - }, - .histograms = { - .name = "histogram", - .events = 0, - .metrics = 0, - .index = STATSD_AVL_INDEX_INIT, - .default_options = STATSD_METRIC_OPTION_NONE, - .first = NULL, - STATSD_FIRST_PTR_MUTEX_INIT - }, - .meters = { - .name = "meter", - .events = 0, - .metrics = 0, - .index = STATSD_AVL_INDEX_INIT, - .default_options = STATSD_METRIC_OPTION_NONE, - .first = NULL, - STATSD_FIRST_PTR_MUTEX_INIT - }, - .sets = { - .name = "set", - .events = 0, - .metrics = 0, - .index = STATSD_AVL_INDEX_INIT, - .default_options = STATSD_METRIC_OPTION_NONE, - .first = NULL, - STATSD_FIRST_PTR_MUTEX_INIT - }, - - .tcp_idle_timeout = 600, - - .apps = NULL, - .histogram_percentile = 95.0, - .histogram_increase_step = 10, - .threads = 0, - .collection_threads_status = NULL, - .sockets = { - .config_section = CONFIG_SECTION_STATSD, - .default_bind_to = "udp:localhost tcp:localhost", - .default_port = STATSD_LISTEN_PORT, - .backlog = STATSD_LISTEN_BACKLOG - }, -}; - - -// -------------------------------------------------------------------------------------------------------------------- -// statsd index management - add/find metrics - -static int statsd_metric_compare(void* a, void* b) { - if(((STATSD_METRIC *)a)->hash < ((STATSD_METRIC *)b)->hash) return -1; - else if(((STATSD_METRIC *)a)->hash > ((STATSD_METRIC *)b)->hash) return 1; - else return strcmp(((STATSD_METRIC *)a)->name, ((STATSD_METRIC *)b)->name); -} - -static inline STATSD_METRIC *statsd_metric_index_find(STATSD_INDEX *index, const char *name, uint32_t hash) { - STATSD_METRIC tmp; - tmp.name = name; - tmp.hash = (hash)?hash:simple_hash(tmp.name); - - return (STATSD_METRIC *)STATSD_AVL_SEARCH(&index->index, (avl *)&tmp); -} - -static inline STATSD_METRIC *statsd_find_or_add_metric(STATSD_INDEX *index, const char *name, STATSD_METRIC_TYPE type) { - debug(D_STATSD, "searching for metric '%s' under '%s'", name, index->name); - - uint32_t hash = simple_hash(name); - - STATSD_METRIC *m = statsd_metric_index_find(index, name, hash); - if(unlikely(!m)) { - debug(D_STATSD, "Creating new %s metric '%s'", index->name, name); - - m = (STATSD_METRIC *)callocz(sizeof(STATSD_METRIC), 1); - m->name = strdupz(name); - m->hash = hash; - m->type = type; - m->options = index->default_options; - - if(type == STATSD_METRIC_TYPE_HISTOGRAM || type == STATSD_METRIC_TYPE_TIMER) { - m->histogram.ext = callocz(sizeof(STATSD_METRIC_HISTOGRAM_EXTENSIONS), 1); - netdata_mutex_init(&m->histogram.ext->mutex); - } - STATSD_METRIC *n = (STATSD_METRIC *)STATSD_AVL_INSERT(&index->index, (avl *)m); - if(unlikely(n != m)) { - freez((void *)m->histogram.ext); - freez((void *)m->name); - freez((void *)m); - m = n; - } - else { - STATSD_FIRST_PTR_MUTEX_LOCK(index); - index->metrics++; - m->next = index->first; - index->first = m; - STATSD_FIRST_PTR_MUTEX_UNLOCK(index); - } - } - - index->events++; - return m; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// statsd parsing numbers - -static inline LONG_DOUBLE statsd_parse_float(const char *v, LONG_DOUBLE def) { - LONG_DOUBLE value; - - if(likely(v && *v)) { - char *e = NULL; - value = str2ld(v, &e); - if(unlikely(e && *e)) - error("STATSD: excess data '%s' after value '%s'", e, v); - } - else - value = def; - - return value; -} - -static inline long long statsd_parse_int(const char *v, long long def) { - long long value; - - if(likely(v && *v)) { - char *e = NULL; - value = str2ll(v, &e); - if(unlikely(e && *e)) - error("STATSD: excess data '%s' after value '%s'", e, v); - } - else - value = def; - - return value; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// statsd processors per metric type - -static inline void statsd_reset_metric(STATSD_METRIC *m) { - m->reset = 0; - m->count = 0; -} - -static inline int value_is_zinit(const char *value) { - return (value && *value == 'z' && *++value == 'i' && *++value == 'n' && *++value == 'i' && *++value == 't' && *++value == '\0'); -} - -static inline void statsd_process_gauge(STATSD_METRIC *m, const char *value, const char *sampling) { - if(unlikely(!value || !*value)) { - error("STATSD: metric '%s' of type gauge, with empty value is ignored.", m->name); - return; - } - - if(unlikely(m->reset)) { - // no need to reset anything specific for gauges - statsd_reset_metric(m); - } - - if(unlikely(value_is_zinit(value))) { - // magic loading of metric, without affecting anything - } - else { - if (unlikely(*value == '+' || *value == '-')) - m->gauge.value += statsd_parse_float(value, 1.0) / statsd_parse_float(sampling, 1.0); - else - m->gauge.value = statsd_parse_float(value, 1.0) / statsd_parse_float(sampling, 1.0); - - m->events++; - m->count++; - } -} - -static inline void statsd_process_counter(STATSD_METRIC *m, const char *value, const char *sampling) { - // we accept empty values for counters - - if(unlikely(m->reset)) statsd_reset_metric(m); - - if(unlikely(value_is_zinit(value))) { - // magic loading of metric, without affecting anything - } - else { - m->counter.value += llrintl((LONG_DOUBLE) statsd_parse_int(value, 1) / statsd_parse_float(sampling, 1.0)); - - m->events++; - m->count++; - } -} - -static inline void statsd_process_meter(STATSD_METRIC *m, const char *value, const char *sampling) { - // this is the same with the counter - statsd_process_counter(m, value, sampling); -} - -static inline void statsd_process_histogram(STATSD_METRIC *m, const char *value, const char *sampling) { - if(unlikely(!value || !*value)) { - error("STATSD: metric '%s' of type histogram, with empty value is ignored.", m->name); - return; - } - - if(unlikely(m->reset)) { - m->histogram.ext->used = 0; - statsd_reset_metric(m); - } - - if(unlikely(value_is_zinit(value))) { - // magic loading of metric, without affecting anything - } - else { - if (unlikely(m->histogram.ext->used == m->histogram.ext->size)) { - netdata_mutex_lock(&m->histogram.ext->mutex); - m->histogram.ext->size += statsd.histogram_increase_step; - m->histogram.ext->values = reallocz(m->histogram.ext->values, sizeof(LONG_DOUBLE) * m->histogram.ext->size); - netdata_mutex_unlock(&m->histogram.ext->mutex); - } - - m->histogram.ext->values[m->histogram.ext->used++] = statsd_parse_float(value, 1.0) / statsd_parse_float(sampling, 1.0); - - m->events++; - m->count++; - } -} - -static inline void statsd_process_timer(STATSD_METRIC *m, const char *value, const char *sampling) { - if(unlikely(!value || !*value)) { - error("STATSD: metric of type timer, with empty value is ignored."); - return; - } - - // timers are a use case of histogram - statsd_process_histogram(m, value, sampling); -} - -static inline void statsd_process_set(STATSD_METRIC *m, const char *value) { - if(unlikely(!value || !*value)) { - error("STATSD: metric of type set, with empty value is ignored."); - return; - } - - if(unlikely(m->reset)) { - if(likely(m->set.dict)) { - dictionary_destroy(m->set.dict); - m->set.dict = NULL; - } - statsd_reset_metric(m); - } - - if (unlikely(!m->set.dict)) { - m->set.dict = dictionary_create(STATSD_DICTIONARY_OPTIONS | DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE); - m->set.unique = 0; - } - - if(unlikely(value_is_zinit(value))) { - // magic loading of metric, without affecting anything - } - else { - void *t = dictionary_get(m->set.dict, value); - if (unlikely(!t)) { - dictionary_set(m->set.dict, value, NULL, 1); - m->set.unique++; - } - - m->events++; - m->count++; - } -} - - -// -------------------------------------------------------------------------------------------------------------------- -// statsd parsing - -static void statsd_process_metric(const char *name, const char *value, const char *type, const char *sampling) { - debug(D_STATSD, "STATSD: raw metric '%s', value '%s', type '%s', rate '%s'", name?name:"(null)", value?value:"(null)", type?type:"(null)", sampling?sampling:"(null)"); - - if(unlikely(!name || !*name)) return; - if(unlikely(!type || !*type)) type = "m"; - - char t0 = type[0], t1 = type[1]; - - if(unlikely(t0 == 'g' && t1 == '\0')) { - statsd_process_gauge( - statsd_find_or_add_metric(&statsd.gauges, name, STATSD_METRIC_TYPE_GAUGE), - value, sampling); - } - else if(unlikely((t0 == 'c' || t0 == 'C') && t1 == '\0')) { - // etsy/statsd uses 'c' - // brubeck uses 'C' - statsd_process_counter( - statsd_find_or_add_metric(&statsd.counters, name, STATSD_METRIC_TYPE_COUNTER), - value, sampling); - } - else if(unlikely(t0 == 'm' && t1 == '\0')) { - statsd_process_meter( - statsd_find_or_add_metric(&statsd.meters, name, STATSD_METRIC_TYPE_METER), - value, sampling); - } - else if(unlikely(t0 == 'h' && t1 == '\0')) { - statsd_process_histogram( - statsd_find_or_add_metric(&statsd.histograms, name, STATSD_METRIC_TYPE_HISTOGRAM), - value, sampling); - } - else if(unlikely(t0 == 's' && t1 == '\0')) { - statsd_process_set( - statsd_find_or_add_metric(&statsd.sets, name, STATSD_METRIC_TYPE_SET), - value); - } - else if(unlikely(t0 == 'm' && t1 == 's' && type[2] == '\0')) { - statsd_process_timer( - statsd_find_or_add_metric(&statsd.timers, name, STATSD_METRIC_TYPE_TIMER), - value, sampling); - } - else { - statsd.unknown_types++; - error("STATSD: metric '%s' with value '%s' is sent with unknown metric type '%s'", name, value?value:"", type); - } -} - -static inline const char *statsd_parse_skip_up_to(const char *s, char d1, char d2) { - char c; - - for(c = *s; c && c != d1 && c != d2 && c != '\r' && c != '\n'; c = *++s) ; - - return s; -} - -const char *statsd_parse_skip_spaces(const char *s) { - char c; - - for(c = *s; c && ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); c = *++s) ; - - return s; -} - -static inline const char *statsd_parse_field_trim(const char *start, char *end) { - if(unlikely(!start)) { - start = end; - return start; - } - - while(start <= end && (*start == ' ' || *start == '\t')) - start++; - - *end = '\0'; - end--; - while(end >= start && (*end == ' ' || *end == '\t')) - *end-- = '\0'; - - return start; -} - -static inline size_t statsd_process(char *buffer, size_t size, int require_newlines) { - buffer[size] = '\0'; - debug(D_STATSD, "RECEIVED: %zu bytes: '%s'", size, buffer); - - const char *s = buffer; - while(*s) { - const char *name = NULL, *value = NULL, *type = NULL, *sampling = NULL; - char *name_end = NULL, *value_end = NULL, *type_end = NULL, *sampling_end = NULL; - - s = name_end = (char *)statsd_parse_skip_up_to(name = s, ':', '|'); - if(name == name_end) { - s = statsd_parse_skip_spaces(s); - continue; - } - - if(likely(*s == ':')) - s = value_end = (char *) statsd_parse_skip_up_to(value = ++s, '|', '|'); - - if(likely(*s == '|')) - s = type_end = (char *) statsd_parse_skip_up_to(type = ++s, '|', '@'); - - if(likely(*s == '|' || *s == '@')) { - s = sampling_end = (char *) statsd_parse_skip_up_to(sampling = ++s, '\r', '\n'); - if(*sampling == '@') sampling++; - } - - // skip everything until the end of the line - while(*s && *s != '\n') s++; - - if(unlikely(require_newlines && *s != '\n' && s > buffer)) { - // move the remaining data to the beginning - size -= (name - buffer); - memmove(buffer, name, size); - return size; - } - else - s = statsd_parse_skip_spaces(s); - - statsd_process_metric( - statsd_parse_field_trim(name, name_end) - , statsd_parse_field_trim(value, value_end) - , statsd_parse_field_trim(type, type_end) - , statsd_parse_field_trim(sampling, sampling_end) - ); - } - - return 0; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// statsd pollfd interface - -#define STATSD_TCP_BUFFER_SIZE 65536 // minimize tcp reads -#define STATSD_UDP_BUFFER_SIZE 9000 // this should be up to MTU - -typedef enum { - STATSD_SOCKET_DATA_TYPE_TCP, - STATSD_SOCKET_DATA_TYPE_UDP -} STATSD_SOCKET_DATA_TYPE; - -struct statsd_tcp { - STATSD_SOCKET_DATA_TYPE type; - size_t size; - size_t len; - char buffer[]; -}; - -#ifdef HAVE_RECVMMSG -struct statsd_udp { - int *running; - STATSD_SOCKET_DATA_TYPE type; - size_t size; - struct iovec *iovecs; - struct mmsghdr *msgs; -}; -#else -struct statsd_udp { - int *running; - STATSD_SOCKET_DATA_TYPE type; - char buffer[STATSD_UDP_BUFFER_SIZE]; -}; -#endif - -// new TCP client connected -static void *statsd_add_callback(POLLINFO *pi, short int *events, void *data) { - (void)pi; - (void)data; - - *events = POLLIN; - - struct statsd_tcp *t = (struct statsd_tcp *)callocz(sizeof(struct statsd_tcp) + STATSD_TCP_BUFFER_SIZE, 1); - t->type = STATSD_SOCKET_DATA_TYPE_TCP; - t->size = STATSD_TCP_BUFFER_SIZE - 1; - statsd.tcp_socket_connects++; - statsd.tcp_socket_connected++; - - return t; -} - -// TCP client disconnected -static void statsd_del_callback(POLLINFO *pi) { - struct statsd_tcp *t = pi->data; - - if(likely(t)) { - if(t->type == STATSD_SOCKET_DATA_TYPE_TCP) { - if(t->len != 0) { - statsd.socket_errors++; - error("STATSD: client is probably sending unterminated metrics. Closed socket left with '%s'. Trying to process it.", t->buffer); - statsd_process(t->buffer, t->len, 0); - } - statsd.tcp_socket_disconnects++; - statsd.tcp_socket_connected--; - } - else - error("STATSD: internal error: received socket data type is %d, but expected %d", (int)t->type, (int)STATSD_SOCKET_DATA_TYPE_TCP); - - freez(t); - } -} - -// Receive data -static int statsd_rcv_callback(POLLINFO *pi, short int *events) { - *events = POLLIN; - - int fd = pi->fd; - - switch(pi->socktype) { - case SOCK_STREAM: { - struct statsd_tcp *d = (struct statsd_tcp *)pi->data; - if(unlikely(!d)) { - error("STATSD: internal error: expected TCP data pointer is NULL"); - statsd.socket_errors++; - return -1; - } - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(d->type != STATSD_SOCKET_DATA_TYPE_TCP)) { - error("STATSD: internal error: socket data type should be %d, but it is %d", (int)STATSD_SOCKET_DATA_TYPE_TCP, (int)d->type); - statsd.socket_errors++; - return -1; - } -#endif - - int ret = 0; - ssize_t rc; - do { - rc = recv(fd, &d->buffer[d->len], d->size - d->len, MSG_DONTWAIT); - if (rc < 0) { - // read failed - if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) { - error("STATSD: recv() on TCP socket %d failed.", fd); - statsd.socket_errors++; - ret = -1; - } - } - else if (!rc) { - // connection closed - debug(D_STATSD, "STATSD: client disconnected."); - ret = -1; - } - else { - // data received - d->len += rc; - statsd.tcp_socket_reads++; - statsd.tcp_bytes_read += rc; - } - - if(likely(d->len > 0)) { - statsd.tcp_packets_received++; - d->len = statsd_process(d->buffer, d->len, 1); - } - - if(unlikely(ret == -1)) - return -1; - - } while (rc != -1); - break; - } - - case SOCK_DGRAM: { - struct statsd_udp *d = (struct statsd_udp *)pi->data; - if(unlikely(!d)) { - error("STATSD: internal error: expected UDP data pointer is NULL"); - statsd.socket_errors++; - return -1; - } - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(d->type != STATSD_SOCKET_DATA_TYPE_UDP)) { - error("STATSD: internal error: socket data should be %d, but it is %d", (int)d->type, (int)STATSD_SOCKET_DATA_TYPE_UDP); - statsd.socket_errors++; - return -1; - } -#endif - -#ifdef HAVE_RECVMMSG - ssize_t rc; - do { - rc = recvmmsg(fd, d->msgs, (unsigned int)d->size, MSG_DONTWAIT, NULL); - if (rc < 0) { - // read failed - if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) { - error("STATSD: recvmmsg() on UDP socket %d failed.", fd); - statsd.socket_errors++; - return -1; - } - } else if (rc) { - // data received - statsd.udp_socket_reads++; - statsd.udp_packets_received += rc; - - size_t i; - for (i = 0; i < (size_t)rc; ++i) { - size_t len = (size_t)d->msgs[i].msg_len; - statsd.udp_bytes_read += len; - statsd_process(d->msgs[i].msg_hdr.msg_iov->iov_base, len, 0); - } - } - } while (rc != -1); - -#else // !HAVE_RECVMMSG - ssize_t rc; - do { - rc = recv(fd, d->buffer, STATSD_UDP_BUFFER_SIZE - 1, MSG_DONTWAIT); - if (rc < 0) { - // read failed - if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) { - error("STATSD: recv() on UDP socket %d failed.", fd); - statsd.socket_errors++; - return -1; - } - } else if (rc) { - // data received - statsd.udp_socket_reads++; - statsd.udp_packets_received++; - statsd.udp_bytes_read += rc; - statsd_process(d->buffer, (size_t) rc, 0); - } - } while (rc != -1); -#endif - - break; - } - - default: { - error("STATSD: internal error: unknown socktype %d on socket %d", pi->socktype, fd); - statsd.socket_errors++; - return -1; - } - } - - return 0; -} - -static int statsd_snd_callback(POLLINFO *pi, short int *events) { - (void)pi; - (void)events; - - error("STATSD: snd_callback() called, but we never requested to send data to statsd clients."); - return -1; -} - -static void statsd_timer_callback(void *timer_data) { - struct collection_thread_status *status = timer_data; - getrusage(RUSAGE_THREAD, &status->rusage); -} - -// -------------------------------------------------------------------------------------------------------------------- -// statsd child thread to collect metrics from network - -void statsd_collector_thread_cleanup(void *data) { - struct statsd_udp *d = data; - *d->running = 0; - - info("cleaning up..."); - -#ifdef HAVE_RECVMMSG - size_t i; - for (i = 0; i < d->size; i++) - freez(d->iovecs[i].iov_base); - - freez(d->iovecs); - freez(d->msgs); -#endif - - freez(d); -} - -void *statsd_collector_thread(void *ptr) { - struct collection_thread_status *status = ptr; - status->status = 1; - - info("STATSD collector thread started with taskid %d", gettid()); - - struct statsd_udp *d = callocz(sizeof(struct statsd_udp), 1); - d->running = &status->status; - - netdata_thread_cleanup_push(statsd_collector_thread_cleanup, d); - -#ifdef HAVE_RECVMMSG - d->type = STATSD_SOCKET_DATA_TYPE_UDP; - d->size = statsd.recvmmsg_size; - d->iovecs = callocz(sizeof(struct iovec), d->size); - d->msgs = callocz(sizeof(struct mmsghdr), d->size); - - size_t i; - for (i = 0; i < d->size; i++) { - d->iovecs[i].iov_base = mallocz(STATSD_UDP_BUFFER_SIZE); - d->iovecs[i].iov_len = STATSD_UDP_BUFFER_SIZE - 1; - d->msgs[i].msg_hdr.msg_iov = &d->iovecs[i]; - d->msgs[i].msg_hdr.msg_iovlen = 1; - } -#endif - - poll_events(&statsd.sockets - , statsd_add_callback - , statsd_del_callback - , statsd_rcv_callback - , statsd_snd_callback - , statsd_timer_callback - , NULL - , (void *)d - , 0 // tcp request timeout, 0 = disabled - , statsd.tcp_idle_timeout // tcp idle timeout, 0 = disabled - , statsd.update_every * 1000 - , ptr // timer_data - , status->max_sockets - ); - - netdata_thread_cleanup_pop(1); - return NULL; -} - - -// -------------------------------------------------------------------------------------------------------------------- -// statsd applications configuration files parsing - -#define STATSD_CONF_LINE_MAX 8192 - -static STATSD_APP_CHART_DIM_VALUE_TYPE string2valuetype(const char *type, size_t line, const char *path, const char *filename) { - if(!type || !*type) type = "last"; - - if(!strcmp(type, "events")) return STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS; - else if(!strcmp(type, "last")) return STATSD_APP_CHART_DIM_VALUE_TYPE_LAST; - else if(!strcmp(type, "min")) return STATSD_APP_CHART_DIM_VALUE_TYPE_MIN; - else if(!strcmp(type, "max")) return STATSD_APP_CHART_DIM_VALUE_TYPE_MAX; - else if(!strcmp(type, "sum")) return STATSD_APP_CHART_DIM_VALUE_TYPE_SUM; - else if(!strcmp(type, "average")) return STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE; - else if(!strcmp(type, "median")) return STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN; - else if(!strcmp(type, "stddev")) return STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV; - else if(!strcmp(type, "percentile")) return STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE; - - error("STATSD: invalid type '%s' at line %zu of file '%s/%s'. Using 'last'.", type, line, path, filename); - return STATSD_APP_CHART_DIM_VALUE_TYPE_LAST; -} - -static const char *valuetype2string(STATSD_APP_CHART_DIM_VALUE_TYPE type) { - switch(type) { - case STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS: return "events"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_LAST: return "last"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_MIN: return "min"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_MAX: return "max"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_SUM: return "sum"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE: return "average"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN: return "median"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV: return "stddev"; - case STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE: return "percentile"; - } - - return "unknown"; -} - -static STATSD_APP_CHART_DIM *add_dimension_to_app_chart( - STATSD_APP *app - , STATSD_APP_CHART *chart - , const char *metric_name - , const char *dim_name - , collected_number multiplier - , collected_number divisor - , RRDDIM_FLAGS flags - , STATSD_APP_CHART_DIM_VALUE_TYPE value_type -) { - STATSD_APP_CHART_DIM *dim = callocz(sizeof(STATSD_APP_CHART_DIM), 1); - - dim->metric = strdupz(metric_name); - dim->metric_hash = simple_hash(dim->metric); - - dim->name = strdupz((dim_name)?dim_name:""); - dim->multiplier = multiplier; - dim->divisor = divisor; - dim->value_type = value_type; - dim->flags = flags; - - if(!dim->multiplier) - dim->multiplier = 1; - - if(!dim->divisor) - dim->divisor = 1; - - // append it to the list of dimension - STATSD_APP_CHART_DIM *tdim; - for(tdim = chart->dimensions; tdim && tdim->next ; tdim = tdim->next) ; - if(!tdim) { - dim->next = chart->dimensions; - chart->dimensions = dim; - } - else { - dim->next = tdim->next; - tdim->next = dim; - } - chart->dimensions_count++; - - debug(D_STATSD, "Added dimension '%s' to chart '%s' of app '%s', for metric '%s', with type %u, multiplier " COLLECTED_NUMBER_FORMAT ", divisor " COLLECTED_NUMBER_FORMAT, - dim->name, chart->id, app->name, dim->metric, dim->value_type, dim->multiplier, dim->divisor); - - return dim; -} - -static int statsd_readfile(const char *path, const char *filename, STATSD_APP *app, STATSD_APP_CHART *chart, DICTIONARY *dict) { - debug(D_STATSD, "STATSD configuration reading file '%s/%s'", path, filename); - - char *buffer = mallocz(STATSD_CONF_LINE_MAX + 1); - - if(filename[0] == '/') - strncpyz(buffer, filename, STATSD_CONF_LINE_MAX); - else - snprintfz(buffer, STATSD_CONF_LINE_MAX, "%s/%s", path, filename); - - FILE *fp = fopen(buffer, "r"); - if(!fp) { - error("STATSD: cannot open file '%s'.", buffer); - freez(buffer); - return -1; - } - - size_t line = 0; - char *s; - while(fgets(buffer, STATSD_CONF_LINE_MAX, fp) != NULL) { - buffer[STATSD_CONF_LINE_MAX] = '\0'; - line++; - - s = trim(buffer); - if (!s || *s == '#') { - debug(D_STATSD, "STATSD: ignoring line %zu of file '%s/%s', it is empty.", line, path, filename); - continue; - } - - debug(D_STATSD, "STATSD: processing line %zu of file '%s/%s': %s", line, path, filename, buffer); - - if(*s == 'i' && strncmp(s, "include", 7) == 0) { - s = trim(&s[7]); - if(s && *s) - statsd_readfile(path, s, app, chart, dict); - else - error("STATSD: ignoring line %zu of file '%s/%s', include filename is empty", line, path, s); - - continue; - } - - int len = (int) strlen(s); - if (*s == '[' && s[len - 1] == ']') { - // new section - s[len - 1] = '\0'; - s++; - - if (!strcmp(s, "app")) { - // a new app - app = callocz(sizeof(STATSD_APP), 1); - app->name = strdupz("unnamed"); - app->rrd_memory_mode = localhost->rrd_memory_mode; - app->rrd_history_entries = localhost->rrd_history_entries; - - app->next = statsd.apps; - statsd.apps = app; - chart = NULL; - dict = NULL; - - { - char lineandfile[FILENAME_MAX + 1]; - snprintfz(lineandfile, FILENAME_MAX, "%zu@%s", line, filename); - app->source = strdupz(lineandfile); - } - } - else if(app) { - if(!strcmp(s, "dictionary")) { - if(!app->dict) - app->dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED); - - dict = app->dict; - } - else { - dict = NULL; - - // a new chart - chart = callocz(sizeof(STATSD_APP_CHART), 1); - netdata_fix_chart_id(s); - chart->id = strdupz(s); - chart->name = strdupz(s); - chart->title = strdupz("Statsd chart"); - chart->context = strdupz(s); - chart->family = strdupz("overview"); - chart->units = strdupz("value"); - chart->priority = STATSD_CHART_PRIORITY; - chart->chart_type = RRDSET_TYPE_LINE; - - chart->next = app->charts; - app->charts = chart; - - { - char lineandfile[FILENAME_MAX + 1]; - snprintfz(lineandfile, FILENAME_MAX, "%zu@%s", line, filename); - chart->source = strdupz(lineandfile); - } - } - } - else - error("STATSD: ignoring line %zu ('%s') of file '%s/%s', [app] is not defined.", line, s, path, filename); - - continue; - } - - if(!app) { - error("STATSD: ignoring line %zu ('%s') of file '%s/%s', it is outside all sections.", line, s, path, filename); - continue; - } - - char *name = s; - char *value = strchr(s, '='); - if(!value) { - error("STATSD: ignoring line %zu ('%s') of file '%s/%s', there is no = in it.", line, s, path, filename); - continue; - } - *value = '\0'; - value++; - - name = trim(name); - value = trim(value); - - if(!name || *name == '#') { - error("STATSD: ignoring line %zu of file '%s/%s', name is empty.", line, path, filename); - continue; - } - if(!value) { - debug(D_CONFIG, "STATSD: ignoring line %zu of file '%s/%s', value is empty.", line, path, filename); - continue; - } - - if(unlikely(dict)) { - // parse [dictionary] members - - dictionary_set(dict, name, value, strlen(value) + 1); - } - else if(!chart) { - // parse [app] members - - if(!strcmp(name, "name")) { - freez((void *)app->name); - netdata_fix_chart_name(value); - app->name = strdupz(value); - } - else if (!strcmp(name, "metrics")) { - simple_pattern_free(app->metrics); - app->metrics = simple_pattern_create(value, NULL, SIMPLE_PATTERN_EXACT); - } - else if (!strcmp(name, "private charts")) { - if (!strcmp(value, "yes") || !strcmp(value, "on")) - app->default_options |= STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - else - app->default_options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - } - else if (!strcmp(name, "gaps when not collected")) { - if (!strcmp(value, "yes") || !strcmp(value, "on")) - app->default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - } - else if (!strcmp(name, "memory mode")) { - app->rrd_memory_mode = rrd_memory_mode_id(value); - } - else if (!strcmp(name, "history")) { - app->rrd_history_entries = atol(value); - if (app->rrd_history_entries < 5) - app->rrd_history_entries = 5; - } - else { - error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [app] section.", line, name, path, filename); - continue; - } - } - else { - // parse [chart] members - - if(!strcmp(name, "name")) { - freez((void *)chart->name); - netdata_fix_chart_id(value); - chart->name = strdupz(value); - } - else if(!strcmp(name, "title")) { - freez((void *)chart->title); - chart->title = strdupz(value); - } - else if (!strcmp(name, "family")) { - freez((void *)chart->family); - chart->family = strdupz(value); - } - else if (!strcmp(name, "context")) { - freez((void *)chart->context); - netdata_fix_chart_id(value); - chart->context = strdupz(value); - } - else if (!strcmp(name, "units")) { - freez((void *)chart->units); - chart->units = strdupz(value); - } - else if (!strcmp(name, "priority")) { - chart->priority = atol(value); - } - else if (!strcmp(name, "type")) { - chart->chart_type = rrdset_type_id(value); - } - else if (!strcmp(name, "dimension")) { - // metric [name [type [multiplier [divisor]]]] - char *words[10]; - pluginsd_split_words(value, words, 10); - - int pattern = 0; - size_t i = 0; - char *metric_name = words[i++]; - - if(strcmp(metric_name, "pattern") == 0) { - metric_name = words[i++]; - pattern = 1; - } - - char *dim_name = words[i++]; - char *type = words[i++]; - char *multipler = words[i++]; - char *divisor = words[i++]; - char *options = words[i++]; - - RRDDIM_FLAGS flags = RRDDIM_FLAG_NONE; - if(options && *options) { - if(strstr(options, "hidden") != NULL) flags |= RRDDIM_FLAG_HIDDEN; - if(strstr(options, "noreset") != NULL) flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS; - if(strstr(options, "nooverflow") != NULL) flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS; - } - - if(!pattern) { - if(app->dict) { - if(dim_name && *dim_name) { - char *n = dictionary_get(app->dict, dim_name); - if(n) dim_name = n; - } - else { - dim_name = dictionary_get(app->dict, metric_name); - } - } - - if(!dim_name || !*dim_name) - dim_name = metric_name; - } - - STATSD_APP_CHART_DIM *dim = add_dimension_to_app_chart( - app - , chart - , metric_name - , dim_name - , (multipler && *multipler)?str2l(multipler):1 - , (divisor && *divisor)?str2l(divisor):1 - , flags - , string2valuetype(type, line, path, filename) - ); - - if(pattern) - dim->metric_pattern = simple_pattern_create(dim->metric, NULL, SIMPLE_PATTERN_EXACT); - } - else { - error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [%s] section.", line, name, path, filename, chart->id); - continue; - } - } - } - - freez(buffer); - fclose(fp); - return 0; -} - -static void statsd_readdir(const char *path) { - size_t pathlen = strlen(path); - - debug(D_STATSD, "STATSD configuration reading directory '%s'", path); - - DIR *dir = opendir(path); - if (!dir) { - error("STATSD 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_STATSD, "STATSD: 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); - statsd_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")) { - statsd_readfile(path, de->d_name, NULL, NULL, NULL); - } - - else debug(D_STATSD, "STATSD: ignoring file '%s'", de->d_name); - } - - closedir(dir); -} - -// -------------------------------------------------------------------------------------------------------------------- -// send metrics to netdata - in private charts - called from the main thread - -// extract chart type and chart id from metric name -static inline void statsd_get_metric_type_and_id(STATSD_METRIC *m, char *type, char *id, const char *defid, size_t len) { - char *s; - - snprintfz(type, len, "%s_%s_%s", STATSD_CHART_PREFIX, defid, m->name); - for(s = type; *s ;s++) - if(unlikely(*s == '.')) break; - - if(*s == '.') { - *s++ = '\0'; - strncpyz(id, s, len); - } - else { - strncpyz(id, defid, len); - } - - netdata_fix_chart_id(type); - netdata_fix_chart_id(id); -} - -static inline RRDSET *statsd_private_rrdset_create( - STATSD_METRIC *m - , 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 -) { - RRD_MEMORY_MODE memory_mode = statsd.private_charts_memory_mode; - long history = statsd.private_charts_rrd_history_entries; - - if(unlikely(statsd.private_charts >= statsd.max_private_charts)) { - debug(D_STATSD, "STATSD: metric '%s' will be charted with memory mode = none, because the maximum number of charts has been reached.", m->name); - info("STATSD: metric '%s' will be charted with memory mode = none, because the maximum number of charts (%zu) has been reached. Increase the number of charts by editing netdata.conf, [statsd] section.", m->name, statsd.max_private_charts); - memory_mode = RRD_MEMORY_MODE_NONE; - history = 5; - } - - statsd.private_charts++; - RRDSET *st = rrdset_create_custom( - localhost // host - , type // type - , id // id - , name // name - , family // family - , context // context - , title // title - , units // units - , "statsd" // plugin - , "private_chart" // module - , priority // priority - , update_every // update every - , chart_type // chart type - , memory_mode // memory mode - , history // history - ); - rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST); - - if(statsd.private_charts_hidden) - rrdset_flag_set(st, RRDSET_FLAG_HIDDEN); - - // rrdset_flag_set(st, RRDSET_FLAG_DEBUG); - return st; -} - -static inline void statsd_private_chart_gauge(STATSD_METRIC *m) { - debug(D_STATSD, "updating private chart for gauge metric '%s'", m->name); - - if(unlikely(!m->st)) { - char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1]; - statsd_get_metric_type_and_id(m, type, id, "gauge", RRD_ID_LENGTH_MAX); - - char context[RRD_ID_LENGTH_MAX + 1]; - snprintfz(context, RRD_ID_LENGTH_MAX, "statsd_gauge.%s", m->name); - - char title[RRD_ID_LENGTH_MAX + 1]; - snprintfz(title, RRD_ID_LENGTH_MAX, "statsd private chart for gauge %s", m->name); - - m->st = statsd_private_rrdset_create( - m - , type - , id - , NULL // name - , "gauges" // family (submenu) - , context // context - , title // title - , "value" // units - , STATSD_CHART_PRIORITY - , statsd.update_every - , RRDSET_TYPE_LINE - ); - - m->rd_value = rrddim_add(m->st, "gauge", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - - if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT) - m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(m->st); - - rrddim_set_by_pointer(m->st, m->rd_value, m->last); - - if(m->rd_count) - rrddim_set_by_pointer(m->st, m->rd_count, m->events); - - rrdset_done(m->st); -} - -static inline void statsd_private_chart_counter_or_meter(STATSD_METRIC *m, const char *dim, const char *family) { - debug(D_STATSD, "updating private chart for %s metric '%s'", dim, m->name); - - if(unlikely(!m->st)) { - char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1]; - statsd_get_metric_type_and_id(m, type, id, dim, RRD_ID_LENGTH_MAX); - - char context[RRD_ID_LENGTH_MAX + 1]; - snprintfz(context, RRD_ID_LENGTH_MAX, "statsd_%s.%s", dim, m->name); - - char title[RRD_ID_LENGTH_MAX + 1]; - snprintfz(title, RRD_ID_LENGTH_MAX, "statsd private chart for %s %s", dim, m->name); - - m->st = statsd_private_rrdset_create( - m - , type - , id - , NULL // name - , family // family (submenu) - , context // context - , title // title - , "events/s" // units - , STATSD_CHART_PRIORITY - , statsd.update_every - , RRDSET_TYPE_AREA - ); - - m->rd_value = rrddim_add(m->st, dim, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT) - m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(m->st); - - rrddim_set_by_pointer(m->st, m->rd_value, m->last); - - if(m->rd_count) - rrddim_set_by_pointer(m->st, m->rd_count, m->events); - - rrdset_done(m->st); -} - -static inline void statsd_private_chart_set(STATSD_METRIC *m) { - debug(D_STATSD, "updating private chart for set metric '%s'", m->name); - - if(unlikely(!m->st)) { - char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1]; - statsd_get_metric_type_and_id(m, type, id, "set", RRD_ID_LENGTH_MAX); - - char context[RRD_ID_LENGTH_MAX + 1]; - snprintfz(context, RRD_ID_LENGTH_MAX, "statsd_set.%s", m->name); - - char title[RRD_ID_LENGTH_MAX + 1]; - snprintfz(title, RRD_ID_LENGTH_MAX, "statsd private chart for set %s", m->name); - - m->st = statsd_private_rrdset_create( - m - , type - , id - , NULL // name - , "sets" // family (submenu) - , context // context - , title // title - , "entries" // units - , STATSD_CHART_PRIORITY - , statsd.update_every - , RRDSET_TYPE_LINE - ); - - m->rd_value = rrddim_add(m->st, "set", "set size", 1, 1, RRD_ALGORITHM_ABSOLUTE); - - if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT) - m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(m->st); - - rrddim_set_by_pointer(m->st, m->rd_value, m->last); - - if(m->rd_count) - rrddim_set_by_pointer(m->st, m->rd_count, m->events); - - rrdset_done(m->st); -} - -static inline void statsd_private_chart_timer_or_histogram(STATSD_METRIC *m, const char *dim, const char *family, const char *units) { - debug(D_STATSD, "updating private chart for %s metric '%s'", dim, m->name); - - if(unlikely(!m->st)) { - char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1]; - statsd_get_metric_type_and_id(m, type, id, dim, RRD_ID_LENGTH_MAX); - - char context[RRD_ID_LENGTH_MAX + 1]; - snprintfz(context, RRD_ID_LENGTH_MAX, "statsd_%s.%s", dim, m->name); - - char title[RRD_ID_LENGTH_MAX + 1]; - snprintfz(title, RRD_ID_LENGTH_MAX, "statsd private chart for %s %s", dim, m->name); - - m->st = statsd_private_rrdset_create( - m - , type - , id - , NULL // name - , family // family (submenu) - , context // context - , title // title - , units // units - , STATSD_CHART_PRIORITY - , statsd.update_every - , RRDSET_TYPE_AREA - ); - - m->histogram.ext->rd_min = rrddim_add(m->st, "min", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - m->histogram.ext->rd_max = rrddim_add(m->st, "max", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - m->rd_value = rrddim_add(m->st, "average", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - m->histogram.ext->rd_percentile = rrddim_add(m->st, statsd.histogram_percentile_str, NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - m->histogram.ext->rd_median = rrddim_add(m->st, "median", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - m->histogram.ext->rd_stddev = rrddim_add(m->st, "stddev", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - m->histogram.ext->rd_sum = rrddim_add(m->st, "sum", NULL, 1, statsd.decimal_detail, RRD_ALGORITHM_ABSOLUTE); - - if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT) - m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else rrdset_next(m->st); - - rrddim_set_by_pointer(m->st, m->histogram.ext->rd_min, m->histogram.ext->last_min); - rrddim_set_by_pointer(m->st, m->histogram.ext->rd_max, m->histogram.ext->last_max); - rrddim_set_by_pointer(m->st, m->histogram.ext->rd_percentile, m->histogram.ext->last_percentile); - rrddim_set_by_pointer(m->st, m->histogram.ext->rd_median, m->histogram.ext->last_median); - rrddim_set_by_pointer(m->st, m->histogram.ext->rd_stddev, m->histogram.ext->last_stddev); - rrddim_set_by_pointer(m->st, m->histogram.ext->rd_sum, m->histogram.ext->last_sum); - rrddim_set_by_pointer(m->st, m->rd_value, m->last); - - if(m->rd_count) - rrddim_set_by_pointer(m->st, m->rd_count, m->events); - - rrdset_done(m->st); -} - -// -------------------------------------------------------------------------------------------------------------------- -// statsd flush metrics - -static inline void statsd_flush_gauge(STATSD_METRIC *m) { - debug(D_STATSD, "flushing gauge metric '%s'", m->name); - - int updated = 0; - if(m->count && !m->reset) { - m->last = (collected_number) (m->gauge.value * statsd.decimal_detail); - - m->reset = 1; - updated = 1; - } - - if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))) - statsd_private_chart_gauge(m); -} - -static inline void statsd_flush_counter_or_meter(STATSD_METRIC *m, const char *dim, const char *family) { - debug(D_STATSD, "flushing %s metric '%s'", dim, m->name); - - int updated = 0; - if(m->count && !m->reset) { - m->last = m->counter.value; - - m->reset = 1; - updated = 1; - } - - if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))) - statsd_private_chart_counter_or_meter(m, dim, family); -} - -static inline void statsd_flush_counter(STATSD_METRIC *m) { - statsd_flush_counter_or_meter(m, "counter", "counters"); -} - -static inline void statsd_flush_meter(STATSD_METRIC *m) { - statsd_flush_counter_or_meter(m, "meter", "meters"); -} - -static inline void statsd_flush_set(STATSD_METRIC *m) { - debug(D_STATSD, "flushing set metric '%s'", m->name); - - int updated = 0; - if(m->count && !m->reset) { - m->last = (collected_number)m->set.unique; - - m->reset = 1; - updated = 1; - } - - if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))) - statsd_private_chart_set(m); -} - -static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char *dim, const char *family, const char *units) { - debug(D_STATSD, "flushing %s metric '%s'", dim, m->name); - - netdata_mutex_lock(&m->histogram.ext->mutex); - - if(unlikely(!m->histogram.ext->zeroed)) { - // reset the metrics - // if we collected anything, they will be updated below - // this ensures that we report zeros if nothing is collected - - m->histogram.ext->last_min = 0; - m->histogram.ext->last_max = 0; - m->last = 0; - m->histogram.ext->last_median = 0; - m->histogram.ext->last_stddev = 0; - m->histogram.ext->last_sum = 0; - m->histogram.ext->last_percentile = 0; - - m->histogram.ext->zeroed = 1; - } - - int updated = 0; - if(m->count && !m->reset && m->histogram.ext->used > 0) { - size_t len = m->histogram.ext->used; - LONG_DOUBLE *series = m->histogram.ext->values; - sort_series(series, len); - - m->histogram.ext->last_min = (collected_number)roundl(series[0] * statsd.decimal_detail); - m->histogram.ext->last_max = (collected_number)roundl(series[len - 1] * statsd.decimal_detail); - m->last = (collected_number)roundl(average(series, len) * statsd.decimal_detail); - m->histogram.ext->last_median = (collected_number)roundl(median_on_sorted_series(series, len) * statsd.decimal_detail); - m->histogram.ext->last_stddev = (collected_number)roundl(standard_deviation(series, len) * statsd.decimal_detail); - m->histogram.ext->last_sum = (collected_number)roundl(sum(series, len) * statsd.decimal_detail); - - size_t pct_len = (size_t)floor((double)len * statsd.histogram_percentile / 100.0); - if(pct_len < 1) - m->histogram.ext->last_percentile = (collected_number)(series[0] * statsd.decimal_detail); - else - m->histogram.ext->last_percentile = (collected_number)roundl(series[pct_len - 1] * statsd.decimal_detail); - - debug(D_STATSD, "STATSD %s metric %s: min " COLLECTED_NUMBER_FORMAT ", max " COLLECTED_NUMBER_FORMAT ", last " COLLECTED_NUMBER_FORMAT ", pcent " COLLECTED_NUMBER_FORMAT ", median " COLLECTED_NUMBER_FORMAT ", stddev " COLLECTED_NUMBER_FORMAT ", sum " COLLECTED_NUMBER_FORMAT, - dim, m->name, m->histogram.ext->last_min, m->histogram.ext->last_max, m->last, m->histogram.ext->last_percentile, m->histogram.ext->last_median, m->histogram.ext->last_stddev, m->histogram.ext->last_sum); - - m->histogram.ext->zeroed = 0; - m->reset = 1; - updated = 1; - } - - if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))) - statsd_private_chart_timer_or_histogram(m, dim, family, units); - - netdata_mutex_unlock(&m->histogram.ext->mutex); -} - -static inline void statsd_flush_timer(STATSD_METRIC *m) { - statsd_flush_timer_or_histogram(m, "timer", "timers", "milliseconds"); -} - -static inline void statsd_flush_histogram(STATSD_METRIC *m) { - statsd_flush_timer_or_histogram(m, "histogram", "histograms", "value"); -} - -static inline RRD_ALGORITHM statsd_algorithm_for_metric(STATSD_METRIC *m) { - switch(m->type) { - default: - case STATSD_METRIC_TYPE_GAUGE: - case STATSD_METRIC_TYPE_SET: - case STATSD_METRIC_TYPE_TIMER: - case STATSD_METRIC_TYPE_HISTOGRAM: - return RRD_ALGORITHM_ABSOLUTE; - - case STATSD_METRIC_TYPE_METER: - case STATSD_METRIC_TYPE_COUNTER: - return RRD_ALGORITHM_INCREMENTAL; - } -} - -static inline void link_metric_to_app_dimension(STATSD_APP *app, STATSD_METRIC *m, STATSD_APP_CHART *chart, STATSD_APP_CHART_DIM *dim) { - if(dim->value_type == STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS) { - dim->value_ptr = &m->events; - dim->algorithm = RRD_ALGORITHM_INCREMENTAL; - } - else if(m->type == STATSD_METRIC_TYPE_HISTOGRAM || m->type == STATSD_METRIC_TYPE_TIMER) { - dim->algorithm = RRD_ALGORITHM_ABSOLUTE; - dim->divisor *= statsd.decimal_detail; - - switch(dim->value_type) { - case STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS: - // will never match - added to avoid warning - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_LAST: - case STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE: - dim->value_ptr = &m->last; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_SUM: - dim->value_ptr = &m->histogram.ext->last_sum; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_MIN: - dim->value_ptr = &m->histogram.ext->last_min; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_MAX: - dim->value_ptr = &m->histogram.ext->last_max; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN: - dim->value_ptr = &m->histogram.ext->last_median; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE: - dim->value_ptr = &m->histogram.ext->last_percentile; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV: - dim->value_ptr = &m->histogram.ext->last_stddev; - break; - } - } - else { - if (dim->value_type != STATSD_APP_CHART_DIM_VALUE_TYPE_LAST) - error("STATSD: unsupported value type for dimension '%s' of chart '%s' of app '%s' on metric '%s'", dim->name, chart->id, app->name, m->name); - - dim->value_ptr = &m->last; - dim->algorithm = statsd_algorithm_for_metric(m); - - if(m->type == STATSD_METRIC_TYPE_GAUGE) - dim->divisor *= statsd.decimal_detail; - } - - if(unlikely(chart->st && dim->rd)) { - rrddim_set_algorithm(chart->st, dim->rd, dim->algorithm); - rrddim_set_multiplier(chart->st, dim->rd, dim->multiplier); - rrddim_set_divisor(chart->st, dim->rd, dim->divisor); - } - - chart->dimensions_linked_count++; - debug(D_STATSD, "metric '%s' of type %u linked with app '%s', chart '%s', dimension '%s', algorithm '%s'", m->name, m->type, app->name, chart->id, dim->name, rrd_algorithm_name(dim->algorithm)); -} - -static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC *m) { - (void)index; - - STATSD_APP *app; - for(app = statsd.apps; app ;app = app->next) { - if(unlikely(simple_pattern_matches(app->metrics, m->name))) { - debug(D_STATSD, "metric '%s' matches app '%s'", m->name, app->name); - - // the metric should get the options from the app - - if(app->default_options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED) - m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - else - m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - - if(app->default_options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED) - m->options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - else - m->options &= ~STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED; - - // check if there is a chart in this app, willing to get this metric - STATSD_APP_CHART *chart; - for(chart = app->charts; chart; chart = chart->next) { - - STATSD_APP_CHART_DIM *dim; - for(dim = chart->dimensions; dim ; dim = dim->next) { - if(unlikely(dim->metric_pattern)) { - size_t dim_name_len = strlen(dim->name); - size_t wildcarded_len = dim_name_len + strlen(m->name) + 1; - char wildcarded[wildcarded_len]; - - strcpy(wildcarded, dim->name); - char *ws = &wildcarded[dim_name_len]; - - if(simple_pattern_matches_extract(dim->metric_pattern, m->name, ws, wildcarded_len - dim_name_len)) { - - char *final_name = NULL; - - if(app->dict) { - if(likely(*wildcarded)) { - // use the name of the wildcarded string - final_name = dictionary_get(app->dict, wildcarded); - } - - if(unlikely(!final_name)) { - // use the name of the metric - final_name = dictionary_get(app->dict, m->name); - } - } - - if(unlikely(!final_name)) - final_name = wildcarded; - - add_dimension_to_app_chart( - app - , chart - , m->name - , final_name - , dim->multiplier - , dim->divisor - , dim->flags - , dim->value_type - ); - - // the new dimension is appended to the list - // so, it will be matched and linked later too - } - } - else if(!dim->value_ptr && dim->metric_hash == m->hash && !strcmp(dim->metric, m->name)) { - // we have a match - this metric should be linked to this dimension - link_metric_to_app_dimension(app, m, chart, dim); - } - } - - } - } - } -} - -static inline RRDDIM *statsd_add_dim_to_app_chart(STATSD_APP *app, STATSD_APP_CHART *chart, STATSD_APP_CHART_DIM *dim) { - (void)app; - - // allow the same statsd metric to be added multiple times to the same chart - - STATSD_APP_CHART_DIM *tdim; - size_t count_same_metric = 0, count_same_metric_value_type = 0; - size_t pos_same_metric_value_type = 0; - - for (tdim = chart->dimensions; tdim && tdim->next; tdim = tdim->next) { - if (dim->metric_hash == tdim->metric_hash && !strcmp(dim->metric, tdim->metric)) { - count_same_metric++; - - if(dim->value_type == tdim->value_type) { - count_same_metric_value_type++; - if (tdim == dim) - pos_same_metric_value_type = count_same_metric_value_type; - } - } - } - - if(count_same_metric > 1) { - // the same metric is found multiple times - - size_t len = strlen(dim->metric) + 100; - char metric[ len + 1 ]; - - if(count_same_metric_value_type > 1) { - // the same metric, with the same value type, is added multiple times - snprintfz(metric, len, "%s_%s%zu", dim->metric, valuetype2string(dim->value_type), pos_same_metric_value_type); - } - else { - // the same metric, with different value type is added - snprintfz(metric, len, "%s_%s", dim->metric, valuetype2string(dim->value_type)); - } - - dim->rd = rrddim_add(chart->st, metric, dim->name, dim->multiplier, dim->divisor, dim->algorithm); - if(dim->flags != RRDDIM_FLAG_NONE) dim->rd->flags |= dim->flags; - return dim->rd; - } - - dim->rd = rrddim_add(chart->st, dim->metric, dim->name, dim->multiplier, dim->divisor, dim->algorithm); - if(dim->flags != RRDDIM_FLAG_NONE) dim->rd->flags |= dim->flags; - return dim->rd; -} - -static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *chart) { - debug(D_STATSD, "updating chart '%s' for app '%s'", chart->id, app->name); - - if(!chart->st) { - chart->st = rrdset_create_custom( - localhost // host - , app->name // type - , chart->id // id - , chart->name // name - , chart->family // family - , chart->context // context - , chart->title // title - , chart->units // units - , "statsd" // plugin - , chart->source // module - , chart->priority // priority - , statsd.update_every // update every - , chart->chart_type // chart type - , app->rrd_memory_mode // memory mode - , app->rrd_history_entries // history - ); - - rrdset_flag_set(chart->st, RRDSET_FLAG_STORE_FIRST); - // rrdset_flag_set(chart->st, RRDSET_FLAG_DEBUG); - } - else rrdset_next(chart->st); - - STATSD_APP_CHART_DIM *dim; - for(dim = chart->dimensions; dim ;dim = dim->next) { - if(likely(!dim->metric_pattern)) { - if (unlikely(!dim->rd)) - statsd_add_dim_to_app_chart(app, chart, dim); - - if (unlikely(dim->value_ptr)) { - debug(D_STATSD, "updating dimension '%s' (%s) of chart '%s' (%s) for app '%s' with value " COLLECTED_NUMBER_FORMAT, dim->name, dim->rd->id, chart->id, chart->st->id, app->name, *dim->value_ptr); - rrddim_set_by_pointer(chart->st, dim->rd, *dim->value_ptr); - } - } - } - - rrdset_done(chart->st); - debug(D_STATSD, "completed update of chart '%s' for app '%s'", chart->id, app->name); -} - -static inline void statsd_update_all_app_charts(void) { - // debug(D_STATSD, "updating app charts"); - - STATSD_APP *app; - for(app = statsd.apps; app ;app = app->next) { - // debug(D_STATSD, "updating charts for app '%s'", app->name); - - STATSD_APP_CHART *chart; - for(chart = app->charts; chart ;chart = chart->next) { - if(unlikely(chart->dimensions_linked_count)) { - statsd_update_app_chart(app, chart); - } - } - } - - // debug(D_STATSD, "completed update of app charts"); -} - -const char *statsd_metric_type_string(STATSD_METRIC_TYPE type) { - switch(type) { - case STATSD_METRIC_TYPE_COUNTER: return "counter"; - case STATSD_METRIC_TYPE_GAUGE: return "gauge"; - case STATSD_METRIC_TYPE_HISTOGRAM: return "histogram"; - case STATSD_METRIC_TYPE_METER: return "meter"; - case STATSD_METRIC_TYPE_SET: return "set"; - case STATSD_METRIC_TYPE_TIMER: return "timer"; - default: return "unknown"; - } -} - -static inline void statsd_flush_index_metrics(STATSD_INDEX *index, void (*flush_metric)(STATSD_METRIC *)) { - STATSD_METRIC *m; - for(m = index->first; m ; m = m->next) { - if(unlikely(!(m->options & STATSD_METRIC_OPTION_CHECKED_IN_APPS))) { - log_access("NEW STATSD METRIC '%s': '%s'", statsd_metric_type_string(m->type), m->name); - check_if_metric_is_for_app(index, m); - m->options |= STATSD_METRIC_OPTION_CHECKED_IN_APPS; - } - - if(unlikely(!(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED))) { - if(statsd.private_charts >= statsd.max_private_charts_hard) { - debug(D_STATSD, "STATSD: metric '%s' will not be charted, because the hard limit of the maximum number of charts has been reached.", m->name); - info("STATSD: metric '%s' will not be charted, because the hard limit of the maximum number of charts (%zu) has been reached. Increase the number of charts by editing netdata.conf, [statsd] section.", m->name, statsd.max_private_charts); - m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - } - else { - if (simple_pattern_matches(statsd.charts_for, m->name)) { - debug(D_STATSD, "STATSD: metric '%s' will be charted.", m->name); - m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - } else { - debug(D_STATSD, "STATSD: metric '%s' will not be charted.", m->name); - m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED; - } - } - - m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED; - } - - flush_metric(m); - } -} - - -// -------------------------------------------------------------------------------------- -// statsd main thread - -static int statsd_listen_sockets_setup(void) { - return listen_sockets_setup(&statsd.sockets); -} - -static void statsd_main_cleanup(void *data) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - info("cleaning up..."); - - if (statsd.collection_threads_status) { - int i; - for (i = 0; i < statsd.threads; i++) { - if(statsd.collection_threads_status[i].status) { - info("STATSD: stopping data collection thread %d...", i + 1); - netdata_thread_cancel(statsd.collection_threads_status[i].thread); - } - else { - info("STATSD: data collection thread %d found stopped.", i + 1); - } - } - } - - info("STATSD: closing sockets..."); - listen_sockets_close(&statsd.sockets); - - info("STATSD: cleanup completed."); - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *statsd_main(void *ptr) { - netdata_thread_cleanup_push(statsd_main_cleanup, ptr); - - // ---------------------------------------------------------------------------------------------------------------- - // statsd configuration - - statsd.enabled = config_get_boolean(CONFIG_SECTION_STATSD, "enabled", statsd.enabled); - - statsd.update_every = default_rrd_update_every; - statsd.update_every = (int)config_get_number(CONFIG_SECTION_STATSD, "update every (flushInterval)", statsd.update_every); - if(statsd.update_every < default_rrd_update_every) { - error("STATSD: minimum flush interval %d given, but the minimum is the update every of netdata. Using %d", statsd.update_every, default_rrd_update_every); - statsd.update_every = default_rrd_update_every; - } - -#ifdef HAVE_RECVMMSG - statsd.recvmmsg_size = (size_t)config_get_number(CONFIG_SECTION_STATSD, "udp messages to process at once", (long long)statsd.recvmmsg_size); -#endif - - statsd.charts_for = simple_pattern_create(config_get(CONFIG_SECTION_STATSD, "create private charts for metrics matching", "*"), NULL, SIMPLE_PATTERN_EXACT); - statsd.max_private_charts = (size_t)config_get_number(CONFIG_SECTION_STATSD, "max private charts allowed", (long long)statsd.max_private_charts); - statsd.max_private_charts_hard = (size_t)config_get_number(CONFIG_SECTION_STATSD, "max private charts hard limit", (long long)statsd.max_private_charts * 5); - statsd.private_charts_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_STATSD, "private charts memory mode", rrd_memory_mode_name(default_rrd_memory_mode))); - statsd.private_charts_rrd_history_entries = (int)config_get_number(CONFIG_SECTION_STATSD, "private charts history", default_rrd_history_entries); - statsd.decimal_detail = (size_t)config_get_number(CONFIG_SECTION_STATSD, "decimal detail", (long long int)statsd.decimal_detail); - statsd.tcp_idle_timeout = (size_t) config_get_number(CONFIG_SECTION_STATSD, "disconnect idle tcp clients after seconds", (long long int)statsd.tcp_idle_timeout); - statsd.private_charts_hidden = (int)config_get_boolean(CONFIG_SECTION_STATSD, "private charts hidden", statsd.private_charts_hidden); - - statsd.histogram_percentile = (double)config_get_float(CONFIG_SECTION_STATSD, "histograms and timers percentile (percentThreshold)", statsd.histogram_percentile); - if(isless(statsd.histogram_percentile, 0) || isgreater(statsd.histogram_percentile, 100)) { - error("STATSD: invalid histograms and timers percentile %0.5f given", statsd.histogram_percentile); - statsd.histogram_percentile = 95.0; - } - { - char buffer[100 + 1]; - snprintf(buffer, 100, "%0.1f%%", statsd.histogram_percentile); - statsd.histogram_percentile_str = strdupz(buffer); - } - - if(config_get_boolean(CONFIG_SECTION_STATSD, "add dimension for number of events received", 1)) { - statsd.gauges.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT; - statsd.counters.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT; - statsd.meters.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT; - statsd.sets.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT; - statsd.histograms.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT; - statsd.timers.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT; - } - - if(config_get_boolean(CONFIG_SECTION_STATSD, "gaps on gauges (deleteGauges)", 0)) - statsd.gauges.default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - if(config_get_boolean(CONFIG_SECTION_STATSD, "gaps on counters (deleteCounters)", 0)) - statsd.counters.default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - if(config_get_boolean(CONFIG_SECTION_STATSD, "gaps on meters (deleteMeters)", 0)) - statsd.meters.default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - if(config_get_boolean(CONFIG_SECTION_STATSD, "gaps on sets (deleteSets)", 0)) - statsd.sets.default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - if(config_get_boolean(CONFIG_SECTION_STATSD, "gaps on histograms (deleteHistograms)", 0)) - statsd.histograms.default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - if(config_get_boolean(CONFIG_SECTION_STATSD, "gaps on timers (deleteTimers)", 0)) - statsd.timers.default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED; - - size_t max_sockets = (size_t)config_get_number(CONFIG_SECTION_STATSD, "statsd server max TCP sockets", (long long int)(rlimit_nofile.rlim_cur / 4)); - -#ifdef STATSD_MULTITHREADED - statsd.threads = (int)config_get_number(CONFIG_SECTION_STATSD, "threads", processors); - if(statsd.threads < 1) { - error("STATSD: Invalid number of threads %d, using %d", statsd.threads, processors); - statsd.threads = processors; - config_set_number(CONFIG_SECTION_STATSD, "collector threads", statsd.threads); - } -#else - statsd.threads = 1; -#endif - - // read custom application definitions - { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/statsd.d", netdata_configured_config_dir); - statsd_readdir(filename); - } - - // ---------------------------------------------------------------------------------------------------------------- - // statsd setup - - if(!statsd.enabled) return NULL; - - statsd_listen_sockets_setup(); - if(!statsd.sockets.opened) { - error("STATSD: No statsd sockets to listen to. statsd will be disabled."); - goto cleanup; - } - - statsd.collection_threads_status = callocz((size_t)statsd.threads, sizeof(struct collection_thread_status)); - - int i; - for(i = 0; i < statsd.threads ;i++) { - statsd.collection_threads_status[i].max_sockets = max_sockets / statsd.threads; - char tag[NETDATA_THREAD_TAG_MAX + 1]; - snprintfz(tag, NETDATA_THREAD_TAG_MAX, "STATSD_COLLECTOR[%d]", i + 1); - netdata_thread_create(&statsd.collection_threads_status[i].thread, tag, NETDATA_THREAD_OPTION_DEFAULT, statsd_collector_thread, &statsd.collection_threads_status[i]); - } - - // ---------------------------------------------------------------------------------------------------------------- - // statsd monitoring charts - - RRDSET *st_metrics = rrdset_create_localhost( - "netdata" - , "statsd_metrics" - , NULL - , "statsd" - , NULL - , "Metrics in the netdata statsd database" - , "metrics" - , "statsd" - , "stats" - , 132010 - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - RRDDIM *rd_metrics_gauge = rrddim_add(st_metrics, "gauges", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_metrics_counter = rrddim_add(st_metrics, "counters", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_metrics_timer = rrddim_add(st_metrics, "timers", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_metrics_meter = rrddim_add(st_metrics, "meters", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_metrics_histogram = rrddim_add(st_metrics, "histograms", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDDIM *rd_metrics_set = rrddim_add(st_metrics, "sets", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - - RRDSET *st_events = rrdset_create_localhost( - "netdata" - , "statsd_events" - , NULL - , "statsd" - , NULL - , "Events processed by the netdata statsd server" - , "events/s" - , "statsd" - , "stats" - , 132011 - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - RRDDIM *rd_events_gauge = rrddim_add(st_events, "gauges", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_counter = rrddim_add(st_events, "counters", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_timer = rrddim_add(st_events, "timers", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_meter = rrddim_add(st_events, "meters", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_histogram = rrddim_add(st_events, "histograms", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_set = rrddim_add(st_events, "sets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_unknown = rrddim_add(st_events, "unknown", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_events_errors = rrddim_add(st_events, "errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - RRDSET *st_reads = rrdset_create_localhost( - "netdata" - , "statsd_reads" - , NULL - , "statsd" - , NULL - , "Read operations made by the netdata statsd server" - , "reads/s" - , "statsd" - , "stats" - , 132012 - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - RRDDIM *rd_reads_tcp = rrddim_add(st_reads, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_reads_udp = rrddim_add(st_reads, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - RRDSET *st_bytes = rrdset_create_localhost( - "netdata" - , "statsd_bytes" - , NULL - , "statsd" - , NULL - , "Bytes read by the netdata statsd server" - , "kilobits/s" - , "netdata" - , "stats" - , 132013 - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - RRDDIM *rd_bytes_tcp = rrddim_add(st_bytes, "tcp", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_bytes_udp = rrddim_add(st_bytes, "udp", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - - RRDSET *st_packets = rrdset_create_localhost( - "netdata" - , "statsd_packets" - , NULL - , "statsd" - , NULL - , "Network packets processed by the netdata statsd server" - , "packets/s" - , "netdata" - , "stats" - , 132014 - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - RRDDIM *rd_packets_tcp = rrddim_add(st_packets, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_packets_udp = rrddim_add(st_packets, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - RRDSET *st_tcp_connects = rrdset_create_localhost( - "netdata" - , "tcp_connects" - , NULL - , "statsd" - , NULL - , "statsd server TCP connects and disconnects" - , "events" - , "statsd" - , "stats" - , 132015 - , statsd.update_every - , RRDSET_TYPE_LINE - ); - RRDDIM *rd_tcp_connects = rrddim_add(st_tcp_connects, "connects", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_tcp_disconnects = rrddim_add(st_tcp_connects, "disconnects", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - RRDSET *st_tcp_connected = rrdset_create_localhost( - "netdata" - , "tcp_connected" - , NULL - , "statsd" - , NULL - , "statsd server TCP connected sockets" - , "connected" - , "statsd" - , "stats" - , 132016 - , statsd.update_every - , RRDSET_TYPE_LINE - ); - RRDDIM *rd_tcp_connected = rrddim_add(st_tcp_connected, "connected", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - - RRDSET *st_pcharts = rrdset_create_localhost( - "netdata" - , "private_charts" - , NULL - , "statsd" - , NULL - , "Private metric charts created by the netdata statsd server" - , "charts" - , "statsd" - , "stats" - , 132020 - , statsd.update_every - , RRDSET_TYPE_AREA - ); - RRDDIM *rd_pcharts = rrddim_add(st_pcharts, "charts", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - - RRDSET *stcpu_thread = rrdset_create_localhost( - "netdata" - , "plugin_statsd_charting_cpu" - , NULL - , "statsd" - , "netdata.statsd_cpu" - , "NetData statsd charting thread CPU usage" - , "milliseconds/s" - , "statsd" - , "stats" - , 132001 - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - - RRDDIM *rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - RRDDIM *rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - struct rusage thread; - - for(i = 0; i < statsd.threads ;i++) { - char id[100 + 1]; - char title[100 + 1]; - - snprintfz(id, 100, "plugin_statsd_collector%d_cpu", i + 1); - snprintfz(title, 100, "NetData statsd collector thread No %d CPU usage", i + 1); - - statsd.collection_threads_status[i].st_cpu = rrdset_create_localhost( - "netdata" - , id - , NULL - , "statsd" - , "netdata.statsd_cpu" - , title - , "milliseconds/s" - , "statsd" - , "stats" - , 132002 + i - , statsd.update_every - , RRDSET_TYPE_STACKED - ); - - statsd.collection_threads_status[i].rd_user = rrddim_add(statsd.collection_threads_status[i].st_cpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - statsd.collection_threads_status[i].rd_system = rrddim_add(statsd.collection_threads_status[i].st_cpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } - - // ---------------------------------------------------------------------------------------------------------------- - // statsd thread to turn metrics into charts - - usec_t step = statsd.update_every * USEC_PER_SEC; - heartbeat_t hb; - heartbeat_init(&hb); - while(!netdata_exit) { - usec_t hb_dt = heartbeat_next(&hb, step); - - statsd_flush_index_metrics(&statsd.gauges, statsd_flush_gauge); - statsd_flush_index_metrics(&statsd.counters, statsd_flush_counter); - statsd_flush_index_metrics(&statsd.meters, statsd_flush_meter); - statsd_flush_index_metrics(&statsd.timers, statsd_flush_timer); - statsd_flush_index_metrics(&statsd.histograms, statsd_flush_histogram); - statsd_flush_index_metrics(&statsd.sets, statsd_flush_set); - - statsd_update_all_app_charts(); - - getrusage(RUSAGE_THREAD, &thread); - - if(unlikely(netdata_exit)) - break; - - if(likely(hb_dt)) { - rrdset_next(st_metrics); - rrdset_next(st_events); - rrdset_next(st_reads); - rrdset_next(st_bytes); - rrdset_next(st_packets); - rrdset_next(st_tcp_connects); - rrdset_next(st_tcp_connected); - rrdset_next(st_pcharts); - rrdset_next(stcpu_thread); - for(i = 0; i < statsd.threads ;i++) - rrdset_next(statsd.collection_threads_status[i].st_cpu); - } - - rrddim_set_by_pointer(st_metrics, rd_metrics_gauge, (collected_number)statsd.gauges.metrics); - rrddim_set_by_pointer(st_metrics, rd_metrics_counter, (collected_number)statsd.counters.metrics); - rrddim_set_by_pointer(st_metrics, rd_metrics_timer, (collected_number)statsd.timers.metrics); - rrddim_set_by_pointer(st_metrics, rd_metrics_meter, (collected_number)statsd.meters.metrics); - rrddim_set_by_pointer(st_metrics, rd_metrics_histogram, (collected_number)statsd.histograms.metrics); - rrddim_set_by_pointer(st_metrics, rd_metrics_set, (collected_number)statsd.sets.metrics); - rrdset_done(st_metrics); - - rrddim_set_by_pointer(st_events, rd_events_gauge, (collected_number)statsd.gauges.events); - rrddim_set_by_pointer(st_events, rd_events_counter, (collected_number)statsd.counters.events); - rrddim_set_by_pointer(st_events, rd_events_timer, (collected_number)statsd.timers.events); - rrddim_set_by_pointer(st_events, rd_events_meter, (collected_number)statsd.meters.events); - rrddim_set_by_pointer(st_events, rd_events_histogram, (collected_number)statsd.histograms.events); - rrddim_set_by_pointer(st_events, rd_events_set, (collected_number)statsd.sets.events); - rrddim_set_by_pointer(st_events, rd_events_unknown, (collected_number)statsd.unknown_types); - rrddim_set_by_pointer(st_events, rd_events_errors, (collected_number)statsd.socket_errors); - rrdset_done(st_events); - - rrddim_set_by_pointer(st_reads, rd_reads_tcp, (collected_number)statsd.tcp_socket_reads); - rrddim_set_by_pointer(st_reads, rd_reads_udp, (collected_number)statsd.udp_socket_reads); - rrdset_done(st_reads); - - rrddim_set_by_pointer(st_bytes, rd_bytes_tcp, (collected_number)statsd.tcp_bytes_read); - rrddim_set_by_pointer(st_bytes, rd_bytes_udp, (collected_number)statsd.udp_bytes_read); - rrdset_done(st_bytes); - - rrddim_set_by_pointer(st_packets, rd_packets_tcp, (collected_number)statsd.tcp_packets_received); - rrddim_set_by_pointer(st_packets, rd_packets_udp, (collected_number)statsd.udp_packets_received); - rrdset_done(st_packets); - - rrddim_set_by_pointer(st_tcp_connects, rd_tcp_connects, (collected_number)statsd.tcp_socket_connects); - rrddim_set_by_pointer(st_tcp_connects, rd_tcp_disconnects, (collected_number)statsd.tcp_socket_disconnects); - rrdset_done(st_tcp_connects); - - rrddim_set_by_pointer(st_tcp_connected, rd_tcp_connected, (collected_number)statsd.tcp_socket_connected); - rrdset_done(st_tcp_connected); - - rrddim_set_by_pointer(st_pcharts, rd_pcharts, (collected_number)statsd.private_charts); - rrdset_done(st_pcharts); - - rrddim_set_by_pointer(stcpu_thread, rd_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set_by_pointer(stcpu_thread, rd_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); - rrdset_done(stcpu_thread); - - for(i = 0; i < statsd.threads ;i++) { - rrddim_set_by_pointer(statsd.collection_threads_status[i].st_cpu, statsd.collection_threads_status[i].rd_user, statsd.collection_threads_status[i].rusage.ru_utime.tv_sec * 1000000ULL + statsd.collection_threads_status[i].rusage.ru_utime.tv_usec); - rrddim_set_by_pointer(statsd.collection_threads_status[i].st_cpu, statsd.collection_threads_status[i].rd_system, statsd.collection_threads_status[i].rusage.ru_stime.tv_sec * 1000000ULL + statsd.collection_threads_status[i].rusage.ru_stime.tv_usec); - rrdset_done(statsd.collection_threads_status[i].st_cpu); - } - } - -cleanup: ; // added semi-colon to prevent older gcc error: label at end of compound statement - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/statsd.h b/src/statsd.h deleted file mode 100644 index 17af098e8..000000000 --- a/src/statsd.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef NETDATA_STATSD_H -#define NETDATA_STATSD_H - -#define STATSD_LISTEN_PORT 8125 -#define STATSD_LISTEN_BACKLOG 4096 - -extern void *statsd_main(void *ptr); - -#endif //NETDATA_STATSD_H diff --git a/src/storage_number.c b/src/storage_number.c deleted file mode 100644 index c7bbaa8d9..000000000 --- a/src/storage_number.c +++ /dev/null @@ -1,231 +0,0 @@ -#include "common.h" - -storage_number pack_storage_number(calculated_number value, uint32_t flags) -{ - // bit 32 = sign 0:positive, 1:negative - // bit 31 = 0:divide, 1:multiply - // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total) - // bit 27, 26, 25 flags - // bit 24 to bit 1 = the value - - storage_number r = get_storage_number_flags(flags); - if(!value) return r; - - int m = 0; - calculated_number n = value; - - // if the value is negative - // add the sign bit and make it positive - if(n < 0) { - r += (1 << 31); // the sign bit 32 - n = -n; - } - - // make its integer part fit in 0x00ffffff - // by dividing it by 10 up to 7 times - // and increasing the multiplier - while(m < 7 && n > (calculated_number)0x00ffffff) { - n /= 10; - m++; - } - - if(m) { - // the value was too big and we divided it - // so we add a multiplier to unpack it - r += (1 << 30) + (m << 27); // the multiplier m - - if(n > (calculated_number)0x00ffffff) { - #ifdef NETDATA_INTERNAL_CHECKS - error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value); - #endif - r += 0x00ffffff; - return r; - } - } - else { - // 0x0019999e is the number that can be multiplied - // by 10 to give 0x00ffffff - // while the value is below 0x0019999e we can - // multiply it by 10, up to 7 times, increasing - // the multiplier - while(m < 7 && n < (calculated_number)0x0019999e) { - n *= 10; - m++; - } - - // the value was small enough and we multiplied it - // so we add a divider to unpack it - r += (0 << 30) + (m << 27); // the divider m - } - -#ifdef STORAGE_WITH_MATH - // without this there are rounding problems - // example: 0.9 becomes 0.89 - r += lrint((double) n); -#else - r += (storage_number)n; -#endif - - return r; -} - -calculated_number unpack_storage_number(storage_number value) -{ - if(!value) return 0; - - int sign = 0, exp = 0; - - value ^= get_storage_number_flags(value); - - if(value & (1 << 31)) { - sign = 1; - value ^= 1 << 31; - } - - if(value & (1 << 30)) { - exp = 1; - value ^= 1 << 30; - } - - int mul = value >> 27; - value ^= mul << 27; - - calculated_number n = value; - - // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n); - - while(mul > 0) { - if(exp) n *= 10; - else n /= 10; - mul--; - } - - if(sign) n = -n; - return n; -} - -/* -int print_calculated_number(char *str, calculated_number value) -{ - char *wstr = str; - - int sign = (value < 0) ? 1 : 0; - if(sign) value = -value; - -#ifdef STORAGE_WITH_MATH - // without llrintl() there are rounding problems - // for example 0.9 becomes 0.89 - unsigned long long uvalue = (unsigned long long int) llrintl(value * (calculated_number)100000); -#else - unsigned long long uvalue = value * (calculated_number)100000; -#endif - - wstr = print_number_llu_r_smart(str, uvalue); - - // make sure we have 6 bytes at least - while((wstr - str) < 6) *wstr++ = '0'; - - // put the sign back - if(sign) *wstr++ = '-'; - - // reverse it - char *begin = str, *end = --wstr, aux; - while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux; - // wstr--; - // strreverse(str, wstr); - - // remove trailing zeros - int decimal = 5; - while(decimal > 0 && *wstr == '0') { - *wstr-- = '\0'; - decimal--; - } - - // terminate it, one position to the right - // to let space for a dot - wstr[2] = '\0'; - - // make space for the dot - int i; - for(i = 0; i < decimal ;i++) { - wstr[1] = wstr[0]; - wstr--; - } - - // put the dot - if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; } - else wstr[1] = '.'; - - // return the buffer length - return (int) ((wstr - str) + 2 + decimal ); -} -*/ - -int print_calculated_number(char *str, calculated_number value) { - // info("printing number " CALCULATED_NUMBER_FORMAT, value); - char integral_str[50], fractional_str[50]; - - char *wstr = str; - - if(unlikely(value < 0)) { - *wstr++ = '-'; - value = -value; - } - - calculated_number integral, fractional; - -#ifdef STORAGE_WITH_MATH - fractional = calculated_number_modf(value, &integral) * 10000000.0; -#else - fractional = ((unsigned long long)(value * 10000000ULL) % 10000000ULL); -#endif - - unsigned long long integral_int = (unsigned long long)integral; - unsigned long long fractional_int = (unsigned long long)calculated_number_llrint(fractional); - if(unlikely(fractional_int >= 10000000)) { - integral_int += 1; - fractional_int -= 10000000; - } - - // info("integral " CALCULATED_NUMBER_FORMAT " (%llu), fractional " CALCULATED_NUMBER_FORMAT " (%llu)", integral, integral_int, fractional, fractional_int); - - char *istre; - if(unlikely(integral_int == 0)) { - integral_str[0] = '0'; - istre = &integral_str[1]; - } - else - // convert the integral part to string (reversed) - istre = print_number_llu_r_smart(integral_str, integral_int); - - // copy reversed the integral string - istre--; - while( istre >= integral_str ) *wstr++ = *istre--; - - if(likely(fractional_int != 0)) { - // add a dot - *wstr++ = '.'; - - // convert the fractional part to string (reversed) - char *fstre = print_number_llu_r_smart(fractional_str, fractional_int); - - // prepend zeros to reach 7 digits length - int decimal = 7; - int len = (int)(fstre - fractional_str); - while(len < decimal) { - *wstr++ = '0'; - len++; - } - - char *begin = fractional_str; - while(begin < fstre && *begin == '0') begin++; - - // copy reversed the fractional string - fstre--; - while( fstre >= begin ) *wstr++ = *fstre--; - } - - *wstr = '\0'; - // info("printed number '%s'", str); - return (int)(wstr - str); -} diff --git a/src/storage_number.h b/src/storage_number.h deleted file mode 100644 index ef81863fd..000000000 --- a/src/storage_number.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef NETDATA_STORAGE_NUMBER_H -#define NETDATA_STORAGE_NUMBER_H - -#ifdef NETDATA_WITHOUT_LONG_DOUBLE - -#define powl pow -#define modfl modf -#define llrintl llrint -#define roundl round -#define sqrtl sqrt -#define copysignl copysign -#define strtold strtod - -typedef double calculated_number; -#define CALCULATED_NUMBER_FORMAT "%0.7f" -#define CALCULATED_NUMBER_FORMAT_ZERO "%0.0f" -#define CALCULATED_NUMBER_FORMAT_AUTO "%f" - -#define LONG_DOUBLE_MODIFIER "f" -typedef double LONG_DOUBLE; - -#else - -typedef long double calculated_number; -#define CALCULATED_NUMBER_FORMAT "%0.7Lf" -#define CALCULATED_NUMBER_FORMAT_ZERO "%0.0Lf" -#define CALCULATED_NUMBER_FORMAT_AUTO "%Lf" - -#define LONG_DOUBLE_MODIFIER "Lf" -typedef long double LONG_DOUBLE; - -#endif - -//typedef long long calculated_number; -//#define CALCULATED_NUMBER_FORMAT "%lld" - -typedef long long collected_number; -#define COLLECTED_NUMBER_FORMAT "%lld" - -/* -typedef long double collected_number; -#define COLLECTED_NUMBER_FORMAT "%0.7Lf" -*/ - -#define calculated_number_modf(x, y) modfl(x, y) -#define calculated_number_llrint(x) llrintl(x) -#define calculated_number_round(x) roundl(x) -#define calculated_number_fabs(x) fabsl(x) -#define calculated_number_epsilon (calculated_number)0.0000001 - -#define calculated_number_equal(a, b) (calculated_number_fabs((a) - (b)) < calculated_number_epsilon) - -typedef uint32_t storage_number; -#define STORAGE_NUMBER_FORMAT "%u" - -#define SN_NOT_EXISTS (0x0 << 24) -#define SN_EXISTS (0x1 << 24) -#define SN_EXISTS_RESET (0x2 << 24) -#define SN_EXISTS_UNDEF1 (0x3 << 24) -#define SN_EXISTS_UNDEF2 (0x4 << 24) -#define SN_EXISTS_UNDEF3 (0x5 << 24) -#define SN_EXISTS_UNDEF4 (0x6 << 24) - -#define SN_FLAGS_MASK (~(0x6 << 24)) - -// extract the flags -#define get_storage_number_flags(value) ((((storage_number)(value)) & (1 << 24)) | (((storage_number)(value)) & (2 << 24)) | (((storage_number)(value)) & (4 << 24))) -#define SN_EMPTY_SLOT 0x00000000 - -// checks -#define does_storage_number_exist(value) ((get_storage_number_flags(value) != 0)?1:0) -#define did_storage_number_reset(value) ((get_storage_number_flags(value) == SN_EXISTS_RESET)?1:0) - -storage_number pack_storage_number(calculated_number value, uint32_t flags); -calculated_number unpack_storage_number(storage_number value); - -int print_calculated_number(char *str, calculated_number value); - -#define STORAGE_NUMBER_POSITIVE_MAX (167772150000000.0) -#define STORAGE_NUMBER_POSITIVE_MIN (0.0000001) -#define STORAGE_NUMBER_NEGATIVE_MAX (-0.0000001) -#define STORAGE_NUMBER_NEGATIVE_MIN (-167772150000000.0) - -// accepted accuracy loss -#define ACCURACY_LOSS 0.0001 -#define accuracy_loss(t1, t2) (((t1) == (t2) || (t1) == 0.0 || (t2) == 0.0) ? 0.0 : (100.0 - (((t1) > (t2)) ? ((t2) * 100.0 / (t1) ) : ((t1) * 100.0 / (t2))))) - -#endif /* NETDATA_STORAGE_NUMBER_H */ diff --git a/src/sys_devices_system_edac_mc.c b/src/sys_devices_system_edac_mc.c deleted file mode 100644 index caa16192e..000000000 --- a/src/sys_devices_system_edac_mc.c +++ /dev/null @@ -1,204 +0,0 @@ -#include "common.h" - -struct mc { - char *name; - char ce_updated; - char ue_updated; - - char *ce_count_filename; - char *ue_count_filename; - - procfile *ce_ff; - procfile *ue_ff; - - collected_number ce_count; - collected_number ue_count; - - RRDDIM *ce_rd; - RRDDIM *ue_rd; - - struct mc *next; -}; -static struct mc *mc_root = NULL; - -static void find_all_mc() { - char name[FILENAME_MAX + 1]; - 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); - if(unlikely(!dir)) { - error("Cannot read ECC memory errors directory '%s'", dirname); - return; - } - - struct dirent *de = NULL; - while((de = readdir(dir))) { - if(de->d_type == DT_DIR && de->d_name[0] == 'm' && de->d_name[1] == 'c' && isdigit(de->d_name[2])) { - struct mc *m = callocz(1, sizeof(struct mc)); - m->name = strdupz(de->d_name); - - struct stat st; - - snprintfz(name, FILENAME_MAX, "%s/%s/ce_count", dirname, de->d_name); - if(stat(name, &st) != -1) - m->ce_count_filename = strdupz(name); - - snprintfz(name, FILENAME_MAX, "%s/%s/ue_count", dirname, de->d_name); - if(stat(name, &st) != -1) - m->ue_count_filename = strdupz(name); - - if(!m->ce_count_filename && !m->ue_count_filename) { - freez(m->name); - freez(m); - } - else { - m->next = mc_root; - mc_root = m; - } - } - } - - closedir(dir); -} - -int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) { - (void)dt; - - if(unlikely(mc_root == NULL)) { - find_all_mc(); - if(unlikely(mc_root == NULL)) - return 1; - } - - static int do_ce = -1, do_ue = -1; - calculated_number ce_sum = 0, ue_sum = 0; - 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_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_BOOLEAN_NO) { - for(m = mc_root; m; m = m->next) { - if(m->ce_count_filename) { - m->ce_updated = 0; - - if(unlikely(!m->ce_ff)) { - m->ce_ff = procfile_open(m->ce_count_filename, " \t", PROCFILE_FLAG_DEFAULT); - if(unlikely(!m->ce_ff)) - continue; - } - - m->ce_ff = procfile_readall(m->ce_ff); - if(unlikely(!m->ce_ff || procfile_lines(m->ce_ff) < 1 || procfile_linewords(m->ce_ff, 0) < 1)) - continue; - - m->ce_count = str2ull(procfile_lineword(m->ce_ff, 0, 0)); - ce_sum += m->ce_count; - m->ce_updated = 1; - } - } - } - - if(do_ue != CONFIG_BOOLEAN_NO) { - for(m = mc_root; m; m = m->next) { - if(m->ue_count_filename) { - m->ue_updated = 0; - - if(unlikely(!m->ue_ff)) { - m->ue_ff = procfile_open(m->ue_count_filename, " \t", PROCFILE_FLAG_DEFAULT); - if(unlikely(!m->ue_ff)) - continue; - } - - m->ue_ff = procfile_readall(m->ue_ff); - if(unlikely(!m->ue_ff || procfile_lines(m->ue_ff) < 1 || procfile_linewords(m->ue_ff, 0) < 1)) - continue; - - m->ue_count = str2ull(procfile_lineword(m->ue_ff, 0, 0)); - ue_sum += m->ue_count; - m->ue_updated = 1; - } - } - } - - // -------------------------------------------------------------------- - - 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_create_localhost( - "mem" - , "ecc_ce" - , NULL - , "ecc" - , NULL - , "ECC Memory Correctable Errors" - , "errors" - , "proc" - , "/sys/devices/system/edac/mc" - , NETDATA_CHART_PRIO_MEM_HW + 50 - , update_every - , RRDSET_TYPE_LINE - ); - } - else - rrdset_next(ce_st); - - for(m = mc_root; m; m = m->next) { - if (m->ce_count_filename && m->ce_updated) { - if(unlikely(!m->ce_rd)) - m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(ce_st, m->ce_rd, m->ce_count); - } - } - - rrdset_done(ce_st); - } - - // -------------------------------------------------------------------- - - 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_create_localhost( - "mem" - , "ecc_ue" - , NULL - , "ecc" - , NULL - , "ECC Memory Uncorrectable Errors" - , "errors" - , "proc" - , "/sys/devices/system/edac/mc" - , NETDATA_CHART_PRIO_MEM_HW + 60 - , update_every - , RRDSET_TYPE_LINE - ); - } - else - rrdset_next(ue_st); - - for(m = mc_root; m; m = m->next) { - if (m->ue_count_filename && m->ue_updated) { - if(unlikely(!m->ue_rd)) - m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(ue_st, m->ue_rd, m->ue_count); - } - } - - rrdset_done(ue_st); - } - - return 0; -} diff --git a/src/sys_devices_system_node.c b/src/sys_devices_system_node.c deleted file mode 100644 index d04c8dc30..000000000 --- a/src/sys_devices_system_node.c +++ /dev/null @@ -1,161 +0,0 @@ -#include "common.h" - -struct node { - char *name; - char *numastat_filename; - procfile *numastat_ff; - RRDSET *numastat_st; - struct node *next; -}; -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", 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); - if(!dir) { - error("Cannot read NUMA node directory '%s'", dirname); - return 0; - } - - struct dirent *de = NULL; - while((de = readdir(dir))) { - if(de->d_type != DT_DIR) - continue; - - if(strncmp(de->d_name, "node", 4) != 0) - continue; - - if(!isdigit(de->d_name[4])) - continue; - - numa_node_count++; - - struct node *m = callocz(1, sizeof(struct node)); - m->name = strdupz(de->d_name); - - struct stat st; - - snprintfz(name, FILENAME_MAX, "%s/%s/numastat", dirname, de->d_name); - if(stat(name, &st) == -1) { - freez(m->name); - freez(m); - continue; - } - - m->numastat_filename = strdupz(name); - - m->next = numa_root; - numa_root = m; - } - - closedir(dir); - - return numa_node_count; -} - -int do_proc_sys_devices_system_node(int update_every, usec_t dt) { - (void)dt; - - 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(); - if(unlikely(numa_root == NULL)) - return 1; - } - - if(unlikely(do_numastat == -1)) { - 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_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; - } - - m->numastat_ff = procfile_readall(m->numastat_ff); - if(unlikely(!m->numastat_ff || procfile_lines(m->numastat_ff) < 1 || procfile_linewords(m->numastat_ff, 0) < 1)) - continue; - - if(unlikely(!m->numastat_st)) { - m->numastat_st = rrdset_create_localhost( - "mem" - , m->name - , NULL - , "numa" - , NULL - , "NUMA events" - , "events/s" - , "proc" - , "/sys/devices/system/node" - , NETDATA_CHART_PRIO_MEM_NUMA + 10 - , 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); - - } - else rrdset_next(m->numastat_st); - - size_t lines = procfile_lines(m->numastat_ff), l; - for(l = 0; l < lines; l++) { - size_t words = procfile_linewords(m->numastat_ff, l); - - if(unlikely(words < 2)) { - if(unlikely(words)) - error("Cannot read %s numastat line %zu. Expected 2 params, read %zu.", m->name, l, words); - continue; - } - - char *name = procfile_lineword(m->numastat_ff, l, 0); - char *value = procfile_lineword(m->numastat_ff, l, 1); - - 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(m->numastat_st); - } - } - } - - return 0; -} diff --git a/src/sys_fs_btrfs.c b/src/sys_fs_btrfs.c deleted file mode 100644 index a8dfb5c91..000000000 --- a/src/sys_fs_btrfs.c +++ /dev/null @@ -1,714 +0,0 @@ -#include "common.h" - -typedef struct btrfs_disk { - char *name; - uint32_t hash; - int exists; - - char *size_filename; - char *hw_sector_size_filename; - unsigned long long size; - unsigned long long hw_sector_size; - - struct btrfs_disk *next; -} BTRFS_DISK; - -typedef struct btrfs_node { - int exists; - int logged_error; - - char *id; - uint32_t hash; - - char *label; - - // unsigned long long int sectorsize; - // unsigned long long int nodesize; - // unsigned long long int quota_override; - - #define declare_btrfs_allocation_section_field(SECTION, FIELD) \ - char *allocation_ ## SECTION ## _ ## FIELD ## _filename; \ - unsigned long long int allocation_ ## SECTION ## _ ## FIELD; - - #define declare_btrfs_allocation_field(FIELD) \ - char *allocation_ ## FIELD ## _filename; \ - unsigned long long int allocation_ ## FIELD; - - RRDSET *st_allocation_disks; - RRDDIM *rd_allocation_disks_unallocated; - RRDDIM *rd_allocation_disks_data_used; - RRDDIM *rd_allocation_disks_data_free; - RRDDIM *rd_allocation_disks_metadata_used; - RRDDIM *rd_allocation_disks_metadata_free; - RRDDIM *rd_allocation_disks_system_used; - RRDDIM *rd_allocation_disks_system_free; - unsigned long long all_disks_total; - - RRDSET *st_allocation_data; - RRDDIM *rd_allocation_data_free; - RRDDIM *rd_allocation_data_used; - declare_btrfs_allocation_section_field(data, total_bytes) - declare_btrfs_allocation_section_field(data, bytes_used) - declare_btrfs_allocation_section_field(data, disk_total) - declare_btrfs_allocation_section_field(data, disk_used) - - RRDSET *st_allocation_metadata; - RRDDIM *rd_allocation_metadata_free; - RRDDIM *rd_allocation_metadata_used; - RRDDIM *rd_allocation_metadata_reserved; - declare_btrfs_allocation_section_field(metadata, total_bytes) - declare_btrfs_allocation_section_field(metadata, bytes_used) - declare_btrfs_allocation_section_field(metadata, disk_total) - declare_btrfs_allocation_section_field(metadata, disk_used) - //declare_btrfs_allocation_field(global_rsv_reserved) - declare_btrfs_allocation_field(global_rsv_size) - - RRDSET *st_allocation_system; - RRDDIM *rd_allocation_system_free; - RRDDIM *rd_allocation_system_used; - declare_btrfs_allocation_section_field(system, total_bytes) - declare_btrfs_allocation_section_field(system, bytes_used) - declare_btrfs_allocation_section_field(system, disk_total) - declare_btrfs_allocation_section_field(system, disk_used) - - BTRFS_DISK *disks; - - struct btrfs_node *next; -} BTRFS_NODE; - -static BTRFS_NODE *nodes = NULL; - -static inline void btrfs_free_disk(BTRFS_DISK *d) { - freez(d->name); - freez(d->size_filename); - freez(d->hw_sector_size_filename); - freez(d); -} - -static inline void btrfs_free_node(BTRFS_NODE *node) { - // info("BTRFS: destroying '%s'", node->id); - - if(node->st_allocation_disks) - rrdset_is_obsolete(node->st_allocation_disks); - - if(node->st_allocation_data) - rrdset_is_obsolete(node->st_allocation_data); - - if(node->st_allocation_metadata) - rrdset_is_obsolete(node->st_allocation_metadata); - - if(node->st_allocation_system) - rrdset_is_obsolete(node->st_allocation_system); - - freez(node->allocation_data_bytes_used_filename); - freez(node->allocation_data_total_bytes_filename); - - freez(node->allocation_metadata_bytes_used_filename); - freez(node->allocation_metadata_total_bytes_filename); - - freez(node->allocation_system_bytes_used_filename); - freez(node->allocation_system_total_bytes_filename); - - while(node->disks) { - BTRFS_DISK *d = node->disks; - node->disks = node->disks->next; - btrfs_free_disk(d); - } - - freez(node->label); - freez(node->id); - freez(node); -} - -static inline int find_btrfs_disks(BTRFS_NODE *node, const char *path) { - char filename[FILENAME_MAX + 1]; - - node->all_disks_total = 0; - - BTRFS_DISK *d; - for(d = node->disks ; d ; d = d->next) - d->exists = 0; - - DIR *dir = opendir(path); - if (!dir) { - if(!node->logged_error) { - error("BTRFS: Cannot open directory '%s'.", path); - node->logged_error = 1; - } - return 1; - } - node->logged_error = 0; - - struct dirent *de = NULL; - while ((de = readdir(dir))) { - if (de->d_type != DT_LNK - || !strcmp(de->d_name, ".") - || !strcmp(de->d_name, "..") - ) { - // info("BTRFS: ignoring '%s'", de->d_name); - continue; - } - - uint32_t hash = simple_hash(de->d_name); - - // -------------------------------------------------------------------- - // search for it - - for(d = node->disks ; d ; d = d->next) { - if(hash == d->hash && !strcmp(de->d_name, d->name)) - break; - } - - // -------------------------------------------------------------------- - // did we find it? - - if(!d) { - d = callocz(sizeof(BTRFS_DISK), 1); - - d->name = strdupz(de->d_name); - d->hash = simple_hash(d->name); - - snprintfz(filename, FILENAME_MAX, "%s/%s/size", path, de->d_name); - d->size_filename = strdupz(filename); - - // for disks - snprintfz(filename, FILENAME_MAX, "%s/%s/queue/hw_sector_size", path, de->d_name); - struct stat sb; - if(stat(filename, &sb) == -1) - // for partitions - snprintfz(filename, FILENAME_MAX, "%s/%s/../queue/hw_sector_size", path, de->d_name); - - d->hw_sector_size_filename = strdupz(filename); - - // link it - d->next = node->disks; - node->disks = d; - } - - d->exists = 1; - - - // -------------------------------------------------------------------- - // update the values - - if(read_single_number_file(d->size_filename, &d->size) != 0) { - error("BTRFS: failed to read '%s'", d->size_filename); - d->exists = 0; - continue; - } - - if(read_single_number_file(d->hw_sector_size_filename, &d->hw_sector_size) != 0) { - error("BTRFS: failed to read '%s'", d->hw_sector_size_filename); - d->exists = 0; - continue; - } - - node->all_disks_total += d->size * d->hw_sector_size; - } - closedir(dir); - - // ------------------------------------------------------------------------ - // cleanup - - BTRFS_DISK *last = NULL; - d = node->disks; - - while(d) { - if(unlikely(!d->exists)) { - if(unlikely(node->disks == d)) { - node->disks = d->next; - btrfs_free_disk(d); - d = node->disks; - last = NULL; - } - else { - last->next = d->next; - btrfs_free_disk(d); - d = last->next; - } - - continue; - } - - last = d; - d = d->next; - } - - return 0; -} - - -static inline int find_all_btrfs_pools(const char *path) { - static int logged_error = 0; - char filename[FILENAME_MAX + 1]; - - BTRFS_NODE *node; - for(node = nodes ; node ; node = node->next) - node->exists = 0; - - DIR *dir = opendir(path); - if (!dir) { - if(!logged_error) { - error("BTRFS: Cannot open directory '%s'.", path); - logged_error = 1; - } - return 1; - } - logged_error = 0; - - struct dirent *de = NULL; - while ((de = readdir(dir))) { - if(de->d_type != DT_DIR - || !strcmp(de->d_name, ".") - || !strcmp(de->d_name, "..") - || !strcmp(de->d_name, "features") - ) { - // info("BTRFS: ignoring '%s'", de->d_name); - continue; - } - - uint32_t hash = simple_hash(de->d_name); - - // search for it - for(node = nodes ; node ; node = node->next) { - if(hash == node->hash && !strcmp(de->d_name, node->id)) - break; - } - - // did we find it? - if(node) { - // info("BTRFS: already exists '%s'", de->d_name); - node->exists = 1; - - // update the disk sizes - snprintfz(filename, FILENAME_MAX, "%s/%s/devices", path, de->d_name); - find_btrfs_disks(node, filename); - - continue; - } - - // info("BTRFS: adding '%s'", de->d_name); - - // not found, create it - node = callocz(sizeof(BTRFS_NODE), 1); - - node->id = strdupz(de->d_name); - node->hash = simple_hash(node->id); - node->exists = 1; - - { - char label[FILENAME_MAX + 1] = ""; - - snprintfz(filename, FILENAME_MAX, "%s/%s/label", path, de->d_name); - read_file(filename, label, FILENAME_MAX); - - char *s = label; - if (s[0]) - s = trim(label); - - if(s && s[0]) - node->label = strdupz(s); - else - node->label = strdupz(node->id); - } - - //snprintfz(filename, FILENAME_MAX, "%s/%s/sectorsize", path, de->d_name); - //if(read_single_number_file(filename, &node->sectorsize) != 0) { - // error("BTRFS: failed to read '%s'", filename); - // btrfs_free_node(node); - // continue; - //} - - //snprintfz(filename, FILENAME_MAX, "%s/%s/nodesize", path, de->d_name); - //if(read_single_number_file(filename, &node->nodesize) != 0) { - // error("BTRFS: failed to read '%s'", filename); - // btrfs_free_node(node); - // continue; - //} - - //snprintfz(filename, FILENAME_MAX, "%s/%s/quota_override", path, de->d_name); - //if(read_single_number_file(filename, &node->quota_override) != 0) { - // error("BTRFS: failed to read '%s'", filename); - // btrfs_free_node(node); - // continue; - //} - - // -------------------------------------------------------------------- - // macros to simplify our life - - #define init_btrfs_allocation_field(FIELD) {\ - snprintfz(filename, FILENAME_MAX, "%s/%s/allocation/" #FIELD, path, de->d_name); \ - if(read_single_number_file(filename, &node->allocation_ ## FIELD) != 0) {\ - error("BTRFS: failed to read '%s'", filename);\ - btrfs_free_node(node);\ - continue;\ - }\ - if(!node->allocation_ ## FIELD ## _filename)\ - node->allocation_ ## FIELD ## _filename = strdupz(filename);\ - } - - #define init_btrfs_allocation_section_field(SECTION, FIELD) {\ - snprintfz(filename, FILENAME_MAX, "%s/%s/allocation/" #SECTION "/" #FIELD, path, de->d_name); \ - if(read_single_number_file(filename, &node->allocation_ ## SECTION ## _ ## FIELD) != 0) {\ - error("BTRFS: failed to read '%s'", filename);\ - btrfs_free_node(node);\ - continue;\ - }\ - if(!node->allocation_ ## SECTION ## _ ## FIELD ## _filename)\ - node->allocation_ ## SECTION ## _ ## FIELD ## _filename = strdupz(filename);\ - } - - // -------------------------------------------------------------------- - // allocation/data - - init_btrfs_allocation_section_field(data, total_bytes); - init_btrfs_allocation_section_field(data, bytes_used); - init_btrfs_allocation_section_field(data, disk_total); - init_btrfs_allocation_section_field(data, disk_used); - - - // -------------------------------------------------------------------- - // allocation/metadata - - init_btrfs_allocation_section_field(metadata, total_bytes); - init_btrfs_allocation_section_field(metadata, bytes_used); - init_btrfs_allocation_section_field(metadata, disk_total); - init_btrfs_allocation_section_field(metadata, disk_used); - - init_btrfs_allocation_field(global_rsv_size); - // init_btrfs_allocation_field(global_rsv_reserved); - - - // -------------------------------------------------------------------- - // allocation/system - - init_btrfs_allocation_section_field(system, total_bytes); - init_btrfs_allocation_section_field(system, bytes_used); - init_btrfs_allocation_section_field(system, disk_total); - init_btrfs_allocation_section_field(system, disk_used); - - - // -------------------------------------------------------------------- - // find all disks related to this node - // and collect their sizes - - snprintfz(filename, FILENAME_MAX, "%s/%s/devices", path, de->d_name); - find_btrfs_disks(node, filename); - - - // -------------------------------------------------------------------- - // link it - - // info("BTRFS: linking '%s'", node->id); - node->next = nodes; - nodes = node; - } - closedir(dir); - - - // ------------------------------------------------------------------------ - // cleanup - - BTRFS_NODE *last = NULL; - node = nodes; - - while(node) { - if(unlikely(!node->exists)) { - if(unlikely(nodes == node)) { - nodes = node->next; - btrfs_free_node(node); - node = nodes; - last = NULL; - } - else { - last->next = node->next; - btrfs_free_node(node); - node = last->next; - } - - continue; - } - - last = node; - node = node->next; - } - - return 0; -} - -int do_sys_fs_btrfs(int update_every, usec_t dt) { - static int initialized = 0 - , do_allocation_disks = CONFIG_BOOLEAN_AUTO - , do_allocation_system = CONFIG_BOOLEAN_AUTO - , do_allocation_data = CONFIG_BOOLEAN_AUTO - , do_allocation_metadata = CONFIG_BOOLEAN_AUTO; - - static usec_t refresh_delta = 0, refresh_every = 60 * USEC_PER_SEC; - static char *btrfs_path = NULL; - - (void)dt; - - if(unlikely(!initialized)) { - initialized = 1; - - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/fs/btrfs"); - btrfs_path = config_get("plugin:proc:/sys/fs/btrfs", "path to monitor", filename); - - refresh_every = config_get_number("plugin:proc:/sys/fs/btrfs", "check for btrfs changes every", refresh_every / USEC_PER_SEC) * USEC_PER_SEC; - refresh_delta = refresh_every; - - do_allocation_disks = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "physical disks allocation", do_allocation_disks); - do_allocation_data = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "data allocation", do_allocation_data); - do_allocation_metadata = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "metadata allocation", do_allocation_metadata); - do_allocation_system = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "system allocation", do_allocation_system); - } - - refresh_delta += dt; - if(refresh_delta >= refresh_every) { - refresh_delta = 0; - find_all_btrfs_pools(btrfs_path); - } - - BTRFS_NODE *node; - for(node = nodes; node ; node = node->next) { - // -------------------------------------------------------------------- - // allocation/system - - #define collect_btrfs_allocation_field(FIELD) \ - read_single_number_file(node->allocation_ ## FIELD ## _filename, &node->allocation_ ## FIELD) - - #define collect_btrfs_allocation_section_field(SECTION, FIELD) \ - read_single_number_file(node->allocation_ ## SECTION ## _ ## FIELD ## _filename, &node->allocation_ ## SECTION ## _ ## FIELD) - - if(do_allocation_disks != CONFIG_BOOLEAN_NO) { - if( collect_btrfs_allocation_section_field(data, disk_total) != 0 - || collect_btrfs_allocation_section_field(data, disk_used) != 0 - || collect_btrfs_allocation_section_field(metadata, disk_total) != 0 - || collect_btrfs_allocation_section_field(metadata, disk_used) != 0 - || collect_btrfs_allocation_section_field(system, disk_total) != 0 - || collect_btrfs_allocation_section_field(system, disk_used) != 0) { - error("BTRFS: failed to collect physical disks allocation for '%s'", node->id); - // make it refresh btrfs at the next iteration - refresh_delta = refresh_every; - continue; - } - } - - if(do_allocation_data != CONFIG_BOOLEAN_NO) { - if (collect_btrfs_allocation_section_field(data, total_bytes) != 0 - || collect_btrfs_allocation_section_field(data, bytes_used) != 0) { - error("BTRFS: failed to collect allocation/data for '%s'", node->id); - // make it refresh btrfs at the next iteration - refresh_delta = refresh_every; - continue; - } - } - - if(do_allocation_metadata != CONFIG_BOOLEAN_NO) { - if (collect_btrfs_allocation_section_field(metadata, total_bytes) != 0 - || collect_btrfs_allocation_section_field(metadata, bytes_used) != 0 - || collect_btrfs_allocation_field(global_rsv_size) != 0 - ) { - error("BTRFS: failed to collect allocation/metadata for '%s'", node->id); - // make it refresh btrfs at the next iteration - refresh_delta = refresh_every; - continue; - } - } - - if(do_allocation_system != CONFIG_BOOLEAN_NO) { - if (collect_btrfs_allocation_section_field(system, total_bytes) != 0 - || collect_btrfs_allocation_section_field(system, bytes_used) != 0) { - error("BTRFS: failed to collect allocation/system for '%s'", node->id); - // make it refresh btrfs at the next iteration - refresh_delta = refresh_every; - continue; - } - } - - // -------------------------------------------------------------------- - // allocation/disks - - if(do_allocation_disks == CONFIG_BOOLEAN_YES || (do_allocation_disks == CONFIG_BOOLEAN_AUTO && node->all_disks_total && node->allocation_data_disk_total)) { - do_allocation_disks = CONFIG_BOOLEAN_YES; - - if(unlikely(!node->st_allocation_disks)) { - char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1]; - - snprintf(id, RRD_ID_LENGTH_MAX, "disk_%s", node->id); - snprintf(name, RRD_ID_LENGTH_MAX, "disk_%s", node->label); - snprintf(title, 200, "BTRFS Disk Allocation for %s", node->label); - - netdata_fix_chart_id(id); - netdata_fix_chart_name(name); - - node->st_allocation_disks = rrdset_create_localhost( - "btrfs" - , id - , name - , node->label - , "btrfs.disk" - , title - , "MB" - , "proc" - , "sys/fs/btrfs" - , 2300 - , update_every - , RRDSET_TYPE_STACKED - ); - - node->rd_allocation_disks_unallocated = rrddim_add(node->st_allocation_disks, "unallocated", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_disks_data_used = rrddim_add(node->st_allocation_disks, "data_used", "data used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_disks_data_free = rrddim_add(node->st_allocation_disks, "data_free", "data free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_disks_metadata_used = rrddim_add(node->st_allocation_disks, "meta_used", "meta used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_disks_metadata_free = rrddim_add(node->st_allocation_disks, "meta_free", "meta free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_disks_system_used = rrddim_add(node->st_allocation_disks, "sys_used", "sys used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_disks_system_free = rrddim_add(node->st_allocation_disks, "sys_free", "sys free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(node->st_allocation_disks); - - // unsigned long long disk_used = node->allocation_data_disk_used + node->allocation_metadata_disk_used + node->allocation_system_disk_used; - unsigned long long disk_total = node->allocation_data_disk_total + node->allocation_metadata_disk_total + node->allocation_system_disk_total; - unsigned long long disk_unallocated = node->all_disks_total - disk_total; - - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_unallocated, disk_unallocated); - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_data_used, node->allocation_data_disk_used); - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_data_free, node->allocation_data_disk_total - node->allocation_data_disk_used); - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_metadata_used, node->allocation_metadata_disk_used); - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_metadata_free, node->allocation_metadata_disk_total - node->allocation_metadata_disk_used); - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_system_used, node->allocation_system_disk_used); - rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_system_free, node->allocation_system_disk_total - node->allocation_system_disk_used); - rrdset_done(node->st_allocation_disks); - } - - - // -------------------------------------------------------------------- - // allocation/data - - if(do_allocation_data == CONFIG_BOOLEAN_YES || (do_allocation_data == CONFIG_BOOLEAN_AUTO && node->allocation_data_total_bytes)) { - do_allocation_data = CONFIG_BOOLEAN_YES; - - if(unlikely(!node->st_allocation_data)) { - char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1]; - - snprintf(id, RRD_ID_LENGTH_MAX, "data_%s", node->id); - snprintf(name, RRD_ID_LENGTH_MAX, "data_%s", node->label); - snprintf(title, 200, "BTRFS Data Allocation for %s", node->label); - - netdata_fix_chart_id(id); - netdata_fix_chart_name(name); - - node->st_allocation_data = rrdset_create_localhost( - "btrfs" - , id - , name - , node->label - , "btrfs.data" - , title - , "MB" - , "proc" - , "sys/fs/btrfs" - , 2301 - , update_every - , RRDSET_TYPE_STACKED - ); - - node->rd_allocation_data_free = rrddim_add(node->st_allocation_data, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_data_used = rrddim_add(node->st_allocation_data, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(node->st_allocation_data); - - rrddim_set_by_pointer(node->st_allocation_data, node->rd_allocation_data_free, node->allocation_data_total_bytes - node->allocation_data_bytes_used); - rrddim_set_by_pointer(node->st_allocation_data, node->rd_allocation_data_used, node->allocation_data_bytes_used); - rrdset_done(node->st_allocation_data); - } - - // -------------------------------------------------------------------- - // allocation/metadata - - if(do_allocation_metadata == CONFIG_BOOLEAN_YES || (do_allocation_metadata == CONFIG_BOOLEAN_AUTO && node->allocation_metadata_total_bytes)) { - do_allocation_metadata = CONFIG_BOOLEAN_YES; - - if(unlikely(!node->st_allocation_metadata)) { - char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1]; - - snprintf(id, RRD_ID_LENGTH_MAX, "metadata_%s", node->id); - snprintf(name, RRD_ID_LENGTH_MAX, "metadata_%s", node->label); - snprintf(title, 200, "BTRFS Metadata Allocation for %s", node->label); - - netdata_fix_chart_id(id); - netdata_fix_chart_name(name); - - node->st_allocation_metadata = rrdset_create_localhost( - "btrfs" - , id - , name - , node->label - , "btrfs.metadata" - , title - , "MB" - , "proc" - , "sys/fs/btrfs" - , 2302 - , update_every - , RRDSET_TYPE_STACKED - ); - - node->rd_allocation_metadata_free = rrddim_add(node->st_allocation_metadata, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_metadata_used = rrddim_add(node->st_allocation_metadata, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_metadata_reserved = rrddim_add(node->st_allocation_metadata, "reserved", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(node->st_allocation_metadata); - - rrddim_set_by_pointer(node->st_allocation_metadata, node->rd_allocation_metadata_free, node->allocation_metadata_total_bytes - node->allocation_metadata_bytes_used - node->allocation_global_rsv_size); - rrddim_set_by_pointer(node->st_allocation_metadata, node->rd_allocation_metadata_used, node->allocation_metadata_bytes_used); - rrddim_set_by_pointer(node->st_allocation_metadata, node->rd_allocation_metadata_reserved, node->allocation_global_rsv_size); - rrdset_done(node->st_allocation_metadata); - } - - // -------------------------------------------------------------------- - // allocation/system - - if(do_allocation_system == CONFIG_BOOLEAN_YES || (do_allocation_system == CONFIG_BOOLEAN_AUTO && node->allocation_system_total_bytes)) { - do_allocation_system = CONFIG_BOOLEAN_YES; - - if(unlikely(!node->st_allocation_system)) { - char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1]; - - snprintf(id, RRD_ID_LENGTH_MAX, "system_%s", node->id); - snprintf(name, RRD_ID_LENGTH_MAX, "system_%s", node->label); - snprintf(title, 200, "BTRFS System Allocation for %s", node->label); - - netdata_fix_chart_id(id); - netdata_fix_chart_name(name); - - node->st_allocation_system = rrdset_create_localhost( - "btrfs" - , id - , name - , node->label - , "btrfs.system" - , title - , "MB" - , "proc" - , "sys/fs/btrfs" - , 2303 - , update_every - , RRDSET_TYPE_STACKED - ); - - node->rd_allocation_system_free = rrddim_add(node->st_allocation_system, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - node->rd_allocation_system_used = rrddim_add(node->st_allocation_system, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else rrdset_next(node->st_allocation_system); - - rrddim_set_by_pointer(node->st_allocation_system, node->rd_allocation_system_free, node->allocation_system_total_bytes - node->allocation_system_bytes_used); - rrddim_set_by_pointer(node->st_allocation_system, node->rd_allocation_system_used, node->allocation_system_bytes_used); - rrdset_done(node->st_allocation_system); - } - } - - return 0; -} - diff --git a/src/sys_fs_cgroup.c b/src/sys_fs_cgroup.c deleted file mode 100644 index f6e613c4b..000000000 --- a/src/sys_fs_cgroup.c +++ /dev/null @@ -1,2765 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// cgroup globals - -#define CHART_PRIORITY_SYSTEMD_SERVICES 19000 -#define CHART_PRIORITY_CONTAINERS 40000 - -static long system_page_size = 4096; // system will be queried via sysconf() in configuration() - -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; - -static int cgroup_enable_new_cgroups_detected_at_runtime = 1; -static int cgroup_check_for_new_every = 10; -static int cgroup_update_every = 1; - -static int cgroup_recheck_zero_blkio_every_iterations = 10; -static int cgroup_recheck_zero_mem_failcnt_every_iterations = 10; -static int cgroup_recheck_zero_mem_detailed_every_iterations = 10; - -static char *cgroup_cpuacct_base = NULL; -static char *cgroup_blkio_base = NULL; -static char *cgroup_memory_base = NULL; -static char *cgroup_devices_base = NULL; - -static int cgroup_root_count = 0; -static int cgroup_root_max = 1000; -static int cgroup_max_depth = 0; - -static SIMPLE_PATTERN *enabled_cgroup_patterns = NULL; -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 = NULL; -static char *cgroups_network_interface_script = NULL; - -static int cgroups_check = 0; - -static uint32_t Read_hash = 0; -static uint32_t Write_hash = 0; -static uint32_t user_hash = 0; -static uint32_t system_hash = 0; - -void read_cgroup_plugin_configuration() { - system_page_size = sysconf(_SC_PAGESIZE); - - Read_hash = simple_hash("Read"); - Write_hash = simple_hash("Write"); - user_hash = simple_hash("user"); - system_hash = simple_hash("system"); - - 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) - cgroup_check_for_new_every = cgroup_update_every; - - cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat (total CPU)", cgroup_enable_cpuacct_stat); - cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage (per core CPU)", cgroup_enable_cpuacct_usage); - - cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory (used mem including cache)", cgroup_enable_memory); - cgroup_enable_detailed_memory = config_get_boolean_ondemand("plugin:cgroups", "enable detailed memory", cgroup_enable_detailed_memory); - cgroup_enable_memory_failcnt = config_get_boolean_ondemand("plugin:cgroups", "enable memory limits fail count", cgroup_enable_memory_failcnt); - cgroup_enable_swap = config_get_boolean_ondemand("plugin:cgroups", "enable swap memory", cgroup_enable_swap); - - cgroup_enable_blkio_io = config_get_boolean_ondemand("plugin:cgroups", "enable blkio bandwidth", cgroup_enable_blkio_io); - cgroup_enable_blkio_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio operations", cgroup_enable_blkio_ops); - cgroup_enable_blkio_throttle_io = config_get_boolean_ondemand("plugin:cgroups", "enable blkio throttle bandwidth", cgroup_enable_blkio_throttle_io); - cgroup_enable_blkio_throttle_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio throttle operations", cgroup_enable_blkio_throttle_ops); - cgroup_enable_blkio_queued_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio queued operations", cgroup_enable_blkio_queued_ops); - cgroup_enable_blkio_merged_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio merged operations", cgroup_enable_blkio_merged_ops); - - cgroup_recheck_zero_blkio_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero blkio every iterations", cgroup_recheck_zero_blkio_every_iterations); - cgroup_recheck_zero_mem_failcnt_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero memory failcnt every iterations", cgroup_recheck_zero_mem_failcnt_every_iterations); - cgroup_recheck_zero_mem_detailed_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero detailed memory every iterations", cgroup_recheck_zero_mem_detailed_every_iterations); - - cgroup_enable_systemd_services = config_get_boolean("plugin:cgroups", "enable systemd services", cgroup_enable_systemd_services); - cgroup_enable_systemd_services_detailed_memory = config_get_boolean("plugin:cgroups", "enable systemd services detailed memory", cgroup_enable_systemd_services_detailed_memory); - cgroup_used_memory_without_cache = config_get_boolean("plugin:cgroups", "report used memory without cache", cgroup_used_memory_without_cache); - - char filename[FILENAME_MAX + 1], *s; - struct mountinfo *mi, *root = mountinfo_read(0); - - mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct"); - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct"); - if(!mi) { - error("CGROUP: cannot find cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct"); - s = "/sys/fs/cgroup/cpuacct"; - } - else s = mi->mount_point; - 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"); - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio"); - if(!mi) { - error("CGROUP: cannot find blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio"); - s = "/sys/fs/cgroup/blkio"; - } - else s = mi->mount_point; - 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"); - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory"); - if(!mi) { - error("CGROUP: cannot find memory mountinfo. Assuming default: /sys/fs/cgroup/memory"); - s = "/sys/fs/cgroup/memory"; - } - else s = mi->mount_point; - 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"); - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices"); - if(!mi) { - error("CGROUP: cannot find devices mountinfo. Assuming default: /sys/fs/cgroup/devices"); - s = "/sys/fs/cgroup/devices"; - } - else s = mi->mount_point; - 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); - cgroup_max_depth = (int)config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth); - - cgroup_enable_new_cgroups_detected_at_runtime = config_get_boolean("plugin:cgroups", "enable new cgroups detected at run time", cgroup_enable_new_cgroups_detected_at_runtime); - - enabled_cgroup_patterns = simple_pattern_create( - config_get("plugin:cgroups", "enable by default cgroups matching", - // ---------------------------------------------------------------- - - " !*/init.scope " // ignore init.scope - " !/system.slice/run-*.scope " // ignore system.slice/run-XXXX.scope - " *.scope " // we need all other *.scope for sure - - // ---------------------------------------------------------------- - - " /machine.slice/*.service " // #3367 systemd-nspawn - - // ---------------------------------------------------------------- - - " !*/vcpu* " // libvirtd adds these sub-cgroups - " !*/emulator " // libvirtd adds these sub-cgroups - " !*.mount " - " !*.partition " - " !*.service " - " !*.socket " - " !*.slice " - " !*.swap " - " !*.user " - " !/ " - " !/docker " - " !/libvirt " - " !/lxc " - " !/lxc/*/* " // #1397 #2649 - " !/machine " - " !/qemu " - " !/system " - " !/systemd " - " !/user " - " * " // enable anything else - ), NULL, SIMPLE_PATTERN_EXACT); - - enabled_cgroup_paths = simple_pattern_create( - config_get("plugin:cgroups", "search for cgroups in subpaths matching", - " !*/init.scope " // ignore init.scope - " !*-qemu " // #345 - " !*.libvirt-qemu " // #3010 - " !/init.scope " - " !/system " - " !/systemd " - " !/user " - " !/user.slice " - " !/lxc/*/* " // #2161 #2649 - " * " - ), NULL, SIMPLE_PATTERN_EXACT); - - snprintfz(filename, FILENAME_MAX, "%s/cgroup-name.sh", netdata_configured_plugins_dir); - cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", filename); - - snprintfz(filename, FILENAME_MAX, "%s/cgroup-network", netdata_configured_plugins_dir); - cgroups_network_interface_script = config_get("plugin:cgroups", "script to get cgroup network interfaces", filename); - - enabled_cgroup_renames = simple_pattern_create( - config_get("plugin:cgroups", "run script to rename cgroups matching", - " !/ " - " !*.mount " - " !*.socket " - " !*.partition " - " /machine.slice/*.service " // #3367 systemd-nspawn - " !*.service " - " !*.slice " - " !*.swap " - " !*.user " - " !init.scope " - " !*.scope/vcpu* " // libvirtd adds these sub-cgroups - " !*.scope/emulator " // libvirtd adds these sub-cgroups - " *.scope " - " *docker* " - " *lxc* " - " *qemu* " - " *kubepods* " // #3396 kubernetes - " *.libvirt-qemu " // #3010 - " * " - ), NULL, SIMPLE_PATTERN_EXACT); - - if(cgroup_enable_systemd_services) { - systemd_services_cgroups = simple_pattern_create( - config_get("plugin:cgroups", "cgroups to match as systemd services", - " !/system.slice/*/*.service " - " /system.slice/*.service " - ), NULL, SIMPLE_PATTERN_EXACT); - } - - mountinfo_free_all(root); -} - -// ---------------------------------------------------------------------------- -// cgroup objects - -struct blkio { - int updated; - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO - int delay_counter; - - char *filename; - - unsigned long long Read; - unsigned long long Write; -/* - unsigned long long Sync; - unsigned long long Async; - unsigned long long Total; -*/ -}; - -// https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt -struct memory { - ARL_BASE *arl_base; - ARL_ENTRY *arl_dirty; - ARL_ENTRY *arl_swap; - - int updated_detailed; - int updated_usage_in_bytes; - int updated_msw_usage_in_bytes; - int updated_failcnt; - - 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; - - char *filename_detailed; - char *filename_usage_in_bytes; - char *filename_msw_usage_in_bytes; - char *filename_failcnt; - - int detailed_has_dirty; - int detailed_has_swap; - - // detailed metrics - unsigned long long cache; - unsigned long long rss; - unsigned long long rss_huge; - unsigned long long mapped_file; - unsigned long long writeback; - unsigned long long dirty; - unsigned long long swap; - unsigned long long pgpgin; - unsigned long long pgpgout; - unsigned long long pgfault; - unsigned long long pgmajfault; -/* - unsigned long long inactive_anon; - unsigned long long active_anon; - unsigned long long inactive_file; - unsigned long long active_file; - unsigned long long unevictable; - unsigned long long hierarchical_memory_limit; - unsigned long long total_cache; - unsigned long long total_rss; - unsigned long long total_rss_huge; - unsigned long long total_mapped_file; - unsigned long long total_writeback; - unsigned long long total_dirty; - unsigned long long total_swap; - unsigned long long total_pgpgin; - unsigned long long total_pgpgout; - unsigned long long total_pgfault; - unsigned long long total_pgmajfault; - unsigned long long total_inactive_anon; - unsigned long long total_active_anon; - unsigned long long total_inactive_file; - unsigned long long total_active_file; - unsigned long long total_unevictable; -*/ - - // single file metrics - unsigned long long usage_in_bytes; - unsigned long long msw_usage_in_bytes; - unsigned long long failcnt; -}; - -// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt -struct cpuacct_stat { - int updated; - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO - - char *filename; - - unsigned long long user; - unsigned long long system; -}; - -// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt -struct cpuacct_usage { - int updated; - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO - - char *filename; - - unsigned int cpus; - unsigned long long *cpu_percpu; -}; - -struct cgroup_network_interface { - const char *host_device; - const char *container_device; - struct cgroup_network_interface *next; -}; - -#define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001 -#define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002 - -struct cgroup { - uint32_t options; - - char available; // found in the filesystem - char enabled; // enabled in the config - - char *id; - uint32_t hash; - - char *chart_id; - uint32_t hash_chart; - - char *chart_title; - - struct cpuacct_stat cpuacct_stat; - struct cpuacct_usage cpuacct_usage; - - struct memory memory; - - struct blkio io_service_bytes; // bytes - struct blkio io_serviced; // operations - - struct blkio throttle_io_service_bytes; // bytes - struct blkio throttle_io_serviced; // operations - - struct blkio io_merged; // operations - struct blkio io_queued; // operations - - struct cgroup_network_interface *interfaces; - - // per cgroup charts - RRDSET *st_cpu; - RRDSET *st_cpu_per_core; - RRDSET *st_mem; - RRDSET *st_writeback; - RRDSET *st_mem_activity; - RRDSET *st_pgfaults; - RRDSET *st_mem_usage; - RRDSET *st_mem_failcnt; - RRDSET *st_io; - RRDSET *st_serviced_ops; - RRDSET *st_throttle_io; - RRDSET *st_throttle_serviced_ops; - RRDSET *st_queued_ops; - RRDSET *st_merged_ops; - - // services - RRDDIM *rd_cpu; - RRDDIM *rd_mem_usage; - RRDDIM *rd_mem_failcnt; - RRDDIM *rd_swap_usage; - - RRDDIM *rd_mem_detailed_cache; - RRDDIM *rd_mem_detailed_rss; - RRDDIM *rd_mem_detailed_mapped; - RRDDIM *rd_mem_detailed_writeback; - RRDDIM *rd_mem_detailed_pgpgin; - RRDDIM *rd_mem_detailed_pgpgout; - RRDDIM *rd_mem_detailed_pgfault; - RRDDIM *rd_mem_detailed_pgmajfault; - - RRDDIM *rd_io_service_bytes_read; - RRDDIM *rd_io_serviced_read; - RRDDIM *rd_throttle_io_read; - RRDDIM *rd_throttle_io_serviced_read; - RRDDIM *rd_io_queued_read; - RRDDIM *rd_io_merged_read; - - RRDDIM *rd_io_service_bytes_write; - RRDDIM *rd_io_serviced_write; - RRDDIM *rd_throttle_io_write; - RRDDIM *rd_throttle_io_serviced_write; - RRDDIM *rd_io_queued_write; - RRDDIM *rd_io_merged_write; - - struct cgroup *next; - -} *cgroup_root = NULL; - -// ---------------------------------------------------------------------------- -// read values from /sys - -static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) { - static procfile *ff = NULL; - - if(likely(cp->filename)) { - 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; - } - - unsigned long i, lines = procfile_lines(ff); - - if(unlikely(lines < 1)) { - error("CGROUP: file '%s' should have 1+ lines.", cp->filename); - cp->updated = 0; - return; - } - - for(i = 0; i < lines ; i++) { - char *s = procfile_lineword(ff, i, 0); - uint32_t hash = simple_hash(s); - - if(unlikely(hash == user_hash && !strcmp(s, "user"))) - cp->user = str2ull(procfile_lineword(ff, i, 1)); - - else if(unlikely(hash == system_hash && !strcmp(s, "system"))) - cp->system = str2ull(procfile_lineword(ff, i, 1)); - } - - cp->updated = 1; - - if(unlikely(cp->enabled == CONFIG_BOOLEAN_AUTO && (cp->user || cp->system))) - cp->enabled = CONFIG_BOOLEAN_YES; - } -} - -static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) { - static procfile *ff = NULL; - - if(likely(ca->filename)) { - 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; - } - - if(unlikely(procfile_lines(ff) < 1)) { - error("CGROUP: file '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff)); - ca->updated = 0; - return; - } - - unsigned long i = procfile_linewords(ff, 0); - if(unlikely(i == 0)) { - ca->updated = 0; - return; - } - - // we may have 1 more CPU reported - while(i > 0) { - char *s = procfile_lineword(ff, 0, i - 1); - if(!*s) i--; - else break; - } - - if(unlikely(i != ca->cpus)) { - freez(ca->cpu_percpu); - ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i); - ca->cpus = (unsigned int)i; - } - - unsigned long long total = 0; - for(i = 0; i < ca->cpus ;i++) { - unsigned long long n = str2ull(procfile_lineword(ff, 0, i)); - ca->cpu_percpu[i] = n; - total += n; - } - - ca->updated = 1; - - if(unlikely(ca->enabled == CONFIG_BOOLEAN_AUTO && total)) - ca->enabled = CONFIG_BOOLEAN_YES; - } -} - -static inline void cgroup_read_blkio(struct blkio *io) { - if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO && io->delay_counter > 0)) { - io->delay_counter--; - return; - } - - if(likely(io->filename)) { - static procfile *ff = NULL; - - 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; - } - - unsigned long i, lines = procfile_lines(ff); - - if(unlikely(lines < 1)) { - error("CGROUP: file '%s' should have 1+ lines.", io->filename); - io->updated = 0; - return; - } - - io->Read = 0; - io->Write = 0; -/* - io->Sync = 0; - io->Async = 0; - io->Total = 0; -*/ - - for(i = 0; i < lines ; i++) { - char *s = procfile_lineword(ff, i, 1); - uint32_t hash = simple_hash(s); - - if(unlikely(hash == Read_hash && !strcmp(s, "Read"))) - io->Read += str2ull(procfile_lineword(ff, i, 2)); - - else if(unlikely(hash == Write_hash && !strcmp(s, "Write"))) - io->Write += str2ull(procfile_lineword(ff, i, 2)); - -/* - else if(unlikely(hash == Sync_hash && !strcmp(s, "Sync"))) - io->Sync += str2ull(procfile_lineword(ff, i, 2)); - - else if(unlikely(hash == Async_hash && !strcmp(s, "Async"))) - io->Async += str2ull(procfile_lineword(ff, i, 2)); - - else if(unlikely(hash == Total_hash && !strcmp(s, "Total"))) - io->Total += str2ull(procfile_lineword(ff, i, 2)); -*/ - } - - io->updated = 1; - - if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO)) { - if(unlikely(io->Read || io->Write)) - io->enabled = CONFIG_BOOLEAN_YES; - else - io->delay_counter = cgroup_recheck_zero_blkio_every_iterations; - } - } -} - -static inline void cgroup_read_memory(struct memory *mem) { - static procfile *ff = NULL; - - // read detailed ram usage - if(likely(mem->filename_detailed)) { - if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO && mem->delay_counter_detailed > 0)) { - mem->delay_counter_detailed--; - goto memory_next; - } - - 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; - } - - unsigned long i, lines = procfile_lines(ff); - - if(unlikely(lines < 1)) { - error("CGROUP: file '%s' should have 1+ lines.", mem->filename_detailed); - mem->updated_detailed = 0; - goto memory_next; - } - - if(unlikely(!mem->arl_base)) { - mem->arl_base = arl_create("cgroup/memory", NULL, 60); - - arl_expect(mem->arl_base, "cache", &mem->cache); - arl_expect(mem->arl_base, "rss", &mem->rss); - arl_expect(mem->arl_base, "rss_huge", &mem->rss_huge); - arl_expect(mem->arl_base, "mapped_file", &mem->mapped_file); - arl_expect(mem->arl_base, "writeback", &mem->writeback); - mem->arl_dirty = arl_expect(mem->arl_base, "dirty", &mem->dirty); - mem->arl_swap = arl_expect(mem->arl_base, "swap", &mem->swap); - arl_expect(mem->arl_base, "pgpgin", &mem->pgpgin); - arl_expect(mem->arl_base, "pgpgout", &mem->pgpgout); - arl_expect(mem->arl_base, "pgfault", &mem->pgfault); - arl_expect(mem->arl_base, "pgmajfault", &mem->pgmajfault); - } - - arl_begin(mem->arl_base); - - for(i = 0; i < lines ; i++) { - if(arl_check(mem->arl_base, - procfile_lineword(ff, i, 0), - procfile_lineword(ff, i, 1))) break; - } - - if(unlikely(mem->arl_dirty->flags & ARL_ENTRY_FLAG_FOUND)) - mem->detailed_has_dirty = 1; - - if(unlikely(mem->arl_swap->flags & ARL_ENTRY_FLAG_FOUND)) - mem->detailed_has_swap = 1; - - // fprintf(stderr, "READ: '%s', cache: %llu, rss: %llu, rss_huge: %llu, mapped_file: %llu, writeback: %llu, dirty: %llu, swap: %llu, pgpgin: %llu, pgpgout: %llu, pgfault: %llu, pgmajfault: %llu, inactive_anon: %llu, active_anon: %llu, inactive_file: %llu, active_file: %llu, unevictable: %llu, hierarchical_memory_limit: %llu, total_cache: %llu, total_rss: %llu, total_rss_huge: %llu, total_mapped_file: %llu, total_writeback: %llu, total_dirty: %llu, total_swap: %llu, total_pgpgin: %llu, total_pgpgout: %llu, total_pgfault: %llu, total_pgmajfault: %llu, total_inactive_anon: %llu, total_active_anon: %llu, total_inactive_file: %llu, total_active_file: %llu, total_unevictable: %llu\n", mem->filename, mem->cache, mem->rss, mem->rss_huge, mem->mapped_file, mem->writeback, mem->dirty, mem->swap, mem->pgpgin, mem->pgpgout, mem->pgfault, mem->pgmajfault, mem->inactive_anon, mem->active_anon, mem->inactive_file, mem->active_file, mem->unevictable, mem->hierarchical_memory_limit, mem->total_cache, mem->total_rss, mem->total_rss_huge, mem->total_mapped_file, mem->total_writeback, mem->total_dirty, mem->total_swap, mem->total_pgpgin, mem->total_pgpgout, mem->total_pgfault, mem->total_pgmajfault, mem->total_inactive_anon, mem->total_active_anon, mem->total_inactive_file, mem->total_active_file, mem->total_unevictable); - - mem->updated_detailed = 1; - - 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_BOOLEAN_YES; - else - mem->delay_counter_detailed = cgroup_recheck_zero_mem_detailed_every_iterations; - } - } - -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_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_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_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_BOOLEAN_AUTO)) { - if(unlikely(!mem->failcnt)) - mem->delay_counter_failcnt = cgroup_recheck_zero_mem_failcnt_every_iterations; - else - mem->enabled_failcnt = CONFIG_BOOLEAN_YES; - } - } - } -} - -static inline void cgroup_read(struct cgroup *cg) { - debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id); - - cgroup_read_cpuacct_stat(&cg->cpuacct_stat); - cgroup_read_cpuacct_usage(&cg->cpuacct_usage); - cgroup_read_memory(&cg->memory); - cgroup_read_blkio(&cg->io_service_bytes); - cgroup_read_blkio(&cg->io_serviced); - cgroup_read_blkio(&cg->throttle_io_service_bytes); - cgroup_read_blkio(&cg->throttle_io_serviced); - cgroup_read_blkio(&cg->io_merged); - cgroup_read_blkio(&cg->io_queued); -} - -static inline void read_all_cgroups(struct cgroup *root) { - debug(D_CGROUP, "reading metrics for all cgroups"); - - struct cgroup *cg; - - for(cg = root; cg ; cg = cg->next) - if(cg->enabled && cg->available) - cgroup_read(cg); -} - -// ---------------------------------------------------------------------------- -// cgroup network interfaces - -#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048 -static inline void read_cgroup_network_interfaces(struct cgroup *cg) { - debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title); - - pid_t cgroup_pid; - char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; - - snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id); - - debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id); - FILE *fp = mypopen(buffer, &cgroup_pid); - if(fp) { - char *s; - while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) { - trim(s); - - if(*s && *s != '\n') { - char *t = s; - while(*t && *t != ' ') t++; - if(*t == ' ') { - *t = '\0'; - t++; - } - - if(!*s) { - error("CGROUP: empty host interface returned by script"); - continue; - } - - if(!*t) { - error("CGROUP: empty guest interface returned by script"); - continue; - } - - struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface)); - i->host_device = strdupz(s); - i->container_device = strdupz(t); - i->next = cg->interfaces; - cg->interfaces = i; - - info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device); - - // register a device rename to proc_net_dev.c - netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id); - } - } - - mypclose(fp, cgroup_pid); - // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id); - } - else - error("CGROUP: cannot popen(\"%s\", \"r\").", buffer); -} - -static inline void free_cgroup_network_interfaces(struct cgroup *cg) { - while(cg->interfaces) { - struct cgroup_network_interface *i = cg->interfaces; - cg->interfaces = i->next; - - // delete the registration of proc_net_dev rename - netdev_rename_device_del(i->host_device); - - freez((void *)i->host_device); - freez((void *)i->container_device); - freez((void *)i); - } -} - -// ---------------------------------------------------------------------------- -// add/remove/find cgroup objects - -#define CGROUP_CHARTID_LINE_MAX 1024 - -static inline char *cgroup_title_strdupz(const char *s) { - if(!s || !*s) s = "/"; - - if(*s == '/' && s[1] != '\0') s++; - - char *r = strdupz(s); - netdata_fix_chart_name(r); - - return r; -} - -static inline char *cgroup_chart_id_strdupz(const char *s) { - if(!s || !*s) s = "/"; - - if(*s == '/' && s[1] != '\0') s++; - - char *r = strdupz(s); - netdata_fix_chart_id(r); - - return r; -} - -static inline void cgroup_get_chart_name(struct cgroup *cg) { - debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title); - - pid_t cgroup_pid; - char buffer[CGROUP_CHARTID_LINE_MAX + 1]; - - snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s' '%s'", cgroups_rename_script, cg->chart_id, cg->id); - - debug(D_CGROUP, "executing command \"%s\" for cgroup '%s'", buffer, cg->id); - FILE *fp = mypopen(buffer, &cgroup_pid); - if(fp) { - // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id); - char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp); - // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id); - mypclose(fp, cgroup_pid); - // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id); - - if(s && *s && *s != '\n') { - debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s); - - trim(s); - - freez(cg->chart_title); - cg->chart_title = cgroup_title_strdupz(s); - - freez(cg->chart_id); - cg->chart_id = cgroup_chart_id_strdupz(s); - cg->hash_chart = simple_hash(cg->chart_id); - } - } - else - error("CGROUP: cannot popen(\"%s\", \"r\").", buffer); -} - -static inline struct cgroup *cgroup_add(const char *id) { - if(!id || !*id) id = "/"; - debug(D_CGROUP, "adding to list, cgroup with id '%s'", id); - - if(cgroup_root_count >= cgroup_root_max) { - info("CGROUP: maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id); - return NULL; - } - - int def = simple_pattern_matches(enabled_cgroup_patterns, id)?cgroup_enable_new_cgroups_detected_at_runtime:0; - struct cgroup *cg = callocz(1, sizeof(struct cgroup)); - - cg->id = strdupz(id); - cg->hash = simple_hash(cg->id); - - cg->chart_title = cgroup_title_strdupz(id); - - cg->chart_id = cgroup_chart_id_strdupz(id); - cg->hash_chart = simple_hash(cg->chart_id); - - if(!cgroup_root) - cgroup_root = cg; - else { - // append it - struct cgroup *e; - for(e = cgroup_root; e->next ;e = e->next) ; - e->next = cg; - } - - cgroup_root_count++; - - // fix the chart_id and title by calling the external script - if(simple_pattern_matches(enabled_cgroup_renames, cg->id)) { - - cgroup_get_chart_name(cg); - - debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title); - } - else - debug(D_CGROUP, "cgroup '%s' will not be renamed - it matches the list of disabled cgroup renames (will be shown as '%s')", cg->id, cg->chart_id); - - int user_configurable = 1; - - // check if this cgroup should be a systemd service - if(cgroup_enable_systemd_services) { - if(simple_pattern_matches(systemd_services_cgroups, cg->id) || - simple_pattern_matches(systemd_services_cgroups, cg->chart_id)) { - debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') matches systemd services cgroups", cg->id, cg->chart_id, cg->chart_title); - - char buffer[CGROUP_CHARTID_LINE_MAX + 1]; - cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE; - - strncpy(buffer, cg->id, CGROUP_CHARTID_LINE_MAX); - char *s = buffer; - - //freez(cg->chart_id); - //cg->chart_id = cgroup_chart_id_strdupz(s); - //cg->hash_chart = simple_hash(cg->chart_id); - - // skip to the last slash - size_t len = strlen(s); - while(len--) if(unlikely(s[len] == '/')) break; - if(len) s = &s[len + 1]; - - // remove extension - len = strlen(s); - while(len--) if(unlikely(s[len] == '.')) break; - if(len) s[len] = '\0'; - - freez(cg->chart_title); - cg->chart_title = cgroup_title_strdupz(s); - - cg->enabled = 1; - user_configurable = 0; - - debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title); - } - else - debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') does not match systemd services groups", cg->id, cg->chart_id, cg->chart_title); - } - - if(user_configurable) { - // allow the user to enable/disable this individualy - char option[FILENAME_MAX + 1]; - snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title); - cg->enabled = (char) config_get_boolean("plugin:cgroups", option, def); - } - - // detect duplicate cgroups - if(cg->enabled) { - struct cgroup *t; - for (t = cgroup_root; t; t = t->next) { - if (t != cg && t->enabled && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) { - if (!strncmp(t->chart_id, "/system.slice/", 14) && !strncmp(cg->chart_id, "/init.scope/system.slice/", 25)) { - error("CGROUP: chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.", - cg->chart_id, t->id, cg->id, t->id); - debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.", - cg->chart_id, t->id, cg->id, t->id); - t->enabled = 0; - t->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE; - } - else { - error("CGROUP: chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.", - cg->chart_id, t->id, cg->id); - debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.", - cg->chart_id, t->id, cg->id); - cg->enabled = 0; - cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE; - } - - break; - } - } - } - - if(cg->enabled && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) - read_cgroup_network_interfaces(cg); - - debug(D_CGROUP, "ADDED CGROUP: '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled"); - - return cg; -} - -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_is_obsolete(cg->st_cpu); - if(cg->st_cpu_per_core) rrdset_is_obsolete(cg->st_cpu_per_core); - if(cg->st_mem) rrdset_is_obsolete(cg->st_mem); - if(cg->st_writeback) rrdset_is_obsolete(cg->st_writeback); - if(cg->st_mem_activity) rrdset_is_obsolete(cg->st_mem_activity); - if(cg->st_pgfaults) rrdset_is_obsolete(cg->st_pgfaults); - if(cg->st_mem_usage) rrdset_is_obsolete(cg->st_mem_usage); - if(cg->st_mem_failcnt) rrdset_is_obsolete(cg->st_mem_failcnt); - if(cg->st_io) rrdset_is_obsolete(cg->st_io); - if(cg->st_serviced_ops) rrdset_is_obsolete(cg->st_serviced_ops); - if(cg->st_throttle_io) rrdset_is_obsolete(cg->st_throttle_io); - if(cg->st_throttle_serviced_ops) rrdset_is_obsolete(cg->st_throttle_serviced_ops); - if(cg->st_queued_ops) rrdset_is_obsolete(cg->st_queued_ops); - if(cg->st_merged_ops) rrdset_is_obsolete(cg->st_merged_ops); - - free_cgroup_network_interfaces(cg); - - freez(cg->cpuacct_usage.cpu_percpu); - - freez(cg->cpuacct_stat.filename); - freez(cg->cpuacct_usage.filename); - - arl_free(cg->memory.arl_base); - freez(cg->memory.filename_detailed); - freez(cg->memory.filename_failcnt); - freez(cg->memory.filename_usage_in_bytes); - freez(cg->memory.filename_msw_usage_in_bytes); - - freez(cg->io_service_bytes.filename); - freez(cg->io_serviced.filename); - - freez(cg->throttle_io_service_bytes.filename); - freez(cg->throttle_io_serviced.filename); - - freez(cg->io_merged.filename); - freez(cg->io_queued.filename); - - freez(cg->id); - freez(cg->chart_id); - freez(cg->chart_title); - - freez(cg); - - cgroup_root_count--; -} - -// find if a given cgroup exists -static inline struct cgroup *cgroup_find(const char *id) { - debug(D_CGROUP, "searching for cgroup '%s'", id); - - uint32_t hash = simple_hash(id); - - struct cgroup *cg; - for(cg = cgroup_root; cg ; cg = cg->next) { - if(hash == cg->hash && strcmp(id, cg->id) == 0) - break; - } - - debug(D_CGROUP, "cgroup '%s' %s in memory", id, (cg)?"found":"not found"); - return cg; -} - -// ---------------------------------------------------------------------------- -// detect running cgroups - -// callback for find_file_in_subdirs() -static inline void found_subdir_in_dir(const char *dir) { - debug(D_CGROUP, "examining cgroup dir '%s'", dir); - - struct cgroup *cg = cgroup_find(dir); - if(!cg) { - if(*dir && cgroup_max_depth > 0) { - int depth = 0; - const char *s; - - for(s = dir; *s ;s++) - if(unlikely(*s == '/')) - depth++; - - if(depth > cgroup_max_depth) { - info("CGROUP: '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth); - return; - } - } - // debug(D_CGROUP, "will add dir '%s' as cgroup", dir); - cg = cgroup_add(dir); - } - - if(cg) cg->available = 1; -} - -static inline int find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) { - if(!this) this = base; - debug(D_CGROUP, "searching for directories in '%s' (base '%s')", this?this:"", base); - - size_t dirlen = strlen(this), baselen = strlen(base); - - int ret = -1; - int enabled = -1; - - const char *relative_path = &this[baselen]; - if(!*relative_path) relative_path = "/"; - - DIR *dir = opendir(this); - if(!dir) { - error("CGROUP: cannot read directory '%s'", base); - return ret; - } - ret = 1; - - callback(relative_path); - - struct dirent *de = NULL; - while((de = readdir(dir))) { - 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') - )) - continue; - - if(de->d_type == DT_DIR) { - if(enabled == -1) { - const char *r = relative_path; - if(*r == '\0') r = "/"; - - // do not decent in directories we are not interested - int def = simple_pattern_matches(enabled_cgroup_paths, r); - - // we check for this option here - // so that the config will not have settings - // for leaf directories - char option[FILENAME_MAX + 1]; - snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r); - option[FILENAME_MAX] = '\0'; - enabled = config_get_boolean("plugin:cgroups", option, def); - } - - if(enabled) { - char *s = mallocz(dirlen + strlen(de->d_name) + 2); - strcpy(s, this); - strcat(s, "/"); - strcat(s, de->d_name); - int ret2 = find_dir_in_subdirs(base, s, callback); - if(ret2 > 0) ret += ret2; - freez(s); - } - } - } - - closedir(dir); - return ret; -} - -static inline void mark_all_cgroups_as_not_available() { - debug(D_CGROUP, "marking all cgroups as not available"); - - struct cgroup *cg; - - // mark all as not available - for(cg = cgroup_root; cg ; cg = cg->next) { - cg->available = 0; - } -} - -static inline void cleanup_all_cgroups() { - struct cgroup *cg = cgroup_root, *last = NULL; - - for(; cg ;) { - if(!cg->available) { - // enable the first duplicate cgroup - { - struct cgroup *t; - for(t = cgroup_root; t ; t = t->next) { - if(t != cg && t->available && !t->enabled && t->options & CGROUP_OPTIONS_DISABLED_DUPLICATE && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) { - debug(D_CGROUP, "Enabling duplicate of cgroup '%s' with id '%s', because the original with id '%s' stopped.", t->chart_id, t->id, cg->id); - t->enabled = 1; - t->options &= ~CGROUP_OPTIONS_DISABLED_DUPLICATE; - break; - } - } - } - - if(!last) - cgroup_root = cg->next; - else - last->next = cg->next; - - cgroup_free(cg); - - if(!last) - cg = cgroup_root; - else - cg = last->next; - } - else { - last = cg; - cg = cg->next; - } - } -} - -static inline void find_all_cgroups() { - debug(D_CGROUP, "searching for cgroups"); - - mark_all_cgroups_as_not_available(); - - 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_BOOLEAN_NO; - error("CGROUP: disabled cpu statistics."); - } - } - - if(cgroup_enable_blkio_io || cgroup_enable_blkio_ops || cgroup_enable_blkio_throttle_io || cgroup_enable_blkio_throttle_ops || cgroup_enable_blkio_merged_ops || cgroup_enable_blkio_queued_ops) { - if(find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir) == -1) { - cgroup_enable_blkio_io = - cgroup_enable_blkio_ops = - cgroup_enable_blkio_throttle_io = - cgroup_enable_blkio_throttle_ops = - cgroup_enable_blkio_merged_ops = - cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_NO; - error("CGROUP: disabled blkio statistics."); - } - } - - if(cgroup_enable_memory || cgroup_enable_detailed_memory || cgroup_enable_swap || cgroup_enable_memory_failcnt) { - if(find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir) == -1) { - cgroup_enable_memory = - cgroup_enable_detailed_memory = - cgroup_enable_swap = - cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_NO; - error("CGROUP: disabled memory statistics."); - } - } - - if(cgroup_search_in_devices) { - if(find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir) == -1) { - cgroup_search_in_devices = 0; - error("CGROUP: disabled devices statistics."); - } - } - - // remove any non-existing cgroups - cleanup_all_cgroups(); - - struct cgroup *cg; - struct stat buf; - for(cg = cgroup_root; cg ; cg = cg->next) { - // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name); - - if(unlikely(!cg->available)) - continue; - - debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id); - - // check for newly added cgroups - // and update the filenames they read - char filename[FILENAME_MAX + 1]; - if(unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->cpuacct_stat.filename = strdupz(filename); - cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat; - debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename); - } - else - debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))) { - snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->cpuacct_usage.filename = strdupz(filename); - cg->cpuacct_usage.enabled = cgroup_enable_cpuacct_usage; - debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename); - } - else - debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely((cgroup_enable_detailed_memory || cgroup_used_memory_without_cache) && !cg->memory.filename_detailed && (cgroup_used_memory_without_cache || cgroup_enable_systemd_services_detailed_memory || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)))) { - 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_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 - debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) { - snprintfz(filename, FILENAME_MAX, "%s%s/memory.usage_in_bytes", cgroup_memory_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->memory.filename_usage_in_bytes = strdupz(filename); - cg->memory.enabled_usage_in_bytes = cgroup_enable_memory; - debug(D_CGROUP, "memory.usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_usage_in_bytes); - } - else - debug(D_CGROUP, "memory.usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) { - snprintfz(filename, FILENAME_MAX, "%s%s/memory.msw_usage_in_bytes", cgroup_memory_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->memory.filename_msw_usage_in_bytes = strdupz(filename); - cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap; - debug(D_CGROUP, "memory.msw_usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_msw_usage_in_bytes); - } - else - debug(D_CGROUP, "memory.msw_usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_memory_failcnt && !cg->memory.filename_failcnt)) { - snprintfz(filename, FILENAME_MAX, "%s%s/memory.failcnt", cgroup_memory_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->memory.filename_failcnt = strdupz(filename); - cg->memory.enabled_failcnt = cgroup_enable_memory_failcnt; - debug(D_CGROUP, "memory.failcnt filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_failcnt); - } - else - debug(D_CGROUP, "memory.failcnt file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->io_service_bytes.filename = strdupz(filename); - cg->io_service_bytes.enabled = cgroup_enable_blkio_io; - debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename); - } - else - debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->io_serviced.filename = strdupz(filename); - cg->io_serviced.enabled = cgroup_enable_blkio_ops; - debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename); - } - else - debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_blkio_throttle_io && !cg->throttle_io_service_bytes.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->throttle_io_service_bytes.filename = strdupz(filename); - cg->throttle_io_service_bytes.enabled = cgroup_enable_blkio_throttle_io; - debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename); - } - else - debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_blkio_throttle_ops && !cg->throttle_io_serviced.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->throttle_io_serviced.filename = strdupz(filename); - cg->throttle_io_serviced.enabled = cgroup_enable_blkio_throttle_ops; - debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename); - } - else - debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_blkio_merged_ops && !cg->io_merged.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->io_merged.filename = strdupz(filename); - cg->io_merged.enabled = cgroup_enable_blkio_merged_ops; - debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename); - } - else - debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - - if(unlikely(cgroup_enable_blkio_queued_ops && !cg->io_queued.filename)) { - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id); - if(likely(stat(filename, &buf) != -1)) { - cg->io_queued.filename = strdupz(filename); - cg->io_queued.enabled = cgroup_enable_blkio_queued_ops; - debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename); - } - else - debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename); - } - } - - debug(D_CGROUP, "done searching for cgroups"); -} - -// ---------------------------------------------------------------------------- -// generate charts - -#define CHART_TITLE_MAX 300 - -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, - *st_mem_usage = NULL, - *st_mem_failcnt = NULL, - *st_swap_usage = NULL, - - *st_mem_detailed_cache = NULL, - *st_mem_detailed_rss = NULL, - *st_mem_detailed_mapped = NULL, - *st_mem_detailed_writeback = NULL, - *st_mem_detailed_pgfault = NULL, - *st_mem_detailed_pgmajfault = NULL, - *st_mem_detailed_pgpgin = NULL, - *st_mem_detailed_pgpgout = NULL, - - *st_io_read = NULL, - *st_io_serviced_read = NULL, - *st_throttle_io_read = NULL, - *st_throttle_ops_read = NULL, - *st_queued_ops_read = NULL, - *st_merged_ops_read = NULL, - - *st_io_write = NULL, - *st_io_serviced_write = NULL, - *st_throttle_io_write = NULL, - *st_throttle_ops_write = NULL, - *st_queued_ops_write = NULL, - *st_merged_ops_write = NULL; - - // create the charts - - 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 - , "%" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_cpu); - } - - if(likely(do_mem_usage)) { - if(unlikely(!st_mem_usage)) { - - 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" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 10 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_mem_usage); - } - - if(likely(do_mem_detailed)) { - if(unlikely(!st_mem_detailed_rss)) { - - st_mem_detailed_rss = rrdset_create_localhost( - "services" - , "mem_rss" - , NULL - , "mem" - , "services.mem_rss" - , "Systemd Services RSS Memory" - , "MB" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_mapped" - , NULL - , "mem" - , "services.mem_mapped" - , "Systemd Services Mapped Memory" - , "MB" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_cache" - , NULL - , "mem" - , "services.mem_cache" - , "Systemd Services Cache Memory" - , "MB" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_writeback" - , NULL - , "mem" - , "services.mem_writeback" - , "Systemd Services Writeback Memory" - , "MB" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_pgfault" - , NULL - , "mem" - , "services.mem_pgfault" - , "Systemd Services Memory Minor Page Faults" - , "MB/s" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_pgmajfault" - , NULL - , "mem" - , "services.mem_pgmajfault" - , "Systemd Services Memory Major Page Faults" - , "MB/s" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_pgpgin" - , NULL - , "mem" - , "services.mem_pgpgin" - , "Systemd Services Memory Charging Activity" - , "MB/s" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "mem_pgpgout" - , NULL - , "mem" - , "services.mem_pgpgout" - , "Systemd Services Memory Uncharging Activity" - , "MB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 90 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_mem_detailed_pgpgout); - } - - if(likely(do_mem_failcnt)) { - if(unlikely(!st_mem_failcnt)) { - - st_mem_failcnt = rrdset_create_localhost( - "services" - , "mem_failcnt" - , NULL - , "mem" - , "services.mem_failcnt" - , "Systemd Services Memory Limit Failures" - , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 110 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_mem_failcnt); - } - - if(likely(do_swap_usage)) { - if(unlikely(!st_swap_usage)) { - - st_swap_usage = rrdset_create_localhost( - "services" - , "swap_usage" - , NULL - , "swap" - , "services.swap_usage" - , "Systemd Services Swap Memory Used" - , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 100 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_swap_usage); - } - - if(likely(do_io)) { - if(unlikely(!st_io_read)) { - - st_io_read = rrdset_create_localhost( - "services" - , "io_read" - , NULL - , "disk" - , "services.io_read" - , "Systemd Services Disk Read Bandwidth" - , "KB/s" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "io_write" - , NULL - , "disk" - , "services.io_write" - , "Systemd Services Disk Write Bandwidth" - , "KB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 130 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_io_write); - } - - if(likely(do_io_ops)) { - if(unlikely(!st_io_serviced_read)) { - - st_io_serviced_read = rrdset_create_localhost( - "services" - , "io_ops_read" - , NULL - , "disk" - , "services.io_ops_read" - , "Systemd Services Disk Read Operations" - , "operations/s" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "io_ops_write" - , NULL - , "disk" - , "services.io_ops_write" - , "Systemd Services Disk Write Operations" - , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 150 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_io_serviced_write); - } - - if(likely(do_throttle_io)) { - if(unlikely(!st_throttle_io_read)) { - - 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" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "throttle_io_write" - , NULL - , "disk" - , "services.throttle_io_write" - , "Systemd Services Throttle Disk Write Bandwidth" - , "KB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 170 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_throttle_io_write); - } - - if(likely(do_throttle_ops)) { - if(unlikely(!st_throttle_ops_read)) { - - 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" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "throttle_io_ops_write" - , NULL - , "disk" - , "services.throttle_io_ops_write" - , "Systemd Services Throttle Disk Write Operations" - , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 190 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_throttle_ops_write); - } - - if(likely(do_queued_ops)) { - if(unlikely(!st_queued_ops_read)) { - - 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" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "queued_io_ops_write" - , NULL - , "disk" - , "services.queued_io_ops_write" - , "Systemd Services Queued Disk Write Operations" - , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 210 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_queued_ops_write); - } - - if(likely(do_merged_ops)) { - if(unlikely(!st_merged_ops_read)) { - - 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" - , "cgroup" - , "systemd" - , 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_create_localhost( - "services" - , "merged_io_ops_write" - , NULL - , "disk" - , "services.merged_io_ops_write" - , "Systemd Services Merged Disk Write Operations" - , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 230 - , update_every - , RRDSET_TYPE_STACKED - ); - - } - else - rrdset_next(st_merged_ops_write); - } - - // update the values - struct cgroup *cg; - for(cg = cgroup_root; cg ; cg = cg->next) { - if(unlikely(!cg->available || !cg->enabled || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))) - continue; - - 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, RRD_ALGORITHM_INCREMENTAL); - - rrddim_set_by_pointer(st_merged_ops_write, cg->rd_io_merged_write, cg->io_merged.Write); - } - } - - // complete the iteration - if(likely(do_cpu)) - rrdset_done(st_cpu); - - if(likely(do_mem_usage)) - rrdset_done(st_mem_usage); - - if(unlikely(do_mem_detailed)) { - rrdset_done(st_mem_detailed_cache); - rrdset_done(st_mem_detailed_rss); - rrdset_done(st_mem_detailed_mapped); - rrdset_done(st_mem_detailed_writeback); - rrdset_done(st_mem_detailed_pgfault); - rrdset_done(st_mem_detailed_pgmajfault); - rrdset_done(st_mem_detailed_pgpgin); - rrdset_done(st_mem_detailed_pgpgout); - } - - if(likely(do_mem_failcnt)) - rrdset_done(st_mem_failcnt); - - if(likely(do_swap_usage)) - rrdset_done(st_swap_usage); - - if(likely(do_io)) { - rrdset_done(st_io_read); - rrdset_done(st_io_write); - } - - if(likely(do_io_ops)) { - rrdset_done(st_io_serviced_read); - rrdset_done(st_io_serviced_write); - } - - if(likely(do_throttle_io)) { - rrdset_done(st_throttle_io_read); - rrdset_done(st_throttle_io_write); - } - - if(likely(do_throttle_ops)) { - rrdset_done(st_throttle_ops_read); - rrdset_done(st_throttle_ops_write); - } - - if(likely(do_queued_ops)) { - rrdset_done(st_queued_ops_read); - rrdset_done(st_queued_ops_write); - } - - if(likely(do_merged_ops)) { - rrdset_done(st_merged_ops_read); - rrdset_done(st_merged_ops_write); - } -} - -static inline char *cgroup_chart_type(char *buffer, const char *id, size_t len) { - if(buffer[0]) return buffer; - - if(id[0] == '\0' || (id[0] == '/' && id[1] == '\0')) - strncpy(buffer, "cgroup_root", len); - else - snprintfz(buffer, len, "cgroup_%s", id); - - netdata_fix_chart_id(buffer); - return buffer; -} - -void update_cgroup_charts(int update_every) { - debug(D_CGROUP, "updating cgroups charts"); - - char type[RRD_ID_LENGTH_MAX + 1]; - char title[CHART_TITLE_MAX + 1]; - - int services_do_cpu = 0, - services_do_mem_usage = 0, - services_do_mem_detailed = 0, - services_do_mem_failcnt = 0, - services_do_swap_usage = 0, - services_do_io = 0, - services_do_io_ops = 0, - services_do_throttle_io = 0, - services_do_throttle_ops = 0, - services_do_queued_ops = 0, - services_do_merged_ops = 0; - - struct cgroup *cg; - for(cg = cgroup_root; cg ; cg = cg->next) { - if(unlikely(!cg->available || !cg->enabled)) - continue; - - if(likely(cgroup_enable_systemd_services && cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) { - 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_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_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "cpu" - , NULL - , "cpu" - , "cgroup.cpu" - , title - , "%" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_cpu, "user", cg->cpuacct_stat.user); - rrddim_set(cg->st_cpu, "system", cg->cpuacct_stat.system); - rrdset_done(cg->st_cpu); - } - - 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)) { - 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 - , "%" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 100 - , update_every - , RRDSET_TYPE_STACKED - ); - - for(i = 0; i < cg->cpuacct_usage.cpus; i++) { - 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, 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_BOOLEAN_YES)) { - if(unlikely(!cg->st_mem)) { - 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" - , "cgroup" - , "default" - , 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); - - if(cg->memory.detailed_has_swap) - 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)) { - 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" - , "cgroup" - , "default" - , 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, 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)) { - 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" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_mem_activity, "pgpgin", cg->memory.pgpgin); - rrddim_set(cg->st_mem_activity, "pgpgout", cg->memory.pgpgout); - rrdset_done(cg->st_mem_activity); - - if(unlikely(!cg->st_pgfaults)) { - 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" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_pgfaults, "pgfault", cg->memory.pgfault); - rrddim_set(cg->st_pgfaults, "pgmajfault", cg->memory.pgmajfault); - rrdset_done(cg->st_pgfaults); - } - - if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "mem_usage" - , NULL - , "mem" - , "cgroup.mem_usage" - , title - , "MB" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_mem_usage, "ram", cg->memory.usage_in_bytes - ((cgroup_used_memory_without_cache)?cg->memory.cache:0)); - rrddim_set(cg->st_mem_usage, "swap", (cg->memory.msw_usage_in_bytes > cg->memory.usage_in_bytes)?cg->memory.msw_usage_in_bytes - cg->memory.usage_in_bytes:0); - rrdset_done(cg->st_mem_usage); - } - - if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES)) { - if(unlikely(!cg->st_mem_failcnt)) { - 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" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_mem_failcnt, "failures", cg->memory.failcnt); - rrdset_done(cg->st_mem_failcnt); - } - - if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) { - if(unlikely(!cg->st_io)) { - 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" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_io, "read", cg->io_service_bytes.Read); - rrddim_set(cg->st_io, "write", cg->io_service_bytes.Write); - rrdset_done(cg->st_io); - } - - if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "serviced_ops" - , NULL - , "disk" - , "cgroup.serviced_ops" - , title - , "operations/s" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_serviced_ops, "read", cg->io_serviced.Read); - rrddim_set(cg->st_serviced_ops, "write", cg->io_serviced.Write); - rrdset_done(cg->st_serviced_ops); - } - - if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "throttle_io" - , NULL - , "disk" - , "cgroup.throttle_io" - , title - , "KB/s" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_throttle_io, "read", cg->throttle_io_service_bytes.Read); - rrddim_set(cg->st_throttle_io, "write", cg->throttle_io_service_bytes.Write); - rrdset_done(cg->st_throttle_io); - } - - if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "throttle_serviced_ops" - , NULL - , "disk" - , "cgroup.throttle_serviced_ops" - , title - , "operations/s" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_throttle_serviced_ops, "read", cg->throttle_io_serviced.Read); - rrddim_set(cg->st_throttle_serviced_ops, "write", cg->throttle_io_serviced.Write); - rrdset_done(cg->st_throttle_serviced_ops); - } - - if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "queued_ops" - , NULL - , "disk" - , "cgroup.queued_ops" - , title - , "operations" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_queued_ops, "read", cg->io_queued.Read); - rrddim_set(cg->st_queued_ops, "write", cg->io_queued.Write); - rrdset_done(cg->st_queued_ops); - } - - if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES)) { - if(unlikely(!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_localhost( - cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX) - , "merged_ops" - , NULL - , "disk" - , "cgroup.merged_ops" - , title - , "operations/s" - , "cgroup" - , "default" - , 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); - - rrddim_set(cg->st_merged_ops, "read", cg->io_merged.Read); - rrddim_set(cg->st_merged_ops, "write", cg->io_merged.Write); - rrdset_done(cg->st_merged_ops); - } - } - - if(likely(cgroup_enable_systemd_services)) - 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"); -} - -// ---------------------------------------------------------------------------- -// cgroups main - -static void cgroup_main_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *cgroups_main(void *ptr) { - netdata_thread_cleanup_push(cgroup_main_cleanup, ptr); - - struct rusage thread; - - // when ZERO, attempt to do it - int vdo_cpu_netdata = config_get_boolean("plugin:cgroups", "cgroups plugin resource charts", 1); - - read_cgroup_plugin_configuration(); - - 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_dt = 0; - - while(!netdata_exit) { - usec_t hb_dt = heartbeat_next(&hb, step); - if(unlikely(netdata_exit)) break; - - // BEGIN -- the job to be done - - find_dt += hb_dt; - if(unlikely(find_dt >= find_every || cgroups_check)) { - find_all_cgroups(); - find_dt = 0; - cgroups_check = 0; - } - - read_all_cgroups(cgroup_root); - update_cgroup_charts(cgroup_update_every); - - // END -- the job is done - - // -------------------------------------------------------------------- - - if(vdo_cpu_netdata) { - getrusage(RUSAGE_THREAD, &thread); - - if(unlikely(!stcpu_thread)) { - - stcpu_thread = rrdset_create_localhost( - "netdata" - , "plugin_cgroups_cpu" - , NULL - , "cgroups" - , NULL - , "NetData CGroups Plugin CPU usage" - , "milliseconds/s" - , "cgroup" - , "stats" - , 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); - - rrddim_set(stcpu_thread, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); - rrdset_done(stcpu_thread); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/sys_kernel_mm_ksm.c b/src/sys_kernel_mm_ksm.c deleted file mode 100644 index 7ca1366b4..000000000 --- a/src/sys_kernel_mm_ksm.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "common.h" - -typedef struct ksm_name_value { - char filename[FILENAME_MAX + 1]; - unsigned long long value; -} KSM_NAME_VALUE; - -#define PAGES_SHARED 0 -#define PAGES_SHARING 1 -#define PAGES_UNSHARED 2 -#define PAGES_VOLATILE 3 -#define PAGES_TO_SCAN 4 - -KSM_NAME_VALUE values[] = { - [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL }, - [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL }, - [PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL }, - [PAGES_VOLATILE] = { "/sys/kernel/mm/ksm/pages_volatile", 0ULL }, - // [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL }, -}; - -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 unsigned long page_size = 0; - - if(unlikely(page_size == 0)) - page_size = (unsigned long)sysconf(_SC_PAGESIZE); - - if(unlikely(!ff_pages_shared)) { - snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_shared"); - snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename)); - ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT); - } - - if(unlikely(!ff_pages_sharing)) { - snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_sharing"); - snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename)); - ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT); - } - - if(unlikely(!ff_pages_unshared)) { - snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_unshared"); - snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename)); - ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT); - } - - if(unlikely(!ff_pages_volatile)) { - snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_volatile"); - snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename)); - ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT); - } - - //if(unlikely(!ff_pages_to_scan)) { - // snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan"); - // snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename)); - // ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT); - //} - - if(unlikely(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile /*|| !ff_pages_to_scan */)) - return 1; - - unsigned long long pages_shared = 0, pages_sharing = 0, pages_unshared = 0, pages_volatile = 0, /*pages_to_scan = 0,*/ offered = 0, saved = 0; - - ff_pages_shared = procfile_readall(ff_pages_shared); - if(unlikely(!ff_pages_shared)) return 0; // we return 0, so that we will retry to open it next time - pages_shared = str2ull(procfile_lineword(ff_pages_shared, 0, 0)); - - ff_pages_sharing = procfile_readall(ff_pages_sharing); - if(unlikely(!ff_pages_sharing)) return 0; // we return 0, so that we will retry to open it next time - pages_sharing = str2ull(procfile_lineword(ff_pages_sharing, 0, 0)); - - ff_pages_unshared = procfile_readall(ff_pages_unshared); - if(unlikely(!ff_pages_unshared)) return 0; // we return 0, so that we will retry to open it next time - pages_unshared = str2ull(procfile_lineword(ff_pages_unshared, 0, 0)); - - ff_pages_volatile = procfile_readall(ff_pages_volatile); - if(unlikely(!ff_pages_volatile)) return 0; // we return 0, so that we will retry to open it next time - pages_volatile = str2ull(procfile_lineword(ff_pages_volatile, 0, 0)); - - //ff_pages_to_scan = procfile_readall(ff_pages_to_scan); - //if(unlikely(!ff_pages_to_scan)) return 0; // we return 0, so that we will retry to open it next time - //pages_to_scan = str2ull(procfile_lineword(ff_pages_to_scan, 0, 0)); - - offered = pages_sharing + pages_shared + pages_unshared + pages_volatile; - saved = pages_sharing; - - if(unlikely(!offered /*|| !pages_to_scan*/)) return 0; - - // -------------------------------------------------------------------- - - { - static RRDSET *st_mem_ksm = NULL; - static RRDDIM *rd_shared = NULL, *rd_unshared = NULL, *rd_sharing = NULL, *rd_volatile = NULL/*, *rd_to_scan = NULL*/; - - if (unlikely(!st_mem_ksm)) { - st_mem_ksm = rrdset_create_localhost( - "mem" - , "ksm" - , NULL - , "ksm" - , NULL - , "Kernel Same Page Merging" - , "MB" - , "proc" - , "/sys/kernel/mm/ksm" - , NETDATA_CHART_PRIO_MEM_KSM - , update_every - , RRDSET_TYPE_AREA - ); - - rd_shared = rrddim_add(st_mem_ksm, "shared", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_unshared = rrddim_add(st_mem_ksm, "unshared", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_sharing = rrddim_add(st_mem_ksm, "sharing", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_volatile = rrddim_add(st_mem_ksm, "volatile", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - //rd_to_scan = rrddim_add(st_mem_ksm, "to_scan", "to scan", -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_mem_ksm); - - rrddim_set_by_pointer(st_mem_ksm, rd_shared, pages_shared * page_size); - rrddim_set_by_pointer(st_mem_ksm, rd_unshared, pages_unshared * page_size); - rrddim_set_by_pointer(st_mem_ksm, rd_sharing, pages_sharing * page_size); - rrddim_set_by_pointer(st_mem_ksm, rd_volatile, pages_volatile * page_size); - //rrddim_set_by_pointer(st_mem_ksm, rd_to_scan, pages_to_scan * page_size); - - rrdset_done(st_mem_ksm); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_mem_ksm_savings = NULL; - static RRDDIM *rd_savings = NULL, *rd_offered = NULL; - - if (unlikely(!st_mem_ksm_savings)) { - st_mem_ksm_savings = rrdset_create_localhost( - "mem" - , "ksm_savings" - , NULL - , "ksm" - , NULL - , "Kernel Same Page Merging Savings" - , "MB" - , "proc" - , "/sys/kernel/mm/ksm" - , NETDATA_CHART_PRIO_MEM_KSM + 1 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_savings = rrddim_add(st_mem_ksm_savings, "savings", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_offered = rrddim_add(st_mem_ksm_savings, "offered", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_mem_ksm_savings); - - rrddim_set_by_pointer(st_mem_ksm_savings, rd_savings, saved * page_size); - rrddim_set_by_pointer(st_mem_ksm_savings, rd_offered, offered * page_size); - - rrdset_done(st_mem_ksm_savings); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_mem_ksm_ratios = NULL; - static RRDDIM *rd_savings = NULL; - - if (unlikely(!st_mem_ksm_ratios)) { - st_mem_ksm_ratios = rrdset_create_localhost( - "mem" - , "ksm_ratios" - , NULL - , "ksm" - , NULL - , "Kernel Same Page Merging Effectiveness" - , "percentage" - , "proc" - , "/sys/kernel/mm/ksm" - , NETDATA_CHART_PRIO_MEM_KSM + 2 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_savings = rrddim_add(st_mem_ksm_ratios, "savings", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_mem_ksm_ratios); - - rrddim_set_by_pointer(st_mem_ksm_ratios, rd_savings, (saved * 1000000) / offered); - - rrdset_done(st_mem_ksm_ratios); - } - - return 0; -} diff --git a/src/threads.c b/src/threads.c deleted file mode 100644 index b9ca3c085..000000000 --- a/src/threads.c +++ /dev/null @@ -1,181 +0,0 @@ -#include "common.h" - -static size_t default_stacksize = 0, wanted_stacksize = 0; -static pthread_attr_t *attr = NULL; - -// ---------------------------------------------------------------------------- -// per thread data - -typedef struct { - void *arg; - pthread_t *thread; - const char *tag; - void *(*start_routine) (void *); - NETDATA_THREAD_OPTIONS options; -} NETDATA_THREAD; - -static __thread NETDATA_THREAD *netdata_thread = NULL; - -const char *netdata_thread_tag(void) { - return ((netdata_thread && netdata_thread->tag && *netdata_thread->tag)?netdata_thread->tag:"MAIN"); -} - -// ---------------------------------------------------------------------------- -// compatibility library functions - -pid_t gettid(void) { -#ifdef __FreeBSD__ - - return (pid_t)pthread_getthreadid_np(); - -#elif defined(__APPLE__) - - #if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) - uint64_t curthreadid; - pthread_threadid_np(NULL, &curthreadid); - return (pid_t)curthreadid; - #else /* __MAC_OS_X_VERSION_MIN_REQUIRED */ - return (pid_t)pthread_self; - #endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */ - -#else /* __APPLE__*/ - - return (pid_t)syscall(SYS_gettid); - -#endif /* __FreeBSD__, __APPLE__*/ -} - -// ---------------------------------------------------------------------------- -// early initialization - -size_t netdata_threads_init(void) { - int i; - - // -------------------------------------------------------------------- - // get the required stack size of the threads of netdata - - attr = callocz(1, sizeof(pthread_attr_t)); - i = pthread_attr_init(attr); - if(i != 0) - fatal("pthread_attr_init() failed with code %d.", i); - - i = pthread_attr_getstacksize(attr, &default_stacksize); - if(i != 0) - fatal("pthread_attr_getstacksize() failed with code %d.", i); - else - debug(D_OPTIONS, "initial pthread stack size is %zu bytes", default_stacksize); - - return default_stacksize; -} - -// ---------------------------------------------------------------------------- -// late initialization - -void netdata_threads_init_after_fork(size_t stacksize) { - wanted_stacksize = stacksize; - int i; - - // ------------------------------------------------------------------------ - // set default pthread stack size - - if(attr && default_stacksize < wanted_stacksize && wanted_stacksize > 0) { - i = pthread_attr_setstacksize(attr, wanted_stacksize); - if(i != 0) - fatal("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", wanted_stacksize, i); - else - debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize); - } -} - - -// ---------------------------------------------------------------------------- -// netdata_thread_create - -static void thread_cleanup(void *ptr) { - if(netdata_thread != ptr) { - NETDATA_THREAD *info = (NETDATA_THREAD *)ptr; - error("THREADS: internal error - thread local variable does not match the one passed to this function. Expected thread '%s', passed thread '%s'", netdata_thread->tag, info->tag); - } - - if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP)) - info("thread with task id %d finished", gettid()); - - freez((void *)netdata_thread->tag); - netdata_thread->tag = NULL; - - freez(netdata_thread); - netdata_thread = NULL; -} - -static void *thread_start(void *ptr) { - netdata_thread = (NETDATA_THREAD *)ptr; - - if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_STARTUP)) - info("thread created with task id %d", gettid()); - - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) - error("cannot set pthread cancel type to DEFERRED."); - - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) - error("cannot set pthread cancel state to ENABLE."); - - void *ret = NULL; - pthread_cleanup_push(thread_cleanup, ptr); - ret = netdata_thread->start_routine(netdata_thread->arg); - pthread_cleanup_pop(1); - - return ret; -} - -int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg) { - NETDATA_THREAD *info = mallocz(sizeof(NETDATA_THREAD)); - info->arg = arg; - info->thread = thread; - info->tag = strdupz(tag); - info->start_routine = start_routine; - info->options = options; - - int ret = pthread_create(thread, attr, thread_start, info); - if(ret != 0) - error("failed to create new thread for %s. pthread_create() failed with code %d", tag, ret); - - else { - if (!(options & NETDATA_THREAD_OPTION_JOINABLE)) { - int ret2 = pthread_detach(*thread); - if (ret2 != 0) - error("cannot request detach of newly created %s thread. pthread_detach() failed with code %d", tag, ret2); - } - } - - return ret; -} - -// ---------------------------------------------------------------------------- -// netdata_thread_cancel - -int netdata_thread_cancel(netdata_thread_t thread) { - int ret = pthread_cancel(thread); - if(ret != 0) - error("cannot cancel thread. pthread_cancel() failed with code %d.", ret); - - return ret; -} - -// ---------------------------------------------------------------------------- -// netdata_thread_join - -int netdata_thread_join(netdata_thread_t thread, void **retval) { - int ret = pthread_join(thread, retval); - if(ret != 0) - error("cannot join thread. pthread_join() failed with code %d.", ret); - - return ret; -} - -int netdata_thread_detach(pthread_t thread) { - int ret = pthread_detach(thread); - if(ret != 0) - error("cannot detach thread. pthread_detach() failed with code %d.", ret); - - return ret; -} diff --git a/src/threads.h b/src/threads.h deleted file mode 100644 index e2ed6a4ff..000000000 --- a/src/threads.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef NETDATA_THREADS_H -#define NETDATA_THREADS_H - -extern pid_t gettid(void); - -typedef enum { - NETDATA_THREAD_OPTION_DEFAULT = 0 << 0, - NETDATA_THREAD_OPTION_JOINABLE = 1 << 0, - NETDATA_THREAD_OPTION_DONT_LOG_STARTUP = 1 << 1, - NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP = 1 << 2, - NETDATA_THREAD_OPTION_DONT_LOG = NETDATA_THREAD_OPTION_DONT_LOG_STARTUP|NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP, -} NETDATA_THREAD_OPTIONS; - -#define netdata_thread_cleanup_push(func, arg) pthread_cleanup_push(func, arg) -#define netdata_thread_cleanup_pop(execute) pthread_cleanup_pop(execute) - -typedef pthread_t netdata_thread_t; - -#define NETDATA_THREAD_TAG_MAX 100 -extern const char *netdata_thread_tag(void); - -extern size_t netdata_threads_init(void); -extern void netdata_threads_init_after_fork(size_t stacksize); - -extern int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg); -extern int netdata_thread_cancel(netdata_thread_t thread); -extern int netdata_thread_join(netdata_thread_t thread, void **retval); -extern int netdata_thread_detach(pthread_t thread); - -#define netdata_thread_self pthread_self -#define netdata_thread_testcancel pthread_testcancel - -#endif //NETDATA_THREADS_H diff --git a/src/unit_test.c b/src/unit_test.c deleted file mode 100644 index e3eb146ad..000000000 --- a/src/unit_test.c +++ /dev/null @@ -1,1368 +0,0 @@ -#include "common.h" - -static int check_number_printing(void) { - struct { - calculated_number n; - const char *correct; - } values[] = { - { .n = 0, .correct = "0" }, - { .n = 0.0000001, .correct = "0.0000001" }, - { .n = 0.00000009, .correct = "0.0000001" }, - { .n = 0.000000001, .correct = "0" }, - { .n = 99.99999999999999999, .correct = "100" }, - { .n = -99.99999999999999999, .correct = "-100" }, - { .n = 123.4567890123456789, .correct = "123.456789" }, - { .n = 9999.9999999, .correct = "9999.9999999" }, - { .n = -9999.9999999, .correct = "-9999.9999999" }, - { .n = 0, .correct = NULL }, - }; - - char netdata[50], system[50]; - int i, failed = 0; - for(i = 0; values[i].correct ; i++) { - print_calculated_number(netdata, values[i].n); - snprintfz(system, 49, "%0.12" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE)values[i].n); - - int ok = 1; - if(strcmp(netdata, values[i].correct) != 0) { - ok = 0; - failed++; - } - - fprintf(stderr, "'%s' (system) printed as '%s' (netdata): %s\n", system, netdata, ok?"OK":"FAILED"); - } - - if(failed) return 1; - return 0; -} - -static int check_rrdcalc_comparisons(void) { - RRDCALC_STATUS a, b; - - // make sure calloc() sets the status to UNINITIALIZED - memset(&a, 0, sizeof(RRDCALC_STATUS)); - if(a != RRDCALC_STATUS_UNINITIALIZED) { - fprintf(stderr, "%s is not zero.\n", rrdcalc_status2string(RRDCALC_STATUS_UNINITIALIZED)); - return 1; - } - - a = RRDCALC_STATUS_REMOVED; - b = RRDCALC_STATUS_UNDEFINED; - if(!(a < b)) { - fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); - return 1; - } - - a = RRDCALC_STATUS_UNDEFINED; - b = RRDCALC_STATUS_UNINITIALIZED; - if(!(a < b)) { - fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); - return 1; - } - - a = RRDCALC_STATUS_UNINITIALIZED; - b = RRDCALC_STATUS_CLEAR; - if(!(a < b)) { - fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); - return 1; - } - - a = RRDCALC_STATUS_CLEAR; - b = RRDCALC_STATUS_RAISED; - if(!(a < b)) { - fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); - return 1; - } - - a = RRDCALC_STATUS_RAISED; - b = RRDCALC_STATUS_WARNING; - if(!(a < b)) { - fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); - return 1; - } - - a = RRDCALC_STATUS_WARNING; - b = RRDCALC_STATUS_CRITICAL; - if(!(a < b)) { - fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); - return 1; - } - - fprintf(stderr, "RRDCALC_STATUSes are sortable.\n"); - - return 0; -} - -int check_storage_number(calculated_number n, int debug) { - char buffer[100]; - uint32_t flags = SN_EXISTS; - - storage_number s = pack_storage_number(n, flags); - calculated_number d = unpack_storage_number(s); - - if(!does_storage_number_exist(s)) { - fprintf(stderr, "Exists flags missing for number " CALCULATED_NUMBER_FORMAT "!\n", n); - return 5; - } - - calculated_number ddiff = d - n; - calculated_number dcdiff = ddiff * 100.0 / n; - - if(dcdiff < 0) dcdiff = -dcdiff; - - size_t len = (size_t)print_calculated_number(buffer, d); - calculated_number p = str2ld(buffer, NULL); - calculated_number pdiff = n - p; - calculated_number pcdiff = pdiff * 100.0 / n; - if(pcdiff < 0) pcdiff = -pcdiff; - - if(debug) { - fprintf(stderr, - CALCULATED_NUMBER_FORMAT " original\n" - CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n" - "%s printed after unpacked (%zu bytes)\n" - CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n", - n, - d, s, ddiff, dcdiff, - buffer, len, - p, pdiff, pcdiff - ); - if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer)); - if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss " CALCULATED_NUMBER_FORMAT " %%\n", n, dcdiff); - if(pcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: re-parsing the packed, unpacked and printed number " CALCULATED_NUMBER_FORMAT " has accuracy loss " CALCULATED_NUMBER_FORMAT " %%\n", n, pcdiff); - } - - if(len != strlen(buffer)) return 1; - if(dcdiff > ACCURACY_LOSS) return 3; - if(pcdiff > ACCURACY_LOSS) return 4; - return 0; -} - -calculated_number storage_number_min(calculated_number n) { - calculated_number r = 1, last; - - do { - last = n; - n /= 2.0; - storage_number t = pack_storage_number(n, SN_EXISTS); - r = unpack_storage_number(t); - } while(r != 0.0 && r != last); - - return last; -} - -void benchmark_storage_number(int loop, int multiplier) { - int i, j; - calculated_number n, d; - storage_number s; - unsigned long long user, system, total, mine, their; - - char buffer[100]; - - struct rusage now, last; - - fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop); - - // ------------------------------------------------------------------------ - - fprintf(stderr, "SYSTEM LONG DOUBLE SIZE: %zu bytes\n", sizeof(calculated_number)); - fprintf(stderr, "NETDATA FLOATING POINT SIZE: %zu bytes\n", sizeof(storage_number)); - - mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop; - their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop; - - if(mine > their) { - fprintf(stderr, "\nNETDATA NEEDS %0.2" LONG_DOUBLE_MODIFIER " TIMES MORE MEMORY. Sorry!\n", (LONG_DOUBLE)(mine / their)); - } - else { - fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2" LONG_DOUBLE_MODIFIER " TIMES LESS MEMORY.\n", (LONG_DOUBLE)(their / mine)); - } - - fprintf(stderr, "\nNETDATA FLOATING POINT\n"); - fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", storage_number_min(1)); - fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX); - fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN); - fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", -storage_number_min(1)); - fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS); - - // ------------------------------------------------------------------------ - - fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: "); - getrusage(RUSAGE_SELF, &last); - - // do the job - for(j = 1; j < 11 ;j++) { - n = STORAGE_NUMBER_POSITIVE_MIN * j; - - for(i = 0; i < loop ;i++) { - n *= multiplier; - if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN; - - print_calculated_number(buffer, n); - } - } - - getrusage(RUSAGE_SELF, &now); - user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec; - system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec; - total = user + system; - mine = total; - - fprintf(stderr, "user %0.5" LONG_DOUBLE_MODIFIER", system %0.5" LONG_DOUBLE_MODIFIER ", total %0.5" LONG_DOUBLE_MODIFIER "\n", (LONG_DOUBLE)(user / 1000000.0), (LONG_DOUBLE)(system / 1000000.0), (LONG_DOUBLE)(total / 1000000.0)); - - // ------------------------------------------------------------------------ - - fprintf(stderr, "SYSTEM LONG DOUBLE PRINTING: "); - getrusage(RUSAGE_SELF, &last); - - // do the job - for(j = 1; j < 11 ;j++) { - n = STORAGE_NUMBER_POSITIVE_MIN * j; - - for(i = 0; i < loop ;i++) { - n *= multiplier; - if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN; - snprintfz(buffer, 100, CALCULATED_NUMBER_FORMAT, n); - } - } - - getrusage(RUSAGE_SELF, &now); - user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec; - system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec; - total = user + system; - their = total; - - fprintf(stderr, "user %0.5" LONG_DOUBLE_MODIFIER ", system %0.5" LONG_DOUBLE_MODIFIER ", total %0.5" LONG_DOUBLE_MODIFIER "\n", (LONG_DOUBLE)(user / 1000000.0), (LONG_DOUBLE)(system / 1000000.0), (LONG_DOUBLE)(total / 1000000.0)); - - if(mine > total) { - fprintf(stderr, "NETDATA CODE IS SLOWER %0.2" LONG_DOUBLE_MODIFIER " %%\n", (LONG_DOUBLE)(mine * 100.0 / their - 100.0)); - } - else { - fprintf(stderr, "NETDATA CODE IS F A S T E R %0.2" LONG_DOUBLE_MODIFIER " %%\n", (LONG_DOUBLE)(their * 100.0 / mine - 100.0)); - } - - // ------------------------------------------------------------------------ - - fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: "); - getrusage(RUSAGE_SELF, &last); - - // do the job - for(j = 1; j < 11 ;j++) { - n = STORAGE_NUMBER_POSITIVE_MIN * j; - - for(i = 0; i < loop ;i++) { - n *= multiplier; - if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN; - - s = pack_storage_number(n, 1); - d = unpack_storage_number(s); - print_calculated_number(buffer, d); - } - } - - getrusage(RUSAGE_SELF, &now); - user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec; - system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec; - total = user + system; - mine = total; - - fprintf(stderr, "user %0.5" LONG_DOUBLE_MODIFIER ", system %0.5" LONG_DOUBLE_MODIFIER ", total %0.5" LONG_DOUBLE_MODIFIER "\n", (LONG_DOUBLE)(user / 1000000.0), (LONG_DOUBLE)(system / 1000000.0), (LONG_DOUBLE)(total / 1000000.0)); - - if(mine > their) { - fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2" LONG_DOUBLE_MODIFIER " %%\n", (LONG_DOUBLE)(mine * 100.0 / their - 100.0)); - } - else { - fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS F A S T E R %0.2" LONG_DOUBLE_MODIFIER " %%\n", (LONG_DOUBLE)(their * 100.0 / mine - 100.0)); - } - - // ------------------------------------------------------------------------ - -} - -static int check_storage_number_exists() { - uint32_t flags = SN_EXISTS; - - - for(flags = 0; flags < 7 ; flags++) { - if(get_storage_number_flags(flags << 24) != flags << 24) { - fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24)); - return 1; - } - } - - flags = SN_EXISTS; - calculated_number n = 0.0; - - storage_number s = pack_storage_number(n, flags); - calculated_number d = unpack_storage_number(s); - if(get_storage_number_flags(s) != flags) { - fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s)); - return 1; - } - if(n != d) { - fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d); - return 1; - } - - return 0; -} - -int unit_test_storage() -{ - if(check_storage_number_exists()) return 0; - - calculated_number c, a = 0; - int i, j, g, r = 0; - - for(g = -1; g <= 1 ; g++) { - a = 0; - - if(!g) continue; - - for(j = 0; j < 9 ;j++) { - a += 0.0000001; - c = a * g; - for(i = 0; i < 21 ;i++, c *= 10) { - if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue; - if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue; - - if(check_storage_number(c, 1)) return 1; - } - } - } - - benchmark_storage_number(1000000, 2); - return r; -} - -int unit_test_str2ld() { - char *values[] = { - "1.2345678", "-35.6", "0.00123", "23842384234234.2", ".1", "1.2e-10", - "hello", "1wrong", "nan", "inf", NULL - }; - - int i; - for(i = 0; values[i] ; i++) { - char *e_mine = "hello", *e_sys = "world"; - LONG_DOUBLE mine = str2ld(values[i], &e_mine); - LONG_DOUBLE sys = strtold(values[i], &e_sys); - - if(isnan(mine)) { - if(!isnan(sys)) { - fprintf(stderr, "Value '%s' is parsed as %" LONG_DOUBLE_MODIFIER ", but system believes it is %" LONG_DOUBLE_MODIFIER ".\n", values[i], mine, sys); - return -1; - } - } - else if(isinf(mine)) { - if(!isinf(sys)) { - fprintf(stderr, "Value '%s' is parsed as %" LONG_DOUBLE_MODIFIER ", but system believes it is %" LONG_DOUBLE_MODIFIER ".\n", values[i], mine, sys); - return -1; - } - } - else if(mine != sys && abs(mine-sys) > 0.000001) { - fprintf(stderr, "Value '%s' is parsed as %" LONG_DOUBLE_MODIFIER ", but system believes it is %" LONG_DOUBLE_MODIFIER ", delta %" LONG_DOUBLE_MODIFIER ".\n", values[i], mine, sys, sys-mine); - return -1; - } - - if(e_mine != e_sys) { - fprintf(stderr, "Value '%s' is parsed correctly, but endptr is not right\n", values[i]); - return -1; - } - - fprintf(stderr, "str2ld() parsed value '%s' exactly the same way with strtold(), returned %" LONG_DOUBLE_MODIFIER " vs %" LONG_DOUBLE_MODIFIER "\n", values[i], mine, sys); - } - - return 0; -} - -int unit_test_buffer() { - BUFFER *wb = buffer_create(1); - char string[2048 + 1]; - char final[9000 + 1]; - int i; - - for(i = 0; i < 2048; i++) - string[i] = (char)((i % 24) + 'a'); - string[2048] = '\0'; - - const char *fmt = "string1: %s\nstring2: %s\nstring3: %s\nstring4: %s"; - buffer_sprintf(wb, fmt, string, string, string, string); - snprintfz(final, 9000, fmt, string, string, string, string); - - const char *s = buffer_tostring(wb); - - if(buffer_strlen(wb) != strlen(final) || strcmp(s, final) != 0) { - fprintf(stderr, "\nbuffer_sprintf() is faulty.\n"); - fprintf(stderr, "\nstring : %s (length %zu)\n", string, strlen(string)); - fprintf(stderr, "\nbuffer : %s (length %zu)\n", s, buffer_strlen(wb)); - fprintf(stderr, "\nexpected: %s (length %zu)\n", final, strlen(final)); - buffer_free(wb); - return -1; - } - - fprintf(stderr, "buffer_sprintf() works as expected.\n"); - buffer_free(wb); - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- - -struct feed_values { - unsigned long long microseconds; - collected_number value; -}; - -struct test { - char name[100]; - char description[1024]; - - int update_every; - unsigned long long multiplier; - unsigned long long divisor; - RRD_ALGORITHM algorithm; - - unsigned long feed_entries; - unsigned long result_entries; - struct feed_values *feed; - calculated_number *results; - - collected_number *feed2; - calculated_number *results2; -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test1 -// test absolute values stored - -struct feed_values test1_feed[] = { - { 0, 10 }, - { 1000000, 20 }, - { 1000000, 30 }, - { 1000000, 40 }, - { 1000000, 50 }, - { 1000000, 60 }, - { 1000000, 70 }, - { 1000000, 80 }, - { 1000000, 90 }, - { 1000000, 100 }, -}; - -calculated_number test1_results[] = { - 20, 30, 40, 50, 60, 70, 80, 90, 100 -}; - -struct test test1 = { - "test1", // name - "test absolute values stored at exactly second boundaries", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_ABSOLUTE, // algorithm - 10, // feed entries - 9, // result entries - test1_feed, // feed - test1_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test2 -// test absolute values stored in the middle of second boundaries - -struct feed_values test2_feed[] = { - { 500000, 10 }, - { 1000000, 20 }, - { 1000000, 30 }, - { 1000000, 40 }, - { 1000000, 50 }, - { 1000000, 60 }, - { 1000000, 70 }, - { 1000000, 80 }, - { 1000000, 90 }, - { 1000000, 100 }, -}; - -calculated_number test2_results[] = { - 20, 30, 40, 50, 60, 70, 80, 90, 100 -}; - -struct test test2 = { - "test2", // name - "test absolute values stored in the middle of second boundaries", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_ABSOLUTE, // algorithm - 10, // feed entries - 9, // result entries - test2_feed, // feed - test2_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test3 - -struct feed_values test3_feed[] = { - { 0, 10 }, - { 1000000, 20 }, - { 1000000, 30 }, - { 1000000, 40 }, - { 1000000, 50 }, - { 1000000, 60 }, - { 1000000, 70 }, - { 1000000, 80 }, - { 1000000, 90 }, - { 1000000, 100 }, -}; - -calculated_number test3_results[] = { - 10, 10, 10, 10, 10, 10, 10, 10, 10 -}; - -struct test test3 = { - "test3", // name - "test incremental values stored at exactly second boundaries", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 9, // result entries - test3_feed, // feed - test3_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test4 - -struct feed_values test4_feed[] = { - { 500000, 10 }, - { 1000000, 20 }, - { 1000000, 30 }, - { 1000000, 40 }, - { 1000000, 50 }, - { 1000000, 60 }, - { 1000000, 70 }, - { 1000000, 80 }, - { 1000000, 90 }, - { 1000000, 100 }, -}; - -calculated_number test4_results[] = { - 10, 10, 10, 10, 10, 10, 10, 10, 10 -}; - -struct test test4 = { - "test4", // name - "test incremental values stored in the middle of second boundaries", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 9, // result entries - test4_feed, // feed - test4_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test5 - -struct feed_values test5_feed[] = { - { 500000, 1000 }, - { 1000000, 2000 }, - { 1000000, 2000 }, - { 1000000, 2000 }, - { 1000000, 3000 }, - { 1000000, 2000 }, - { 1000000, 2000 }, - { 1000000, 2000 }, - { 1000000, 2000 }, - { 1000000, 2000 }, -}; - -calculated_number test5_results[] = { - 1000, 500, 0, 500, 500, 0, 0, 0, 0 -}; - -struct test test5 = { - "test5", // name - "test incremental values ups and downs", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 9, // result entries - test5_feed, // feed - test5_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test6 - -struct feed_values test6_feed[] = { - { 250000, 1000 }, - { 250000, 2000 }, - { 250000, 3000 }, - { 250000, 4000 }, - { 250000, 5000 }, - { 250000, 6000 }, - { 250000, 7000 }, - { 250000, 8000 }, - { 250000, 9000 }, - { 250000, 10000 }, - { 250000, 11000 }, - { 250000, 12000 }, - { 250000, 13000 }, - { 250000, 14000 }, - { 250000, 15000 }, - { 250000, 16000 }, -}; - -calculated_number test6_results[] = { - 4000, 4000, 4000, 4000 -}; - -struct test test6 = { - "test6", // name - "test incremental values updated within the same second", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 16, // feed entries - 4, // result entries - test6_feed, // feed - test6_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test7 - -struct feed_values test7_feed[] = { - { 500000, 1000 }, - { 2000000, 2000 }, - { 2000000, 3000 }, - { 2000000, 4000 }, - { 2000000, 5000 }, - { 2000000, 6000 }, - { 2000000, 7000 }, - { 2000000, 8000 }, - { 2000000, 9000 }, - { 2000000, 10000 }, -}; - -calculated_number test7_results[] = { - 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500 -}; - -struct test test7 = { - "test7", // name - "test incremental values updated in long durations", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 18, // result entries - test7_feed, // feed - test7_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test8 - -struct feed_values test8_feed[] = { - { 500000, 1000 }, - { 2000000, 2000 }, - { 2000000, 3000 }, - { 2000000, 4000 }, - { 2000000, 5000 }, - { 2000000, 6000 }, -}; - -calculated_number test8_results[] = { - 1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000 -}; - -struct test test8 = { - "test8", // name - "test absolute values updated in long durations", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_ABSOLUTE, // algorithm - 6, // feed entries - 10, // result entries - test8_feed, // feed - test8_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test9 - -struct feed_values test9_feed[] = { - { 250000, 1000 }, - { 250000, 2000 }, - { 250000, 3000 }, - { 250000, 4000 }, - { 250000, 5000 }, - { 250000, 6000 }, - { 250000, 7000 }, - { 250000, 8000 }, - { 250000, 9000 }, - { 250000, 10000 }, - { 250000, 11000 }, - { 250000, 12000 }, - { 250000, 13000 }, - { 250000, 14000 }, - { 250000, 15000 }, - { 250000, 16000 }, -}; - -calculated_number test9_results[] = { - 4000, 8000, 12000, 16000 -}; - -struct test test9 = { - "test9", // name - "test absolute values updated within the same second", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_ABSOLUTE, // algorithm - 16, // feed entries - 4, // result entries - test9_feed, // feed - test9_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test10 - -struct feed_values test10_feed[] = { - { 500000, 1000 }, - { 600000, 1000 + 600 }, - { 200000, 1600 + 200 }, - { 1000000, 1800 + 1000 }, - { 200000, 2800 + 200 }, - { 2000000, 3000 + 2000 }, - { 600000, 5000 + 600 }, - { 400000, 5600 + 400 }, - { 900000, 6000 + 900 }, - { 1000000, 6900 + 1000 }, -}; - -calculated_number test10_results[] = { - 1000, 1000, 1000, 1000, 1000, 1000, 1000 -}; - -struct test test10 = { - "test10", // name - "test incremental values updated in short and long durations", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 7, // result entries - test10_feed, // feed - test10_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test11 - -struct feed_values test11_feed[] = { - { 0, 10 }, - { 1000000, 20 }, - { 1000000, 30 }, - { 1000000, 40 }, - { 1000000, 50 }, - { 1000000, 60 }, - { 1000000, 70 }, - { 1000000, 80 }, - { 1000000, 90 }, - { 1000000, 100 }, -}; - -collected_number test11_feed2[] = { - 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 -}; - -calculated_number test11_results[] = { - 50, 50, 50, 50, 50, 50, 50, 50, 50 -}; - -calculated_number test11_results2[] = { - 50, 50, 50, 50, 50, 50, 50, 50, 50 -}; - -struct test test11 = { - "test11", // name - "test percentage-of-incremental-row with equal values", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm - 10, // feed entries - 9, // result entries - test11_feed, // feed - test11_results, // results - test11_feed2, // feed2 - test11_results2 // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test12 - -struct feed_values test12_feed[] = { - { 0, 10 }, - { 1000000, 20 }, - { 1000000, 30 }, - { 1000000, 40 }, - { 1000000, 50 }, - { 1000000, 60 }, - { 1000000, 70 }, - { 1000000, 80 }, - { 1000000, 90 }, - { 1000000, 100 }, -}; - -collected_number test12_feed2[] = { - 10*3, 20*3, 30*3, 40*3, 50*3, 60*3, 70*3, 80*3, 90*3, 100*3 -}; - -calculated_number test12_results[] = { - 25, 25, 25, 25, 25, 25, 25, 25, 25 -}; - -calculated_number test12_results2[] = { - 75, 75, 75, 75, 75, 75, 75, 75, 75 -}; - -struct test test12 = { - "test12", // name - "test percentage-of-incremental-row with equal values", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm - 10, // feed entries - 9, // result entries - test12_feed, // feed - test12_results, // results - test12_feed2, // feed2 - test12_results2 // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test13 - -struct feed_values test13_feed[] = { - { 500000, 1000 }, - { 600000, 1000 + 600 }, - { 200000, 1600 + 200 }, - { 1000000, 1800 + 1000 }, - { 200000, 2800 + 200 }, - { 2000000, 3000 + 2000 }, - { 600000, 5000 + 600 }, - { 400000, 5600 + 400 }, - { 900000, 6000 + 900 }, - { 1000000, 6900 + 1000 }, -}; - -calculated_number test13_results[] = { - 83.3333300, 100, 100, 100, 100, 100, 100 -}; - -struct test test13 = { - "test13", // name - "test incremental values updated in short and long durations", - 1, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm - 10, // feed entries - 7, // result entries - test13_feed, // feed - test13_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test14 - -struct feed_values test14_feed[] = { - { 0, 0x015397dc42151c41ULL }, - { 13573000, 0x015397e612e3ff5dULL }, - { 29969000, 0x015397f905ecdaa8ULL }, - { 29958000, 0x0153980c2a6cb5e4ULL }, - { 30054000, 0x0153981f4032fb83ULL }, - { 34952000, 0x015398355efadaccULL }, - { 25046000, 0x01539845ba4b09f8ULL }, - { 29947000, 0x0153985948bf381dULL }, - { 30054000, 0x0153986c5b9c27e2ULL }, - { 29942000, 0x0153987f888982d0ULL }, -}; - -calculated_number test14_results[] = { - 23.1383300, 21.8515600, 21.8804600, 21.7788000, 22.0112200, 22.4386100, 22.0906100, 21.9150800 -}; - -struct test test14 = { - "test14", // name - "issue #981 with real data", - 30, // update_every - 8, // multiplier - 1000000000, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 8, // result entries - test14_feed, // feed - test14_results, // results - NULL, // feed2 - NULL // results2 -}; - -struct feed_values test14b_feed[] = { - { 0, 0 }, - { 13573000, 13573000 }, - { 29969000, 13573000 + 29969000 }, - { 29958000, 13573000 + 29969000 + 29958000 }, - { 30054000, 13573000 + 29969000 + 29958000 + 30054000 }, - { 34952000, 13573000 + 29969000 + 29958000 + 30054000 + 34952000 }, - { 25046000, 13573000 + 29969000 + 29958000 + 30054000 + 34952000 + 25046000 }, - { 29947000, 13573000 + 29969000 + 29958000 + 30054000 + 34952000 + 25046000 + 29947000 }, - { 30054000, 13573000 + 29969000 + 29958000 + 30054000 + 34952000 + 25046000 + 29947000 + 30054000 }, - { 29942000, 13573000 + 29969000 + 29958000 + 30054000 + 34952000 + 25046000 + 29947000 + 30054000 + 29942000 }, -}; - -calculated_number test14b_results[] = { - 1000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000 -}; - -struct test test14b = { - "test14b", // name - "issue #981 with dummy data", - 30, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 8, // result entries - test14b_feed, // feed - test14b_results, // results - NULL, // feed2 - NULL // results2 -}; - -struct feed_values test14c_feed[] = { - { 29000000, 29000000 }, - { 1000000, 29000000 + 1000000 }, - { 30000000, 29000000 + 1000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 + 30000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 }, - { 30000000, 29000000 + 1000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 + 30000000 }, -}; - -calculated_number test14c_results[] = { - 1000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000 -}; - -struct test test14c = { - "test14c", // name - "issue #981 with dummy data, checking for late start", - 30, // update_every - 1, // multiplier - 1, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 9, // result entries - test14c_feed, // feed - test14c_results, // results - NULL, // feed2 - NULL // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- -// test15 - -struct feed_values test15_feed[] = { - { 0, 1068066388 }, - { 1008752, 1068822698 }, - { 993809, 1069573072 }, - { 995911, 1070324135 }, - { 1014562, 1071078166 }, - { 994684, 1071831349 }, - { 993128, 1072235739 }, - { 1010332, 1072958871 }, - { 1003394, 1073707019 }, - { 995201, 1074460255 }, -}; - -collected_number test15_feed2[] = { - 178825286, 178825286, 178825286, 178825286, 178825498, 178825498, 179165652, 179202964, 179203282, 179204130 -}; - -calculated_number test15_results[] = { - 5857.4080000, 5898.4540000, 5891.6590000, 5806.3160000, 5914.2640000, 3202.2630000, 5589.6560000, 5822.5260000, 5911.7520000 -}; - -calculated_number test15_results2[] = { - 0.0000000, 0.0000000, 0.0024944, 1.6324779, 0.0212777, 2655.1890000, 290.5387000, 5.6733610, 6.5960220 -}; - -struct test test15 = { - "test15", // name - "test incremental with 2 dimensions", - 1, // update_every - 8, // multiplier - 1024, // divisor - RRD_ALGORITHM_INCREMENTAL, // algorithm - 10, // feed entries - 9, // result entries - test15_feed, // feed - test15_results, // results - test15_feed2, // feed2 - test15_results2 // results2 -}; - -// -------------------------------------------------------------------------------------------------------------------- - -int run_test(struct test *test) -{ - fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description); - - default_rrd_memory_mode = RRD_MEMORY_MODE_ALLOC; - default_rrd_update_every = test->update_every; - - char name[101]; - snprintfz(name, 100, "unittest-%s", test->name); - - // create the chart - RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", "unittest", NULL, 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); - - rrdset_flag_set(st, RRDSET_FLAG_DEBUG); - - // feed it with the test data - time_t time_now = 0, time_start = now_realtime_sec(); - unsigned long c; - collected_number last = 0; - for(c = 0; c < test->feed_entries; c++) { - if(debug_flags) fprintf(stderr, "\n\n"); - - if(c) { - time_now += test->feed[c].microseconds; - fprintf(stderr, " > %s: feeding position %lu, after %0.3f seconds (%0.3f seconds from start), delta " CALCULATED_NUMBER_FORMAT ", rate " CALCULATED_NUMBER_FORMAT "\n", - test->name, c+1, - (float)test->feed[c].microseconds / 1000000.0, - (float)time_now / 1000000.0, - ((calculated_number)test->feed[c].value - (calculated_number)last) * (calculated_number)test->multiplier / (calculated_number)test->divisor, - (((calculated_number)test->feed[c].value - (calculated_number)last) * (calculated_number)test->multiplier / (calculated_number)test->divisor) / (calculated_number)test->feed[c].microseconds * (calculated_number)1000000); - - // rrdset_next_usec_unfiltered(st, test->feed[c].microseconds); - st->usec_since_last_update = test->feed[c].microseconds; - } - else { - fprintf(stderr, " > %s: feeding position %lu\n", test->name, c+1); - } - - fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value); - rrddim_set(st, "dim1", test->feed[c].value); - last = test->feed[c].value; - - if(rd2) { - fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]); - rrddim_set(st, "dim2", test->feed2[c]); - } - - rrdset_done(st); - - // align the first entry to second boundary - if(!c) { - fprintf(stderr, " > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds); - rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds; - // time_start = st->last_collected_time.tv_sec; - } - } - - // check the result - int errors = 0; - - if(st->counter != test->result_entries) { - fprintf(stderr, " %s stored %zu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries); - errors++; - } - - unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries; - for(c = 0 ; c < max ; c++) { - calculated_number v = unpack_storage_number(rd->values[c]); - calculated_number n = test->results[c]; - int same = (calculated_number_round(v * 10000000.0) == calculated_number_round(n * 10000000.0))?1:0; - fprintf(stderr, " %s/%s: checking position %lu (at %lu secs), expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", - test->name, rd->name, c+1, - (rrdset_first_entry_t(st) + c * st->update_every) - time_start, - n, v, (same)?"OK":"### E R R O R ###"); - - if(!same) errors++; - - if(rd2) { - v = unpack_storage_number(rd2->values[c]); - n = test->results2[c]; - same = (calculated_number_round(v * 10000000.0) == calculated_number_round(n * 10000000.0))?1:0; - fprintf(stderr, " %s/%s: checking position %lu (at %lu secs), expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", - test->name, rd2->name, c+1, - (rrdset_first_entry_t(st) + c * st->update_every) - time_start, - n, v, (same)?"OK":"### E R R O R ###"); - if(!same) errors++; - } - } - - return errors; -} - -static int test_variable_renames(void) { - fprintf(stderr, "Creating chart\n"); - RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", "unittest", NULL, 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, 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, RRD_ALGORITHM_INCREMENTAL); - fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd2->id, rd2->name); - - fprintf(stderr, "Renaming chart to CHARTNAME1\n"); - rrdset_set_name(st, "CHARTNAME1"); - fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", st->id, st->name); - - fprintf(stderr, "Renaming chart to CHARTNAME2\n"); - rrdset_set_name(st, "CHARTNAME2"); - fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", st->id, st->name); - - fprintf(stderr, "Renaming dimension DIM1 to DIM1NAME1\n"); - rrddim_set_name(st, rd1, "DIM1NAME1"); - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd1->id, rd1->name); - - fprintf(stderr, "Renaming dimension DIM1 to DIM1NAME2\n"); - rrddim_set_name(st, rd1, "DIM1NAME2"); - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd1->id, rd1->name); - - fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME1\n"); - rrddim_set_name(st, rd2, "DIM2NAME1"); - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name); - - fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME2\n"); - rrddim_set_name(st, rd2, "DIM2NAME2"); - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name); - - BUFFER *buf = buffer_create(1); - health_api_v1_chart_variables2json(st, buf); - fprintf(stderr, "%s", buffer_tostring(buf)); - buffer_free(buf); - return 1; -} - -int run_all_mockup_tests(void) -{ - if(check_number_printing()) - return 1; - - if(check_rrdcalc_comparisons()) - return 1; - - if(!test_variable_renames()) - return 1; - - if(run_test(&test1)) - return 1; - - if(run_test(&test2)) - return 1; - - if(run_test(&test3)) - return 1; - - if(run_test(&test4)) - return 1; - - if(run_test(&test5)) - return 1; - - if(run_test(&test6)) - return 1; - - if(run_test(&test7)) - return 1; - - if(run_test(&test8)) - return 1; - - if(run_test(&test9)) - return 1; - - if(run_test(&test10)) - return 1; - - if(run_test(&test11)) - return 1; - - if(run_test(&test12)) - return 1; - - if(run_test(&test13)) - return 1; - - if(run_test(&test14)) - return 1; - - if(run_test(&test14b)) - return 1; - - if(run_test(&test14c)) - return 1; - - if(run_test(&test15)) - return 1; - - - - return 0; -} - -int unit_test(long delay, long shift) -{ - static int repeat = 0; - repeat++; - - char name[101]; - snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift); - - //debug_flags = 0xffffffff; - default_rrd_memory_mode = RRD_MEMORY_MODE_ALLOC; - 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_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", "unittest", NULL, 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, 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; - - unsigned long c, dimensions = 0; - RRDDIM *rd; - for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++; - - for(c = 0; c < 20 ;c++) { - i += increment; - - fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i); - if(c) { - // rrdset_next_usec_unfiltered(st, delay); - st->usec_since_last_update = delay; - } - if(do_abs) rrddim_set(st, "absolute", i); - if(do_inc) rrddim_set(st, "incremental", i); - if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i); - if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i); - - if(!c) { - now_realtime_timeval(&st->last_collected_time); - st->last_collected_time.tv_usec = shift; - } - - // prevent it from deleting the dimensions - for(rd = st->dimensions ; rd ; rd = rd->next) - rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec; - - rrdset_done(st); - } - - unsigned long oincrement = increment; - increment = increment * st->update_every * 1000000 / delay; - fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %ld, DELAY %ld, SHIFT %ld\n", oincrement * 10, increment * 10, delay, shift); - - int ret = 0; - storage_number sn; - calculated_number cn, v; - for(c = 0 ; c < st->counter ; c++) { - fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10); - - for(rd = st->dimensions ; rd ; rd = rd->next) { - sn = rd->values[c]; - cn = unpack_storage_number(sn); - fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ") -> ", rd->id, cn, sn); - - if(rd == rdabs) v = - ( oincrement - // + (increment * (1000000 - shift) / 1000000) - + (c + 1) * increment - ); - - else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000)); - else if(rd == rdabst) v = oincrement / dimensions / 10; - else if(rd == rdabsi) v = oincrement / dimensions / 10; - else v = 0; - - if(v == cn) fprintf(stderr, "passed.\n"); - else { - fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v); - ret = 1; - } - } - } - - if(ret) - fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift); - - return ret; -} diff --git a/src/unit_test.h b/src/unit_test.h deleted file mode 100644 index 68ed61fcb..000000000 --- a/src/unit_test.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NETDATA_UNIT_TEST_H -#define NETDATA_UNIT_TEST_H 1 - -extern int unit_test_storage(void); -extern int unit_test(long delay, long shift); -extern int run_all_mockup_tests(void); -extern int unit_test_str2ld(void); -extern int unit_test_buffer(void); - -#endif /* NETDATA_UNIT_TEST_H */ diff --git a/src/url.c b/src/url.c deleted file mode 100644 index 6be4d9648..000000000 --- a/src/url.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "common.h" - -// ---------------------------------------------------------------------------- -// URL encode / decode -// code from: http://www.geekhideout.com/urlcode.shtml - -/* Converts a hex character to its integer value */ -char from_hex(char ch) { - return (char)(isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10); -} - -/* Converts an integer value to its hex character*/ -char to_hex(char code) { - static char hex[] = "0123456789abcdef"; - return hex[code & 15]; -} - -/* Returns a url-encoded version of str */ -/* IMPORTANT: be sure to free() the returned string after use */ -char *url_encode(char *str) { - char *buf, *pbuf; - - pbuf = buf = mallocz(strlen(str) * 3 + 1); - - while (*str) { - if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~') - *pbuf++ = *str; - - else if (*str == ' ') - *pbuf++ = '+'; - - else - *pbuf++ = '%', *pbuf++ = to_hex(*str >> 4), *pbuf++ = to_hex(*str & 15); - - str++; - } - *pbuf = '\0'; - - pbuf = strdupz(buf); - freez(buf); - return pbuf; -} - -/* Returns a url-decoded version of str */ -/* IMPORTANT: be sure to free() the returned string after use */ -char *url_decode(char *str) { - size_t size = strlen(str) + 1; - - char *buf = mallocz(size); - return url_decode_r(buf, str, size); -} - -char *url_decode_r(char *to, char *url, size_t size) { - char *s = url, // source - *d = to, // destination - *e = &to[size - 1]; // destination end - - while(*s && d < e) { - if(unlikely(*s == '%')) { - if(likely(s[1] && s[2])) { - *d++ = from_hex(s[1]) << 4 | from_hex(s[2]); - s += 2; - } - } - else if(unlikely(*s == '+')) - *d++ = ' '; - - else - *d++ = *s; - - s++; - } - - *d = '\0'; - - return to; -} diff --git a/src/url.h b/src/url.h deleted file mode 100644 index fa44d49a8..000000000 --- a/src/url.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef NETDATA_URL_H -#define NETDATA_URL_H 1 - -// ---------------------------------------------------------------------------- -// URL encode / decode -// code from: http://www.geekhideout.com/urlcode.shtml - -/* Converts a hex character to its integer value */ -extern char from_hex(char ch); - -/* Converts an integer value to its hex character*/ -extern char to_hex(char code); - -/* Returns a url-encoded version of str */ -/* IMPORTANT: be sure to free() the returned string after use */ -extern char *url_encode(char *str); - -/* Returns a url-decoded version of str */ -/* IMPORTANT: be sure to free() the returned string after use */ -extern char *url_decode(char *str); - -extern char *url_decode_r(char *to, char *url, size_t size); - -#endif /* NETDATA_URL_H */ diff --git a/src/web_api_old.c b/src/web_api_old.c deleted file mode 100644 index 373e7e9f8..000000000 --- a/src/web_api_old.c +++ /dev/null @@ -1,237 +0,0 @@ -#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 deleted file mode 100644 index dff48c2f3..000000000 --- a/src/web_api_old.h +++ /dev/null @@ -1,13 +0,0 @@ -#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 deleted file mode 100644 index c32660c81..000000000 --- a/src/web_api_v1.c +++ /dev/null @@ -1,1017 +0,0 @@ -#include "common.h" - -static struct { - const char *name; - uint32_t hash; - int value; -} api_v1_data_groups[] = { - { "average" , 0 , GROUP_AVERAGE} - , {"min" , 0 , GROUP_MIN} - , {"max" , 0 , GROUP_MAX} - , {"sum" , 0 , GROUP_SUM} - , {"incremental_sum", 0 , GROUP_INCREMENTAL_SUM} - , {"incremental-sum", 0 , GROUP_INCREMENTAL_SUM} - , { NULL, 0, 0} -}; - -static struct { - const char *name; - uint32_t hash; - uint32_t value; -} api_v1_data_options[] = { - { "nonzero" , 0 , RRDR_OPTION_NONZERO} - , {"flip" , 0 , RRDR_OPTION_REVERSED} - , {"reversed" , 0 , RRDR_OPTION_REVERSED} - , {"reverse" , 0 , RRDR_OPTION_REVERSED} - , {"jsonwrap" , 0 , RRDR_OPTION_JSON_WRAP} - , {"min2max" , 0 , RRDR_OPTION_MIN2MAX} - , {"ms" , 0 , RRDR_OPTION_MILLISECONDS} - , {"milliseconds" , 0 , RRDR_OPTION_MILLISECONDS} - , {"abs" , 0 , RRDR_OPTION_ABSOLUTE} - , {"absolute" , 0 , RRDR_OPTION_ABSOLUTE} - , {"absolute_sum" , 0 , RRDR_OPTION_ABSOLUTE} - , {"absolute-sum" , 0 , RRDR_OPTION_ABSOLUTE} - , {"display_absolute", 0 , RRDR_OPTION_DISPLAY_ABS} - , {"display-absolute", 0 , RRDR_OPTION_DISPLAY_ABS} - , {"seconds" , 0 , RRDR_OPTION_SECONDS} - , {"null2zero" , 0 , RRDR_OPTION_NULL2ZERO} - , {"objectrows" , 0 , RRDR_OPTION_OBJECTSROWS} - , {"google_json" , 0 , RRDR_OPTION_GOOGLE_JSON} - , {"google-json" , 0 , RRDR_OPTION_GOOGLE_JSON} - , {"percentage" , 0 , RRDR_OPTION_PERCENTAGE} - , {"unaligned" , 0 , RRDR_OPTION_NOT_ALIGNED} - , {"match_ids" , 0 , RRDR_OPTION_MATCH_IDS} - , {"match-ids" , 0 , RRDR_OPTION_MATCH_IDS} - , {"match_names" , 0 , RRDR_OPTION_MATCH_NAMES} - , {"match-names" , 0 , RRDR_OPTION_MATCH_NAMES} - , { NULL, 0, 0} -}; - -static struct { - const char *name; - uint32_t hash; - uint32_t value; -} api_v1_data_formats[] = { - { DATASOURCE_FORMAT_DATATABLE_JSON , 0 , DATASOURCE_DATATABLE_JSON} - , {DATASOURCE_FORMAT_DATATABLE_JSONP, 0 , DATASOURCE_DATATABLE_JSONP} - , {DATASOURCE_FORMAT_JSON , 0 , DATASOURCE_JSON} - , {DATASOURCE_FORMAT_JSONP , 0 , DATASOURCE_JSONP} - , {DATASOURCE_FORMAT_SSV , 0 , DATASOURCE_SSV} - , {DATASOURCE_FORMAT_CSV , 0 , DATASOURCE_CSV} - , {DATASOURCE_FORMAT_TSV , 0 , DATASOURCE_TSV} - , {"tsv-excel" , 0 , DATASOURCE_TSV} - , {DATASOURCE_FORMAT_HTML , 0 , DATASOURCE_HTML} - , {DATASOURCE_FORMAT_JS_ARRAY , 0 , DATASOURCE_JS_ARRAY} - , {DATASOURCE_FORMAT_SSV_COMMA , 0 , DATASOURCE_SSV_COMMA} - , {DATASOURCE_FORMAT_CSV_JSON_ARRAY , 0 , DATASOURCE_CSV_JSON_ARRAY} - , { NULL, 0, 0} -}; - -static struct { - const char *name; - uint32_t hash; - uint32_t value; -} api_v1_data_google_formats[] = { - // this is not error - when google requests json, it expects javascript - // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source#responseformat - { "json" , 0 , DATASOURCE_DATATABLE_JSONP} - , {"html" , 0 , DATASOURCE_HTML} - , {"csv" , 0 , DATASOURCE_CSV} - , {"tsv-excel", 0 , DATASOURCE_TSV} - , { NULL, 0, 0} -}; - -void web_client_api_v1_init(void) { - int i; - - for(i = 0; api_v1_data_groups[i].name ; i++) - api_v1_data_groups[i].hash = simple_hash(api_v1_data_groups[i].name); - - for(i = 0; api_v1_data_options[i].name ; i++) - api_v1_data_options[i].hash = simple_hash(api_v1_data_options[i].name); - - for(i = 0; api_v1_data_formats[i].name ; i++) - api_v1_data_formats[i].hash = simple_hash(api_v1_data_formats[i].name); - - for(i = 0; api_v1_data_google_formats[i].name ; i++) - api_v1_data_google_formats[i].hash = simple_hash(api_v1_data_google_formats[i].name); -} - -inline int web_client_api_request_v1_data_group(char *name, int def) { - int i; - - uint32_t hash = simple_hash(name); - for(i = 0; api_v1_data_groups[i].name ; i++) - if(unlikely(hash == api_v1_data_groups[i].hash && !strcmp(name, api_v1_data_groups[i].name))) - return api_v1_data_groups[i].value; - - 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; - - uint32_t hash = simple_hash(tok); - int i; - for(i = 0; api_v1_data_options[i].name ; i++) { - if (unlikely(hash == api_v1_data_options[i].hash && !strcmp(tok, api_v1_data_options[i].name))) { - ret |= api_v1_data_options[i].value; - break; - } - } - } - - return ret; -} - -inline uint32_t web_client_api_request_v1_data_format(char *name) { - uint32_t hash = simple_hash(name); - int i; - - for(i = 0; api_v1_data_formats[i].name ; i++) { - if (unlikely(hash == api_v1_data_formats[i].hash && !strcmp(name, api_v1_data_formats[i].name))) { - return api_v1_data_formats[i].value; - } - } - - return DATASOURCE_JSON; -} - -inline uint32_t web_client_api_request_v1_data_google_format(char *name) { - uint32_t hash = simple_hash(name); - int i; - - for(i = 0; api_v1_data_google_formats[i].name ; i++) { - if (unlikely(hash == api_v1_data_google_formats[i].hash && !strcmp(name, api_v1_data_google_formats[i].name))) { - return api_v1_data_google_formats[i].value; - } - } - - 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; - int help = 0, types = 0, timestamps = 1, names = backend_send_names; // prometheus options - const char *prometheus_server = w->client_ip; - uint32_t prometheus_options = backend_options; - const char *prometheus_prefix = backend_prefix; - - 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_PROMETHEUS_ALL_HOSTS)) - format = ALLMETRICS_PROMETHEUS_ALL_HOSTS; - else if(!strcmp(value, ALLMETRICS_FORMAT_JSON)) - format = ALLMETRICS_JSON; - else - format = 0; - } - else if(!strcmp(name, "help")) { - if(!strcmp(value, "yes")) - help = 1; - else - help = 0; - } - else if(!strcmp(name, "types")) { - if(!strcmp(value, "yes")) - types = 1; - else - types = 0; - } - else if(!strcmp(name, "names")) { - if(!strcmp(value, "yes")) - names = 1; - else - names = 0; - } - else if(!strcmp(name, "timestamps")) { - if(!strcmp(value, "yes")) - timestamps = 1; - else - timestamps = 0; - } - else if(!strcmp(name, "server")) { - prometheus_server = value; - } - else if(!strcmp(name, "prefix")) { - prometheus_prefix = value; - } - else if(!strcmp(name, "data") || !strcmp(name, "source") || !strcmp(name, "data source") || !strcmp(name, "data-source") || !strcmp(name, "data_source") || !strcmp(name, "datasource")) { - prometheus_options = backend_parse_data_source(value, prometheus_options); - } - } - - 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_single_host(host, w->response.data, prometheus_server, prometheus_prefix, prometheus_options, help, types, names, timestamps); - return 200; - - case ALLMETRICS_PROMETHEUS_ALL_HOSTS: - w->response.data->contenttype = CT_PROMETHEUS; - rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(host, w->response.data, prometheus_server, prometheus_prefix, prometheus_options, help, types, names, timestamps); - return 200; - - default: - w->response.data->contenttype = CT_TEXT_PLAIN; - buffer_strcat(w->response.data, "Which format? '" ALLMETRICS_FORMAT_SHELL "', '" ALLMETRICS_FORMAT_PROMETHEUS "', '" ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS "' 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 - , *scale_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, "scale")) scale_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; - } - - int scale = (scale_str && *scale_str)?str2i(scale_str):100; - - 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, scale, 0); - 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, scale, 0); - 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, - scale, - options - ); - 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, 0, 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, - scale, - options - ); - } - - 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 - , *group_time_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, "gtime")) group_time_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; - long group_time = (group_time_str && *group_time_str)?str2l(group_time_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, group_time - , 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(unlikely(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w))) { - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work."); - return 400; - } - - if(unlikely(action == 'H')) { - // HELLO request, dashboard ACL - if(unlikely(!web_client_can_access_dashboard(w))) - return web_client_permission_denied(w); - } - else { - // everything else, registry ACL - if(unlikely(!web_client_can_access_registry(w))) - return web_client_permission_denied(w); - } - - switch(action) { - case 'A': - if(unlikely(!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; - } - - web_client_enable_tracking_required(w); - return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec()); - - case 'D': - if(unlikely(!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; - } - - web_client_enable_tracking_required(w); - return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec()); - - case 'S': - if(unlikely(!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; - } - - web_client_enable_tracking_required(w); - return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec()); - - case 'W': - if(unlikely(!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; - } - - web_client_enable_tracking_required(w); - return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec()); - - case 'H': - 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; - } -} - -static struct api_command { - const char *command; - uint32_t hash; - WEB_CLIENT_ACL acl; - int (*callback)(RRDHOST *host, struct web_client *w, char *url); -} api_commands[] = { - { "data", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_data }, - { "chart", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_chart }, - { "charts", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_charts }, - - // registry checks the ACL by itself, so we allow everything - { "registry", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v1_registry }, - - // badges can be fetched with both dashboard and badge permissions - { "badge.svg", 0, WEB_CLIENT_ACL_DASHBOARD|WEB_CLIENT_ACL_BADGE, web_client_api_request_v1_badge }, - - { "alarms", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_alarms }, - { "alarm_log", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_alarm_log }, - { "alarm_variables", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_alarm_variables }, - { "allmetrics", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_allmetrics }, - - // terminator - { NULL, 0, WEB_CLIENT_ACL_NONE, NULL }, -}; - -inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) { - static int initialized = 0; - int i; - - if(unlikely(initialized == 0)) { - initialized = 1; - - for(i = 0; api_commands[i].command ; i++) - api_commands[i].hash = simple_hash(api_commands[i].command); - } - - // 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); - - for(i = 0; api_commands[i].command ;i++) { - if(unlikely(hash == api_commands[i].hash && !strcmp(tok, api_commands[i].command))) { - if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl)) - return web_client_permission_denied(w); - - return api_commands[i].callback(host, w, url); - } - } - - 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 deleted file mode 100644 index 6f4de1aba..000000000 --- a/src/web_api_v1.h +++ /dev/null @@ -1,23 +0,0 @@ -#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); - -extern void web_client_api_v1_init(void); - -#endif //NETDATA_WEB_API_V1_H diff --git a/src/web_buffer.c b/src/web_buffer.c deleted file mode 100644 index 50c76f6d6..000000000 --- a/src/web_buffer.c +++ /dev/null @@ -1,400 +0,0 @@ -#include "common.h" - -#define BUFFER_OVERFLOW_EOF "EOF" - -static inline void buffer_overflow_init(BUFFER *b) -{ - b->buffer[b->size] = '\0'; - strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF); -} - -#ifdef NETDATA_INTERNAL_CHECKS -#define buffer_overflow_check(b) _buffer_overflow_check(b, __FILE__, __FUNCTION__, __LINE__) -#else -#define buffer_overflow_check(b) -#endif - -static inline void _buffer_overflow_check(BUFFER *b, const char *file, const char *function, const unsigned long line) -{ - if(b->len > b->size) { - error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file); - b->len = b->size; - } - - if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0) { - error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file); - buffer_overflow_init(b); - } -} - - -void buffer_reset(BUFFER *wb) -{ - buffer_flush(wb); - - wb->contenttype = CT_TEXT_PLAIN; - wb->options = 0; - wb->date = 0; - wb->expires = 0; - - buffer_overflow_check(wb); -} - -const char *buffer_tostring(BUFFER *wb) -{ - buffer_need_bytes(wb, 1); - wb->buffer[wb->len] = '\0'; - - buffer_overflow_check(wb); - - return(wb->buffer); -} - -void buffer_char_replace(BUFFER *wb, char from, char to) -{ - char *s = wb->buffer, *end = &wb->buffer[wb->len]; - - while(s != end) { - if(*s == from) *s = to; - s++; - } - - buffer_overflow_check(wb); -} - -// This trick seems to give an 80% speed increase in 32bit systems -// print_calculated_number_llu_r() will just print the digits up to the -// point the remaining value fits in 32 bits, and then calls -// print_calculated_number_lu_r() to print the rest with 32 bit arithmetic. - -inline char *print_number_lu_r(char *str, unsigned long uvalue) { - char *wstr = str; - - // print each digit - do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10); - return wstr; -} - -inline char *print_number_llu_r(char *str, unsigned long long uvalue) { - char *wstr = str; - - // print each digit - do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff); - if(uvalue) return print_number_lu_r(wstr, uvalue); - return wstr; -} - -inline char *print_number_llu_r_smart(char *str, unsigned long long uvalue) { -#ifdef ENVIRONMENT32 - if(uvalue > (unsigned long long)0xffffffff) - str = print_number_llu_r(str, uvalue); - else - str = print_number_lu_r(str, uvalue); -#else - do *str++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10); -#endif - - return str; -} - -void buffer_print_llu(BUFFER *wb, unsigned long long uvalue) -{ - buffer_need_bytes(wb, 50); - - char *str = &wb->buffer[wb->len]; - char *wstr = str; - -#ifdef ENVIRONMENT32 - if(uvalue > (unsigned long long)0xffffffff) - wstr = print_number_llu_r(wstr, uvalue); - else - wstr = print_number_lu_r(wstr, uvalue); -#else - do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10); -#endif - - // terminate it - *wstr = '\0'; - - // reverse it - char *begin = str, *end = wstr - 1, aux; - while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux; - - // return the buffer length - wb->len += wstr - str; -} - -void buffer_strcat(BUFFER *wb, const char *txt) -{ - // buffer_sprintf(wb, "%s", txt); - - if(unlikely(!txt || !*txt)) return; - - buffer_need_bytes(wb, 1); - - char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size]; - size_t len = wb->len; - - start = s; - while(*txt && s != end) - *s++ = *txt++; - - len += s - start; - - wb->len = len; - buffer_overflow_check(wb); - - if(*txt) { - debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size); - len = strlen(txt); - buffer_increase(wb, len); - buffer_strcat(wb, txt); - } - else { - // terminate the string - // without increasing the length - buffer_need_bytes(wb, (size_t)1); - wb->buffer[wb->len] = '\0'; - } -} - -void buffer_strcat_htmlescape(BUFFER *wb, const char *txt) -{ - while(*txt) { - switch(*txt) { - case '&': buffer_strcat(wb, "&"); break; - case '<': buffer_strcat(wb, "<"); break; - case '>': buffer_strcat(wb, ">"); break; - case '"': buffer_strcat(wb, """); break; - case '/': buffer_strcat(wb, "/"); break; - case '\'': buffer_strcat(wb, "'"); break; - default: { - buffer_need_bytes(wb, 1); - wb->buffer[wb->len++] = *txt; - } - } - txt++; - } - - buffer_overflow_check(wb); -} - -void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) -{ - if(unlikely(!fmt || !*fmt)) return; - - buffer_need_bytes(wb, len + 1); - - va_list args; - va_start(args, fmt); - wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args); - va_end(args); - - buffer_overflow_check(wb); - - // the buffer is \0 terminated by vsnprintfz -} - -void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args) -{ - if(unlikely(!fmt || !*fmt)) return; - - buffer_need_bytes(wb, 2); - - size_t len = wb->size - wb->len - 1; - - wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args); - - buffer_overflow_check(wb); - - // the buffer is \0 terminated by vsnprintfz -} - -void buffer_sprintf(BUFFER *wb, const char *fmt, ...) -{ - if(unlikely(!fmt || !*fmt)) return; - - va_list args; - size_t wrote = 0, need = 2, multiplier = 0, len; - - do { - need += wrote + multiplier * WEB_DATA_LENGTH_INCREASE_STEP; - multiplier++; - - debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu, by %zu bytes (wrote = %zu)\n", wb->len, wb->size, need, wrote); - buffer_need_bytes(wb, need); - - len = wb->size - wb->len - 1; - - va_start(args, fmt); - wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args); - va_end(args); - - } while(wrote >= len); - - wb->len += wrote; - - // the buffer is \0 terminated by vsnprintf -} - - -void buffer_rrd_value(BUFFER *wb, calculated_number value) -{ - buffer_need_bytes(wb, 50); - - if(isnan(value) || isinf(value)) { - buffer_strcat(wb, "null"); - return; - } - else - wb->len += print_calculated_number(&wb->buffer[wb->len], value); - - // terminate it - buffer_need_bytes(wb, 1); - wb->buffer[wb->len] = '\0'; - - buffer_overflow_check(wb); -} - -// generate a javascript date, the fastest possible way... -void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds) -{ - // 10 20 30 = 35 - // 01234567890123456789012345678901234 - // Date(2014,04,01,03,28,20) - - buffer_need_bytes(wb, 30); - - char *b = &wb->buffer[wb->len], *p; - unsigned int *q = (unsigned int *)b; - - #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - *q++ = 0x65746144; // "Date" backwards. - #else - *q++ = 0x44617465; // "Date" - #endif - p = (char *)q; - - *p++ = '('; - *p++ = '0' + year / 1000; year %= 1000; - *p++ = '0' + year / 100; year %= 100; - *p++ = '0' + year / 10; - *p++ = '0' + year % 10; - *p++ = ','; - *p = '0' + month / 10; if (*p != '0') p++; - *p++ = '0' + month % 10; - *p++ = ','; - *p = '0' + day / 10; if (*p != '0') p++; - *p++ = '0' + day % 10; - *p++ = ','; - *p = '0' + hours / 10; if (*p != '0') p++; - *p++ = '0' + hours % 10; - *p++ = ','; - *p = '0' + minutes / 10; if (*p != '0') p++; - *p++ = '0' + minutes % 10; - *p++ = ','; - *p = '0' + seconds / 10; if (*p != '0') p++; - *p++ = '0' + seconds % 10; - - unsigned short *r = (unsigned short *)p; - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - *r++ = 0x0029; // ")\0" backwards. - #else - *r++ = 0x2900; // ")\0" - #endif - - wb->len += (size_t)((char *)r - b - 1); - - // terminate it - wb->buffer[wb->len] = '\0'; - buffer_overflow_check(wb); -} - -// generate a date, the fastest possible way... -void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds) -{ - // 10 20 30 = 35 - // 01234567890123456789012345678901234 - // 2014-04-01 03:28:20 - - buffer_need_bytes(wb, 36); - - char *b = &wb->buffer[wb->len]; - char *p = b; - - *p++ = '0' + year / 1000; year %= 1000; - *p++ = '0' + year / 100; year %= 100; - *p++ = '0' + year / 10; - *p++ = '0' + year % 10; - *p++ = '-'; - *p++ = '0' + month / 10; - *p++ = '0' + month % 10; - *p++ = '-'; - *p++ = '0' + day / 10; - *p++ = '0' + day % 10; - *p++ = ' '; - *p++ = '0' + hours / 10; - *p++ = '0' + hours % 10; - *p++ = ':'; - *p++ = '0' + minutes / 10; - *p++ = '0' + minutes % 10; - *p++ = ':'; - *p++ = '0' + seconds / 10; - *p++ = '0' + seconds % 10; - *p = '\0'; - - wb->len += (size_t)(p - b); - - // terminate it - wb->buffer[wb->len] = '\0'; - buffer_overflow_check(wb); -} - -BUFFER *buffer_create(size_t size) -{ - BUFFER *b; - - debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size); - - b = callocz(1, sizeof(BUFFER)); - b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2); - b->buffer[0] = '\0'; - b->size = size; - b->contenttype = CT_TEXT_PLAIN; - buffer_overflow_init(b); - buffer_overflow_check(b); - - return(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); - - freez(b->buffer); - freez(b); -} - -void buffer_increase(BUFFER *b, size_t free_size_required) -{ - buffer_overflow_check(b); - - size_t left = b->size - b->len; - - if(left >= free_size_required) return; - - size_t increase = free_size_required - left; - if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP; - - debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase); - - b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2); - b->size += increase; - - buffer_overflow_init(b); - buffer_overflow_check(b); -} diff --git a/src/web_buffer.h b/src/web_buffer.h deleted file mode 100644 index 694c9d4ce..000000000 --- a/src/web_buffer.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef NETDATA_WEB_BUFFER_H -#define NETDATA_WEB_BUFFER_H 1 - -#define WEB_DATA_LENGTH_INCREASE_STEP 1024 - -typedef struct web_buffer { - size_t size; // allocation size of buffer, in bytes - size_t len; // current data length in buffer, in bytes - char *buffer; // the buffer itself - uint8_t contenttype; // the content type of the data in the buffer - uint8_t options; // options related to the content - time_t date; // the timestamp this content has been generated - time_t expires; // the timestamp this content expires -} BUFFER; - -// options -#define WB_CONTENT_CACHEABLE 1 -#define WB_CONTENT_NO_CACHEABLE 2 - -// content-types -#define CT_APPLICATION_JSON 1 -#define CT_TEXT_PLAIN 2 -#define CT_TEXT_HTML 3 -#define CT_APPLICATION_X_JAVASCRIPT 4 -#define CT_TEXT_CSS 5 -#define CT_TEXT_XML 6 -#define CT_APPLICATION_XML 7 -#define CT_TEXT_XSL 8 -#define CT_APPLICATION_OCTET_STREAM 9 -#define CT_APPLICATION_X_FONT_TRUETYPE 10 -#define CT_APPLICATION_X_FONT_OPENTYPE 11 -#define CT_APPLICATION_FONT_WOFF 12 -#define CT_APPLICATION_FONT_WOFF2 13 -#define CT_APPLICATION_VND_MS_FONTOBJ 14 -#define CT_IMAGE_SVG_XML 15 -#define CT_IMAGE_PNG 16 -#define CT_IMAGE_JPG 17 -#define CT_IMAGE_GIF 18 -#define CT_IMAGE_XICON 19 -#define CT_IMAGE_ICNS 20 -#define CT_IMAGE_BMP 21 -#define CT_PROMETHEUS 22 - -#define buffer_cacheable(wb) do { (wb)->options |= WB_CONTENT_CACHEABLE; if((wb)->options & WB_CONTENT_NO_CACHEABLE) (wb)->options &= ~WB_CONTENT_NO_CACHEABLE; } while(0) -#define buffer_no_cacheable(wb) do { (wb)->options |= WB_CONTENT_NO_CACHEABLE; if((wb)->options & WB_CONTENT_CACHEABLE) (wb)->options &= ~WB_CONTENT_CACHEABLE; (wb)->expires = 0; } while(0) - -#define buffer_strlen(wb) ((wb)->len) -extern const char *buffer_tostring(BUFFER *wb); - -#define buffer_flush(wb) wb->buffer[(wb)->len = 0] = '\0' -extern void buffer_reset(BUFFER *wb); - -extern void buffer_strcat(BUFFER *wb, const char *txt); -extern void buffer_rrd_value(BUFFER *wb, calculated_number value); - -extern void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds); -extern void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds); - -extern BUFFER *buffer_create(size_t size); -extern void buffer_free(BUFFER *b); -extern void buffer_increase(BUFFER *b, size_t free_size_required); - -extern void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) PRINTFLIKE(3, 4); -extern void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args); -extern void buffer_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3); -extern void buffer_strcat_htmlescape(BUFFER *wb, const char *txt); - -extern void buffer_char_replace(BUFFER *wb, char from, char to); - -extern char *print_number_lu_r(char *str, unsigned long uvalue); -extern char *print_number_llu_r(char *str, unsigned long long uvalue); -extern char *print_number_llu_r_smart(char *str, unsigned long long uvalue); - -extern void buffer_print_llu(BUFFER *wb, unsigned long long uvalue); - -static inline void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) { - if(unlikely(buffer->size - buffer->len < needed_free_size)) - buffer_increase(buffer, needed_free_size); -} - -#endif /* NETDATA_WEB_BUFFER_H */ diff --git a/src/web_buffer_svg.c b/src/web_buffer_svg.c deleted file mode 100644 index c05e526ed..000000000 --- a/src/web_buffer_svg.c +++ /dev/null @@ -1,832 +0,0 @@ -#include "common.h" - -#define BADGE_HORIZONTAL_PADDING 4 -#define VERDANA_KERNING 0.2 -#define VERDANA_PADDING 1.0 - -/* - * verdana11_widths[] has been generated with this method: - * https://github.com/badges/shields/blob/master/measure-text.js -*/ - -double verdana11_widths[256] = { - [0] = 0.0, - [1] = 0.0, - [2] = 0.0, - [3] = 0.0, - [4] = 0.0, - [5] = 0.0, - [6] = 0.0, - [7] = 0.0, - [8] = 0.0, - [9] = 0.0, - [10] = 0.0, - [11] = 0.0, - [12] = 0.0, - [13] = 0.0, - [14] = 0.0, - [15] = 0.0, - [16] = 0.0, - [17] = 0.0, - [18] = 0.0, - [19] = 0.0, - [20] = 0.0, - [21] = 0.0, - [22] = 0.0, - [23] = 0.0, - [24] = 0.0, - [25] = 0.0, - [26] = 0.0, - [27] = 0.0, - [28] = 0.0, - [29] = 0.0, - [30] = 0.0, - [31] = 0.0, - [32] = 3.8671874999999996, // - [33] = 4.3291015625, // ! - [34] = 5.048828125, // " - [35] = 9.001953125, // # - [36] = 6.9931640625, // $ - [37] = 11.837890625, // % - [38] = 7.992187499999999, // & - [39] = 2.9541015625, // ' - [40] = 4.9951171875, // ( - [41] = 4.9951171875, // ) - [42] = 6.9931640625, // * - [43] = 9.001953125, // + - [44] = 4.00146484375, // , - [45] = 4.9951171875, // - - [46] = 4.00146484375, // . - [47] = 4.9951171875, // / - [48] = 6.9931640625, // 0 - [49] = 6.9931640625, // 1 - [50] = 6.9931640625, // 2 - [51] = 6.9931640625, // 3 - [52] = 6.9931640625, // 4 - [53] = 6.9931640625, // 5 - [54] = 6.9931640625, // 6 - [55] = 6.9931640625, // 7 - [56] = 6.9931640625, // 8 - [57] = 6.9931640625, // 9 - [58] = 4.9951171875, // : - [59] = 4.9951171875, // ; - [60] = 9.001953125, // < - [61] = 9.001953125, // = - [62] = 9.001953125, // > - [63] = 5.99951171875, // ? - [64] = 11.0, // @ - [65] = 7.51953125, // A - [66] = 7.541015625, // B - [67] = 7.680664062499999, // C - [68] = 8.4755859375, // D - [69] = 6.95556640625, // E - [70] = 6.32177734375, // F - [71] = 8.529296875, // G - [72] = 8.26611328125, // H - [73] = 4.6298828125, // I - [74] = 5.00048828125, // J - [75] = 7.62158203125, // K - [76] = 6.123046875, // L - [77] = 9.2705078125, // M - [78] = 8.228515625, // N - [79] = 8.658203125, // O - [80] = 6.63330078125, // P - [81] = 8.658203125, // Q - [82] = 7.6484375, // R - [83] = 7.51953125, // S - [84] = 6.7783203125, // T - [85] = 8.05126953125, // U - [86] = 7.51953125, // V - [87] = 10.87646484375, // W - [88] = 7.53564453125, // X - [89] = 6.767578125, // Y - [90] = 7.53564453125, // Z - [91] = 4.9951171875, // [ - [92] = 4.9951171875, // backslash - [93] = 4.9951171875, // ] - [94] = 9.001953125, // ^ - [95] = 6.9931640625, // _ - [96] = 6.9931640625, // ` - [97] = 6.6064453125, // a - [98] = 6.853515625, // b - [99] = 5.73095703125, // c - [100] = 6.853515625, // d - [101] = 6.552734375, // e - [102] = 3.8671874999999996, // f - [103] = 6.853515625, // g - [104] = 6.9609375, // h - [105] = 3.0185546875, // i - [106] = 3.78662109375, // j - [107] = 6.509765625, // k - [108] = 3.0185546875, // l - [109] = 10.69921875, // m - [110] = 6.9609375, // n - [111] = 6.67626953125, // o - [112] = 6.853515625, // p - [113] = 6.853515625, // q - [114] = 4.6943359375, // r - [115] = 5.73095703125, // s - [116] = 4.33447265625, // t - [117] = 6.9609375, // u - [118] = 6.509765625, // v - [119] = 9.001953125, // w - [120] = 6.509765625, // x - [121] = 6.509765625, // y - [122] = 5.779296875, // z - [123] = 6.982421875, // { - [124] = 4.9951171875, // | - [125] = 6.982421875, // } - [126] = 9.001953125, // ~ - [127] = 0.0, - [128] = 0.0, - [129] = 0.0, - [130] = 0.0, - [131] = 0.0, - [132] = 0.0, - [133] = 0.0, - [134] = 0.0, - [135] = 0.0, - [136] = 0.0, - [137] = 0.0, - [138] = 0.0, - [139] = 0.0, - [140] = 0.0, - [141] = 0.0, - [142] = 0.0, - [143] = 0.0, - [144] = 0.0, - [145] = 0.0, - [146] = 0.0, - [147] = 0.0, - [148] = 0.0, - [149] = 0.0, - [150] = 0.0, - [151] = 0.0, - [152] = 0.0, - [153] = 0.0, - [154] = 0.0, - [155] = 0.0, - [156] = 0.0, - [157] = 0.0, - [158] = 0.0, - [159] = 0.0, - [160] = 0.0, - [161] = 0.0, - [162] = 0.0, - [163] = 0.0, - [164] = 0.0, - [165] = 0.0, - [166] = 0.0, - [167] = 0.0, - [168] = 0.0, - [169] = 0.0, - [170] = 0.0, - [171] = 0.0, - [172] = 0.0, - [173] = 0.0, - [174] = 0.0, - [175] = 0.0, - [176] = 0.0, - [177] = 0.0, - [178] = 0.0, - [179] = 0.0, - [180] = 0.0, - [181] = 0.0, - [182] = 0.0, - [183] = 0.0, - [184] = 0.0, - [185] = 0.0, - [186] = 0.0, - [187] = 0.0, - [188] = 0.0, - [189] = 0.0, - [190] = 0.0, - [191] = 0.0, - [192] = 0.0, - [193] = 0.0, - [194] = 0.0, - [195] = 0.0, - [196] = 0.0, - [197] = 0.0, - [198] = 0.0, - [199] = 0.0, - [200] = 0.0, - [201] = 0.0, - [202] = 0.0, - [203] = 0.0, - [204] = 0.0, - [205] = 0.0, - [206] = 0.0, - [207] = 0.0, - [208] = 0.0, - [209] = 0.0, - [210] = 0.0, - [211] = 0.0, - [212] = 0.0, - [213] = 0.0, - [214] = 0.0, - [215] = 0.0, - [216] = 0.0, - [217] = 0.0, - [218] = 0.0, - [219] = 0.0, - [220] = 0.0, - [221] = 0.0, - [222] = 0.0, - [223] = 0.0, - [224] = 0.0, - [225] = 0.0, - [226] = 0.0, - [227] = 0.0, - [228] = 0.0, - [229] = 0.0, - [230] = 0.0, - [231] = 0.0, - [232] = 0.0, - [233] = 0.0, - [234] = 0.0, - [235] = 0.0, - [236] = 0.0, - [237] = 0.0, - [238] = 0.0, - [239] = 0.0, - [240] = 0.0, - [241] = 0.0, - [242] = 0.0, - [243] = 0.0, - [244] = 0.0, - [245] = 0.0, - [246] = 0.0, - [247] = 0.0, - [248] = 0.0, - [249] = 0.0, - [250] = 0.0, - [251] = 0.0, - [252] = 0.0, - [253] = 0.0, - [254] = 0.0, - [255] = 0.0 -}; - -// find the width of the string using the verdana 11points font -// re-write the string in place, skiping zero-length characters -static inline double verdana11_width(char *s) { - double w = 0.0; - char *d = s; - - while(*s) { - double t = verdana11_widths[(unsigned char)*s]; - if(t == 0.0) - s++; - else { - w += t + VERDANA_KERNING; - if(d != s) - *d++ = *s++; - else - d = ++s; - } - } - - *d = '\0'; - w -= VERDANA_KERNING; - w += VERDANA_PADDING; - return w; -} - -static inline size_t escape_xmlz(char *dst, const char *src, size_t len) { - size_t i = len; - - // required escapes from - // https://github.com/badges/shields/blob/master/badge.js - while(*src && i) { - switch(*src) { - case '\\': - *dst++ = '/'; - src++; - i--; - break; - - case '&': - if(i > 5) { - strcpy(dst, "&"); - i -= 5; - dst += 5; - src++; - } - else goto cleanup; - break; - - case '<': - if(i > 4) { - strcpy(dst, "<"); - i -= 4; - dst += 4; - src++; - } - else goto cleanup; - break; - - case '>': - if(i > 4) { - strcpy(dst, ">"); - i -= 4; - dst += 4; - src++; - } - else goto cleanup; - break; - - case '"': - if(i > 6) { - strcpy(dst, """); - i -= 6; - dst += 6; - src++; - } - else goto cleanup; - break; - - case '\'': - if(i > 6) { - strcpy(dst, "'"); - i -= 6; - dst += 6; - src++; - } - else goto cleanup; - break; - - default: - i--; - *dst++ = *src++; - break; - } - } - -cleanup: - *dst = '\0'; - return len - i; -} - -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 = calculated_number_fabs(value); - } - - if(isgreaterequal(abs, 1000)) { - len = snprintfz(value_string, value_string_len, "%0.0" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - trim_zeros = 0; - } - else if(isgreaterequal(abs, 10)) len = snprintfz(value_string, value_string_len, "%0.1" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, value_string_len, "%0.2" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.2" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - else if(isgreaterequal(abs, 0.01)) len = snprintfz(value_string, value_string_len, "%0.4" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - else if(isgreaterequal(abs, 0.001)) len = snprintfz(value_string, value_string_len, "%0.5" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - else if(isgreaterequal(abs, 0.0001)) len = snprintfz(value_string, value_string_len, "%0.6" LONG_DOUBLE_MODIFIER, (LONG_DOUBLE) value); - else len = snprintfz(value_string, value_string_len, "%0.7" LONG_DOUBLE_MODIFIER, (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.*" LONG_DOUBLE_MODIFIER "%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) { - // colors from: - // https://github.com/badges/shields/blob/master/colorscheme.json - if(!strcmp(color, "brightgreen")) return "#4c1"; - else if(!strcmp(color, "green")) return "#97CA00"; - else if(!strcmp(color, "yellow")) return "#dfb317"; - else if(!strcmp(color, "yellowgreen")) return "#a4a61d"; - else if(!strcmp(color, "orange")) return "#fe7d37"; - else if(!strcmp(color, "red")) return "#e05d44"; - else if(!strcmp(color, "blue")) return "#007ec6"; - else if(!strcmp(color, "grey")) return "#555"; - else if(!strcmp(color, "gray")) return "#555"; - else if(!strcmp(color, "lightgrey")) return "#9f9f9f"; - else if(!strcmp(color, "lightgray")) return "#9f9f9f"; - return color; -} - -typedef enum color_comparison { - COLOR_COMPARE_EQUAL, - COLOR_COMPARE_NOTEQUAL, - COLOR_COMPARE_LESS, - COLOR_COMPARE_LESSEQUAL, - COLOR_COMPARE_GREATER, - COLOR_COMPARE_GREATEREQUAL, -} BADGE_COLOR_COMPARISON; - -static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value) { - if(isnan(value) || isinf(value)) - value = NAN; - - char color_buffer[256 + 1] = ""; - char value_buffer[256 + 1] = ""; - BADGE_COLOR_COMPARISON comparison = COLOR_COMPARE_GREATER; - - // example input: - // colormin|color:null... - - const char *c = color; - while(*c) { - char *dc = color_buffer, *dv = NULL; - size_t ci = 0, vi = 0; - - const char *t = c; - - while(*t && *t != '|') { - switch(*t) { - case '!': - if(t[1] == '=') t++; - comparison = COLOR_COMPARE_NOTEQUAL; - dv = value_buffer; - break; - - case '=': - case ':': - comparison = COLOR_COMPARE_EQUAL; - dv = value_buffer; - break; - - case '}': - case ')': - case '>': - if(t[1] == '=') { - comparison = COLOR_COMPARE_GREATEREQUAL; - t++; - } - else - comparison = COLOR_COMPARE_GREATER; - dv = value_buffer; - break; - - case '{': - case '(': - case '<': - if(t[1] == '=') { - comparison = COLOR_COMPARE_LESSEQUAL; - t++; - } - else if(t[1] == '>' || t[1] == ')' || t[1] == '}') { - comparison = COLOR_COMPARE_NOTEQUAL; - t++; - } - else - comparison = COLOR_COMPARE_LESS; - dv = value_buffer; - break; - - default: - if(dv) { - if(vi < 256) { - vi++; - *dv++ = *t; - } - } - else { - if(ci < 256) { - ci++; - *dc++ = *t; - } - } - break; - } - - t++; - } - - // prepare for next iteration - if(*t == '|') t++; - c = t; - - // do the math - *dc = '\0'; - if(dv) { - *dv = '\0'; - calculated_number v; - - if(!*value_buffer || !strcmp(value_buffer, "null")) { - v = NAN; - } - else { - v = str2l(value_buffer); - if(isnan(v) || isinf(v)) - v = NAN; - } - - if(unlikely(isnan(value) || isnan(v))) { - if(isnan(value) && isnan(v)) - break; - } - else { - if (unlikely(comparison == COLOR_COMPARE_LESS && isless(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_LESSEQUAL && islessequal(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_GREATER && isgreater(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_GREATEREQUAL && isgreaterequal(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_EQUAL && !islessgreater(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_NOTEQUAL && islessgreater(value, v))) break; - } - } - else - break; - } - - const char *b; - if(color_buffer[0]) - b = color_buffer; - else - b = color; - - strncpyz(final, b, len); -} - -// value + units -#define VALUE_STRING_SIZE 100 - -// label -#define LABEL_STRING_SIZE 200 - -// 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 precision, int scale, uint32_t options) { - char label_buffer[LABEL_STRING_SIZE + 1] - , value_color_buffer[COLOR_STRING_SIZE + 1] - , value_string[VALUE_STRING_SIZE + 1] - , label_escaped[LABEL_STRING_SIZE + 1] - , value_escaped[VALUE_STRING_SIZE + 1] - , label_color_escaped[COLOR_STRING_SIZE + 1] - , value_color_escaped[COLOR_STRING_SIZE + 1]; - - double label_width, value_width, total_width, height = 20.0, font_size = 11.0, text_offset = 5.8, round_corner = 3.0; - - if(scale < 100) scale = 100; - - if(unlikely(!label_color || !*label_color)) - label_color = "#555"; - - if(unlikely(!value_color || !*value_color)) - value_color = (isnan(value) || isinf(value))?"#999":"#4c1"; - - calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value); - format_value_and_unit(value_string, VALUE_STRING_SIZE, (options & RRDR_OPTION_DISPLAY_ABS)?calculated_number_fabs(value):value, units, precision); - - // we need to copy the label, since verdana11_width may write to it - strncpyz(label_buffer, label, LABEL_STRING_SIZE); - - label_width = verdana11_width(label_buffer) + (BADGE_HORIZONTAL_PADDING * 2); - value_width = verdana11_width(value_string) + (BADGE_HORIZONTAL_PADDING * 2); - total_width = label_width + value_width; - - escape_xmlz(label_escaped, label_buffer, LABEL_STRING_SIZE); - escape_xmlz(value_escaped, value_string, VALUE_STRING_SIZE); - escape_xmlz(label_color_escaped, color_map(label_color), COLOR_STRING_SIZE); - escape_xmlz(value_color_escaped, color_map(value_color_buffer), COLOR_STRING_SIZE); - - wb->contenttype = CT_IMAGE_SVG_XML; - - total_width = total_width * scale / 100.0; - height = height * scale / 100.0; - font_size = font_size * scale / 100.0; - text_offset = text_offset * scale / 100.0; - label_width = label_width * scale / 100.0; - value_width = value_width * scale / 100.0; - round_corner = round_corner * scale / 100.0; - - // svg template from: - // https://raw.githubusercontent.com/badges/shields/master/templates/flat-template.svg - buffer_sprintf(wb, - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "%s" - "%s" - "%s" - "%s" - "" - "", - total_width, height, - total_width, height, round_corner, - label_width, height, label_color_escaped, - label_width, value_width, height, value_color_escaped, - total_width, height, - font_size, - label_width / 2, ceil(height - text_offset), label_escaped, - label_width / 2, ceil(height - text_offset - 1.0), label_escaped, - label_width + value_width / 2 -1, ceil(height - text_offset), value_escaped, - label_width + value_width / 2 -1, ceil(height - text_offset - 1.0), value_escaped); -} diff --git a/src/web_buffer_svg.h b/src/web_buffer_svg.h deleted file mode 100644 index c23abf0dc..000000000 --- a/src/web_buffer_svg.h +++ /dev/null @@ -1,7 +0,0 @@ -#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 precision, int scale, uint32_t options); -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 deleted file mode 100644 index 477fb3d57..000000000 --- a/src/web_client.c +++ /dev/null @@ -1,1706 +0,0 @@ -#include "common.h" - -// this is an async I/O implementation of the web server request parser -// it is used by all netdata web servers - -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; -#endif /* NETDATA_WITH_ZLIB */ - -inline int web_client_permission_denied(struct web_client *w) { - w->response.data->contenttype = CT_TEXT_PLAIN; - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "You are not allowed to access this resource."); - w->response.code = 403; - return 403; -} - -static inline int web_client_crock_socket(struct web_client *w) { -#ifdef TCP_CORK - if(likely(web_client_is_corkable(w) && !w->tcp_cork && w->ofd != -1)) { - w->tcp_cork = 1; - if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) { - error("%llu: failed to enable TCP_CORK on socket.", w->id); - - w->tcp_cork = 0; - return -1; - } - } -#else - (void)w; -#endif /* TCP_CORK */ - - return 0; -} - -static inline int web_client_uncrock_socket(struct web_client *w) { -#ifdef TCP_CORK - if(likely(w->tcp_cork && w->ofd != -1)) { - w->tcp_cork = 0; - if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) { - error("%llu: failed to disable TCP_CORK on socket.", w->id); - w->tcp_cork = 1; - return -1; - } - } -#else - (void)w; -#endif /* TCP_CORK */ - - return 0; -} - -void web_client_request_done(struct web_client *w) { - web_client_uncrock_socket(w); - - debug(D_WEB_CLIENT, "%llu: Resetting client.", w->id); - - if(likely(w->last_url[0])) { - struct timeval tv; - now_realtime_timeval(&tv); - - size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len; - size_t sent = size; -#ifdef NETDATA_WITH_ZLIB - if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out; -#endif - - // -------------------------------------------------------------------- - // global statistics - - finished_web_request_statistics(dt_usec(&tv, &w->tv_in), - w->stats_received_bytes, - w->stats_sent_bytes, - size, - sent); - - w->stats_received_bytes = 0; - w->stats_sent_bytes = 0; - - - // -------------------------------------------------------------------- - - const char *mode; - switch(w->mode) { - case WEB_CLIENT_MODE_FILECOPY: - mode = "FILECOPY"; - break; - - case WEB_CLIENT_MODE_OPTIONS: - mode = "OPTIONS"; - break; - - case WEB_CLIENT_MODE_STREAM: - mode = "STREAM"; - break; - - case WEB_CLIENT_MODE_NORMAL: - mode = "DATA"; - break; - - default: - mode = "UNKNOWN"; - break; - } - - // access log - log_access("%llu: %d '[%s]:%s' '%s' (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %d '%s'", - w->id - , gettid() - , w->client_ip - , w->client_port - , mode - , sent - , size - , -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0) - , dt_usec(&w->tv_ready, &w->tv_in) / 1000.0 - , dt_usec(&tv, &w->tv_ready) / 1000.0 - , dt_usec(&tv, &w->tv_in) / 1000.0 - , w->response.code - , w->last_url - ); - } - - if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) { - if(w->ifd != w->ofd) { - debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd); - - if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) { - if (w->ifd != -1) close(w->ifd); - } - - w->ifd = w->ofd; - } - } - - w->last_url[0] = '\0'; - w->cookie1[0] = '\0'; - w->cookie2[0] = '\0'; - w->origin[0] = '*'; - w->origin[1] = '\0'; - - freez(w->user_agent); w->user_agent = NULL; - - w->mode = WEB_CLIENT_MODE_NORMAL; - - w->tcp_cork = 0; - web_client_disable_donottrack(w); - web_client_disable_tracking_required(w); - web_client_disable_keepalive(w); - w->decoded_url[0] = '\0'; - - buffer_reset(w->response.header_output); - buffer_reset(w->response.header); - buffer_reset(w->response.data); - w->response.rlen = 0; - w->response.sent = 0; - w->response.code = 0; - - w->header_parse_tries = 0; - w->header_parse_last_size = 0; - - web_client_enable_wait_receive(w); - web_client_disable_wait_send(w); - - w->response.zoutput = 0; - - // if we had enabled compression, release it -#ifdef NETDATA_WITH_ZLIB - if(w->response.zinitialized) { - debug(D_DEFLATE, "%llu: Freeing compression resources.", w->id); - deflateEnd(&w->response.zstream); - w->response.zsent = 0; - w->response.zhave = 0; - w->response.zstream.avail_in = 0; - w->response.zstream.avail_out = 0; - w->response.zstream.total_in = 0; - w->response.zstream.total_out = 0; - w->response.zinitialized = 0; - } -#endif // NETDATA_WITH_ZLIB -} - -uid_t web_files_uid(void) { - static char *web_owner = NULL; - static uid_t owner_uid = 0; - - if(unlikely(!web_owner)) { - // getpwuid() is not thread safe, - // but we have called this function once - // while single threaded - struct passwd *pw = getpwuid(geteuid()); - web_owner = config_get(CONFIG_SECTION_WEB, "web files owner", (pw)?(pw->pw_name?pw->pw_name:""):""); - if(!web_owner || !*web_owner) - owner_uid = geteuid(); - else { - // getpwnam() is not thread safe, - // but we have called this function once - // while single threaded - pw = getpwnam(web_owner); - if(!pw) { - error("User '%s' is not present. Ignoring option.", web_owner); - owner_uid = geteuid(); - } - else { - debug(D_WEB_CLIENT, "Web files owner set to %s.", web_owner); - owner_uid = pw->pw_uid; - } - } - } - - return(owner_uid); -} - -gid_t web_files_gid(void) { - static char *web_group = NULL; - static gid_t owner_gid = 0; - - if(unlikely(!web_group)) { - // getgrgid() is not thread safe, - // but we have called this function once - // while single threaded - struct group *gr = getgrgid(getegid()); - web_group = config_get(CONFIG_SECTION_WEB, "web files group", (gr)?(gr->gr_name?gr->gr_name:""):""); - if(!web_group || !*web_group) - owner_gid = getegid(); - else { - // getgrnam() is not thread safe, - // but we have called this function once - // while single threaded - gr = getgrnam(web_group); - if(!gr) { - error("Group '%s' is not present. Ignoring option.", web_group); - owner_gid = getegid(); - } - else { - debug(D_WEB_CLIENT, "Web files group set to %s.", web_group); - owner_gid = gr->gr_gid; - } - } - } - - return(owner_gid); -} - -static struct { - const char *extension; - uint32_t hash; - uint8_t contenttype; -} mime_types[] = { - { "html" , 0 , CT_TEXT_HTML} - , {"js" , 0 , CT_APPLICATION_X_JAVASCRIPT} - , {"css" , 0 , CT_TEXT_CSS} - , {"xml" , 0 , CT_TEXT_XML} - , {"xsl" , 0 , CT_TEXT_XSL} - , {"txt" , 0 , CT_TEXT_PLAIN} - , {"svg" , 0 , CT_IMAGE_SVG_XML} - , {"ttf" , 0 , CT_APPLICATION_X_FONT_TRUETYPE} - , {"otf" , 0 , CT_APPLICATION_X_FONT_OPENTYPE} - , {"woff2", 0 , CT_APPLICATION_FONT_WOFF2} - , {"woff" , 0 , CT_APPLICATION_FONT_WOFF} - , {"eot" , 0 , CT_APPLICATION_VND_MS_FONTOBJ} - , {"png" , 0 , CT_IMAGE_PNG} - , {"jpg" , 0 , CT_IMAGE_JPG} - , {"jpeg" , 0 , CT_IMAGE_JPG} - , {"gif" , 0 , CT_IMAGE_GIF} - , {"bmp" , 0 , CT_IMAGE_BMP} - , {"ico" , 0 , CT_IMAGE_XICON} - , {"icns" , 0 , CT_IMAGE_ICNS} - , { NULL, 0, 0} -}; - -static inline uint8_t contenttype_for_filename(const char *filename) { - // info("checking filename '%s'", filename); - - static int initialized = 0; - int i; - - if(unlikely(!initialized)) { - for (i = 0; mime_types[i].extension; i++) - mime_types[i].hash = simple_hash(mime_types[i].extension); - - initialized = 1; - } - - const char *s = filename, *last_dot = NULL; - - // find the last dot - while(*s) { - if(unlikely(*s == '.')) last_dot = s; - s++; - } - - if(unlikely(!last_dot || !*last_dot || !last_dot[1])) { - // info("no extension for filename '%s'", filename); - return CT_APPLICATION_OCTET_STREAM; - } - last_dot++; - - // info("extension for filename '%s' is '%s'", filename, last_dot); - - uint32_t hash = simple_hash(last_dot); - for(i = 0; mime_types[i].extension ; i++) { - if(unlikely(hash == mime_types[i].hash && !strcmp(last_dot, mime_types[i].extension))) { - // info("matched extension for filename '%s': '%s'", filename, last_dot); - return mime_types[i].contenttype; - } - } - - // info("not matched extension for filename '%s': '%s'", filename, last_dot); - return CT_APPLICATION_OCTET_STREAM; -} - -static inline int access_to_file_is_not_permitted(struct web_client *w, const char *filename) { - w->response.data->contenttype = CT_TEXT_HTML; - buffer_strcat(w->response.data, "Access to file is not permitted: "); - buffer_strcat_htmlescape(w->response.data, filename); - return 403; -} - -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); - - if(!web_client_can_access_dashboard(w)) - return web_client_permission_denied(w); - - // skip leading slashes - while (*filename == '/') filename++; - - // if the filename contain known paths, skip them - if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0) - filename = &filename[strlen(WEB_PATH_FILE) + 1]; - - // if the filename contains "strange" characters, refuse to serve it - char *s; - 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; - } - } - - // 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; - } - - // find the physical file on disk - char webfilename[FILENAME_MAX + 1]; - snprintfz(webfilename, FILENAME_MAX, "%s/%s", netdata_configured_web_dir, filename); - - struct stat statbuf; - int done = 0; - while(!done) { - // check if the file exists - if (lstat(webfilename, &statbuf) != 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; - } - - if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { - snprintfz(webfilename, FILENAME_MAX, "%s/%s/index.html", netdata_configured_web_dir, filename); - continue; - } - - if ((statbuf.st_mode & S_IFMT) != S_IFREG) { - error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename); - return access_to_file_is_not_permitted(w, webfilename); - } - - // check if the file is owned by expected user - if (statbuf.st_uid != web_files_uid()) { - error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, statbuf.st_uid, web_files_uid()); - return access_to_file_is_not_permitted(w, webfilename); - } - - // check if the file is owned by expected group - if (statbuf.st_gid != web_files_gid()) { - error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, statbuf.st_gid, web_files_gid()); - return access_to_file_is_not_permitted(w, webfilename); - } - - done = 1; - } - - // open the file - w->ifd = open(webfilename, O_NONBLOCK, O_RDONLY); - if(w->ifd == -1) { - w->ifd = w->ofd; - - 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); - return 307; - } - 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; - } - } - - sock_setnonblock(w->ifd); - - w->response.data->contenttype = contenttype_for_filename(webfilename); - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, statbuf.st_size, w->ifd, w->ofd); - - w->mode = WEB_CLIENT_MODE_FILECOPY; - web_client_enable_wait_receive(w); - web_client_disable_wait_send(w); - buffer_flush(w->response.data); - buffer_need_bytes(w->response.data, (size_t)statbuf.st_size); - w->response.rlen = (size_t)statbuf.st_size; -#ifdef __APPLE__ - w->response.data->date = statbuf.st_mtimespec.tv_sec; -#else - w->response.data->date = statbuf.st_mtim.tv_sec; -#endif /* __APPLE__ */ - buffer_cacheable(w->response.data); - - return 200; -} - - -#ifdef NETDATA_WITH_ZLIB -void web_client_enable_deflate(struct web_client *w, int gzip) { - if(unlikely(w->response.zinitialized)) { - debug(D_DEFLATE, "%llu: Compression has already be initialized for this client.", w->id); - return; - } - - if(unlikely(w->response.sent)) { - error("%llu: Cannot enable compression in the middle of a conversation.", w->id); - return; - } - - w->response.zstream.zalloc = Z_NULL; - w->response.zstream.zfree = Z_NULL; - w->response.zstream.opaque = Z_NULL; - - w->response.zstream.next_in = (Bytef *)w->response.data->buffer; - w->response.zstream.avail_in = 0; - w->response.zstream.total_in = 0; - - w->response.zstream.next_out = w->response.zbuffer; - w->response.zstream.avail_out = 0; - w->response.zstream.total_out = 0; - - w->response.zstream.zalloc = Z_NULL; - w->response.zstream.zfree = Z_NULL; - w->response.zstream.opaque = Z_NULL; - -// if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) { -// error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id); -// return; -// } - - // Select GZIP compression: windowbits = 15 + 16 = 31 - if(deflateInit2(&w->response.zstream, web_gzip_level, Z_DEFLATED, 15 + ((gzip)?16:0), 8, web_gzip_strategy) != Z_OK) { - error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id); - return; - } - - w->response.zsent = 0; - w->response.zoutput = 1; - w->response.zinitialized = 1; - - debug(D_DEFLATE, "%llu: Initialized compression.", w->id); -} -#endif // NETDATA_WITH_ZLIB - -void buffer_data_options2string(BUFFER *wb, uint32_t options) { - int count = 0; - - if(options & RRDR_OPTION_NONZERO) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "nonzero"); - } - - if(options & RRDR_OPTION_REVERSED) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "flip"); - } - - if(options & RRDR_OPTION_JSON_WRAP) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "jsonwrap"); - } - - if(options & RRDR_OPTION_MIN2MAX) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "min2max"); - } - - if(options & RRDR_OPTION_MILLISECONDS) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "ms"); - } - - if(options & RRDR_OPTION_ABSOLUTE) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "absolute"); - } - - if(options & RRDR_OPTION_SECONDS) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "seconds"); - } - - if(options & RRDR_OPTION_NULL2ZERO) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "null2zero"); - } - - if(options & RRDR_OPTION_OBJECTSROWS) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "objectrows"); - } - - if(options & RRDR_OPTION_GOOGLE_JSON) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "google_json"); - } - - if(options & RRDR_OPTION_PERCENTAGE) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "percentage"); - } - - if(options & RRDR_OPTION_NOT_ALIGNED) { - if(count++) buffer_strcat(wb, " "); - buffer_strcat(wb, "unaligned"); - } -} - -const char *group_method2string(int group) { - switch(group) { - case GROUP_UNDEFINED: - return ""; - - case GROUP_AVERAGE: - return "average"; - - case GROUP_MIN: - return "min"; - - case GROUP_MAX: - return "max"; - - case GROUP_SUM: - return "sum"; - - case GROUP_INCREMENTAL_SUM: - return "incremental-sum"; - - default: - return "unknown-group-method"; - } -} - -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_strcat(w->response.data, "This host does not maintain a database"); - return 400; - } - - return func(host, w, url); -} - -static inline int check_host_and_dashboard_acl_and_call(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) { - if(!web_client_can_access_dashboard(w)) - return web_client_permission_denied(w); - - return check_host_and_call(host, w, url, func); -} - -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(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; - } - } - else { - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Which API version?"); - return 400; - } -} - -const char *web_content_type_to_string(uint8_t contenttype) { - switch(contenttype) { - case CT_TEXT_HTML: - return "text/html; charset=utf-8"; - - case CT_APPLICATION_XML: - return "application/xml; charset=utf-8"; - - case CT_APPLICATION_JSON: - return "application/json; charset=utf-8"; - - case CT_APPLICATION_X_JAVASCRIPT: - return "application/x-javascript; charset=utf-8"; - - case CT_TEXT_CSS: - return "text/css; charset=utf-8"; - - case CT_TEXT_XML: - return "text/xml; charset=utf-8"; - - case CT_TEXT_XSL: - return "text/xsl; charset=utf-8"; - - case CT_APPLICATION_OCTET_STREAM: - return "application/octet-stream"; - - case CT_IMAGE_SVG_XML: - return "image/svg+xml"; - - case CT_APPLICATION_X_FONT_TRUETYPE: - return "application/x-font-truetype"; - - case CT_APPLICATION_X_FONT_OPENTYPE: - return "application/x-font-opentype"; - - case CT_APPLICATION_FONT_WOFF: - return "application/font-woff"; - - case CT_APPLICATION_FONT_WOFF2: - return "application/font-woff2"; - - case CT_APPLICATION_VND_MS_FONTOBJ: - return "application/vnd.ms-fontobject"; - - case CT_IMAGE_PNG: - return "image/png"; - - case CT_IMAGE_JPG: - return "image/jpeg"; - - case CT_IMAGE_GIF: - return "image/gif"; - - case CT_IMAGE_XICON: - return "image/x-icon"; - - case CT_IMAGE_BMP: - return "image/bmp"; - - case CT_IMAGE_ICNS: - return "image/icns"; - - case CT_PROMETHEUS: - return "text/plain; version=0.0.4"; - - default: - case CT_TEXT_PLAIN: - return "text/plain; charset=utf-8"; - } -} - - -const char *web_response_code_to_string(int code) { - switch(code) { - case 200: - return "OK"; - - case 307: - return "Temporary Redirect"; - - case 400: - return "Bad Request"; - - case 403: - return "Forbidden"; - - case 404: - return "Not Found"; - - case 412: - return "Preconditions Failed"; - - default: - if(code >= 100 && code < 200) - return "Informational"; - - if(code >= 200 && code < 300) - return "Successful"; - - if(code >= 300 && code < 400) - return "Redirection"; - - if(code >= 400 && code < 500) - return "Bad Request"; - - if(code >= 500 && code < 600) - return "Server Error"; - - return "Undefined Error"; - } -} - -static inline char *http_header_parse(struct web_client *w, char *s, int parse_useragent) { - static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0, hash_useragent = 0; - - if(unlikely(!hash_origin)) { - hash_origin = simple_uhash("Origin"); - hash_connection = simple_uhash("Connection"); - hash_accept_encoding = simple_uhash("Accept-Encoding"); - hash_donottrack = simple_uhash("DNT"); - hash_useragent = simple_uhash("User-Agent"); - } - - char *e = s; - - // find the : - while(*e && *e != ':') e++; - if(!*e) return e; - - // get the name - *e = '\0'; - - // find the value - char *v = e + 1, *ve; - - // skip leading spaces from value - while(*v == ' ') v++; - ve = v; - - // find the \r - while(*ve && *ve != '\r') ve++; - if(!*ve || ve[1] != '\n') { - *e = ':'; - return ve; - } - - // terminate the value - *ve = '\0'; - - // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v); - uint32_t hash = simple_uhash(s); - - if(hash == hash_origin && !strcasecmp(s, "Origin")) - strncpyz(w->origin, v, NETDATA_WEB_REQUEST_ORIGIN_HEADER_SIZE); - - else if(hash == hash_connection && !strcasecmp(s, "Connection")) { - if(strcasestr(v, "keep-alive")) - web_client_enable_keepalive(w); - } - else if(respect_web_browser_do_not_track_policy && hash == hash_donottrack && !strcasecmp(s, "DNT")) { - if(*v == '0') web_client_disable_donottrack(w); - else if(*v == '1') web_client_enable_donottrack(w); - } - else if(parse_useragent && hash == hash_useragent && !strcasecmp(s, "User-Agent")) { - w->user_agent = strdupz(v); - } -#ifdef NETDATA_WITH_ZLIB - else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) { - if(web_enable_gzip) { - if(strcasestr(v, "gzip")) - web_client_enable_deflate(w, 1); - // - // does not seem to work - // else if(strcasestr(v, "deflate")) - // web_client_enable_deflate(w, 0); - } - } -#endif /* NETDATA_WITH_ZLIB */ - - *e = ':'; - *ve = '\r'; - return ve; -} - -// http_request_validate() -// returns: -// = 0 : all good, process the request -// > 0 : request is not supported -// < 0 : request is incomplete - wait for more data - -typedef enum { - 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 = (char *)buffer_tostring(w->response.data), *encoded_url = NULL; - - size_t last_pos = w->header_parse_last_size; - if(last_pos > 4) last_pos -= 4; // allow searching for \r\n\r\n - else last_pos = 0; - - w->header_parse_tries++; - w->header_parse_last_size = buffer_strlen(w->response.data); - - if(w->header_parse_tries > 1) { - if(w->header_parse_last_size < last_pos) - last_pos = 0; - - if(strstr(&s[last_pos], "\r\n\r\n") == NULL) { - if(w->header_parse_tries > 10) { - info("Disabling slow client after %zu attempts to read the request (%zu bytes received)", w->header_parse_tries, buffer_strlen(w->response.data)); - w->header_parse_tries = 0; - w->header_parse_last_size = 0; - web_client_disable_wait_receive(w); - return HTTP_VALIDATION_NOT_SUPPORTED; - } - - return HTTP_VALIDATION_INCOMPLETE; - } - } - - // is is a valid request? - if(!strncmp(s, "GET ", 4)) { - encoded_url = s = &s[4]; - w->mode = WEB_CLIENT_MODE_NORMAL; - } - else if(!strncmp(s, "OPTIONS ", 8)) { - 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->header_parse_tries = 0; - w->header_parse_last_size = 0; - web_client_disable_wait_receive(w); - return HTTP_VALIDATION_NOT_SUPPORTED; - } - - // find the SPACE + "HTTP/" - while(*s) { - // find the next space - while (*s && *s != ' ') s++; - - // is it SPACE + "HTTP/" ? - if(*s && !strncmp(s, " HTTP/", 6)) break; - else s++; - } - - // incomplete requests - if(unlikely(!*s)) { - web_client_enable_wait_receive(w); - return HTTP_VALIDATION_INCOMPLETE; - } - - // we have the end of encoded_url - remember it - char *ue = s; - - // make sure we have complete request - // complete requests contain: \r\n\r\n - while(*s) { - // find a line feed - while(*s && *s++ != '\r'); - - // did we reach the end? - if(unlikely(!*s)) break; - - // is it \r\n ? - if(likely(*s++ == '\n')) { - - // is it again \r\n ? (header end) - if(unlikely(*s == '\r' && s[1] == '\n')) { - // a valid complete HTTP request found - - *ue = '\0'; - url_decode_r(w->decoded_url, encoded_url, NETDATA_WEB_REQUEST_URL_SIZE + 1); - *ue = ' '; - - // copy the URL - we are going to overwrite parts of it - // FIXME -- we should avoid it - strncpyz(w->last_url, w->decoded_url, NETDATA_WEB_REQUEST_URL_SIZE); - - w->header_parse_tries = 0; - w->header_parse_last_size = 0; - web_client_disable_wait_receive(w); - return HTTP_VALIDATION_OK; - } - - // another header line - s = http_header_parse(w, s, - (w->mode == WEB_CLIENT_MODE_STREAM) // parse user agent - ); - } - } - - // incomplete request - web_client_enable_wait_receive(w); - return HTTP_VALIDATION_INCOMPLETE; -} - -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 + 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, 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(w->response.code); - - // prepare the last modified and expiration dates - char date[32], edate[32]; - { - struct tm tmbuf, *tm; - - tm = gmtime_r(&w->response.data->date, &tmbuf); - strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", tm); - - tm = gmtime_r(&w->response.data->expires, &tmbuf); - strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", tm); - } - - buffer_sprintf(w->response.header_output, - "HTTP/1.1 %d %s\r\n" - "Connection: %s\r\n" - "Server: NetData Embedded HTTP Server v%s\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 - , web_client_has_keepalive(w)?"keep-alive":"close" - , VERSION - , 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); - } - - if(w->cookie2[0]) { - buffer_sprintf(w->response.header_output, - "Set-Cookie: %s\r\n", - w->cookie2); - } - - if(respect_web_browser_do_not_track_policy) - buffer_sprintf(w->response.header_output, - "Tk: T;cookies\r\n"); - } - else { - if(respect_web_browser_do_not_track_policy) { - if(web_client_has_tracking_required(w)) - buffer_sprintf(w->response.header_output, - "Tk: T;cookies\r\n"); - else - buffer_sprintf(w->response.header_output, - "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 - ); - } - 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); - } - - // copy a possibly available custom header - if(unlikely(buffer_strlen(w->response.header))) - buffer_strcat(w->response.header_output, buffer_tostring(w->response.header)); - - // 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" - ); - } - else { - if(likely((w->response.data->len || w->response.rlen))) { - // we know the content length, put it - buffer_sprintf(w->response.header_output, "Content-Length: %zu\r\n", w->response.data->len? w->response.data->len: w->response.rlen); - } - else { - // we don't know the content length, disable keep-alive - web_client_disable_keepalive(w); - } - } - - // end of HTTP header - buffer_strcat(w->response.header_output, "\r\n"); - - // 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) - ); - - web_client_crock_socket(w); - - size_t count = 0; - ssize_t bytes; - while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) { - count++; - - if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) { - error("Cannot send HTTP headers to web client."); - break; - } - } - - if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) { - if(bytes > 0) - w->stats_sent_bytes += bytes; - - error("HTTP headers failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client." - , buffer_strlen(w->response.header_output) - , bytes); - - WEB_CLIENT_IS_DEAD(w); - return; - } - 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, NETDATA_WEB_REQUEST_URL_SIZE - 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_dashboard_acl_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_dashboard_acl_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_dashboard_acl_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_dashboard_acl_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_dashboard_acl_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 - if(unlikely(!web_client_can_access_netdataconf(w))) - return web_client_permission_denied(w); - - 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)) { - if(unlikely(!web_client_can_access_netdataconf(w))) - return web_client_permission_denied(w); - - 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)) { - if(unlikely(!web_client_can_access_netdataconf(w))) - return web_client_permission_denied(w); - - 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)) { - if(unlikely(!web_client_can_access_netdataconf(w))) - return web_client_permission_denied(w); - - 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: - if(unlikely(!web_client_can_access_stream(w))) { - web_client_permission_denied(w); - return; - } - - w->response.code = rrdpush_receiver_thread_spawn(localhost, w, w->decoded_url); - return; - - case WEB_CLIENT_MODE_OPTIONS: - if(unlikely(!web_client_can_access_dashboard(w) && !web_client_can_access_registry(w) && !web_client_can_access_badges(w))) { - web_client_permission_denied(w); - return; - } - - 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: - if(unlikely(!web_client_can_access_dashboard(w) && !web_client_can_access_registry(w) && !web_client_can_access_badges(w))) { - web_client_permission_denied(w); - return; - } - - w->response.code = web_client_process_url(localhost, w, w->decoded_url); - break; - } - break; - - case HTTP_VALIDATION_INCOMPLETE: - if(w->response.data->len > NETDATA_WEB_REQUEST_MAX_SIZE) { - 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) web_client_enable_wait_send(w); - else web_client_disable_wait_send(w); - - 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; - - case WEB_CLIENT_MODE_NORMAL: - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len); - break; - - case WEB_CLIENT_MODE_FILECOPY: - if(w->response.rlen) { - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen); - web_client_enable_wait_receive(w); - - /* - // utilize the kernel sendfile() for copying the file to the socket. - // this block of code can be commented, without anything missing. - // when it is commented, the program will copy the data using async I/O. - { - long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes); - if(len != w->response.data->rbytes) - error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len); - else - web_client_request_done(w); - } - */ - } - else - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending an unknown amount of bytes to client.", w->id); - break; - - default: - fatal("%llu: Unknown client mode %u.", w->id, w->mode); - break; - } -} - -ssize_t web_client_send_chunk_header(struct web_client *w, size_t len) -{ - debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len); - char buf[24]; - sprintf(buf, "%zX\r\n", len); - - ssize_t bytes = send(w->ofd, buf, strlen(buf), 0); - if(bytes > 0) { - debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes); - w->stats_sent_bytes += bytes; - } - - else if(bytes == 0) { - debug(D_WEB_CLIENT, "%llu: Did not send chunk header to the client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - else { - debug(D_WEB_CLIENT, "%llu: Failed to send chunk header to client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return bytes; -} - -ssize_t web_client_send_chunk_close(struct web_client *w) -{ - //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id); - - ssize_t bytes = send(w->ofd, "\r\n", 2, 0); - if(bytes > 0) { - debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes); - w->stats_sent_bytes += bytes; - } - - else if(bytes == 0) { - debug(D_WEB_CLIENT, "%llu: Did not send chunk suffix to the client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - else { - debug(D_WEB_CLIENT, "%llu: Failed to send chunk suffix to client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return bytes; -} - -ssize_t web_client_send_chunk_finalize(struct web_client *w) -{ - //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id); - - ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0); - if(bytes > 0) { - debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes); - w->stats_sent_bytes += bytes; - } - - else if(bytes == 0) { - debug(D_WEB_CLIENT, "%llu: Did not send chunk finalize suffix to the client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - else { - debug(D_WEB_CLIENT, "%llu: Failed to send chunk finalize suffix to client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return bytes; -} - -#ifdef NETDATA_WITH_ZLIB -ssize_t web_client_send_deflate(struct web_client *w) -{ - ssize_t len = 0, t = 0; - - // when using compression, - // w->response.sent is the amount of bytes passed through compression - - debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.", - w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out); - - if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) { - // there is nothing to send - - debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id); - - // finalize the chunk - if(w->response.sent != 0) { - t = web_client_send_chunk_finalize(w); - if(t < 0) return t; - } - - if(w->mode == WEB_CLIENT_MODE_FILECOPY && web_client_has_wait_receive(w) && w->response.rlen && w->response.rlen > w->response.data->len) { - // we have to wait, more data will come - debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id); - web_client_disable_wait_send(w); - return t; - } - - if(unlikely(!web_client_has_keepalive(w))) { - debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent); - WEB_CLIENT_IS_DEAD(w); - return t; - } - - // reset the client - web_client_request_done(w); - debug(D_WEB_CLIENT, "%llu: Done sending all data on socket.", w->id); - return t; - } - - if(w->response.zhave == w->response.zsent) { - // compress more input data - - // close the previous open chunk - if(w->response.sent != 0) { - t = web_client_send_chunk_close(w); - if(t < 0) return t; - } - - debug(D_DEFLATE, "%llu: Compressing %zu new bytes starting from %zu (and %u left behind).", w->id, (w->response.data->len - w->response.sent), w->response.sent, w->response.zstream.avail_in); - - // give the compressor all the data not passed through the compressor yet - if(w->response.data->len > w->response.sent) { - w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent - w->response.zstream.avail_in]; - w->response.zstream.avail_in += (uInt) (w->response.data->len - w->response.sent); - } - - // reset the compressor output buffer - w->response.zstream.next_out = w->response.zbuffer; - w->response.zstream.avail_out = NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE; - - // ask for FINISH if we have all the input - int flush = Z_SYNC_FLUSH; - if(w->mode == WEB_CLIENT_MODE_NORMAL - || (w->mode == WEB_CLIENT_MODE_FILECOPY && !web_client_has_wait_receive(w) && w->response.data->len == w->response.rlen)) { - flush = Z_FINISH; - debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id); - } - else { - debug(D_DEFLATE, "%llu: Requesting Z_SYNC_FLUSH.", w->id); - } - - // compress - if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) { - error("%llu: Compression failed. Closing down client.", w->id); - web_client_request_done(w); - return(-1); - } - - w->response.zhave = NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE - w->response.zstream.avail_out; - w->response.zsent = 0; - - // keep track of the bytes passed through the compressor - w->response.sent = w->response.data->len; - - debug(D_DEFLATE, "%llu: Compression produced %zu bytes.", w->id, w->response.zhave); - - // open a new chunk - ssize_t t2 = web_client_send_chunk_header(w, w->response.zhave); - if(t2 < 0) return t2; - t += t2; - } - - debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t); - - len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT); - if(len > 0) { - w->stats_sent_bytes += len; - w->response.zsent += len; - len += t; - debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, len); - } - else if(len == 0) { - debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %zu, zsent = %zu, need to send = %zu).", - w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent); - - WEB_CLIENT_IS_DEAD(w); - } - else { - debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return(len); -} -#endif // NETDATA_WITH_ZLIB - -ssize_t web_client_send(struct web_client *w) { -#ifdef NETDATA_WITH_ZLIB - if(likely(w->response.zoutput)) return web_client_send_deflate(w); -#endif // NETDATA_WITH_ZLIB - - ssize_t bytes; - - if(unlikely(w->response.data->len - w->response.sent == 0)) { - // there is nothing to send - - debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id); - - // there can be two cases for this - // A. we have done everything - // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd - - if(w->mode == WEB_CLIENT_MODE_FILECOPY && web_client_has_wait_receive(w) && w->response.rlen && w->response.rlen > w->response.data->len) { - // we have to wait, more data will come - debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id); - web_client_disable_wait_send(w); - return 0; - } - - if(unlikely(!web_client_has_keepalive(w))) { - debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent); - WEB_CLIENT_IS_DEAD(w); - return 0; - } - - web_client_request_done(w); - debug(D_WEB_CLIENT, "%llu: Done sending all data on socket. Waiting for next request on the same socket.", w->id); - return 0; - } - - bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT); - if(likely(bytes > 0)) { - w->stats_sent_bytes += bytes; - w->response.sent += bytes; - debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, bytes); - } - else if(likely(bytes == 0)) { - debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - else { - debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return(bytes); -} - -ssize_t web_client_read_file(struct web_client *w) -{ - if(unlikely(w->response.rlen > w->response.data->size)) - buffer_need_bytes(w->response.data, w->response.rlen - w->response.data->size); - - if(unlikely(w->response.rlen <= w->response.data->len)) - return 0; - - ssize_t left = w->response.rlen - w->response.data->len; - ssize_t bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t)left); - if(likely(bytes > 0)) { - size_t old = w->response.data->len; - w->response.data->len += bytes; - w->response.data->buffer[w->response.data->len] = '\0'; - - debug(D_WEB_CLIENT, "%llu: Read %zd bytes.", w->id, bytes); - debug(D_WEB_DATA, "%llu: Read data: '%s'.", w->id, &w->response.data->buffer[old]); - - web_client_enable_wait_send(w); - - if(w->response.rlen && w->response.data->len >= w->response.rlen) - web_client_disable_wait_receive(w); - } - else if(likely(bytes == 0)) { - debug(D_WEB_CLIENT, "%llu: Out of input file data.", w->id); - - // if we cannot read, it means we have an error on input. - // if however, we are copying a file from ifd to ofd, we should not return an error. - // in this case, the error should be generated when the file has been sent to the client. - - // we are copying data from ifd to ofd - // let it finish copying... - web_client_disable_wait_receive(w); - - debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id); - - if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) { - if (w->ifd != w->ofd) close(w->ifd); - } - - w->ifd = w->ofd; - } - else { - debug(D_WEB_CLIENT, "%llu: read data failed.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return(bytes); -} - -ssize_t web_client_receive(struct web_client *w) -{ - if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) - return web_client_read_file(w); - - // do we have any space for more data? - buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_RECEIVE_SIZE); - - ssize_t left = w->response.data->size - w->response.data->len; - ssize_t bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT); - - if(likely(bytes > 0)) { - w->stats_received_bytes += bytes; - - size_t old = w->response.data->len; - w->response.data->len += bytes; - w->response.data->buffer[w->response.data->len] = '\0'; - - debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes); - debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]); - } - else { - debug(D_WEB_CLIENT, "%llu: receive data failed.", w->id); - WEB_CLIENT_IS_DEAD(w); - } - - return(bytes); -} diff --git a/src/web_client.h b/src/web_client.h deleted file mode 100644 index b495c37e1..000000000 --- a/src/web_client.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef NETDATA_WEB_CLIENT_H -#define NETDATA_WEB_CLIENT_H 1 - -#ifdef NETDATA_WITH_ZLIB -extern int web_enable_gzip, - web_gzip_level, - web_gzip_strategy; -#endif /* NETDATA_WITH_ZLIB */ - -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; - -typedef enum web_client_flags { - WEB_CLIENT_FLAG_DEAD = 1 << 1, // if set, this client is dead - - WEB_CLIENT_FLAG_KEEPALIVE = 1 << 2, // if set, the web client will be re-used - - WEB_CLIENT_FLAG_WAIT_RECEIVE = 1 << 3, // if set, we are waiting more input data - WEB_CLIENT_FLAG_WAIT_SEND = 1 << 4, // if set, we have data to send to the client - - WEB_CLIENT_FLAG_DO_NOT_TRACK = 1 << 5, // if set, we should not set cookies on this client - WEB_CLIENT_FLAG_TRACKING_REQUIRED = 1 << 6, // if set, we need to send cookies - - WEB_CLIENT_FLAG_TCP_CLIENT = 1 << 7, // if set, the client is using a TCP socket - WEB_CLIENT_FLAG_UNIX_CLIENT = 1 << 8, // if set, the client is using a UNIX socket - - WEB_CLIENT_FLAG_DONT_CLOSE_SOCKET = 1 << 9, // don't close the socket when cleaning up (static-threaded web server) -} WEB_CLIENT_FLAGS; - -//#ifdef HAVE_C___ATOMIC -//#define web_client_flag_check(w, flag) (__atomic_load_n(&((w)->flags), __ATOMIC_SEQ_CST) & flag) -//#define web_client_flag_set(w, flag) __atomic_or_fetch(&((w)->flags), flag, __ATOMIC_SEQ_CST) -//#define web_client_flag_clear(w, flag) __atomic_and_fetch(&((w)->flags), ~flag, __ATOMIC_SEQ_CST) -//#else -#define web_client_flag_check(w, flag) ((w)->flags & (flag)) -#define web_client_flag_set(w, flag) (w)->flags |= flag -#define web_client_flag_clear(w, flag) (w)->flags &= ~flag -//#endif - -#define WEB_CLIENT_IS_DEAD(w) web_client_flag_set(w, WEB_CLIENT_FLAG_DEAD) -#define web_client_check_dead(w) web_client_flag_check(w, WEB_CLIENT_FLAG_DEAD) - -#define web_client_has_keepalive(w) web_client_flag_check(w, WEB_CLIENT_FLAG_KEEPALIVE) -#define web_client_enable_keepalive(w) web_client_flag_set(w, WEB_CLIENT_FLAG_KEEPALIVE) -#define web_client_disable_keepalive(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_KEEPALIVE) - -#define web_client_has_donottrack(w) web_client_flag_check(w, WEB_CLIENT_FLAG_DO_NOT_TRACK) -#define web_client_enable_donottrack(w) web_client_flag_set(w, WEB_CLIENT_FLAG_DO_NOT_TRACK) -#define web_client_disable_donottrack(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_DO_NOT_TRACK) - -#define web_client_has_tracking_required(w) web_client_flag_check(w, WEB_CLIENT_FLAG_TRACKING_REQUIRED) -#define web_client_enable_tracking_required(w) web_client_flag_set(w, WEB_CLIENT_FLAG_TRACKING_REQUIRED) -#define web_client_disable_tracking_required(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_TRACKING_REQUIRED) - -#define web_client_has_wait_receive(w) web_client_flag_check(w, WEB_CLIENT_FLAG_WAIT_RECEIVE) -#define web_client_enable_wait_receive(w) web_client_flag_set(w, WEB_CLIENT_FLAG_WAIT_RECEIVE) -#define web_client_disable_wait_receive(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_WAIT_RECEIVE) - -#define web_client_has_wait_send(w) web_client_flag_check(w, WEB_CLIENT_FLAG_WAIT_SEND) -#define web_client_enable_wait_send(w) web_client_flag_set(w, WEB_CLIENT_FLAG_WAIT_SEND) -#define web_client_disable_wait_send(w) web_client_flag_clear(w, WEB_CLIENT_FLAG_WAIT_SEND) - -#define web_client_set_tcp(w) web_client_flag_set(w, WEB_CLIENT_FLAG_TCP_CLIENT) -#define web_client_set_unix(w) web_client_flag_set(w, WEB_CLIENT_FLAG_UNIX_CLIENT) -#define web_client_check_unix(w) web_client_flag_check(w, WEB_CLIENT_FLAG_UNIX_CLIENT) - -#define web_client_is_corkable(w) web_client_flag_check(w, WEB_CLIENT_FLAG_TCP_CLIENT) - -#define NETDATA_WEB_REQUEST_URL_SIZE 8192 -#define NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE 16384 -#define NETDATA_WEB_RESPONSE_HEADER_SIZE 4096 -#define NETDATA_WEB_REQUEST_COOKIE_SIZE 1024 -#define NETDATA_WEB_REQUEST_ORIGIN_HEADER_SIZE 1024 -#define NETDATA_WEB_RESPONSE_INITIAL_SIZE 16384 -#define NETDATA_WEB_REQUEST_RECEIVE_SIZE 16384 -#define NETDATA_WEB_REQUEST_MAX_SIZE 16384 - -struct response { - BUFFER *header; // our response header - BUFFER *header_output; // internal use - BUFFER *data; // our response data buffer - - int code; // the HTTP response code - - size_t rlen; // if non-zero, the excepted size of ifd (input of firecopy) - size_t sent; // current data length sent to output - - int zoutput; // if set to 1, web_client_send() will send compressed data -#ifdef NETDATA_WITH_ZLIB - z_stream zstream; // zlib stream for sending compressed output to client - Bytef zbuffer[NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE]; // temporary buffer for storing compressed output - size_t zsent; // the compressed bytes we have sent to the client - size_t zhave; // the compressed bytes that we have received from zlib - int zinitialized:1; -#endif /* NETDATA_WITH_ZLIB */ - -}; - -typedef enum web_client_acl { - WEB_CLIENT_ACL_NONE = 0, - WEB_CLIENT_ACL_NOCHECK = 0, - WEB_CLIENT_ACL_DASHBOARD = 1 << 0, - WEB_CLIENT_ACL_REGISTRY = 1 << 1, - WEB_CLIENT_ACL_BADGE = 1 << 2 -} WEB_CLIENT_ACL; - -#define web_client_can_access_dashboard(w) ((w)->acl & WEB_CLIENT_ACL_DASHBOARD) -#define web_client_can_access_registry(w) ((w)->acl & WEB_CLIENT_ACL_REGISTRY) -#define web_client_can_access_badges(w) ((w)->acl & WEB_CLIENT_ACL_BADGE) - -#define web_client_can_access_stream(w) \ - (!web_allow_streaming_from || simple_pattern_matches(web_allow_streaming_from, (w)->client_ip)) - -#define web_client_can_access_netdataconf(w) \ - (!web_allow_netdataconf_from || simple_pattern_matches(web_allow_netdataconf_from, (w)->client_ip)) - -struct web_client { - unsigned long long id; - - WEB_CLIENT_FLAGS flags; // status flags for the client - WEB_CLIENT_MODE mode; // the operational mode of the client - WEB_CLIENT_ACL acl; // the access list of the client - - size_t header_parse_tries; - size_t header_parse_last_size; - - int tcp_cork; // 1 = we have a cork on the socket - - int ifd; - int ofd; - - char client_ip[NI_MAXHOST+1]; - char client_port[NI_MAXSERV+1]; - - char decoded_url[NETDATA_WEB_REQUEST_URL_SIZE + 1]; // we decode the URL in this buffer - char last_url[NETDATA_WEB_REQUEST_URL_SIZE+1]; // we keep a copy of the decoded URL here - - struct timeval tv_in, tv_ready; - - char cookie1[NETDATA_WEB_REQUEST_COOKIE_SIZE+1]; - char cookie2[NETDATA_WEB_REQUEST_COOKIE_SIZE+1]; - char origin[NETDATA_WEB_REQUEST_ORIGIN_HEADER_SIZE+1]; - char *user_agent; - - struct response response; - - size_t stats_received_bytes; - size_t stats_sent_bytes; - - // cache of web_client allocations - struct web_client *prev; // maintain a linked list of web clients - struct web_client *next; // for the web servers that need it - - // MULTI-THREADED WEB SERVER MEMBERS - netdata_thread_t thread; // the thread servicing this client - volatile int running; // 1 when the thread runs, 0 otherwise - - // STATIC-THREADED WEB SERVER MEMBERS - size_t pollinfo_slot; // POLLINFO slot of the web client - size_t pollinfo_filecopy_slot; // POLLINFO slot of the file read -}; - -extern uid_t web_files_uid(void); -extern uid_t web_files_gid(void); - -extern int web_client_permission_denied(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 ssize_t web_client_read_file(struct web_client *w); - -extern void web_client_process_request(struct web_client *w); -extern void web_client_request_done(struct web_client *w); - -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 deleted file mode 100644 index 31c546411..000000000 --- a/src/web_server.c +++ /dev/null @@ -1,1292 +0,0 @@ -#include "common.h" - -// this file includes 3 web servers: -// -// 1. single-threaded, based on select() -// 2. multi-threaded, based on poll() that spawns threads to handle the requests, based on select() -// 3. static-threaded, based on poll() using a fixed number of threads (configured at netdata.conf) - -WEB_SERVER_MODE web_server_mode = WEB_SERVER_MODE_STATIC_THREADED; - -// -------------------------------------------------------------------------------------- - -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, "static") || !strcmp(mode, "static-threaded")) - return WEB_SERVER_MODE_STATIC_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"; - - case WEB_SERVER_MODE_STATIC_THREADED: - return "static-threaded"; - - default: - case WEB_SERVER_MODE_MULTI_THREADED: - return "multi-threaded"; - } -} - -// -------------------------------------------------------------------------------------- -// API sockets - -static LISTEN_SOCKETS api_sockets = { - .config_section = CONFIG_SECTION_WEB, - .default_bind_to = "*", - .default_port = API_LISTEN_PORT, - .backlog = API_LISTEN_BACKLOG -}; - -int api_listen_sockets_setup(void) { - int socks = listen_sockets_setup(&api_sockets); - - if(!socks) - fatal("LISTENER: Cannot listen on any API socket. Exiting..."); - - return socks; -} - - -// -------------------------------------------------------------------------------------- -// access lists - -SIMPLE_PATTERN *web_allow_connections_from = NULL; -SIMPLE_PATTERN *web_allow_streaming_from = NULL; -SIMPLE_PATTERN *web_allow_netdataconf_from = NULL; - -// WEB_CLIENT_ACL -SIMPLE_PATTERN *web_allow_dashboard_from = NULL; -SIMPLE_PATTERN *web_allow_registry_from = NULL; -SIMPLE_PATTERN *web_allow_badges_from = NULL; - -static void web_client_update_acl_matches(struct web_client *w) { - w->acl = WEB_CLIENT_ACL_NONE; - - if(!web_allow_dashboard_from || simple_pattern_matches(web_allow_dashboard_from, w->client_ip)) - w->acl |= WEB_CLIENT_ACL_DASHBOARD; - - if(!web_allow_registry_from || simple_pattern_matches(web_allow_registry_from, w->client_ip)) - w->acl |= WEB_CLIENT_ACL_REGISTRY; - - if(!web_allow_badges_from || simple_pattern_matches(web_allow_badges_from, w->client_ip)) - w->acl |= WEB_CLIENT_ACL_BADGE; -} - - -// -------------------------------------------------------------------------------------- - -static void log_connection(struct web_client *w, const char *msg) { - log_access("%llu: %d '[%s]:%s' '%s'", w->id, gettid(), w->client_ip, w->client_port, msg); -} - -// ---------------------------------------------------------------------------- -// allocate and free web_clients - -static void web_client_zero(struct web_client *w) { - // zero everything about it - but keep the buffers - - // remember the pointers to the buffers - BUFFER *b1 = w->response.data; - BUFFER *b2 = w->response.header; - BUFFER *b3 = w->response.header_output; - - // empty the buffers - buffer_flush(b1); - buffer_flush(b2); - buffer_flush(b3); - - freez(w->user_agent); - - // zero everything - memset(w, 0, sizeof(struct web_client)); - - // restore the pointers of the buffers - w->response.data = b1; - w->response.header = b2; - w->response.header_output = b3; -} - -static void web_client_free(struct web_client *w) { - buffer_free(w->response.header_output); - buffer_free(w->response.header); - buffer_free(w->response.data); - freez(w->user_agent); - freez(w); -} - -static struct web_client *web_client_alloc(void) { - struct web_client *w = callocz(1, sizeof(struct web_client)); - w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE); - w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE); - w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_SIZE); - return w; -} - -// ---------------------------------------------------------------------------- -// web clients caching - -// When clients connect and disconnect, avoid allocating and releasing memory. -// Instead, when new clients get connected, reuse any memory previously allocated -// for serving web clients that are now disconnected. - -// The size of the cache is adaptive. It caches the structures of 2x -// the number of currently connected clients. - -// Comments per server: -// SINGLE-THREADED : 1 cache is maintained -// MULTI-THREADED : 1 cache is maintained -// STATIC-THREADED : 1 cache for each thred of the web server - -struct clients_cache { - pid_t pid; - - struct web_client *used; // the structures of the currently connected clients - size_t used_count; // the count the currently connected clients - - struct web_client *avail; // the cached structures, available for future clients - size_t avail_count; // the number of cached structures - - size_t reused; // the number of re-uses - size_t allocated; // the number of allocations -}; - -static __thread struct clients_cache web_clients_cache = { - .pid = 0, - .used = NULL, - .used_count = 0, - .avail = NULL, - .avail_count = 0, - .allocated = 0, - .reused = 0 -}; - -static inline void web_client_cache_verify(int force) { -#ifdef NETDATA_INTERNAL_CHECKS - static __thread size_t count = 0; - count++; - - if(unlikely(force || count > 1000)) { - count = 0; - - struct web_client *w; - size_t used = 0, avail = 0; - for(w = web_clients_cache.used; w ; w = w->next) used++; - for(w = web_clients_cache.avail; w ; w = w->next) avail++; - - info("web_client_cache has %zu (%zu) used and %zu (%zu) available clients, allocated %zu, reused %zu (hit %zu%%)." - , used, web_clients_cache.used_count - , avail, web_clients_cache.avail_count - , web_clients_cache.allocated - , web_clients_cache.reused - , (web_clients_cache.allocated + web_clients_cache.reused)?(web_clients_cache.reused * 100 / (web_clients_cache.allocated + web_clients_cache.reused)):0 - ); - } -#else - if(unlikely(force)) { - info("web_client_cache has %zu used and %zu available clients, allocated %zu, reused %zu (hit %zu%%)." - , web_clients_cache.used_count - , web_clients_cache.avail_count - , web_clients_cache.allocated - , web_clients_cache.reused - , (web_clients_cache.allocated + web_clients_cache.reused)?(web_clients_cache.reused * 100 / (web_clients_cache.allocated + web_clients_cache.reused)):0 - ); - } -#endif -} - -// destroy the cache and free all the memory it uses -static void web_client_cache_destroy(void) { -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid())) - error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid()); - - web_client_cache_verify(1); -#endif - - netdata_thread_disable_cancelability(); - - struct web_client *w, *t; - - w = web_clients_cache.used; - while(w) { - t = w; - w = w->next; - web_client_free(t); - } - web_clients_cache.used = NULL; - web_clients_cache.used_count = 0; - - w = web_clients_cache.avail; - while(w) { - t = w; - w = w->next; - web_client_free(t); - } - web_clients_cache.avail = NULL; - web_clients_cache.avail_count = 0; - - netdata_thread_enable_cancelability(); -} - -static struct web_client *web_client_get_from_cache_or_allocate() { - -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(web_clients_cache.pid == 0)) - web_clients_cache.pid = gettid(); - - if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid())) - error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid()); -#endif - - netdata_thread_disable_cancelability(); - - struct web_client *w = web_clients_cache.avail; - - if(w) { - // get it from avail - if (w == web_clients_cache.avail) web_clients_cache.avail = w->next; - if(w->prev) w->prev->next = w->next; - if(w->next) w->next->prev = w->prev; - web_clients_cache.avail_count--; - web_client_zero(w); - web_clients_cache.reused++; - } - else { - // allocate it - w = web_client_alloc(); - web_clients_cache.allocated++; - } - - // link it to used web clients - if (web_clients_cache.used) web_clients_cache.used->prev = w; - w->next = web_clients_cache.used; - w->prev = NULL; - web_clients_cache.used = w; - web_clients_cache.used_count++; - - // initialize it - w->id = web_client_connected(); - w->mode = WEB_CLIENT_MODE_NORMAL; - - netdata_thread_enable_cancelability(); - - return w; -} - -static void web_client_release(struct web_client *w) { -#ifdef NETDATA_INTERNAL_CHECKS - if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid())) - error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid()); - - if(unlikely(w->running)) - error("%llu: releasing web client from %s port %s, but it still running.", w->id, w->client_ip, w->client_port); -#endif - - debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port); - - log_connection(w, "DISCONNECTED"); - web_client_request_done(w); - web_client_disconnected(); - - netdata_thread_disable_cancelability(); - - if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) { - if (w->ifd != -1) close(w->ifd); - if (w->ofd != -1 && w->ofd != w->ifd) close(w->ofd); - w->ifd = w->ofd = -1; - } - - // unlink it from the used - if (w == web_clients_cache.used) web_clients_cache.used = w->next; - if(w->prev) w->prev->next = w->next; - if(w->next) w->next->prev = w->prev; - web_clients_cache.used_count--; - - if(web_clients_cache.avail_count >= 2 * web_clients_cache.used_count) { - // we have too many of them - free it - web_client_free(w); - } - else { - // link it to the avail - if (web_clients_cache.avail) web_clients_cache.avail->prev = w; - w->next = web_clients_cache.avail; - w->prev = NULL; - web_clients_cache.avail = w; - web_clients_cache.avail_count++; - } - - netdata_thread_enable_cancelability(); -} - - -// ---------------------------------------------------------------------------- -// high level web clients connection management - -static void web_client_initialize_connection(struct web_client *w) { - int flag = 1; - if(setsockopt(w->ifd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0) - error("%llu: failed to enable TCP_NODELAY on socket fd %d.", w->id, w->ifd); - - flag = 1; - if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0) - error("%llu: failed to enable SO_KEEPALIVE on socket fd %d.", w->id, w->ifd); - - web_client_update_acl_matches(w); - - w->origin[0] = '*'; w->origin[1] = '\0'; - w->cookie1[0] = '\0'; w->cookie2[0] = '\0'; - freez(w->user_agent); w->user_agent = NULL; - - web_client_enable_wait_receive(w); - - log_connection(w, "CONNECTED"); - - web_client_cache_verify(0); -} - -static struct web_client *web_client_create_on_fd(int fd, const char *client_ip, const char *client_port) { - struct web_client *w; - - w = web_client_get_from_cache_or_allocate(); - w->ifd = w->ofd = fd; - - strncpyz(w->client_ip, client_ip, sizeof(w->client_ip) - 1); - strncpyz(w->client_port, client_port, sizeof(w->client_port) - 1); - - if(unlikely(!*w->client_ip)) strcpy(w->client_ip, "-"); - if(unlikely(!*w->client_port)) strcpy(w->client_port, "-"); - - web_client_initialize_connection(w); - return(w); -} - -static struct web_client *web_client_create_on_listenfd(int listener) { - struct web_client *w; - - w = web_client_get_from_cache_or_allocate(); - w->ifd = w->ofd = accept_socket(listener, SOCK_NONBLOCK, w->client_ip, sizeof(w->client_ip), w->client_port, sizeof(w->client_port), web_allow_connections_from); - - if(unlikely(!*w->client_ip)) strcpy(w->client_ip, "-"); - if(unlikely(!*w->client_port)) strcpy(w->client_port, "-"); - - if (w->ifd == -1) { - if(errno == EPERM) - log_connection(w, "ACCESS DENIED"); - else { - log_connection(w, "CONNECTION FAILED"); - error("%llu: Failed to accept new incoming connection.", w->id); - } - - web_client_release(w); - return NULL; - } - - web_client_initialize_connection(w); - return(w); -} - - -// -------------------------------------------------------------------------------------- -// the thread of a single client - for the MULTI-THREADED web server - -// 1. waits for input and output, using async I/O -// 2. it processes HTTP requests -// 3. it generates HTTP responses -// 4. it copies data from input to output if mode is FILECOPY - -int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS; -int web_client_first_request_timeout = DEFAULT_TIMEOUT_TO_RECEIVE_FIRST_WEB_REQUEST; - -static void multi_threaded_web_client_worker_main_cleanup(void *ptr) { - struct web_client *w = ptr; - WEB_CLIENT_IS_DEAD(w); - w->running = 0; -} - -static void *multi_threaded_web_client_worker_main(void *ptr) { - netdata_thread_cleanup_push(multi_threaded_web_client_worker_main_cleanup, ptr); - - struct web_client *w = ptr; - w->running = 1; - - struct pollfd fds[2], *ifd, *ofd; - int retval, timeout_ms; - nfds_t fdmax = 0; - - while(!netdata_exit) { - if(unlikely(web_client_check_dead(w))) { - debug(D_WEB_CLIENT, "%llu: client is dead.", w->id); - break; - } - else if(unlikely(!web_client_has_wait_receive(w) && !web_client_has_wait_send(w))) { - debug(D_WEB_CLIENT, "%llu: client is not set for neither receiving nor sending data.", w->id); - break; - } - - if(unlikely(w->ifd < 0 || w->ofd < 0)) { - error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd", w->id, w->ifd, w->ofd); - break; - } - - if(w->ifd == w->ofd) { - fds[0].fd = w->ifd; - fds[0].events = 0; - fds[0].revents = 0; - - if(web_client_has_wait_receive(w)) fds[0].events |= POLLIN; - if(web_client_has_wait_send(w)) fds[0].events |= POLLOUT; - - fds[1].fd = -1; - fds[1].events = 0; - fds[1].revents = 0; - - ifd = ofd = &fds[0]; - - fdmax = 1; - } - else { - fds[0].fd = w->ifd; - fds[0].events = 0; - fds[0].revents = 0; - if(web_client_has_wait_receive(w)) fds[0].events |= POLLIN; - ifd = &fds[0]; - - fds[1].fd = w->ofd; - fds[1].events = 0; - fds[1].revents = 0; - if(web_client_has_wait_send(w)) fds[1].events |= POLLOUT; - ofd = &fds[1]; - - fdmax = 2; - } - - debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, web_client_has_wait_receive(w)?"INPUT":"", web_client_has_wait_send(w)?"OUTPUT":""); - errno = 0; - timeout_ms = web_client_timeout * 1000; - retval = poll(fds, fdmax, timeout_ms); - - if(unlikely(netdata_exit)) break; - - if(unlikely(retval == -1)) { - if(errno == EAGAIN || errno == EINTR) { - debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id); - continue; - } - - debug(D_WEB_CLIENT, "%llu: LISTENER: poll() failed (input fd = %d, output fd = %d). Closing client.", w->id, w->ifd, w->ofd); - break; - } - else if(unlikely(!retval)) { - debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, web_client_has_wait_receive(w)?"INPUT":"", web_client_has_wait_send(w)?"OUTPUT":""); - break; - } - - if(unlikely(netdata_exit)) break; - - int used = 0; - if(web_client_has_wait_send(w) && ofd->revents & POLLOUT) { - used++; - if(web_client_send(w) < 0) { - debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id); - break; - } - } - - if(unlikely(netdata_exit)) break; - - if(web_client_has_wait_receive(w) && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) { - used++; - if(web_client_receive(w) < 0) { - debug(D_WEB_CLIENT, "%llu: Cannot receive data from client. Closing client.", w->id); - break; - } - - if(w->mode == WEB_CLIENT_MODE_NORMAL) { - debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id); - 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; - } - } - - if(unlikely(!used)) { - debug(D_WEB_CLIENT_ACCESS, "%llu: Received error on socket.", w->id); - break; - } - } - - if(w->mode != WEB_CLIENT_MODE_STREAM) - log_connection(w, "DISCONNECTED"); - - web_client_request_done(w); - - debug(D_WEB_CLIENT, "%llu: done...", w->id); - - // close the sockets/files now - // to free file descriptors - if(w->ifd == w->ofd) { - if(w->ifd != -1) close(w->ifd); - } - else { - if(w->ifd != -1) close(w->ifd); - if(w->ofd != -1) close(w->ofd); - } - w->ifd = -1; - w->ofd = -1; - - netdata_thread_cleanup_pop(1); - return NULL; -} - -// -------------------------------------------------------------------------------------- -// the main socket listener - MULTI-THREADED - -// 1. it accepts new incoming requests on our port -// 2. creates a new web_client for each connection received -// 3. spawns a new netdata_thread to serve the client (this is optimal for keep-alive clients) -// 4. cleans up old web_clients that their netdata_threads have been exited - -static void web_client_multi_threaded_web_server_release_clients(void) { - struct web_client *w; - for(w = web_clients_cache.used; w ; ) { - if(unlikely(!w->running && web_client_check_dead(w))) { - struct web_client *t = w->next; - web_client_release(w); - w = t; - } - else - w = w->next; - } -} - -static void web_client_multi_threaded_web_server_stop_all_threads(void) { - struct web_client *w; - - int found = 1, max = 2 * USEC_PER_SEC, step = 50000; - for(w = web_clients_cache.used; w ; w = w->next) { - if(w->running) { - found++; - info("stopping web client %s, id %llu", w->client_ip, w->id); - netdata_thread_cancel(w->thread); - } - } - - while(found && max > 0) { - max -= step; - info("Waiting %d web threads to finish...", found); - sleep_usec(step); - found = 0; - for(w = web_clients_cache.used; w ; w = w->next) - if(w->running) found++; - } - - if(found) - error("%d web threads are taking too long to finish. Giving up.", found); -} - -static struct pollfd *socket_listen_main_multi_threaded_fds = NULL; - -static void socket_listen_main_multi_threaded_cleanup(void *data) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("cleaning up..."); - - info("releasing allocated memory..."); - freez(socket_listen_main_multi_threaded_fds); - - info("closing all sockets..."); - listen_sockets_close(&api_sockets); - - info("stopping all running web server threads..."); - web_client_multi_threaded_web_server_stop_all_threads(); - - info("freeing web clients cache..."); - web_client_cache_destroy(); - - info("cleanup completed."); - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -#define CLEANUP_EVERY_EVENTS 60 -void *socket_listen_main_multi_threaded(void *ptr) { - netdata_thread_cleanup_push(socket_listen_main_multi_threaded_cleanup, ptr); - - web_server_mode = WEB_SERVER_MODE_MULTI_THREADED; - web_server_is_multithreaded = 1; - - struct web_client *w; - int retval, counter = 0; - - if(!api_sockets.opened) - fatal("LISTENER: No sockets to listen to."); - - socket_listen_main_multi_threaded_fds = callocz(sizeof(struct pollfd), api_sockets.opened); - - size_t i; - for(i = 0; i < api_sockets.opened ;i++) { - socket_listen_main_multi_threaded_fds[i].fd = api_sockets.fds[i]; - socket_listen_main_multi_threaded_fds[i].events = POLLIN; - socket_listen_main_multi_threaded_fds[i].revents = 0; - - info("Listening on '%s'", (api_sockets.fds_names[i])?api_sockets.fds_names[i]:"UNKNOWN"); - } - - int timeout_ms = 1 * 1000; - - while(!netdata_exit) { - - // debug(D_WEB_CLIENT, "LISTENER: Waiting..."); - retval = poll(socket_listen_main_multi_threaded_fds, api_sockets.opened, timeout_ms); - - if(unlikely(retval == -1)) { - error("LISTENER: poll() failed."); - continue; - } - else if(unlikely(!retval)) { - debug(D_WEB_CLIENT, "LISTENER: poll() timeout."); - counter++; - continue; - } - - for(i = 0 ; i < api_sockets.opened ; i++) { - short int revents = socket_listen_main_multi_threaded_fds[i].revents; - - // check for new incoming connections - if(revents & POLLIN || revents & POLLPRI) { - socket_listen_main_multi_threaded_fds[i].revents = 0; - - w = web_client_create_on_listenfd(socket_listen_main_multi_threaded_fds[i].fd); - if(unlikely(!w)) { - // no need for error log - web_client_create_on_listenfd already logged the error - continue; - } - - if(api_sockets.fds_families[i] == AF_UNIX) - web_client_set_unix(w); - else - web_client_set_tcp(w); - - char tag[NETDATA_THREAD_TAG_MAX + 1]; - snprintfz(tag, NETDATA_THREAD_TAG_MAX, "WEB_CLIENT[%llu,[%s]:%s]", w->id, w->client_ip, w->client_port); - - w->running = 1; - if(netdata_thread_create(&w->thread, tag, NETDATA_THREAD_OPTION_DONT_LOG, multi_threaded_web_client_worker_main, w) != 0) { - w->running = 0; - web_client_release(w); - } - } - } - - counter++; - if(counter > CLEANUP_EVERY_EVENTS) { - counter = 0; - web_client_multi_threaded_web_server_release_clients(); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - - -// -------------------------------------------------------------------------------------- -// the main socket listener - SINGLE-THREADED - -struct web_client *single_threaded_clients[FD_SETSIZE]; - -static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) { - if(unlikely(web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w)))) { - return 1; - } - - if(unlikely(w->ifd < 0 || w->ifd >= (int)FD_SETSIZE || w->ofd < 0 || w->ofd >= (int)FD_SETSIZE)) { - error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, (int)FD_SETSIZE); - return 1; - } - - FD_SET(w->ifd, efds); - if(unlikely(*max < w->ifd)) *max = w->ifd; - - if(unlikely(w->ifd != w->ofd)) { - if(*max < w->ofd) *max = w->ofd; - FD_SET(w->ofd, efds); - } - - if(web_client_has_wait_receive(w)) FD_SET(w->ifd, ifds); - if(web_client_has_wait_send(w)) FD_SET(w->ofd, ofds); - - single_threaded_clients[w->ifd] = w; - single_threaded_clients[w->ofd] = w; - - return 0; -} - -static inline int single_threaded_unlink_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds) { - FD_CLR(w->ifd, efds); - if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds); - - if(web_client_has_wait_receive(w)) FD_CLR(w->ifd, ifds); - if(web_client_has_wait_send(w)) FD_CLR(w->ofd, ofds); - - single_threaded_clients[w->ifd] = NULL; - single_threaded_clients[w->ofd] = NULL; - - if(unlikely(web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w)))) { - return 1; - } - - return 0; -} - -static void socket_listen_main_single_threaded_cleanup(void *data) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - info("closing all sockets..."); - listen_sockets_close(&api_sockets); - - info("freeing web clients cache..."); - web_client_cache_destroy(); - - info("cleanup completed."); - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *socket_listen_main_single_threaded(void *ptr) { - netdata_thread_cleanup_push(socket_listen_main_single_threaded_cleanup, ptr); - web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED; - web_server_is_multithreaded = 0; - - struct web_client *w; - - if(!api_sockets.opened) - fatal("LISTENER: no listen sockets available."); - - size_t i; - for(i = 0; i < (size_t)FD_SETSIZE ; i++) - single_threaded_clients[i] = NULL; - - fd_set ifds, ofds, efds, rifds, rofds, refds; - FD_ZERO (&ifds); - FD_ZERO (&ofds); - FD_ZERO (&efds); - int fdmax = 0; - - for(i = 0; i < api_sockets.opened ; i++) { - if (api_sockets.fds[i] < 0 || api_sockets.fds[i] >= (int)FD_SETSIZE) - fatal("LISTENER: Listen socket %d is not ready, or invalid.", api_sockets.fds[i]); - - info("Listening on '%s'", (api_sockets.fds_names[i])?api_sockets.fds_names[i]:"UNKNOWN"); - - FD_SET(api_sockets.fds[i], &ifds); - FD_SET(api_sockets.fds[i], &efds); - if(fdmax < api_sockets.fds[i]) - fdmax = api_sockets.fds[i]; - } - - while(!netdata_exit) { - debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax); - - struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; - rifds = ifds; - rofds = ofds; - refds = efds; - int retval = select(fdmax+1, &rifds, &rofds, &refds, &tv); - - if(unlikely(retval == -1)) { - error("LISTENER: select() failed."); - continue; - } - else if(likely(retval)) { - debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something."); - - for(i = 0; i < api_sockets.opened ; i++) { - if (FD_ISSET(api_sockets.fds[i], &rifds)) { - debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection."); - w = web_client_create_on_listenfd(api_sockets.fds[i]); - if(unlikely(!w)) - continue; - - if(api_sockets.fds_families[i] == AF_UNIX) - web_client_set_unix(w); - else - web_client_set_tcp(w); - - if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) { - web_client_release(w); - } - } - } - - for(i = 0 ; i <= (size_t)fdmax ; i++) { - if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds))) - continue; - - w = single_threaded_clients[i]; - if(unlikely(!w)) { - // error("no client on slot %zu", i); - continue; - } - - if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) { - // error("failed to unlink client %zu", i); - web_client_release(w); - continue; - } - - if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) { - // error("no input on client %zu", i); - web_client_release(w); - continue; - } - - if (unlikely(web_client_has_wait_receive(w) && FD_ISSET(w->ifd, &rifds))) { - if (unlikely(web_client_receive(w) < 0)) { - // error("cannot read from client %zu", i); - web_client_release(w); - continue; - } - - if (w->mode != WEB_CLIENT_MODE_FILECOPY) { - debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id); - web_client_process_request(w); - } - } - - if (unlikely(web_client_has_wait_send(w) && FD_ISSET(w->ofd, &rofds))) { - if (unlikely(web_client_send(w) < 0)) { - // error("cannot send data to client %zu", i); - debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id); - web_client_release(w); - continue; - } - } - - if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) { - // error("failed to link client %zu", i); - web_client_release(w); - } - } - } - else { - debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout."); - } - } - - netdata_thread_cleanup_pop(1); - return NULL; -} - - -// -------------------------------------------------------------------------------------- -// the main socket listener - STATIC-THREADED - -struct web_server_static_threaded_worker { - netdata_thread_t thread; - - int id; - int running; - - size_t max_sockets; - - volatile size_t connected; - volatile size_t disconnected; - volatile size_t receptions; - volatile size_t sends; - volatile size_t max_concurrent; - - volatile size_t files_read; - volatile size_t file_reads; -}; - -static long long static_threaded_workers_count = 1; -static struct web_server_static_threaded_worker *static_workers_private_data = NULL; -static __thread struct web_server_static_threaded_worker *worker_private = NULL; - -// ---------------------------------------------------------------------------- - -static inline int web_server_check_client_status(struct web_client *w) { - if(unlikely(web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w)))) - return -1; - - return 0; -} - -// ---------------------------------------------------------------------------- -// web server files - -static void *web_server_file_add_callback(POLLINFO *pi, short int *events, void *data) { - struct web_client *w = (struct web_client *)data; - - worker_private->files_read++; - - debug(D_WEB_CLIENT, "%llu: ADDED FILE READ ON FD %d", w->id, pi->fd); - *events = POLLIN; - pi->data = w; - return w; -} - -static void web_werver_file_del_callback(POLLINFO *pi) { - struct web_client *w = (struct web_client *)pi->data; - debug(D_WEB_CLIENT, "%llu: RELEASE FILE READ ON FD %d", w->id, pi->fd); - - w->pollinfo_filecopy_slot = 0; - - if(unlikely(!w->pollinfo_slot)) { - debug(D_WEB_CLIENT, "%llu: CROSS WEB CLIENT CLEANUP (iFD %d, oFD %d)", w->id, pi->fd, w->ofd); - web_client_release(w); - } -} - -static int web_server_file_read_callback(POLLINFO *pi, short int *events) { - struct web_client *w = (struct web_client *)pi->data; - - // if there is no POLLINFO linked to this, it means the client disconnected - // stop the file reading too - if(unlikely(!w->pollinfo_slot)) { - debug(D_WEB_CLIENT, "%llu: PREVENTED ATTEMPT TO READ FILE ON FD %d, ON CLOSED WEB CLIENT", w->id, pi->fd); - return -1; - } - - if(unlikely(w->mode != WEB_CLIENT_MODE_FILECOPY || w->ifd == w->ofd)) { - debug(D_WEB_CLIENT, "%llu: PREVENTED ATTEMPT TO READ FILE ON FD %d, ON NON-FILECOPY WEB CLIENT", w->id, pi->fd); - return -1; - } - - debug(D_WEB_CLIENT, "%llu: READING FILE ON FD %d", w->id, pi->fd); - - worker_private->file_reads++; - ssize_t ret = unlikely(web_client_read_file(w)); - - if(likely(web_client_has_wait_send(w))) { - POLLJOB *p = pi->p; // our POLLJOB - POLLINFO *wpi = pollinfo_from_slot(p, w->pollinfo_slot); // POLLINFO of the client socket - - debug(D_WEB_CLIENT, "%llu: SIGNALING W TO SEND (iFD %d, oFD %d)", w->id, pi->fd, wpi->fd); - p->fds[wpi->slot].events |= POLLOUT; - } - - if(unlikely(ret <= 0 || w->ifd == w->ofd)) { - debug(D_WEB_CLIENT, "%llu: DONE READING FILE ON FD %d", w->id, pi->fd); - return -1; - } - - *events = POLLIN; - return 0; -} - -static int web_server_file_write_callback(POLLINFO *pi, short int *events) { - (void)pi; - (void)events; - - error("Writing to web files is not supported!"); - - return -1; -} - -// ---------------------------------------------------------------------------- -// web server clients - -static void *web_server_add_callback(POLLINFO *pi, short int *events, void *data) { - (void)data; - - worker_private->connected++; - - size_t concurrent = worker_private->connected - worker_private->disconnected; - if(unlikely(concurrent > worker_private->max_concurrent)) - worker_private->max_concurrent = concurrent; - - *events = POLLIN; - - debug(D_WEB_CLIENT_ACCESS, "LISTENER on %d: new connection.", pi->fd); - struct web_client *w = web_client_create_on_fd(pi->fd, pi->client_ip, pi->client_port); - w->pollinfo_slot = pi->slot; - - if(unlikely(pi->socktype == AF_UNIX)) - web_client_set_unix(w); - else - web_client_set_tcp(w); - - debug(D_WEB_CLIENT, "%llu: ADDED CLIENT FD %d", w->id, pi->fd); - return w; -} - -// TCP client disconnected -static void web_server_del_callback(POLLINFO *pi) { - worker_private->disconnected++; - - struct web_client *w = (struct web_client *)pi->data; - - w->pollinfo_slot = 0; - if(unlikely(w->pollinfo_filecopy_slot)) { - POLLINFO *fpi = pollinfo_from_slot(pi->p, w->pollinfo_filecopy_slot); // POLLINFO of the client socket - debug(D_WEB_CLIENT, "%llu: THE CLIENT WILL BE FRED BY READING FILE JOB ON FD %d", w->id, fpi->fd); - } - else { - if(web_client_flag_check(w, WEB_CLIENT_FLAG_DONT_CLOSE_SOCKET)) - pi->flags |= POLLINFO_FLAG_DONT_CLOSE; - - debug(D_WEB_CLIENT, "%llu: CLOSING CLIENT FD %d", w->id, pi->fd); - web_client_release(w); - } -} - -static int web_server_rcv_callback(POLLINFO *pi, short int *events) { - worker_private->receptions++; - - struct web_client *w = (struct web_client *)pi->data; - int fd = pi->fd; - - if(unlikely(web_client_receive(w) < 0)) - return -1; - - debug(D_WEB_CLIENT, "%llu: processing received data on fd %d.", w->id, fd); - web_client_process_request(w); - - if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) { - if(w->pollinfo_filecopy_slot == 0) { - debug(D_WEB_CLIENT, "%llu: FILECOPY DETECTED ON FD %d", w->id, pi->fd); - - if (unlikely(w->ifd != -1 && w->ifd != w->ofd && w->ifd != fd)) { - // add a new socket to poll_events, with the same - debug(D_WEB_CLIENT, "%llu: CREATING FILECOPY SLOT ON FD %d", w->id, pi->fd); - - POLLINFO *fpi = poll_add_fd( - pi->p - , w->ifd - , 0 - , POLLINFO_FLAG_CLIENT_SOCKET - , "FILENAME" - , "" - , web_server_file_add_callback - , web_werver_file_del_callback - , web_server_file_read_callback - , web_server_file_write_callback - , (void *) w - ); - - if(fpi) - w->pollinfo_filecopy_slot = fpi->slot; - else { - error("Failed to add filecopy fd. Closing client."); - return -1; - } - } - } - } - else { - if(unlikely(w->ifd == fd && web_client_has_wait_receive(w))) - *events |= POLLIN; - } - - if(unlikely(w->ofd == fd && web_client_has_wait_send(w))) - *events |= POLLOUT; - - return web_server_check_client_status(w); -} - -static int web_server_snd_callback(POLLINFO *pi, short int *events) { - worker_private->sends++; - - struct web_client *w = (struct web_client *)pi->data; - int fd = pi->fd; - - debug(D_WEB_CLIENT, "%llu: sending data on fd %d.", w->id, fd); - - if(unlikely(web_client_send(w) < 0)) - return -1; - - if(unlikely(w->ifd == fd && web_client_has_wait_receive(w))) - *events |= POLLIN; - - if(unlikely(w->ofd == fd && web_client_has_wait_send(w))) - *events |= POLLOUT; - - return web_server_check_client_status(w); -} - -static void web_server_tmr_callback(void *timer_data) { - worker_private = (struct web_server_static_threaded_worker *)timer_data; - - static __thread RRDSET *st = NULL; - static __thread RRDDIM *rd_user = NULL, *rd_system = NULL; - - if(unlikely(!st)) { - char id[100 + 1]; - char title[100 + 1]; - - snprintfz(id, 100, "web_thread%d_cpu", worker_private->id + 1); - snprintfz(title, 100, "NetData web server thread No %d CPU usage", worker_private->id + 1); - - st = rrdset_create_localhost( - "netdata" - , id - , NULL - , "web" - , "netdata.web_cpu" - , title - , "milliseconds/s" - , "web" - , "stats" - , 132000 + worker_private->id - , default_rrd_update_every - , RRDSET_TYPE_STACKED - ); - - rd_user = rrddim_add(st, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rd_system = rrddim_add(st, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st); - - struct rusage rusage; - getrusage(RUSAGE_THREAD, &rusage); - rrddim_set_by_pointer(st, rd_user, rusage.ru_utime.tv_sec * 1000000ULL + rusage.ru_utime.tv_usec); - rrddim_set_by_pointer(st, rd_system, rusage.ru_stime.tv_sec * 1000000ULL + rusage.ru_stime.tv_usec); - rrdset_done(st); -} - -// ---------------------------------------------------------------------------- -// web server worker thread - -static void socket_listen_main_static_threaded_worker_cleanup(void *ptr) { - worker_private = (struct web_server_static_threaded_worker *)ptr; - - info("freeing local web clients cache..."); - web_client_cache_destroy(); - - info("stopped after %zu connects, %zu disconnects (max concurrent %zu), %zu receptions and %zu sends", - worker_private->connected, - worker_private->disconnected, - worker_private->max_concurrent, - worker_private->receptions, - worker_private->sends - ); - - worker_private->running = 0; -} - -void *socket_listen_main_static_threaded_worker(void *ptr) { - worker_private = (struct web_server_static_threaded_worker *)ptr; - worker_private->running = 1; - - netdata_thread_cleanup_push(socket_listen_main_static_threaded_worker_cleanup, ptr); - - poll_events(&api_sockets - , web_server_add_callback - , web_server_del_callback - , web_server_rcv_callback - , web_server_snd_callback - , web_server_tmr_callback - , web_allow_connections_from - , NULL - , web_client_first_request_timeout - , web_client_timeout - , default_rrd_update_every * 1000 // timer_milliseconds - , ptr // timer_data - , worker_private->max_sockets - ); - - netdata_thread_cleanup_pop(1); - return NULL; -} - - -// ---------------------------------------------------------------------------- -// web server main thread - also becomes a worker - -static void socket_listen_main_static_threaded_cleanup(void *ptr) { - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; - - int i, found = 0, max = 2 * USEC_PER_SEC, step = 50000; - - // we start from 1, - 0 is self - for(i = 1; i < static_threaded_workers_count; i++) { - if(static_workers_private_data[i].running) { - found++; - info("stopping worker %d", i + 1); - netdata_thread_cancel(static_workers_private_data[i].thread); - } - else - info("found stopped worker %d", i + 1); - } - - while(found && max > 0) { - max -= step; - info("Waiting %d static web threads to finish...", found); - sleep_usec(step); - found = 0; - - // we start from 1, - 0 is self - for(i = 1; i < static_threaded_workers_count; i++) { - if (static_workers_private_data[i].running) - found++; - } - } - - if(found) - error("%d static web threads are taking too long to finish. Giving up.", found); - - info("closing all web server sockets..."); - listen_sockets_close(&api_sockets); - - info("all static web threads stopped."); - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; -} - -void *socket_listen_main_static_threaded(void *ptr) { - netdata_thread_cleanup_push(socket_listen_main_static_threaded_cleanup, ptr); - web_server_mode = WEB_SERVER_MODE_STATIC_THREADED; - - if(!api_sockets.opened) - fatal("LISTENER: no listen sockets available."); - - // 6 threads is the optimal value - // since 6 are the parallel connections browsers will do - // so, if the machine has more CPUs, avoid using resources unnecessarily - int def_thread_count = (processors > 6)?6:processors; - - static_threaded_workers_count = config_get_number(CONFIG_SECTION_WEB, "web server threads", def_thread_count); - if(static_threaded_workers_count < 1) static_threaded_workers_count = 1; - - size_t max_sockets = (size_t)config_get_number(CONFIG_SECTION_WEB, "web server max sockets", (long long int)(rlimit_nofile.rlim_cur / 2)); - - static_workers_private_data = callocz((size_t)static_threaded_workers_count, sizeof(struct web_server_static_threaded_worker)); - - web_server_is_multithreaded = (static_threaded_workers_count > 1); - - int i; - for(i = 1; i < static_threaded_workers_count; i++) { - static_workers_private_data[i].id = i; - static_workers_private_data[i].max_sockets = max_sockets / static_threaded_workers_count; - - char tag[50 + 1]; - snprintfz(tag, 50, "WEB_SERVER[static%d]", i+1); - - info("starting worker %d", i+1); - netdata_thread_create(&static_workers_private_data[i].thread, tag, NETDATA_THREAD_OPTION_DEFAULT, socket_listen_main_static_threaded_worker, (void *)&static_workers_private_data[i]); - } - - // and the main one - static_workers_private_data[0].max_sockets = max_sockets / static_threaded_workers_count; - socket_listen_main_static_threaded_worker((void *)&static_workers_private_data[0]); - - netdata_thread_cleanup_pop(1); - return NULL; -} diff --git a/src/web_server.h b/src/web_server.h deleted file mode 100644 index 7492547ef..000000000 --- a/src/web_server.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef NETDATA_WEB_SERVER_H -#define NETDATA_WEB_SERVER_H 1 - -#define WEB_PATH_FILE "file" -#define WEB_PATH_DATA "data" -#define WEB_PATH_DATASOURCE "datasource" -#define WEB_PATH_GRAPH "graph" - -#ifndef API_LISTEN_PORT -#define API_LISTEN_PORT 19999 -#endif - -#ifndef API_LISTEN_BACKLOG -#define API_LISTEN_BACKLOG 4096 -#endif - -typedef enum web_server_mode { - WEB_SERVER_MODE_SINGLE_THREADED, - WEB_SERVER_MODE_STATIC_THREADED, - WEB_SERVER_MODE_MULTI_THREADED, - WEB_SERVER_MODE_NONE -} WEB_SERVER_MODE; - -extern SIMPLE_PATTERN *web_allow_connections_from; -extern SIMPLE_PATTERN *web_allow_dashboard_from; -extern SIMPLE_PATTERN *web_allow_registry_from; -extern SIMPLE_PATTERN *web_allow_badges_from; -extern SIMPLE_PATTERN *web_allow_streaming_from; -extern SIMPLE_PATTERN *web_allow_netdataconf_from; - -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); -extern void *socket_listen_main_static_threaded(void *ptr); -extern int api_listen_sockets_setup(void); - -#define DEFAULT_TIMEOUT_TO_RECEIVE_FIRST_WEB_REQUEST 60 -#define DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS 60 -extern int web_client_timeout; -extern int web_client_first_request_timeout; - -#endif /* NETDATA_WEB_SERVER_H */ diff --git a/src/zfs_common.c b/src/zfs_common.c deleted file mode 100644 index 05935dd0f..000000000 --- a/src/zfs_common.c +++ /dev/null @@ -1,713 +0,0 @@ -#include "common.h" -#include "zfs_common.h" - -struct arcstats arcstats = { 0 }; - -void generate_charts_arcstats(const char *plugin, int update_every) { - - // ARC reads - unsigned long long aread = arcstats.hits + arcstats.misses; - - // Demand reads - unsigned long long dhit = arcstats.demand_data_hits + arcstats.demand_metadata_hits; - unsigned long long dmiss = arcstats.demand_data_misses + arcstats.demand_metadata_misses; - unsigned long long dread = dhit + dmiss; - - // Prefetch reads - unsigned long long phit = arcstats.prefetch_data_hits + arcstats.prefetch_metadata_hits; - unsigned long long pmiss = arcstats.prefetch_data_misses + arcstats.prefetch_metadata_misses; - unsigned long long pread = phit + pmiss; - - // Metadata reads - unsigned long long mhit = arcstats.prefetch_metadata_hits + arcstats.demand_metadata_hits; - unsigned long long mmiss = arcstats.prefetch_metadata_misses + arcstats.demand_metadata_misses; - unsigned long long mread = mhit + mmiss; - - // l2 reads - unsigned long long l2hit = arcstats.l2_hits; - unsigned long long l2miss = arcstats.l2_misses; - unsigned long long l2read = l2hit + l2miss; - - // -------------------------------------------------------------------- - - { - static RRDSET *st_arc_size = NULL; - static RRDDIM *rd_arc_size = NULL; - static RRDDIM *rd_arc_target_size = NULL; - static RRDDIM *rd_arc_target_min_size = NULL; - static RRDDIM *rd_arc_target_max_size = NULL; - - if (unlikely(!st_arc_size)) { - st_arc_size = rrdset_create_localhost( - "zfs" - , "arc_size" - , NULL - , ZFS_FAMILY_SIZE - , NULL - , "ZFS ARC Size" - , "MB" - , plugin - , "zfs" - , 2500 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_arc_size = rrddim_add(st_arc_size, "size", "arcsz", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_arc_target_size = rrddim_add(st_arc_size, "target", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_arc_target_min_size = rrddim_add(st_arc_size, "min", "min (hard limit)", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_arc_target_max_size = rrddim_add(st_arc_size, "max", "max (high water)", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_arc_size); - - rrddim_set_by_pointer(st_arc_size, rd_arc_size, arcstats.size); - rrddim_set_by_pointer(st_arc_size, rd_arc_target_size, arcstats.c); - rrddim_set_by_pointer(st_arc_size, rd_arc_target_min_size, arcstats.c_min); - rrddim_set_by_pointer(st_arc_size, rd_arc_target_max_size, arcstats.c_max); - rrdset_done(st_arc_size); - } - - // -------------------------------------------------------------------- - - if(likely(arcstats.l2exist)) { - static RRDSET *st_l2_size = NULL; - static RRDDIM *rd_l2_size = NULL; - static RRDDIM *rd_l2_asize = NULL; - - if (unlikely(!st_l2_size)) { - st_l2_size = rrdset_create_localhost( - "zfs" - , "l2_size" - , NULL - , ZFS_FAMILY_SIZE - , NULL - , "ZFS L2 ARC Size" - , "MB" - , plugin - , "zfs" - , 2500 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_l2_asize = rrddim_add(st_l2_size, "actual", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - rd_l2_size = rrddim_add(st_l2_size, "size", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_l2_size); - - rrddim_set_by_pointer(st_l2_size, rd_l2_size, arcstats.l2_size); - rrddim_set_by_pointer(st_l2_size, rd_l2_asize, arcstats.l2_asize); - rrdset_done(st_l2_size); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_reads = NULL; - static RRDDIM *rd_aread = NULL; - static RRDDIM *rd_dread = NULL; - static RRDDIM *rd_pread = NULL; - static RRDDIM *rd_mread = NULL; - static RRDDIM *rd_l2read = NULL; - - if (unlikely(!st_reads)) { - st_reads = rrdset_create_localhost( - "zfs" - , "reads" - , NULL - , ZFS_FAMILY_ACCESSES - , NULL - , "ZFS Reads" - , "reads/s" - , plugin - , "zfs" - , 2510 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_aread = rrddim_add(st_reads, "areads", "arc", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_dread = rrddim_add(st_reads, "dreads", "demand", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_pread = rrddim_add(st_reads, "preads", "prefetch", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_mread = rrddim_add(st_reads, "mreads", "metadata", 1, 1, RRD_ALGORITHM_INCREMENTAL); - - if(arcstats.l2exist) - rd_l2read = rrddim_add(st_reads, "l2reads", "l2", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_reads); - - rrddim_set_by_pointer(st_reads, rd_aread, aread); - rrddim_set_by_pointer(st_reads, rd_dread, dread); - rrddim_set_by_pointer(st_reads, rd_pread, pread); - rrddim_set_by_pointer(st_reads, rd_mread, mread); - - if(arcstats.l2exist) - rrddim_set_by_pointer(st_reads, rd_l2read, l2read); - - rrdset_done(st_reads); - } - - // -------------------------------------------------------------------- - - if(likely(arcstats.l2exist)) { - static RRDSET *st_l2bytes = NULL; - static RRDDIM *rd_l2_read_bytes = NULL; - static RRDDIM *rd_l2_write_bytes = NULL; - - if (unlikely(!st_l2bytes)) { - st_l2bytes = rrdset_create_localhost( - "zfs" - , "bytes" - , NULL - , ZFS_FAMILY_ACCESSES - , NULL - , "ZFS ARC L2 Read/Write Rate" - , "kilobytes/s" - , plugin - , "zfs" - , 2700 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_l2_read_bytes = rrddim_add(st_l2bytes, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL); - rd_l2_write_bytes = rrddim_add(st_l2bytes, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_l2bytes); - - rrddim_set_by_pointer(st_l2bytes, rd_l2_read_bytes, arcstats.l2_read_bytes); - rrddim_set_by_pointer(st_l2bytes, rd_l2_write_bytes, arcstats.l2_write_bytes); - rrdset_done(st_l2bytes); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_ahits = NULL; - static RRDDIM *rd_ahits = NULL; - static RRDDIM *rd_amisses = NULL; - - if (unlikely(!st_ahits)) { - st_ahits = rrdset_create_localhost( - "zfs" - , "hits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS ARC Hits" - , "percentage" - , plugin - , "zfs" - , 2520 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_ahits = rrddim_add(st_ahits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_amisses = rrddim_add(st_ahits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_ahits); - - rrddim_set_by_pointer(st_ahits, rd_ahits, arcstats.hits); - rrddim_set_by_pointer(st_ahits, rd_amisses, arcstats.misses); - rrdset_done(st_ahits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_dhits = NULL; - static RRDDIM *rd_dhits = NULL; - static RRDDIM *rd_dmisses = NULL; - - if (unlikely(!st_dhits)) { - st_dhits = rrdset_create_localhost( - "zfs" - , "dhits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS Demand Hits" - , "percentage" - , plugin - , "zfs" - , 2530 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_dhits = rrddim_add(st_dhits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_dmisses = rrddim_add(st_dhits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_dhits); - - rrddim_set_by_pointer(st_dhits, rd_dhits, dhit); - rrddim_set_by_pointer(st_dhits, rd_dmisses, dmiss); - rrdset_done(st_dhits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_phits = NULL; - static RRDDIM *rd_phits = NULL; - static RRDDIM *rd_pmisses = NULL; - - if (unlikely(!st_phits)) { - st_phits = rrdset_create_localhost( - "zfs" - , "phits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS Prefetch Hits" - , "percentage" - , plugin - , "zfs" - , 2540 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_phits = rrddim_add(st_phits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_pmisses = rrddim_add(st_phits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_phits); - - rrddim_set_by_pointer(st_phits, rd_phits, phit); - rrddim_set_by_pointer(st_phits, rd_pmisses, pmiss); - rrdset_done(st_phits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_mhits = NULL; - static RRDDIM *rd_mhits = NULL; - static RRDDIM *rd_mmisses = NULL; - - if (unlikely(!st_mhits)) { - st_mhits = rrdset_create_localhost( - "zfs" - , "mhits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS Metadata Hits" - , "percentage" - , plugin - , "zfs" - , 2550 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_mhits = rrddim_add(st_mhits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_mmisses = rrddim_add(st_mhits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_mhits); - - rrddim_set_by_pointer(st_mhits, rd_mhits, mhit); - rrddim_set_by_pointer(st_mhits, rd_mmisses, mmiss); - rrdset_done(st_mhits); - } - - // -------------------------------------------------------------------- - - if(likely(arcstats.l2exist)) { - static RRDSET *st_l2hits = NULL; - static RRDDIM *rd_l2hits = NULL; - static RRDDIM *rd_l2misses = NULL; - - if (unlikely(!st_l2hits)) { - st_l2hits = rrdset_create_localhost( - "zfs" - , "l2hits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS L2 Hits" - , "percentage" - , plugin - , "zfs" - , 2560 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_l2hits = rrddim_add(st_l2hits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_l2misses = rrddim_add(st_l2hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_l2hits); - - rrddim_set_by_pointer(st_l2hits, rd_l2hits, l2hit); - rrddim_set_by_pointer(st_l2hits, rd_l2misses, l2miss); - rrdset_done(st_l2hits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_list_hits = NULL; - static RRDDIM *rd_mfu = NULL; - static RRDDIM *rd_mru = NULL; - static RRDDIM *rd_mfug = NULL; - static RRDDIM *rd_mrug = NULL; - - if (unlikely(!st_list_hits)) { - st_list_hits = rrdset_create_localhost( - "zfs" - , "list_hits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS List Hits" - , "hits/s" - , plugin - , "zfs" - , 2600 - , update_every - , RRDSET_TYPE_AREA - ); - - rd_mfu = rrddim_add(st_list_hits, "mfu", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_mfug = rrddim_add(st_list_hits, "mfug", "mfu ghost", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_mru = rrddim_add(st_list_hits, "mru", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_mrug = rrddim_add(st_list_hits, "mrug", "mru ghost", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_list_hits); - - rrddim_set_by_pointer(st_list_hits, rd_mfu, arcstats.mfu_hits); - rrddim_set_by_pointer(st_list_hits, rd_mru, arcstats.mru_hits); - rrddim_set_by_pointer(st_list_hits, rd_mfug, arcstats.mfu_ghost_hits); - rrddim_set_by_pointer(st_list_hits, rd_mrug, arcstats.mru_ghost_hits); - rrdset_done(st_list_hits); - } -} - -void generate_charts_arc_summary(const char *plugin, int update_every) { - unsigned long long arc_accesses_total = arcstats.hits + arcstats.misses; - unsigned long long real_hits = arcstats.mfu_hits + arcstats.mru_hits; - unsigned long long real_misses = arc_accesses_total - real_hits; - - //unsigned long long anon_hits = arcstats.hits - (arcstats.mfu_hits + arcstats.mru_hits + arcstats.mfu_ghost_hits + arcstats.mru_ghost_hits); - - unsigned long long arc_size = arcstats.size; - unsigned long long mru_size = arcstats.p; - //unsigned long long target_min_size = arcstats.c_min; - //unsigned long long target_max_size = arcstats.c_max; - unsigned long long target_size = arcstats.c; - //unsigned long long target_size_ratio = (target_max_size / target_min_size); - - unsigned long long mfu_size; - if(arc_size > target_size) - mfu_size = arc_size - mru_size; - else - mfu_size = target_size - mru_size; - - // -------------------------------------------------------------------- - - { - static RRDSET *st_arc_size_breakdown = NULL; - static RRDDIM *rd_most_recent = NULL; - static RRDDIM *rd_most_frequent = NULL; - - if (unlikely(!st_arc_size_breakdown)) { - st_arc_size_breakdown = rrdset_create_localhost( - "zfs" - , "arc_size_breakdown" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS ARC Size Breakdown" - , "percentage" - , plugin - , "zfs" - , 2520 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_most_recent = rrddim_add(st_arc_size_breakdown, "recent", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL); - rd_most_frequent = rrddim_add(st_arc_size_breakdown, "frequent", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL); - } - else - rrdset_next(st_arc_size_breakdown); - - rrddim_set_by_pointer(st_arc_size_breakdown, rd_most_recent, mru_size); - rrddim_set_by_pointer(st_arc_size_breakdown, rd_most_frequent, mfu_size); - rrdset_done(st_arc_size_breakdown); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_memory = NULL; -#ifndef __FreeBSD__ - static RRDDIM *rd_direct = NULL; -#endif - static RRDDIM *rd_throttled = NULL; -#ifndef __FreeBSD__ - static RRDDIM *rd_indirect = NULL; -#endif - - if (unlikely(!st_memory)) { - st_memory = rrdset_create_localhost( - "zfs" - , "memory_ops" - , NULL - , ZFS_FAMILY_OPERATIONS - , NULL - , "ZFS Memory Operations" - , "operations/s" - , plugin - , "zfs" - , 2523 - , update_every - , RRDSET_TYPE_LINE - ); - -#ifndef __FreeBSD__ - rd_direct = rrddim_add(st_memory, "direct", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); -#endif - rd_throttled = rrddim_add(st_memory, "throttled", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); -#ifndef __FreeBSD__ - rd_indirect = rrddim_add(st_memory, "indirect", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); -#endif - } - else - rrdset_next(st_memory); - -#ifndef __FreeBSD__ - rrddim_set_by_pointer(st_memory, rd_direct, arcstats.memory_direct_count); -#endif - rrddim_set_by_pointer(st_memory, rd_throttled, arcstats.memory_throttle_count); -#ifndef __FreeBSD__ - rrddim_set_by_pointer(st_memory, rd_indirect, arcstats.memory_indirect_count); -#endif - rrdset_done(st_memory); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_important_ops = NULL; - static RRDDIM *rd_deleted = NULL; - static RRDDIM *rd_mutex_misses = NULL; - static RRDDIM *rd_evict_skips = NULL; - static RRDDIM *rd_hash_collisions = NULL; - - if (unlikely(!st_important_ops)) { - st_important_ops = rrdset_create_localhost( - "zfs" - , "important_ops" - , NULL - , ZFS_FAMILY_OPERATIONS - , NULL - , "ZFS Important Operations" - , "operations/s" - , plugin - , "zfs" - , 2522 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_evict_skips = rrddim_add(st_important_ops, "eskip", "evict skip", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_deleted = rrddim_add(st_important_ops, "deleted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_mutex_misses = rrddim_add(st_important_ops, "mtxmis", "mutex miss", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rd_hash_collisions = rrddim_add(st_important_ops, "hash_collisions", "hash collisions", 1, 1, RRD_ALGORITHM_INCREMENTAL); - } - else - rrdset_next(st_important_ops); - - rrddim_set_by_pointer(st_important_ops, rd_deleted, arcstats.deleted); - rrddim_set_by_pointer(st_important_ops, rd_evict_skips, arcstats.evict_skip); - rrddim_set_by_pointer(st_important_ops, rd_mutex_misses, arcstats.mutex_miss); - rrddim_set_by_pointer(st_important_ops, rd_hash_collisions, arcstats.hash_collisions); - rrdset_done(st_important_ops); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_actual_hits = NULL; - static RRDDIM *rd_actual_hits = NULL; - static RRDDIM *rd_actual_misses = NULL; - - if (unlikely(!st_actual_hits)) { - st_actual_hits = rrdset_create_localhost( - "zfs" - , "actual_hits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS Actual Cache Hits" - , "percentage" - , plugin - , "zfs" - , 2519 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_actual_hits = rrddim_add(st_actual_hits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_actual_misses = rrddim_add(st_actual_hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_actual_hits); - - rrddim_set_by_pointer(st_actual_hits, rd_actual_hits, real_hits); - rrddim_set_by_pointer(st_actual_hits, rd_actual_misses, real_misses); - rrdset_done(st_actual_hits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_demand_data_hits = NULL; - static RRDDIM *rd_demand_data_hits = NULL; - static RRDDIM *rd_demand_data_misses = NULL; - - if (unlikely(!st_demand_data_hits)) { - st_demand_data_hits = rrdset_create_localhost( - "zfs" - , "demand_data_hits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS Data Demand Efficiency" - , "percentage" - , plugin - , "zfs" - , 2531 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_demand_data_hits = rrddim_add(st_demand_data_hits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_demand_data_misses = rrddim_add(st_demand_data_hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_demand_data_hits); - - rrddim_set_by_pointer(st_demand_data_hits, rd_demand_data_hits, arcstats.demand_data_hits); - rrddim_set_by_pointer(st_demand_data_hits, rd_demand_data_misses, arcstats.demand_data_misses); - rrdset_done(st_demand_data_hits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_prefetch_data_hits = NULL; - static RRDDIM *rd_prefetch_data_hits = NULL; - static RRDDIM *rd_prefetch_data_misses = NULL; - - if (unlikely(!st_prefetch_data_hits)) { - st_prefetch_data_hits = rrdset_create_localhost( - "zfs" - , "prefetch_data_hits" - , NULL - , ZFS_FAMILY_EFFICIENCY - , NULL - , "ZFS Data Prefetch Efficiency" - , "percentage" - , plugin - , "zfs" - , 2532 - , update_every - , RRDSET_TYPE_STACKED - ); - - rd_prefetch_data_hits = rrddim_add(st_prefetch_data_hits, "hits", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rd_prefetch_data_misses = rrddim_add(st_prefetch_data_hits, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - } - else - rrdset_next(st_prefetch_data_hits); - - rrddim_set_by_pointer(st_prefetch_data_hits, rd_prefetch_data_hits, arcstats.prefetch_data_hits); - rrddim_set_by_pointer(st_prefetch_data_hits, rd_prefetch_data_misses, arcstats.prefetch_data_misses); - rrdset_done(st_prefetch_data_hits); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_hash_elements = NULL; - static RRDDIM *rd_hash_elements_current = NULL; - static RRDDIM *rd_hash_elements_max = NULL; - - if (unlikely(!st_hash_elements)) { - st_hash_elements = rrdset_create_localhost( - "zfs" - , "hash_elements" - , NULL - , ZFS_FAMILY_HASH - , NULL - , "ZFS ARC Hash Elements" - , "elements" - , plugin - , "zfs" - , 2800 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_hash_elements_current = rrddim_add(st_hash_elements, "current", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_hash_elements_max = rrddim_add(st_hash_elements, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_hash_elements); - - rrddim_set_by_pointer(st_hash_elements, rd_hash_elements_current, arcstats.hash_elements); - rrddim_set_by_pointer(st_hash_elements, rd_hash_elements_max, arcstats.hash_elements_max); - rrdset_done(st_hash_elements); - } - - // -------------------------------------------------------------------- - - { - static RRDSET *st_hash_chains = NULL; - static RRDDIM *rd_hash_chains_current = NULL; - static RRDDIM *rd_hash_chains_max = NULL; - - if (unlikely(!st_hash_chains)) { - st_hash_chains = rrdset_create_localhost( - "zfs" - , "hash_chains" - , NULL - , ZFS_FAMILY_HASH - , NULL - , "ZFS ARC Hash Chains" - , "chains" - , plugin - , "zfs" - , 2810 - , update_every - , RRDSET_TYPE_LINE - ); - - rd_hash_chains_current = rrddim_add(st_hash_chains, "current", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rd_hash_chains_max = rrddim_add(st_hash_chains, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } - else - rrdset_next(st_hash_chains); - - rrddim_set_by_pointer(st_hash_chains, rd_hash_chains_current, arcstats.hash_chains); - rrddim_set_by_pointer(st_hash_chains, rd_hash_chains_max, arcstats.hash_chain_max); - rrdset_done(st_hash_chains); - } - - // -------------------------------------------------------------------- - -} \ No newline at end of file diff --git a/src/zfs_common.h b/src/zfs_common.h deleted file mode 100644 index 4494e70ca..000000000 --- a/src/zfs_common.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef NETDATA_ZFS_COMMON_H -#define NETDATA_ZFS_COMMON_H - -#define ZFS_FAMILY_SIZE "size" -#define ZFS_FAMILY_EFFICIENCY "efficiency" -#define ZFS_FAMILY_ACCESSES "accesses" -#define ZFS_FAMILY_OPERATIONS "operations" -#define ZFS_FAMILY_HASH "hashes" - -struct arcstats { - // values - unsigned long long hits; - unsigned long long misses; - unsigned long long demand_data_hits; - unsigned long long demand_data_misses; - unsigned long long demand_metadata_hits; - unsigned long long demand_metadata_misses; - unsigned long long prefetch_data_hits; - unsigned long long prefetch_data_misses; - unsigned long long prefetch_metadata_hits; - unsigned long long prefetch_metadata_misses; - unsigned long long mru_hits; - unsigned long long mru_ghost_hits; - unsigned long long mfu_hits; - unsigned long long mfu_ghost_hits; - unsigned long long deleted; - unsigned long long mutex_miss; - unsigned long long evict_skip; - unsigned long long evict_not_enough; - unsigned long long evict_l2_cached; - unsigned long long evict_l2_eligible; - unsigned long long evict_l2_ineligible; - unsigned long long evict_l2_skip; - unsigned long long hash_elements; - unsigned long long hash_elements_max; - unsigned long long hash_collisions; - unsigned long long hash_chains; - unsigned long long hash_chain_max; - unsigned long long p; - unsigned long long c; - unsigned long long c_min; - unsigned long long c_max; - unsigned long long size; - unsigned long long hdr_size; - unsigned long long data_size; - unsigned long long metadata_size; - unsigned long long other_size; - unsigned long long anon_size; - unsigned long long anon_evictable_data; - unsigned long long anon_evictable_metadata; - unsigned long long mru_size; - unsigned long long mru_evictable_data; - unsigned long long mru_evictable_metadata; - unsigned long long mru_ghost_size; - unsigned long long mru_ghost_evictable_data; - unsigned long long mru_ghost_evictable_metadata; - unsigned long long mfu_size; - unsigned long long mfu_evictable_data; - unsigned long long mfu_evictable_metadata; - unsigned long long mfu_ghost_size; - unsigned long long mfu_ghost_evictable_data; - unsigned long long mfu_ghost_evictable_metadata; - unsigned long long l2_hits; - unsigned long long l2_misses; - unsigned long long l2_feeds; - unsigned long long l2_rw_clash; - unsigned long long l2_read_bytes; - unsigned long long l2_write_bytes; - unsigned long long l2_writes_sent; - unsigned long long l2_writes_done; - unsigned long long l2_writes_error; - unsigned long long l2_writes_lock_retry; - unsigned long long l2_evict_lock_retry; - unsigned long long l2_evict_reading; - unsigned long long l2_evict_l1cached; - unsigned long long l2_free_on_write; - unsigned long long l2_cdata_free_on_write; - unsigned long long l2_abort_lowmem; - unsigned long long l2_cksum_bad; - unsigned long long l2_io_error; - unsigned long long l2_size; - unsigned long long l2_asize; - unsigned long long l2_hdr_size; - unsigned long long l2_compress_successes; - unsigned long long l2_compress_zeros; - unsigned long long l2_compress_failures; - unsigned long long memory_throttle_count; - unsigned long long duplicate_buffers; - unsigned long long duplicate_buffers_size; - unsigned long long duplicate_reads; - unsigned long long memory_direct_count; - unsigned long long memory_indirect_count; - unsigned long long arc_no_grow; - unsigned long long arc_tempreserve; - unsigned long long arc_loaned_bytes; - unsigned long long arc_prune; - unsigned long long arc_meta_used; - unsigned long long arc_meta_limit; - unsigned long long arc_meta_max; - unsigned long long arc_meta_min; - unsigned long long arc_need_free; - unsigned long long arc_sys_free; - - // flags - int l2exist; -}; - -void generate_charts_arcstats(const char *plugin, int update_every); -void generate_charts_arc_summary(const char *plugin, int update_every); - -#endif //NETDATA_ZFS_COMMON_H -- cgit v1.2.3