summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFederico Ceratto <federico.ceratto@gmail.com>2017-04-30 16:09:37 +0000
committerFederico Ceratto <federico.ceratto@gmail.com>2017-04-30 16:09:37 +0000
commit51f689a8e17ff3929acd2dbf39e936d2cd3ac723 (patch)
tree92e54f543171b69dcbc639be09d11221cf96ba28
parentNew upstream version 1.5.0+dfsg (diff)
downloadnetdata-upstream/1.6.0+dfsg.tar.xz
netdata-upstream/1.6.0+dfsg.zip
New upstream version 1.6.0+dfsgupstream/1.6.0+dfsg
-rw-r--r--.codeclimate.yml4
-rw-r--r--.gitignore2
-rw-r--r--ChangeLog168
-rw-r--r--Makefile.am17
-rw-r--r--Makefile.in372
-rw-r--r--README.md71
-rw-r--r--aclocal.m4777
-rwxr-xr-xautogen.sh2
-rw-r--r--charts.d/Makefile.am8
-rw-r--r--charts.d/Makefile.in146
-rw-r--r--[-rwxr-xr-x]charts.d/ap.chart.sh142
-rw-r--r--[-rwxr-xr-x]charts.d/apache.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/apcupsd.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/cpu_apps.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/cpufreq.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/example.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/hddtemp.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/load_average.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/mem_apps.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/mysql.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/nginx.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/nut.chart.sh31
-rw-r--r--[-rwxr-xr-x]charts.d/opensips.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/phpfpm.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/postfix.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/sensors.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/squid.chart.sh0
-rw-r--r--[-rwxr-xr-x]charts.d/tomcat.chart.sh0
-rwxr-xr-xcompile347
-rw-r--r--conf.d/Makefile.am38
-rw-r--r--conf.d/Makefile.in246
-rw-r--r--conf.d/apps_groups.conf5
-rw-r--r--conf.d/charts.d/nut.conf6
-rw-r--r--conf.d/health.d/cpu.conf4
-rw-r--r--conf.d/health.d/disks.conf32
-rw-r--r--conf.d/health.d/fping.conf53
-rw-r--r--conf.d/health.d/ipmi.conf20
-rw-r--r--conf.d/health.d/memcached.conf2
-rw-r--r--conf.d/health.d/mysql.conf4
-rw-r--r--conf.d/health.d/net.conf18
-rw-r--r--conf.d/health.d/tcp_resets.conf6
-rw-r--r--conf.d/health.d/web_log.conf161
-rw-r--r--conf.d/health_alarm_notify.conf37
-rw-r--r--conf.d/node.d/snmp.conf.md700
-rw-r--r--conf.d/python.d.conf37
-rw-r--r--conf.d/python.d/elasticsearch.conf7
-rw-r--r--conf.d/python.d/fail2ban.conf19
-rw-r--r--conf.d/python.d/mongodb.conf (renamed from conf.d/python.d/gunicorn_log.conf)26
-rw-r--r--conf.d/python.d/nsd.conf (renamed from conf.d/python.d/nginx_log.conf)38
-rw-r--r--conf.d/python.d/smartd_log.conf85
-rw-r--r--conf.d/python.d/varnish.conf8
-rw-r--r--conf.d/python.d/web_log.conf147
-rw-r--r--conf.d/stream.conf143
-rwxr-xr-xconfig.guess489
-rw-r--r--config.h.in67
-rwxr-xr-xconfig.sub180
-rw-r--r--configs.signatures48
-rwxr-xr-xconfigure4658
-rw-r--r--configure.ac494
-rw-r--r--contrib/Makefile.in126
-rw-r--r--contrib/debian/changelog3
-rw-r--r--contrib/debian/compat1
-rw-r--r--contrib/debian/control25
-rw-r--r--contrib/debian/control.wheezy25
-rw-r--r--contrib/debian/copyright10
-rw-r--r--contrib/debian/netdata.conf16
-rw-r--r--contrib/debian/netdata.default5
-rw-r--r--contrib/debian/netdata.docs1
-rwxr-xr-xcontrib/debian/netdata.init56
-rw-r--r--contrib/debian/netdata.install1
-rw-r--r--contrib/debian/netdata.lintian-overrides16
-rw-r--r--contrib/debian/netdata.postinst.in41
-rw-r--r--contrib/debian/netdata.postrm43
-rw-r--r--contrib/debian/netdata.service14
-rwxr-xr-xcontrib/debian/rules87
-rw-r--r--contrib/debian/source/format1
-rwxr-xr-xcoverity-scan.sh7
-rwxr-xr-xdepcomp487
-rw-r--r--diagrams/netdata-for-ephemeral-nodes.xml1
-rw-r--r--diagrams/netdata-proxies-example.xml1
-rwxr-xr-xinstall-sh374
-rw-r--r--installer/functions.sh344
-rw-r--r--m4/ax_c_lto.m421
-rwxr-xr-xmissing414
-rwxr-xr-xnetdata-installer.sh933
-rw-r--r--netdata.spec196
-rw-r--r--netdata.spec.in194
-rw-r--r--node.d/Makefile.in147
-rw-r--r--node.d/snmp.node.js31
-rw-r--r--plugins.d/Makefile.in141
-rwxr-xr-xplugins.d/alarm-notify.sh162
-rwxr-xr-xplugins.d/cgroup-name.sh7
-rwxr-xr-xplugins.d/fping.plugin31
-rwxr-xr-xplugins.d/python.d.plugin76
-rwxr-xr-xplugins.d/tc-qos-helper.sh100
-rw-r--r--python.d/Makefile.am16
-rw-r--r--python.d/Makefile.in182
-rw-r--r--python.d/README.md378
-rw-r--r--python.d/bind_rndc.chart.py48
-rw-r--r--python.d/cpufreq.chart.py1
-rw-r--r--python.d/elasticsearch.chart.py401
-rw-r--r--python.d/fail2ban.chart.py97
-rw-r--r--python.d/freeradius.chart.py18
-rw-r--r--python.d/gunicorn_log.chart.py72
-rw-r--r--python.d/isc_dhcpd.chart.py37
-rw-r--r--python.d/mongodb.chart.py672
-rw-r--r--python.d/mysql.chart.py546
-rw-r--r--python.d/nginx_log.chart.py82
-rw-r--r--python.d/nsd.chart.py93
-rw-r--r--[-rwxr-xr-x]python.d/phpfpm.chart.py183
-rw-r--r--python.d/postgres.chart.py526
-rw-r--r--[-rwxr-xr-x]python.d/python_modules/__init__.py0
-rw-r--r--python.d/python_modules/base.py372
-rw-r--r--python.d/smartd_log.chart.py221
-rw-r--r--python.d/tomcat.chart.py91
-rw-r--r--python.d/varnish.chart.py18
-rw-r--r--python.d/web_log.chart.py653
-rw-r--r--src/Makefile.am201
-rw-r--r--src/Makefile.in526
-rw-r--r--src/adaptive_resortable_list.c40
-rw-r--r--src/appconfig.c310
-rw-r--r--src/appconfig.h67
-rw-r--r--src/apps_plugin.c2089
-rw-r--r--src/avl.c16
-rw-r--r--src/avl.h8
-rw-r--r--src/backends.c556
-rw-r--r--src/clocks.c114
-rw-r--r--src/clocks.h94
-rw-r--r--src/common.c81
-rw-r--r--src/common.h41
-rw-r--r--src/daemon.c154
-rw-r--r--src/dictionary.c14
-rw-r--r--src/dictionary.h2
-rw-r--r--src/freebsd_sysctl.c4861
-rw-r--r--src/freeipmi_plugin.c1621
-rw-r--r--src/global_statistics.c83
-rw-r--r--[-rwxr-xr-x]src/health.c3133
-rw-r--r--src/health.h88
-rw-r--r--src/health_config.c877
-rw-r--r--src/health_json.c256
-rw-r--r--src/health_log.c465
-rw-r--r--src/inlined.h47
-rw-r--r--src/ipc.c22
-rw-r--r--src/locks.h294
-rw-r--r--src/log.c6
-rw-r--r--src/log.h56
-rw-r--r--src/macos_fw.c179
-rw-r--r--src/macos_mach_smi.c72
-rw-r--r--src/macos_sysctl.c566
-rw-r--r--src/main.c474
-rw-r--r--src/main.h2
-rw-r--r--src/plugin_checks.c31
-rw-r--r--src/plugin_freebsd.c156
-rw-r--r--src/plugin_freebsd.h113
-rw-r--r--src/plugin_idlejitter.c15
-rw-r--r--src/plugin_macos.c30
-rw-r--r--src/plugin_macos.h4
-rw-r--r--src/plugin_nfacct.c855
-rw-r--r--src/plugin_proc.c34
-rw-r--r--src/plugin_proc_diskspace.c233
-rw-r--r--src/plugin_tc.c679
-rw-r--r--src/plugins_d.c506
-rw-r--r--src/plugins_d.h3
-rw-r--r--src/proc_diskstats.c556
-rw-r--r--src/proc_interrupts.c16
-rw-r--r--src/proc_loadavg.c31
-rw-r--r--src/proc_meminfo.c103
-rw-r--r--src/proc_net_dev.c434
-rw-r--r--src/proc_net_ip_vs_stats.c31
-rw-r--r--src/proc_net_netstat.c254
-rw-r--r--src/proc_net_rpc_nfs.c47
-rw-r--r--src/proc_net_rpc_nfsd.c171
-rw-r--r--src/proc_net_snmp.c203
-rw-r--r--src/proc_net_snmp6.c465
-rw-r--r--src/proc_net_softnet_stat.c16
-rw-r--r--src/proc_net_stat_conntrack.c94
-rw-r--r--src/proc_net_stat_synproxy.c62
-rw-r--r--src/proc_self_mountinfo.c8
-rw-r--r--src/proc_softirqs.c16
-rw-r--r--src/proc_stat.c63
-rw-r--r--src/proc_sys_kernel_random_entropy_avail.c9
-rw-r--r--src/proc_uptime.c9
-rw-r--r--src/proc_vmstat.c64
-rw-r--r--src/procfile.c298
-rw-r--r--src/procfile.h16
-rw-r--r--src/registry.c98
-rw-r--r--src/registry.h13
-rw-r--r--src/registry_init.c41
-rw-r--r--src/registry_internals.c36
-rw-r--r--src/registry_internals.h8
-rw-r--r--src/registry_machine.c2
-rw-r--r--src/registry_person.c2
-rw-r--r--src/rrd.c1642
-rw-r--r--src/rrd.h460
-rw-r--r--src/rrd2json.c755
-rw-r--r--src/rrd2json.h29
-rw-r--r--src/rrd2json_api_old.c487
-rw-r--r--src/rrd2json_api_old.h14
-rw-r--r--src/rrdcalc.c415
-rw-r--r--src/rrdcalctemplate.c62
-rw-r--r--src/rrddim.c313
-rw-r--r--src/rrddimvar.c210
-rw-r--r--src/rrdfamily.c58
-rw-r--r--src/rrdhost.c583
-rw-r--r--src/rrdpush.c761
-rw-r--r--src/rrdpush.h15
-rw-r--r--src/rrdset.c1310
-rw-r--r--src/rrdsetvar.c120
-rw-r--r--src/rrdvar.c265
-rw-r--r--src/simple_pattern.c8
-rw-r--r--src/socket.c101
-rw-r--r--src/socket.h4
-rw-r--r--src/sys_devices_system_edac_mc.c34
-rw-r--r--src/sys_devices_system_node.c90
-rw-r--r--src/sys_fs_cgroup.c1081
-rw-r--r--src/sys_kernel_mm_ksm.c46
-rw-r--r--src/unit_test.c67
-rw-r--r--src/web_api_old.c237
-rw-r--r--src/web_api_old.h13
-rw-r--r--src/web_api_v1.c903
-rw-r--r--src/web_api_v1.h21
-rw-r--r--src/web_buffer.c5
-rw-r--r--src/web_buffer_svg.c332
-rw-r--r--src/web_buffer_svg.h3
-rw-r--r--src/web_client.c1759
-rw-r--r--src/web_client.h25
-rw-r--r--src/web_server.c42
-rw-r--r--src/web_server.h14
-rw-r--r--system/Makefile.in128
-rw-r--r--system/netdata.service.in2
-rw-r--r--web/Makefile.am3
-rw-r--r--web/Makefile.in174
-rw-r--r--web/dashboard.html2
-rw-r--r--web/dashboard.js1014
-rw-r--r--web/dashboard_info.js315
-rw-r--r--web/dashboard_info_custom_example.js58
-rw-r--r--web/index.html816
-rw-r--r--web/lib/gauge-1.3.2.min.js1
-rw-r--r--web/lib/gauge-d5260c3.min.js1
-rw-r--r--web/netdata-swagger.json71
-rw-r--r--web/netdata-swagger.yaml32
-rw-r--r--web/registry.html2
-rw-r--r--web/tv.html2
-rw-r--r--web/version.txt2
244 files changed, 34764 insertions, 22093 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml
index 91e0babae..02b452647 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -13,6 +13,8 @@ engines:
checks:
Similar code:
enabled: false
+ Identical code:
+ enabled: false
eslint:
enabled: true
checks:
@@ -28,6 +30,8 @@ engines:
enabled: false
no-alert:
enabled: false
+ no-undef-init:
+ enabled: false
fixme:
enabled: false
phpmd:
diff --git a/.gitignore b/.gitignore
index e5f27403d..0169e9316 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@ stamp-h1
netdata
apps.plugin
+freeipmi.plugin
netdata.spec
*.tar.*
@@ -37,6 +38,7 @@ netdata-coverity-analysis.tgz
.cproject
.idea/
+.vscode/
.project
README
TODO.md
diff --git a/ChangeLog b/ChangeLog
index c0950dec1..1f6c5f274 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,168 @@
-netdata (1.5.0) - 2016-01-22
+netdata (1.6.0) - 2017-03-20
+
+ * birthday release: 1 year netdata
+
+ netdata was first published on March 30th, 2016.
+ It has been a crazy year since then:
+
+ 225.000 unique netdata users
+ currently, at 1.000 new unique users per day
+
+ 80.000 unique netdata installations
+ currently, at 500 new installation per day
+
+ 610.000 docker pulls on docker hub
+
+ 4.000.000 netdata sessions served
+ currently, at 15.000 sessions served per day
+
+ 20.000 github stars
+
+ Thank you!
+ You are awesome!
+
+ * central netdata is here
+
+ This is the first release that supports real-time streaming of
+ metrics between netdata servers.
+
+ netdata can now be:
+
+ - autonomous host monitoring
+ (like it always has been)
+
+ - headless data collector
+ (collect and stream metrics in real-time to another netdata)
+
+ - headless proxy
+ (collect metrics from multiple netdata and stream them to another netdata)
+
+ - store and forward proxy
+ (like headless proxy, but with a local database)
+
+ - central database
+ (metrics from multiple hosts are aggregated)
+
+ metrics databases can be configured on all nodes and each node maintaining
+ a database may have a different retention policy and possibly run
+ (even different) alarms on them.
+
+ * monitoring ephemeral nodes
+
+ netdata now supports monitoring autoscaled ephemeral nodes,
+ that are started and stopped on demand (their IP is not known).
+
+ When the ephemeral nodes start streaming metrics to the central
+ netdata, the central netdata will show register them at "my-netdata"
+ menu on the dashboard.
+
+ For more information check:
+ https://github.com/firehol/netdata/wiki/monitoring-ephemeral-nodes
+
+ * monitoring ephemeral containers and VM guests
+
+ netdata now cleans up container, guest VM, network interfaces and mounted
+ disk metrics, disabling automatically their alarms too.
+
+ For more information check:
+ https://github.com/firehol/netdata/wiki/monitoring-ephemeral-containers
+
+ * apps.plugin ported for FreeBSD
+
+ @vlvkobal has ported "apps.plugin" to FreeBSD. netdata can now provide
+ "Applications", "Users" and "User Groups" on FreeBSD.
+
+ * web_log plugin
+
+ @l2isbad has done a wonderful job creating a unified web log parsing plugin
+ for all kinds of web server logs. With it, netdata provides real-time
+ performance information and health monitoring alarms for web applications
+ and web sites!
+
+ For more information check:
+ https://github.com/firehol/netdata/wiki/The-spectacles-of-a-web-server-log-file
+
+ * backends
+
+ netdata can now archive metrics to `JSON` backends
+ (both push, by @lfdominguez, and pull modes).
+
+ * IPMI monitoring
+
+ netdata now has an IPMI plugin (based on freeipmi)
+ for monitoring server hardware.
+
+ The plugin creates (up to) 8 charts:
+
+ 1. number of sensors by state
+ 2. number of events in SEL
+ 3. Temperatures CELCIUS
+ 4. Temperatures FAHRENHEIT
+ 5. Voltages
+ 6. Currents
+ 7. Power
+ 8. Fans
+
+ It also supports alarms (including the number of sensors in critical state).
+
+ For more information, check:
+ https://github.com/firehol/netdata/wiki/monitoring-IPMI
+
+ * new plugins
+
+ @l2isbad builds python data collection plugins for netdata at an wonderfull
+ rate! He rocks!
+
+ - **web_log** for monitoring in real-time all kinds of web server log files @l2isbad
+ - **freeipmi** for monitoring IPMI (server hardware)
+ - **nsd** (the [name server daemon](https://www.nlnetlabs.nl/projects/nsd/)) @383c57
+ - **mongodb** @l2isbad
+ - **smartd_log** (monitoring disk S.M.A.R.T. values) @l2isbad
+
+ * improved plugins
+
+ - **nfacct** reworked and now collects connection tracker information using netlink.
+ - **ElasticSearch** re-worked @l2isbad
+ - **mysql** re-worked to allow faster development of custom mysql based plugins (MySQLService) @l2isbad
+ - **SNMP**
+ - **tomcat** @NMcCloud
+ - **ap** (monitoring hostapd access points)
+ - **php_fpm** @l2isbad
+ - **postgres** @l2isbad
+ - **isc_dhcpd** @l2isbad
+ - **bind_rndc** @l2isbad
+ - **numa**
+ - **apps.plugin** improvements and freebsd support @vlvkobal
+ - **fail2ban** @l2isbad
+ - **freeradius** @l2isbad
+ - **nut** (monitoring UPSes)
+ - **tc** (Linux QoS) now works on qdiscs instead of classes for the same result (a lot faster) @t-h-e
+ - **varnish** @l2isbad
+
+ * new and improved alarms
+ - **web_log**, many alarms to detect common web site/API issues
+ - **fping**, alarms to detect packet loss, disconnects and unusually high latency
+ - **cpu**, cpu utilization alarm now ignores `nice`
+
+ * new and improved alarm notification methods
+ - **HipChat** to allow hosted HipChat @frei-style
+ - **discordapp** @lowfive
+
+ * dashboard improvements
+ - dashboard now works on HiDPi screens
+ - dashboard now shows version of netdata
+ - dashboard now resets charts properly
+ - dashboard updated to use latest gauge.js release
+
+ * other improvements
+ - thanks to @rlefevre netdata now uses a lot of different high resolution system clocks.
+
+ netdata has received a lot more improvements from many more contributors!
+
+ Thank you all!
+
+
+netdata (1.5.0) - 2017-01-22
* yet another release that makes netdata the fastest
netdata ever!
@@ -27,7 +191,7 @@ netdata (1.5.0) - 2016-01-22
Ilya Mashchenko (@l2isbad) has created most of the python
data collection plugins in this release !
- - Systemd Services (using cgroups!)
+ - systemd Services (using cgroups!)
- FPing (yes, network latency in netdata!)
- postgres databases @facetoe, @moumoul
- Vanish disk cache (v3 and v4) @l2isbad
diff --git a/Makefile.am b/Makefile.am
index ab77bc734..3ccf82f8f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,8 +23,18 @@ EXTRA_DIST = \
.eslintignore \
.eslintrc \
.travis \
- m4/ax_check_enable_debug.m4 \
- m4/ax_c_statement_expressions.m4 \
+ m4/jemalloc.m4 \
+ m4/ax_c___atomic.m4 \
+ m4/ax_check_enable_debug.m4 \
+ m4/ax_c_mallinfo.m4 \
+ m4/ax_gcc_func_attribute.m4 \
+ m4/ax_check_compile_flag.m4 \
+ m4/ax_c_statement_expressions.m4 \
+ m4/ax_pthread.m4 \
+ m4/ax_c_lto.m4 \
+ m4/ax_c_mallopt.m4 \
+ m4/tcmalloc.m4 \
+ m4/ax_c__generic.m4 \
autogen.sh \
README.md \
LICENSE.md \
@@ -48,6 +58,8 @@ SUBDIRS = \
dist_noinst_DATA= \
diagrams/config.puml \
diagrams/registry.puml \
+ diagrams/netdata-for-ephemeral-nodes.xml \
+ diagrams/netdata-proxies-example.xml \
configs.signatures \
Dockerfile \
netdata.spec \
@@ -60,4 +72,5 @@ dist_noinst_SCRIPTS= \
coverity-scan.sh \
docker-build.sh \
netdata-installer.sh \
+ installer/functions.sh \
$(NULL)
diff --git a/Makefile.in b/Makefile.in
index 412345f61..492376f5e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,9 +36,14 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = .
+DIST_COMMON = $(am__configure_deps) $(dist_noinst_DATA) \
+ $(dist_noinst_SCRIPTS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(srcdir)/netdata.spec.in $(top_srcdir)/configure COPYING \
+ ChangeLog config.guess config.sub depcomp install-sh missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -101,9 +52,6 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
- $(am__configure_deps) $(dist_noinst_SCRIPTS) \
- $(dist_noinst_DATA) $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
@@ -111,67 +59,24 @@ CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = netdata.spec
CONFIG_CLEAN_VPATH_FILES =
SCRIPTS = $(dist_noinst_SCRIPTS)
-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 =
SOURCES =
DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
- ctags-recursive dvi-recursive html-recursive info-recursive \
- install-data-recursive install-dvi-recursive \
- install-exec-recursive install-html-recursive \
- install-info-recursive install-pdf-recursive \
- install-ps-recursive install-recursive installcheck-recursive \
- installdirs-recursive pdf-recursive ps-recursive \
- tags-recursive uninstall-recursive
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
DATA = $(dist_noinst_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
- $(RECURSIVE_TARGETS) \
- $(RECURSIVE_CLEAN_TARGETS) \
- $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
- cscope distdir dist dist-all distcheck
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
- $(LISP)config.h.in
-# 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)`
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir dist dist-all distcheck
ETAGS = etags
CTAGS = ctags
-CSCOPE = cscope
DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
- $(srcdir)/netdata.spec.in COPYING ChangeLog compile \
- config.guess config.sub install-sh missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
@@ -181,7 +86,6 @@ am__remove_distdir = \
&& rm -rf "$(distdir)" \
|| { sleep 5 && rm -rf "$(distdir)"; }; \
else :; fi
-am__post_remove_distdir = $(am__remove_distdir)
am__relativize = \
dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
@@ -209,14 +113,12 @@ am__relativize = \
reldir="$$dir2"
DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).tar.xz
GZIP_ENV = --best
-DIST_TARGETS = dist-xz dist-bzip2 dist-gzip
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -240,7 +142,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -254,6 +160,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -375,8 +285,18 @@ EXTRA_DIST = \
.eslintignore \
.eslintrc \
.travis \
- m4/ax_check_enable_debug.m4 \
- m4/ax_c_statement_expressions.m4 \
+ m4/jemalloc.m4 \
+ m4/ax_c___atomic.m4 \
+ m4/ax_check_enable_debug.m4 \
+ m4/ax_c_mallinfo.m4 \
+ m4/ax_gcc_func_attribute.m4 \
+ m4/ax_check_compile_flag.m4 \
+ m4/ax_c_statement_expressions.m4 \
+ m4/ax_pthread.m4 \
+ m4/ax_c_lto.m4 \
+ m4/ax_c_mallopt.m4 \
+ m4/tcmalloc.m4 \
+ m4/ax_c__generic.m4 \
autogen.sh \
README.md \
LICENSE.md \
@@ -400,6 +320,8 @@ SUBDIRS = \
dist_noinst_DATA = \
diagrams/config.puml \
diagrams/registry.puml \
+ diagrams/netdata-for-ephemeral-nodes.xml \
+ diagrams/netdata-proxies-example.xml \
configs.signatures \
Dockerfile \
netdata.spec \
@@ -413,6 +335,7 @@ dist_noinst_SCRIPTS = \
coverity-scan.sh \
docker-build.sh \
netdata-installer.sh \
+ installer/functions.sh \
$(NULL)
all: config.h
@@ -434,6 +357,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -454,8 +378,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
config.h: stamp-h1
- @test -f $@ || rm -f stamp-h1
- @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+ @if test ! -f $@; then rm -f stamp-h1; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
@@ -471,25 +395,22 @@ netdata.spec: $(top_builddir)/config.status $(srcdir)/netdata.spec.in
cd $(top_builddir) && $(SHELL) ./config.status $@
# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-# (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
- @fail=; \
- if $(am__make_keepgoing); then \
- failcom='fail=yes'; \
- else \
- failcom='exit 1'; \
- fi; \
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
- case "$@" in \
- distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
- *) list='$(SUBDIRS)' ;; \
- esac; \
- for subdir in $$list; do \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
@@ -504,12 +425,57 @@ $(am__recursive_targets):
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
-ID: $(am__tagged_files)
- $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
-TAGS: tags
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
@@ -525,7 +491,12 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
- $(am__define_uniq_tagged_files); \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
@@ -537,11 +508,15 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$$unique; \
fi; \
fi
-ctags: ctags-recursive
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
- $(am__define_uniq_tagged_files); \
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
@@ -550,31 +525,9 @@ GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
-cscope: cscope.files
- test ! -s cscope.files \
- || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
-clean-cscope:
- -rm -f cscope.files
-cscope.files: clean-cscope cscopelist
-cscopelist: cscopelist-recursive
-
-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
- -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
distdir: $(DISTFILES)
$(am__remove_distdir)
@@ -610,10 +563,13 @@ distdir: $(DISTFILES)
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
- $(am__make_dryrun) \
- || test -d "$(distdir)/$$subdir" \
- || $(MKDIR_P) "$(distdir)/$$subdir" \
- || exit 1; \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \
new_distdir=$$reldir; \
@@ -642,40 +598,40 @@ distdir: $(DISTFILES)
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
dist-lzip: distdir
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
+
+dist-lzma: distdir
+ tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+ $(am__remove_distdir)
dist-xz: distdir
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
dist-tarZ: distdir
- @echo WARNING: "Support for distribution archives compressed with" \
- "legacy program 'compress' is deprecated." >&2
- @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
dist-shar: distdir
- @echo WARNING: "Support for shar distribution archives is" \
- "deprecated." >&2
- @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
-dist dist-all:
- $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
- $(am__post_remove_distdir)
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
@@ -686,6 +642,8 @@ distcheck: dist
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lzma*) \
+ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
*.tar.lz*) \
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
*.tar.xz*) \
@@ -697,19 +655,18 @@ distcheck: dist
*.zip*) \
unzip $(distdir).zip ;;\
esac
- chmod -R a-w $(distdir)
- chmod u+w $(distdir)
- mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
chmod a-w $(distdir)
test -d $(distdir)/_build || exit 0; \
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& am__cwd=`pwd` \
- && $(am__cd) $(distdir)/_build/sub \
- && ../../configure \
+ && $(am__cd) $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
- --srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
@@ -732,7 +689,7 @@ distcheck: dist
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
&& cd "$$am__cwd" \
|| exit 1
- $(am__post_remove_distdir)
+ $(am__remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
@@ -867,12 +824,13 @@ ps-am:
uninstall-am:
-.MAKE: $(am__recursive_targets) all install-am install-strip
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \
+ ctags-recursive install-am install-strip tags-recursive
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
- am--refresh check check-am clean clean-cscope clean-generic \
- cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
- dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am am--refresh check check-am clean clean-generic \
+ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
+ dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
distcheck distclean distclean-generic distclean-hdr \
distclean-tags distcleancheck distdir distuninstallcheck dvi \
dvi-am html html-am info info-am install install-am \
@@ -882,10 +840,8 @@ uninstall-am:
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs installdirs-am \
maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
- uninstall-am
-
-.PRECIOUS: Makefile
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/README.md b/README.md
index 5165078d4..cff7f31bd 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# netdata [![Build Status](https://travis-ci.org/firehol/netdata.svg?branch=master)](https://travis-ci.org/firehol/netdata) [![Coverity Scan Build Status](https://scan.coverity.com/projects/9140/badge.svg)](https://scan.coverity.com/projects/firehol-netdata) [![Code Climate](https://codeclimate.com/github/firehol/netdata/badges/gpa.svg)](https://codeclimate.com/github/firehol/netdata) [![Docker Pulls](https://img.shields.io/docker/pulls/titpetric/netdata.svg)](https://hub.docker.com/r/titpetric/netdata/)
+# netdata [![Build Status](https://travis-ci.org/firehol/netdata.svg?branch=master)](https://travis-ci.org/firehol/netdata) [![Coverity Scan Build Status](https://scan.coverity.com/projects/9140/badge.svg)](https://scan.coverity.com/projects/firehol-netdata) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a994873f30d045b9b4b83606c3eb3498)](https://www.codacy.com/app/netdata/netdata?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=firehol/netdata&amp;utm_campaign=Badge_Grade) [![Code Climate](https://codeclimate.com/github/firehol/netdata/badges/gpa.svg)](https://codeclimate.com/github/firehol/netdata)
> *New to netdata? Here is a live demo: [http://my-netdata.io](http://my-netdata.io)*
**netdata** is a system for **distributed real-time performance and health monitoring**.
@@ -10,12 +10,16 @@ _netdata is **fast** and **efficient**, designed to permanently run on all syste
(**physical** & **virtual** servers, **containers**, **IoT** devices), without
disrupting their core function._
+netdata runs on **Linux**, **FreeBSD**, and **MacOS**.
+
+[![Twitter Follow](https://img.shields.io/twitter/follow/linuxnetdata.svg?style=social&label=New%20-%20stay%20in%20touch%20-%20follow%20netdata%20on%20twitter)](https://twitter.com/linuxnetdata)
+
---
## User base
*Since May 16th 2016 (the date the [global public netdata registry](https://github.com/firehol/netdata/wiki/mynetdata-menu-item) was released):*<br/>
-[![User Base](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=persons&label=user%20base&units=null&value_color=blue&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Monitored Servers](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=machines&label=servers%20monitored&units=null&value_color=orange&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Sessions Served](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_sessions&label=sessions%20served&units=null&value_color=yellowgreen&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry)
+[![User Base](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=persons&label=user%20base&units=null&value_color=blue&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Monitored Servers](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=machines&label=servers%20monitored&units=null&value_color=orange&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Sessions Served](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_sessions&label=sessions%20served&units=null&value_color=yellowgreen&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Docker Pulls](https://img.shields.io/docker/pulls/titpetric/netdata.svg)](https://hub.docker.com/r/titpetric/netdata/)
*in the last 24 hours:*<br/>
[![New Users Today](http://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=persons&after=-86400&options=unaligned&group=incremental-sum&label=new%20users%20today&units=null&value_color=blue&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![New Machines Today](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=machines&group=incremental-sum&after=-86400&options=unaligned&label=servers%20added%20today&units=null&value_color=orange&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Sessions Today](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_sessions&after=-86400&group=incremental-sum&options=unaligned&label=sessions%20served%20today&units=null&value_color=yellowgreen&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry)
@@ -29,15 +33,16 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank
<a href="https://octoverse.github.com/" target="_blank"><img src="https://cloud.githubusercontent.com/assets/2662304/21743260/23ebe62c-d507-11e6-80c0-76b95f53e464.png"/></a>
</p>
-`Jan 22nd, 2017` - **[netdata v1.5.0 released!](https://github.com/firehol/netdata/releases)**
+`Mar 20th, 2017` - **[netdata v1.6.0 released!](https://github.com/firehol/netdata/releases)**
- - netdata now runs on **FreeBSD** and **MacOS**
- - netdata now supports **Graphite**, **OpenTSDB**, **Prometheus** and compatible backends
- - netdata now monitors **SystemD Services**
- - new plugins: fping, postgres, varnish, elasticsearch, haproxy, freeradius, mdstat, ISC dhcpd, fail2ban, openvpn, NUMA memory, CPU Idle States, gunicorn, ECC memory errors, IPC semaphores, uptime
- - improved plugins: netfilter conntrack, mysql/mariadb, ipfs, cpufreq, hddtemp, sensors, nginx, nginx_log, phpfpm, redis, dovecot, containers and cgroups, disk space, apps.plugin, tc (QoS) and almost all internal plugins (memory, IPv4 and IPv6, network interfaces, QoS, etc)
- - dozens of new and improved alarms (including performance monitoring alarms for mysql)
- - new alarm notifications: messagebird.com, pagerduty.com, pushbullet.com, twilio.com, hipchat, kafka
+ - central netdata is here! headless collectors, proxies, streaming of metrics, etc.
+ - [monitoring ephemeral nodes (auto-scaled VMs)](https://github.com/firehol/netdata/wiki/monitoring-ephemeral-nodes)
+ - [monitoring ephemeral containers and VM guests](https://github.com/firehol/netdata/wiki/monitoring-ephemeral-containers)
+ - [monitoring web servers](https://github.com/firehol/netdata/wiki/The-spectacles-of-a-web-server-log-file)
+ - apps.plugin ported for FreeBSD
+ - [monitoring IPMI](https://github.com/firehol/netdata/wiki/monitoring-IPMI)
+ - dozens of new and improved plugins
+ - dozens of new and improved alarms
- dozens more improvements and performance optimizations
---
@@ -60,9 +65,10 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank
with just 1% CPU utilization of a single core, a few MB of RAM and no disk I/O at all
- **Sophisticated alarming**<br/>
+ hundreds of alarms, **out of the box**!<br/>
supports dynamic thresholds, hysteresis, alarm templates,
multiple role-based notification methods (such as email, slack.com,
- pushover.net, pushbullet.com telegram.org, twilio.com, messagebird.com)
+ pushover.net, pushbullet.com, telegram.org, twilio.com, messagebird.com)
- **Extensible**<br/>
you can monitor anything you can get a metric for,
@@ -89,8 +95,12 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank
- **scales to infinity**<br/>
requiring minimal central resources
- - **back-ends supported**<br/>
- can archive its metrics on `graphite` or `opentsdb`, in the same or lower detail
+ - **several operating modes**<br/>
+ autonomous host monitoring, headless data collector, forwarding proxy, store and forward proxy, central multi-host monitoring, in all possible configurations.
+ Each node may have different metrics retention policy and run with or without health monitoring.
+
+ - **time-series back-ends supported**<br/>
+ can archive its metrics on `graphite`, `opentsdb`, `prometheus`, json document DBs, in the same or lower detail
(lower: to prevent it from congesting these servers due to the amount of data collected)
![netdata](https://cloud.githubusercontent.com/assets/2662304/14092712/93b039ea-f551-11e5-822c-beadbf2b2a2e.gif)
@@ -99,7 +109,7 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank
## What does it monitor?
-netdata monitors several thousands of metrics per device.
+netdata collects several thousands of metrics per device.
All these metrics are collected and visualized in real-time.
> _Almost all metrics are auto-detected, without any configuration._
@@ -107,13 +117,13 @@ All these metrics are collected and visualized in real-time.
This is a list of what it currently monitors:
- **CPU**<br/>
- usage, interrupts, softirqs, frequency, total and per core
+ usage, interrupts, softirqs, frequency, total and per core, CPU states
- **Memory**<br/>
RAM, swap and kernel memory usage, KSM (Kernel Samepage Merging), NUMA
- **Disks**<br/>
- per disk: I/O, operations, backlog, utilization, space
+ per disk: I/O, operations, backlog, utilization, space, software RAID (md)
![sda](https://cloud.githubusercontent.com/assets/2662304/14093195/c882bbf4-f554-11e5-8863-1788d643d2c0.gif)
@@ -189,6 +199,9 @@ This is a list of what it currently monitors:
- **Tomcat**<br/>
accesses, threads, free memory, volume
+- **web server log files**<br/>
+ extracting in real-time, web server performance metrics and applying several health checks
+
- **mySQL databases**<br/>
multiple servers, each showing: bandwidth, queries/s, handlers, locks, issues,
tmp operations, connections, binlog metrics, threads, innodb metrics, and more
@@ -201,12 +214,21 @@ This is a list of what it currently monitors:
- **Redis databases**<br/>
multiple servers, each showing: operations, hit rate, memory, keys, clients, slaves
+- **mongodb**<br/>
+ operations, clients, transactions, cursors, connections, asserts, locks, etc
+
- **memcached databases**<br/>
multiple servers, each showing: bandwidth, connections, items
+- **elasticsearch**<br/>
+ search and index performance, latency, timings, cluster statistics, threads statistics, etc
+
- **ISC Bind name servers**<br/>
multiple servers, each showing: clients, requests, queries, updates, failures and several per view metrics
+- **NSD name servers**<br/>
+ queries, zones, protocols, query types, transfers, etc.
+
- **Postfix email servers**<br/>
message queue (entries, size)
@@ -215,14 +237,26 @@ This is a list of what it currently monitors:
- **Dovecot** POP3/IMAP servers<br/>
+- **ISC dhcpd**<br/>
+ pools utilization, leases, etc.
+
- **IPFS**<br/>
bandwidth, peers
- **Squid proxy servers**<br/>
multiple servers, each showing: clients bandwidth and requests, servers bandwidth and requests
+- **HAproxy**<br/>
+ bandwidth, sessions, backends, etc
+
+- **varnish**<br/>
+ threads, sessions, hits, objects, backends, etc
+
+- **OpenVPN**<br/>
+ status per tunnel
+
- **Hardware sensors**<br/>
- temperature, voltage, fans, power, humidity
+ `lm_sensors` and `IPMI`: temperature, voltage, fans, power, humidity
- **NUT and APC UPSes**<br/>
load, charge, battery voltage, temperature, utility metrics, output metrics
@@ -233,6 +267,9 @@ This is a list of what it currently monitors:
- **hddtemp**<br/>
disk temperatures
+- **smartd**<br/>
+ disk S.M.A.R.T. values
+
- **SNMP devices**<br/>
can be monitored too (although you will need to configure these)
diff --git a/aclocal.m4 b/aclocal.m4
index 9867db245..2bb8c79ed 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,7 +1,8 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# generated automatically by aclocal 1.11.3 -*- Autoconf -*-
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+# Inc.
# This file 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.
@@ -11,14 +12,13 @@
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
-m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
-[m4_warning([this file was generated for autoconf 2.69.
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
+[m4_warning([this file was generated for autoconf 2.68.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
-To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
@@ -180,77 +180,25 @@ else
fi[]dnl
])# PKG_CHECK_MODULES
-
-# PKG_INSTALLDIR(DIRECTORY)
-# -------------------------
-# Substitutes the variable pkgconfigdir as the location where a module
-# should install pkg-config .pc files. By default the directory is
-# $libdir/pkgconfig, but the default can be changed by passing
-# DIRECTORY. The user can override through the --with-pkgconfigdir
-# parameter.
-AC_DEFUN([PKG_INSTALLDIR],
-[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
-m4_pushdef([pkg_description],
- [pkg-config installation directory @<:@]pkg_default[@:>@])
-AC_ARG_WITH([pkgconfigdir],
- [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
- [with_pkgconfigdir=]pkg_default)
-AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
-m4_popdef([pkg_default])
-m4_popdef([pkg_description])
-]) dnl PKG_INSTALLDIR
-
-
-# PKG_NOARCH_INSTALLDIR(DIRECTORY)
-# -------------------------
-# Substitutes the variable noarch_pkgconfigdir as the location where a
-# module should install arch-independent pkg-config .pc files. By
-# default the directory is $datadir/pkgconfig, but the default can be
-# changed by passing DIRECTORY. The user can override through the
-# --with-noarch-pkgconfigdir parameter.
-AC_DEFUN([PKG_NOARCH_INSTALLDIR],
-[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
-m4_pushdef([pkg_description],
- [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
-AC_ARG_WITH([noarch-pkgconfigdir],
- [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
- [with_noarch_pkgconfigdir=]pkg_default)
-AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
-m4_popdef([pkg_default])
-m4_popdef([pkg_description])
-]) dnl PKG_NOARCH_INSTALLDIR
-
-
-# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
-# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-# -------------------------------------------
-# Retrieves the value of the pkg-config variable for the given module.
-AC_DEFUN([PKG_CHECK_VAR],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
-
-_PKG_CONFIG([$1], [variable="][$3]["], [$2])
-AS_VAR_COPY([$1], [pkg_cv_][$1])
-
-AS_VAR_IF([$1], [""], [$5], [$4])dnl
-])# PKG_CHECK_VAR
-
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
+# Foundation, Inc.
#
# This file 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.
+# serial 1
+
# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been
# generated from the m4 files accompanying Automake X.Y.
# (This private macro should not be called outside this file.)
AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.15'
+[am__api_version='1.11'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.11.3], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -266,22 +214,24 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.11.3])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
#
# This file 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.
+# serial 1
+
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
-# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
-# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
#
# Of course, Automake must honor this variable whenever it calls a
# tool from the auxiliary directory. The problem is that $srcdir (and
@@ -300,7 +250,7 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
#
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
# are both prefixed by $srcdir. In an in-source build this is usually
-# harmless because $srcdir is '.', but things will broke when you
+# harmless because $srcdir is `.', but things will broke when you
# start a VPATH build or use an absolute $srcdir.
#
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
@@ -318,26 +268,30 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
-[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
-# Expand $ac_aux_dir to an absolute path.
-am_aux_dir=`cd "$ac_aux_dir" && pwd`
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
#
# This file 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.
+# serial 9
+
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
-[AC_PREREQ([2.52])dnl
- m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
- [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])dnl
AC_SUBST([$1_FALSE])dnl
_AM_SUBST_NOTMAKE([$1_TRUE])dnl
@@ -356,14 +310,16 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009,
+# 2010, 2011 Free Software Foundation, Inc.
#
# This file 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.
+# serial 12
-# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
# will think it sees a *use*, and therefore will trigger all it's
# C support machinery. Also note that it means that autoscan, seeing
@@ -373,7 +329,7 @@ fi])])
# _AM_DEPENDENCIES(NAME)
# ----------------------
# See how the compiler implements dependency checking.
-# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
# We try a few techniques and use that to set a single cache variable.
#
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
@@ -386,13 +342,12 @@ AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
AC_REQUIRE([AM_DEP_TRACK])dnl
-m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
- [$1], [CXX], [depcc="$CXX" am_compiler_list=],
- [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
- [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
- [$1], [UPC], [depcc="$UPC" am_compiler_list=],
- [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
- [depcc="$$1" am_compiler_list=])
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
AC_CACHE_CHECK([dependency style of $depcc],
[am_cv_$1_dependencies_compiler_type],
@@ -400,8 +355,8 @@ AC_CACHE_CHECK([dependency style of $depcc],
# We make a subdir and do the tests there. Otherwise we can end up
# making bogus files that we don't know about and never remove. For
# instance it was reported that on HP-UX the gcc test will end up
- # making a dummy file named 'D' -- because '-MD' means "put the output
- # in D".
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
rm -rf conftest.dir
mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're
@@ -441,16 +396,16 @@ AC_CACHE_CHECK([dependency style of $depcc],
: > sub/conftest.c
for i in 1 2 3 4 5 6; do
echo '#include "conftst'$i'.h"' >> sub/conftest.c
- # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
- # Solaris 10 /bin/sh.
- echo '/* dummy */' > sub/conftst$i.h
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
done
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
- # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
# mode. It turns out that the SunPro C++ compiler does not properly
- # handle '-M -o', and we need to detect this. Also, some Intel
- # versions had trouble with output in subdirs.
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
am__obj=sub/conftest.${OBJEXT-o}
am__minus_obj="-o $am__obj"
case $depmode in
@@ -459,8 +414,8 @@ AC_CACHE_CHECK([dependency style of $depcc],
test "$am__universal" = false || continue
;;
nosideeffect)
- # After this tag, mechanisms are not by side-effect, so they'll
- # only be used when explicitly requested.
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
if test "x$enable_dependency_tracking" = xyes; then
continue
else
@@ -468,7 +423,7 @@ AC_CACHE_CHECK([dependency style of $depcc],
fi
;;
msvc7 | msvc7msys | msvisualcpp | msvcmsys)
- # This compiler won't grok '-c -o', but also, the minuso test has
+ # This compiler won't grok `-c -o', but also, the minuso test has
# not run yet. These depmodes are late enough in the game, and
# so weak that their functioning should not be impacted.
am__obj=conftest.${OBJEXT-o}
@@ -516,7 +471,7 @@ AM_CONDITIONAL([am__fastdep$1], [
# AM_SET_DEPDIR
# -------------
# Choose a directory name for dependency files.
-# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
AC_DEFUN([AM_SET_DEPDIR],
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
@@ -526,13 +481,9 @@ AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
# AM_DEP_TRACK
# ------------
AC_DEFUN([AM_DEP_TRACK],
-[AC_ARG_ENABLE([dependency-tracking], [dnl
-AS_HELP_STRING(
- [--enable-dependency-tracking],
- [do not reject slow dependency extractors])
-AS_HELP_STRING(
- [--disable-dependency-tracking],
- [speeds up one-time build])])
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\'
@@ -547,18 +498,20 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
#
# This file 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.
+#serial 5
# _AM_OUTPUT_DEPENDENCY_COMMANDS
# ------------------------------
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
[{
- # Older Autoconf quotes --file arguments for eval, but not when files
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
# are listed without --file. Let's play safe and only enable the eval
# if we detect the quoting.
case $CONFIG_FILES in
@@ -571,7 +524,7 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
# Strip MF so we end up with the name of the file.
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
- # We used to match only the files named 'Makefile.in', but
+ # We used to match only the files named `Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
@@ -583,19 +536,21 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
- # from the Makefile without running 'make'.
+ # from the Makefile without running `make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
- test -z "$am__include" && continue
+ test -z "am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
- sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`AS_DIRNAME(["$file"])`
@@ -613,7 +568,7 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
# This macro should only be invoked once -- use via AC_REQUIRE.
#
# This code is only required when automatic dependency tracking
-# is enabled. FIXME. This creates each '.P' file that we will
+# is enabled. FIXME. This creates each `.P' file that we will
# need in order to bootstrap the dependency handling code.
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
[AC_CONFIG_COMMANDS([depfiles],
@@ -623,21 +578,18 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
#
# This file 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.
+# serial 16
+
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
-dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
-m4_define([AC_PROG_CC],
-m4_defn([AC_PROG_CC])
-[_AM_PROG_CC_C_O
-])
-
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
# -----------------------------------------------
@@ -650,7 +602,7 @@ m4_defn([AC_PROG_CC])
# arguments mandatory, and then we can depend on a new Autoconf
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
-[AC_PREREQ([2.65])dnl
+[AC_PREREQ([2.62])dnl
dnl Autoconf wants to disallow AM_ names. We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
@@ -679,42 +631,33 @@ AC_SUBST([CYGPATH_W])
# Define the identity of the package.
dnl Distinguish between old-style and new-style calls.
m4_ifval([$2],
-[AC_DIAGNOSE([obsolete],
- [$0: two- and three-arguments forms are deprecated.])
-m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
AC_SUBST([PACKAGE], [$1])dnl
AC_SUBST([VERSION], [$2])],
[_AM_SET_OPTIONS([$1])dnl
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
-m4_if(
- m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
- [ok:ok],,
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
_AM_IF_OPTION([no-define],,
-[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
- AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
# Some tools Automake needs.
AC_REQUIRE([AM_SANITY_CHECK])dnl
AC_REQUIRE([AC_ARG_PROGRAM])dnl
-AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
-AM_MISSING_PROG([AUTOCONF], [autoconf])
-AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
-AM_MISSING_PROG([AUTOHEADER], [autoheader])
-AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
-AC_REQUIRE([AC_PROG_MKDIR_P])dnl
-# For better backward compatibility. To be removed once Automake 1.9.x
-# dies out for good. For more background, see:
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
-AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target (and possibly the TAP driver). The
-# system "awk" is bad on some platforms.
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@@ -723,82 +666,34 @@ _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
[_AM_PROG_TAR([v7])])])
_AM_IF_OPTION([no-dependencies],,
[AC_PROVIDE_IFELSE([AC_PROG_CC],
- [_AM_DEPENDENCIES([CC])],
- [m4_define([AC_PROG_CC],
- m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_CXX],
- [_AM_DEPENDENCIES([CXX])],
- [m4_define([AC_PROG_CXX],
- m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_OBJC],
- [_AM_DEPENDENCIES([OBJC])],
- [m4_define([AC_PROG_OBJC],
- m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
-AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
- [_AM_DEPENDENCIES([OBJCXX])],
- [m4_define([AC_PROG_OBJCXX],
- m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
])
-AC_REQUIRE([AM_SILENT_RULES])dnl
-dnl The testsuite driver may need to know about EXEEXT, so add the
-dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
-dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
AC_CONFIG_COMMANDS_PRE(dnl
[m4_provide_if([_AM_COMPILER_EXEEXT],
[AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
-
-# POSIX will say in a future version that running "rm -f" with no argument
-# is OK; and we want to be able to make that assumption in our Makefile
-# recipes. So use an aggressive probe to check that the usage we want is
-# actually supported "in the wild" to an acceptable degree.
-# See automake bug#10828.
-# To make any issue more visible, cause the running configure to be aborted
-# by default if the 'rm' program in use doesn't match our expectations; the
-# user can still override this though.
-if rm -f && rm -fr && rm -rf; then : OK; else
- cat >&2 <<'END'
-Oops!
-
-Your 'rm' program seems unable to run without file operands specified
-on the command line, even when the '-f' option is present. This is contrary
-to the behaviour of most rm programs out there, and not conforming with
-the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
-
-Please tell bug-automake@gnu.org about your system, including the value
-of your $PATH and any error possibly output before this message. This
-can help us improve future automake versions.
-
-END
- if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
- echo 'Configuration will proceed anyway, since you have set the' >&2
- echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
- echo >&2
- else
- cat >&2 <<'END'
-Aborting the configuration process, to ensure you take notice of the issue.
-
-You can download and install GNU coreutils to get an 'rm' implementation
-that behaves properly: <http://www.gnu.org/software/coreutils/>.
-
-If you want to complete the configuration process using your problematic
-'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
-to "yes", and re-run configure.
-
-END
- AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
- fi
-fi
-dnl The trailing newline in this macro's definition is deliberate, for
-dnl backward compatibility and to allow trailing 'dnl'-style comments
-dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
])
-dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
dnl mangled by Autoconf and run in a shell conditional statement.
m4_define([_AC_COMPILER_EXEEXT],
m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
# When config.status generates a header, we must update the stamp-h file.
# This file resides in the same directory as the config header
# that is generated. The stamp files are numbered to have different names.
@@ -820,18 +715,21 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation,
+# Inc.
#
# This file 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.
+# serial 1
+
# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh+set}" != xset; then
+if test x"${install_sh}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -839,14 +737,16 @@ if test x"${install_sh+set}" != xset; then
install_sh="\${SHELL} $am_aux_dir/install-sh"
esac
fi
-AC_SUBST([install_sh])])
+AC_SUBST(install_sh)])
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
#
# This file 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.
+# serial 2
+
# Check whether the underlying file-system supports filenames
# with a leading dot. For instance MS-DOS doesn't.
AC_DEFUN([AM_SET_LEADING_DOT],
@@ -863,17 +763,20 @@ AC_SUBST([am__leading_dot])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
+# 2011 Free Software Foundation, Inc.
#
# This file 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.
+# serial 5
+
# AM_MAINTAINER_MODE([DEFAULT-MODE])
# ----------------------------------
# Control maintainer-specific portions of Makefiles.
-# Default is to disable them, unless 'enable' is passed literally.
-# For symmetry, 'disable' may be passed as well. Anyway, the user
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
# can override the default with the --enable/--disable switch.
AC_DEFUN([AM_MAINTAINER_MODE],
[m4_case(m4_default([$1], [disable]),
@@ -884,11 +787,10 @@ AC_DEFUN([AM_MAINTAINER_MODE],
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
AC_ARG_ENABLE([maintainer-mode],
- [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
- am_maintainer_other[ make rules and dependencies not useful
- (and sometimes confusing) to the casual installer])],
- [USE_MAINTAINER_MODE=$enableval],
- [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
MAINT=$MAINTAINER_MODE_TRUE
@@ -896,14 +798,18 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
]
)
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
#
# This file 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.
+# serial 4
+
# AM_MAKE_INCLUDE()
# -----------------
# Check to see how make treats includes.
@@ -921,7 +827,7 @@ am__quote=
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
-# Ignore all kinds of additional output from 'make'.
+# Ignore all kinds of additional output from `make'.
case `$am_make -s -f confmf 2> /dev/null` in #(
*the\ am__doit\ target*)
am__include=include
@@ -948,12 +854,15 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
#
# This file 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.
+# serial 6
+
# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
AC_DEFUN([AM_MISSING_PROG],
@@ -961,10 +870,11 @@ AC_DEFUN([AM_MISSING_PROG],
$1=${$1-"${am_missing_run}$2"}
AC_SUBST($1)])
+
# AM_MISSING_HAS_RUN
# ------------------
-# Define MISSING if not defined so far and test if it is modern enough.
-# If it is, set am_missing_run to use it, otherwise, to nothing.
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
AC_REQUIRE_AUX_FILE([missing])dnl
@@ -977,22 +887,54 @@ if test x"${MISSING+set}" != xset; then
esac
fi
# Use eval to expand $SHELL
-if eval "$MISSING --is-lightweight"; then
- am_missing_run="$MISSING "
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
else
am_missing_run=
- AC_MSG_WARN(['missing' script is too old or missing])
+ AC_MSG_WARN([`missing' script is too old or missing])
fi
])
+# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation,
+# Inc.
+#
+# This file 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.
+
+# serial 1
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software
+# Foundation, Inc.
#
# This file 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.
+# serial 5
+
# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_MANGLE_OPTION],
@@ -1002,7 +944,7 @@ AC_DEFUN([_AM_MANGLE_OPTION],
# --------------------
# Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
-[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
# _AM_SET_OPTIONS(OPTIONS)
# ------------------------
@@ -1016,82 +958,24 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-#
-# This file 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.
-
-# _AM_PROG_CC_C_O
-# ---------------
-# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
-# to automatically call this.
-AC_DEFUN([_AM_PROG_CC_C_O],
-[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-AC_REQUIRE_AUX_FILE([compile])dnl
-AC_LANG_PUSH([C])dnl
-AC_CACHE_CHECK(
- [whether $CC understands -c and -o together],
- [am_cv_prog_cc_c_o],
- [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
- # Make sure it works both with $CC and with simple cc.
- # Following AC_PROG_CC_C_O, we do the test twice because some
- # compilers refuse to overwrite an existing .o file with -o,
- # though they will create one.
- am_cv_prog_cc_c_o=yes
- for am_i in 1 2; do
- if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
- && test -f conftest2.$ac_objext; then
- : OK
- else
- am_cv_prog_cc_c_o=no
- break
- fi
- done
- rm -f core conftest*
- unset am_i])
-if test "$am_cv_prog_cc_c_o" != yes; then
- # Losing compiler, so override with the script.
- # FIXME: It is wrong to rewrite CC.
- # But if we don't then we get into trouble of one sort or another.
- # A longer-term fix would be to have automake use am__CC in this case,
- # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
- CC="$am_aux_dir/compile $CC"
-fi
-AC_LANG_POP([C])])
-
-# For backward compatibility.
-AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file 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.
-
-# AM_RUN_LOG(COMMAND)
-# -------------------
-# Run COMMAND, save the exit status in ac_status, and log it.
-# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
-AC_DEFUN([AM_RUN_LOG],
-[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
- ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
- (exit $ac_status); }])
-
# Check to make sure that the build environment is sane. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
#
# This file 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.
+# serial 5
+
# AM_SANITY_CHECK
# ---------------
AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
# Reject unsafe characters in $srcdir or the absolute working directory
# name. Accept space and tab only in the latter.
am_lf='
@@ -1102,40 +986,32 @@ case `pwd` in
esac
case $srcdir in
*[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
- AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
esac
-# Do 'set' in a subshell so we don't clobber the current shell's
+# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
- am_has_slept=no
- for am_try in 1 2; do
- echo "timestamp, slept: $am_has_slept" > conftest.file
- set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
- if test "$[*]" = "X"; then
- # -L didn't work.
- set X `ls -t "$srcdir/configure" conftest.file`
- fi
- if test "$[*]" != "X $srcdir/configure conftest.file" \
- && test "$[*]" != "X conftest.file $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
- alias in your environment])
- fi
- if test "$[2]" = conftest.file || test $am_try -eq 2; then
- break
- fi
- # Just in case.
- sleep 1
- am_has_slept=yes
- done
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
test "$[2]" = conftest.file
)
then
@@ -1145,118 +1021,46 @@ else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
-AC_MSG_RESULT([yes])
-# If we didn't sleep, we still need to ensure time stamps of config.status and
-# generated files are strictly newer.
-am_sleep_pid=
-if grep 'slept: no' conftest.file >/dev/null 2>&1; then
- ( sleep 1 ) &
- am_sleep_pid=$!
-fi
-AC_CONFIG_COMMANDS_PRE(
- [AC_MSG_CHECKING([that generated files are newer than configure])
- if test -n "$am_sleep_pid"; then
- # Hide warnings about reused PIDs.
- wait $am_sleep_pid 2>/dev/null
- fi
- AC_MSG_RESULT([done])])
-rm -f conftest.file
-])
+AC_MSG_RESULT(yes)])
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
#
# This file 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.
-# AM_SILENT_RULES([DEFAULT])
-# --------------------------
-# Enable less verbose build rules; with the default set to DEFAULT
-# ("yes" being less verbose, "no" or empty being verbose).
-AC_DEFUN([AM_SILENT_RULES],
-[AC_ARG_ENABLE([silent-rules], [dnl
-AS_HELP_STRING(
- [--enable-silent-rules],
- [less verbose build output (undo: "make V=1")])
-AS_HELP_STRING(
- [--disable-silent-rules],
- [verbose build output (undo: "make V=0")])dnl
-])
-case $enable_silent_rules in @%:@ (((
- yes) AM_DEFAULT_VERBOSITY=0;;
- no) AM_DEFAULT_VERBOSITY=1;;
- *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
-esac
-dnl
-dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
-dnl do not support nested variable expansions.
-dnl See automake bug#9928 and bug#10237.
-am_make=${MAKE-make}
-AC_CACHE_CHECK([whether $am_make supports nested variables],
- [am_cv_make_support_nested_variables],
- [if AS_ECHO([['TRUE=$(BAR$(V))
-BAR0=false
-BAR1=true
-V=1
-am__doit:
- @$(TRUE)
-.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
- am_cv_make_support_nested_variables=yes
-else
- am_cv_make_support_nested_variables=no
-fi])
-if test $am_cv_make_support_nested_variables = yes; then
- dnl Using '$V' instead of '$(V)' breaks IRIX make.
- AM_V='$(V)'
- AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
-else
- AM_V=$AM_DEFAULT_VERBOSITY
- AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
-fi
-AC_SUBST([AM_V])dnl
-AM_SUBST_NOTMAKE([AM_V])dnl
-AC_SUBST([AM_DEFAULT_V])dnl
-AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
-AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
-AM_BACKSLASH='\'
-AC_SUBST([AM_BACKSLASH])dnl
-_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
-])
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file 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.
+# serial 1
# AM_PROG_INSTALL_STRIP
# ---------------------
-# One issue with vendor 'install' (even GNU) is that you can't
+# One issue with vendor `install' (even GNU) is that you can't
# specify the program used to strip binaries. This is especially
# annoying in cross-compiling environments, where the build's strip
# is unlikely to handle the host's binaries.
# Fortunately install-sh will honor a STRIPPROG variable, so we
-# always use install-sh in "make install-strip", and initialize
+# always use install-sh in `make install-strip', and initialize
# STRIPPROG with the value of the STRIP variable (set by the user).
AC_DEFUN([AM_PROG_INSTALL_STRIP],
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
-# Installed binaries are usually stripped using 'strip' when the user
-# run "make install-strip". However 'strip' might not be the right
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
-# will honor the 'STRIP' environment variable to overrule this program.
-dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
if test "$cross_compiling" != no; then
AC_CHECK_TOOL([STRIP], [strip], :)
fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
#
# This file 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.
+# serial 3
+
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
@@ -1270,16 +1074,18 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc.
#
# This file 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.
+# serial 2
+
# _AM_PROG_TAR(FORMAT)
# --------------------
# Check how to create a tarball in format FORMAT.
-# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+# FORMAT should be one of `v7', `ustar', or `pax'.
#
# Substitute a variable $(am__tar) that is a command
# writing to stdout a FORMAT-tarball containing the directory
@@ -1289,120 +1095,83 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Substitute a variable $(am__untar) that extract such
# a tarball read from stdin.
# $(am__untar) < result.tar
-#
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AC_SUBST([AMTAR], ['$${TAR-tar}'])
-
-# We'll loop over all known methods to create a tar archive until one works.
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
-m4_if([$1], [v7],
- [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
-
- [m4_case([$1],
- [ustar],
- [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
- # There is notably a 21 bits limit for the UID and the GID. In fact,
- # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
- # and bug#13588).
- am_max_uid=2097151 # 2^21 - 1
- am_max_gid=$am_max_uid
- # The $UID and $GID variables are not portable, so we need to resort
- # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
- # below are definitely unexpected, so allow the users to see them
- # (that is, avoid stderr redirection).
- am_uid=`id -u || echo unknown`
- am_gid=`id -g || echo unknown`
- AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
- if test $am_uid -le $am_max_uid; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- _am_tools=none
- fi
- AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
- if test $am_gid -le $am_max_gid; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- _am_tools=none
- fi],
-
- [pax],
- [],
-
- [m4_fatal([Unknown tar format])])
-
- AC_MSG_CHECKING([how to create a $1 tar archive])
-
- # Go ahead even if we have the value already cached. We do so because we
- # need to set the values for the 'am__tar' and 'am__untar' variables.
- _am_tools=${am_cv_prog_tar_$1-$_am_tools}
-
- for _am_tool in $_am_tools; do
- case $_am_tool in
- gnutar)
- for _am_tar in tar gnutar gtar; do
- AM_RUN_LOG([$_am_tar --version]) && break
- done
- am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
- am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
- am__untar="$_am_tar -xf -"
- ;;
- plaintar)
- # Must skip GNU tar: if it does not support --format= it doesn't create
- # ustar tarball either.
- (tar --version) >/dev/null 2>&1 && continue
- am__tar='tar chf - "$$tardir"'
- am__tar_='tar chf - "$tardir"'
- am__untar='tar xf -'
- ;;
- pax)
- am__tar='pax -L -x $1 -w "$$tardir"'
- am__tar_='pax -L -x $1 -w "$tardir"'
- am__untar='pax -r'
- ;;
- cpio)
- am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
- am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
- am__untar='cpio -i -H $1 -d'
- ;;
- none)
- am__tar=false
- am__tar_=false
- am__untar=false
- ;;
- esac
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
- # If the value was cached, stop now. We just wanted to have am__tar
- # and am__untar set.
- test -n "${am_cv_prog_tar_$1}" && break
-
- # tar/untar a dummy directory, and stop if the command works.
- rm -rf conftest.dir
- mkdir conftest.dir
- echo GrepMe > conftest.dir/file
- AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
- rm -rf conftest.dir
- if test -s conftest.tar; then
- AM_RUN_LOG([$am__untar <conftest.tar])
- AM_RUN_LOG([cat conftest.dir/file])
- grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
- fi
- done
+ # tar/untar a dummy directory, and stop if the command works
rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
- AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
- AC_MSG_RESULT([$am_cv_prog_tar_$1])])
-
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR
m4_include([m4/ax_c___atomic.m4])
m4_include([m4/ax_c__generic.m4])
+m4_include([m4/ax_c_lto.m4])
m4_include([m4/ax_c_mallinfo.m4])
m4_include([m4/ax_c_mallopt.m4])
m4_include([m4/ax_check_compile_flag.m4])
diff --git a/autogen.sh b/autogen.sh
index 3b076d1a1..38e2ed159 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,2 +1,2 @@
-#!/bin/sh
+#!/usr/bin/env sh
autoreconf -ivf
diff --git a/charts.d/Makefile.am b/charts.d/Makefile.am
index ec0e101f3..85bcef3cf 100644
--- a/charts.d/Makefile.am
+++ b/charts.d/Makefile.am
@@ -4,6 +4,10 @@
MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
dist_charts_SCRIPTS = \
+ $(NULL)
+
+dist_charts_DATA = \
+ README.md \
ap.chart.sh \
apcupsd.chart.sh \
apache.chart.sh \
@@ -24,7 +28,3 @@ dist_charts_SCRIPTS = \
squid.chart.sh \
tomcat.chart.sh \
$(NULL)
-
-dist_charts_DATA = \
- README.md \
- $(NULL)
diff --git a/charts.d/Makefile.in b/charts.d/Makefile.in
index ef63f78f3..a613e1b31 100644
--- a/charts.d/Makefile.in
+++ b/charts.d/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,9 +36,11 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = charts.d
+DIST_COMMON = $(dist_charts_DATA) $(dist_charts_SCRIPTS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -101,8 +49,6 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_charts_SCRIPTS) \
- $(dist_charts_DATA) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
@@ -136,32 +82,12 @@ am__uninstall_files_from_dir = { \
}
am__installdirs = "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsdir)"
SCRIPTS = $(dist_charts_SCRIPTS)
-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 =
SOURCES =
DIST_SOURCES =
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
DATA = $(dist_charts_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -185,7 +111,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -199,6 +129,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -301,6 +235,10 @@ webdir = @webdir@
#
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
dist_charts_SCRIPTS = \
+ $(NULL)
+
+dist_charts_DATA = \
+ README.md \
ap.chart.sh \
apcupsd.chart.sh \
apache.chart.sh \
@@ -322,10 +260,6 @@ dist_charts_SCRIPTS = \
tomcat.chart.sh \
$(NULL)
-dist_charts_DATA = \
- README.md \
- $(NULL)
-
all: all-am
.SUFFIXES:
@@ -341,6 +275,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu charts.d/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu charts.d/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -360,11 +295,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_chartsSCRIPTS: $(dist_charts_SCRIPTS)
@$(NORMAL_INSTALL)
+ test -z "$(chartsdir)" || $(MKDIR_P) "$(DESTDIR)$(chartsdir)"
@list='$(dist_charts_SCRIPTS)'; test -n "$(chartsdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(chartsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(chartsdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
@@ -395,11 +327,8 @@ uninstall-dist_chartsSCRIPTS:
dir='$(DESTDIR)$(chartsdir)'; $(am__uninstall_files_from_dir)
install-dist_chartsDATA: $(dist_charts_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(chartsdir)" || $(MKDIR_P) "$(DESTDIR)$(chartsdir)"
@list='$(dist_charts_DATA)'; test -n "$(chartsdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(chartsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(chartsdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -414,11 +343,11 @@ uninstall-dist_chartsDATA:
@list='$(dist_charts_DATA)'; test -n "$(chartsdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(chartsdir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
+tags: TAGS
+TAGS:
-ctags CTAGS:
-
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -557,21 +486,18 @@ uninstall-am: uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-dist_chartsDATA \
- install-dist_chartsSCRIPTS 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-ps install-ps-am install-strip \
- installcheck installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
- pdf-am ps ps-am tags-am uninstall uninstall-am \
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_chartsDATA install-dist_chartsSCRIPTS 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-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/charts.d/ap.chart.sh b/charts.d/ap.chart.sh
index 0e85c486d..ce2eefc9f 100755..100644
--- a/charts.d/ap.chart.sh
+++ b/charts.d/ap.chart.sh
@@ -16,7 +16,7 @@ declare -A ap_devs=()
# _check is called once, to find out if this chart should be enabled or not
ap_check() {
require_cmd iw || return 1
-
+
local ev=$(run iw dev | awk '
BEGIN {
i = "";
@@ -77,20 +77,19 @@ DIMENSION retries 'tx retries' incremental 1 1
DIMENSION failures 'tx failures' incremental -1 1
CHART ap_signal.${dev} '' "Average Signal for ${ssid} on ${dev}" "dBm" ${dev} ap.signal line $((ap_priority + 5)) $ap_update_every
-DIMENSION signal 'average signal' absolute 1 1
+DIMENSION signal 'average signal' absolute 1 1000
CHART ap_bitrate.${dev} '' "Bitrate for ${ssid} on ${dev}" "Mbps" ${dev} ap.bitrate line $((ap_priority + 6)) $ap_update_every
DIMENSION receive '' absolute 1 1000
DIMENSION transmit '' absolute -1 1000
DIMENSION expected 'expected throughput' absolute 1 1000
EOF
-
done
return 0
}
-# _update is called continiously, to collect the values
+# _update is called continuously, to collect the values
ap_update() {
# the first argument to this function is the microseconds since last update
# pass this parameter to the BEGIN statement (see bellow).
@@ -101,66 +100,81 @@ ap_update() {
for dev in "${!ap_devs[@]}"
do
- iw ${dev} station dump |\
- awk "
- BEGIN {
- c = 0;
- rb = 0;
- tb = 0;
- rp = 0;
- tp = 0;
- tr = 0;
- tf = 0;
- tt = 0;
- rt = 0;
- s = 0;
- g = 0;
- e = 0;
- }
- /^Station/ { c++; }
- /^[ \\t]+rx bytes:/ { rb += \$3 }
- /^[ \\t]+tx bytes:/ { tb += \$3 }
- /^[ \\t]+rx packets:/ { rp += \$3 }
- /^[ \\t]+tx packets:/ { tp += \$3 }
- /^[ \\t]+tx retries:/ { tr += \$3 }
- /^[ \\t]+tx failed:/ { tf += \$3 }
- /^[ \\t]+signal:/ { s += \$2; }
- /^[ \\t]+rx bitrate:/ { x = \$3; rt += x * 1000; }
- /^[ \\t]+tx bitrate:/ { x = \$3; tt += x * 1000; }
- /^[ \\t]+expected throughput:(.*)Mbps/ {
- x=\$3;
- sub(/Mbps/, \"\", x);
- e += x * 1000;
- }
- END {
- print \"BEGIN ap_clients.${dev}\"
- print \"SET clients = \" c;
- print \"END\"
- print \"BEGIN ap_bandwidth.${dev}\"
- print \"SET received = \" rb;
- print \"SET sent = \" tb;
- print \"END\"
- print \"BEGIN ap_packets.${dev}\"
- print \"SET received = \" rp;
- print \"SET sent = \" tp;
- print \"END\"
- print \"BEGIN ap_issues.${dev}\"
- print \"SET retries = \" tr;
- print \"SET failures = \" tf;
- print \"END\"
- print \"BEGIN ap_signal.${dev}\"
- print \"SET signal = \" s / c;
- print \"END\"
-
- if( c == 0 ) c = 1;
- print \"BEGIN ap_bitrate.${dev}\"
- print \"SET receive = \" rt / c;
- print \"SET transmit = \" tt / c;
- print \"SET expected = \" e / c;
- print \"END\"
- }
- "
- done
+ echo
+ echo "DEVICE ${dev}"
+ iw ${dev} station dump
+ done | awk "
+ function zero_data() {
+ dev = \"\";
+ c = 0;
+ rb = 0;
+ tb = 0;
+ rp = 0;
+ tp = 0;
+ tr = 0;
+ tf = 0;
+ tt = 0;
+ rt = 0;
+ s = 0;
+ g = 0;
+ e = 0;
+ }
+ function print_device() {
+ if(dev != \"\" && length(dev) > 0) {
+ print \"BEGIN ap_clients.\" dev;
+ print \"SET clients = \" c;
+ print \"END\";
+ print \"BEGIN ap_bandwidth.\" dev;
+ print \"SET received = \" rb;
+ print \"SET sent = \" tb;
+ print \"END\";
+ print \"BEGIN ap_packets.\" dev;
+ print \"SET received = \" rp;
+ print \"SET sent = \" tp;
+ print \"END\";
+ print \"BEGIN ap_issues.\" dev;
+ print \"SET retries = \" tr;
+ print \"SET failures = \" tf;
+ print \"END\";
+
+ if( c == 0 ) c = 1;
+ print \"BEGIN ap_signal.\" dev;
+ print \"SET signal = \" int(s / c);
+ print \"END\";
+ print \"BEGIN ap_bitrate.\" dev;
+ print \"SET receive = \" int(rt / c);
+ print \"SET transmit = \" int(tt / c);
+ print \"SET expected = \" int(e / c);
+ print \"END\";
+ }
+ zero_data();
+ }
+ BEGIN {
+ zero_data();
+ }
+ /^DEVICE / {
+ print_device();
+ dev = \$2;
+ }
+ /^Station/ { c++; }
+ /^[ \\t]+rx bytes:/ { rb += \$3; }
+ /^[ \\t]+tx bytes:/ { tb += \$3; }
+ /^[ \\t]+rx packets:/ { rp += \$3; }
+ /^[ \\t]+tx packets:/ { tp += \$3; }
+ /^[ \\t]+tx retries:/ { tr += \$3; }
+ /^[ \\t]+tx failed:/ { tf += \$3; }
+ /^[ \\t]+signal:/ { x = \$2; s += x * 1000; }
+ /^[ \\t]+rx bitrate:/ { x = \$3; rt += x * 1000; }
+ /^[ \\t]+tx bitrate:/ { x = \$3; tt += x * 1000; }
+ /^[ \\t]+expected throughput:(.*)Mbps/ {
+ x=\$3;
+ sub(/Mbps/, \"\", x);
+ e += x * 1000;
+ }
+ END {
+ print_device();
+ }
+ "
return 0
}
diff --git a/charts.d/apache.chart.sh b/charts.d/apache.chart.sh
index b503e74e3..b503e74e3 100755..100644
--- a/charts.d/apache.chart.sh
+++ b/charts.d/apache.chart.sh
diff --git a/charts.d/apcupsd.chart.sh b/charts.d/apcupsd.chart.sh
index 46a86101c..46a86101c 100755..100644
--- a/charts.d/apcupsd.chart.sh
+++ b/charts.d/apcupsd.chart.sh
diff --git a/charts.d/cpu_apps.chart.sh b/charts.d/cpu_apps.chart.sh
index 8e075831a..8e075831a 100755..100644
--- a/charts.d/cpu_apps.chart.sh
+++ b/charts.d/cpu_apps.chart.sh
diff --git a/charts.d/cpufreq.chart.sh b/charts.d/cpufreq.chart.sh
index b21504a0e..b21504a0e 100755..100644
--- a/charts.d/cpufreq.chart.sh
+++ b/charts.d/cpufreq.chart.sh
diff --git a/charts.d/example.chart.sh b/charts.d/example.chart.sh
index 86fde4901..86fde4901 100755..100644
--- a/charts.d/example.chart.sh
+++ b/charts.d/example.chart.sh
diff --git a/charts.d/hddtemp.chart.sh b/charts.d/hddtemp.chart.sh
index 15895c5e1..15895c5e1 100755..100644
--- a/charts.d/hddtemp.chart.sh
+++ b/charts.d/hddtemp.chart.sh
diff --git a/charts.d/load_average.chart.sh b/charts.d/load_average.chart.sh
index 70d3aec7a..70d3aec7a 100755..100644
--- a/charts.d/load_average.chart.sh
+++ b/charts.d/load_average.chart.sh
diff --git a/charts.d/mem_apps.chart.sh b/charts.d/mem_apps.chart.sh
index 3bc65fe24..3bc65fe24 100755..100644
--- a/charts.d/mem_apps.chart.sh
+++ b/charts.d/mem_apps.chart.sh
diff --git a/charts.d/mysql.chart.sh b/charts.d/mysql.chart.sh
index 1363d01f4..1363d01f4 100755..100644
--- a/charts.d/mysql.chart.sh
+++ b/charts.d/mysql.chart.sh
diff --git a/charts.d/nginx.chart.sh b/charts.d/nginx.chart.sh
index 0ae7d6307..0ae7d6307 100755..100644
--- a/charts.d/nginx.chart.sh
+++ b/charts.d/nginx.chart.sh
diff --git a/charts.d/nut.chart.sh b/charts.d/nut.chart.sh
index e0b1b4cf9..6137639f9 100755..100644
--- a/charts.d/nut.chart.sh
+++ b/charts.d/nut.chart.sh
@@ -2,7 +2,7 @@
# netdata
# real-time performance and health monitoring, done right!
-# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
+# (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
# GPL v3+
#
@@ -13,8 +13,13 @@ nut_ups=
# how frequently to collect UPS data
nut_update_every=2
+# how much time in seconds, to wait for nut to respond
nut_timeout=2
+# set this to 1, to enable another chart showing the number
+# of UPS clients connected to upsd
+nut_clients_chart=0
+
# the priority of nut related to other charts
nut_priority=90000
@@ -26,6 +31,12 @@ nut_get_all() {
nut_get() {
run -t $nut_timeout upsc "$1"
+
+ if [ "${nut_clients_chart}" -eq "1" ]
+ then
+ printf "ups.connected_clients: "
+ run -t $nut_timeout upsc -c "$1" | wc -l
+ fi
}
nut_check() {
@@ -97,6 +108,15 @@ DIMENSION load load absolute 1 100
CHART nut_$x.temp '' "UPS Temperature" "temperature" ups nut.temperature line $((nut_priority + 7)) $nut_update_every
DIMENSION temp temp absolute 1 100
EOF
+
+ if [ "${nut_clients_chart}" = "1" ]
+ then
+ cat <<EOF2
+CHART nut_$x.clients '' "UPS Connected Clients" "clients" ups nut.clients area $((nut_priority + 8)) $nut_update_every
+DIMENSION clients '' absolute 1 1
+EOF2
+ fi
+
done
return 0
@@ -131,6 +151,8 @@ BEGIN {
output_voltage = 0;
load = 0;
temp = 0;
+ client = 0;
+ do_clients = ${nut_clients_chart};
}
/^battery.charge: .*/ { battery_charge = \$2 * 100 };
/^battery.voltage: .*/ { battery_voltage = \$2 * 100 };
@@ -146,6 +168,7 @@ BEGIN {
/^output.voltage: .*/ { output_voltage = \$2 * 100 };
/^ups.load: .*/ { load = \$2 * 100 };
/^ups.temperature: .*/ { temp = \$2 * 100 };
+/^ups.connected_clients: .*/ { clients = \$2 };
END {
print \"BEGIN nut_$x.charge $1\";
print \"SET battery_charge = \" battery_charge;
@@ -184,6 +207,12 @@ END {
print \"BEGIN nut_$x.temp $1\";
print \"SET temp = \" temp;
print \"END\"
+
+ if(do_clients) {
+ print \"BEGIN nut_$x.clients $1\";
+ print \"SET clients = \" clients;
+ print \"END\"
+ }
}"
[ $? -ne 0 ] && unset nut_ids[$i] && error "failed to get values for '$i', disabling it."
done
diff --git a/charts.d/opensips.chart.sh b/charts.d/opensips.chart.sh
index 2a0249dae..2a0249dae 100755..100644
--- a/charts.d/opensips.chart.sh
+++ b/charts.d/opensips.chart.sh
diff --git a/charts.d/phpfpm.chart.sh b/charts.d/phpfpm.chart.sh
index a5ee0ad56..a5ee0ad56 100755..100644
--- a/charts.d/phpfpm.chart.sh
+++ b/charts.d/phpfpm.chart.sh
diff --git a/charts.d/postfix.chart.sh b/charts.d/postfix.chart.sh
index 85604fcbe..85604fcbe 100755..100644
--- a/charts.d/postfix.chart.sh
+++ b/charts.d/postfix.chart.sh
diff --git a/charts.d/sensors.chart.sh b/charts.d/sensors.chart.sh
index 125c925da..125c925da 100755..100644
--- a/charts.d/sensors.chart.sh
+++ b/charts.d/sensors.chart.sh
diff --git a/charts.d/squid.chart.sh b/charts.d/squid.chart.sh
index 2c19c35d5..2c19c35d5 100755..100644
--- a/charts.d/squid.chart.sh
+++ b/charts.d/squid.chart.sh
diff --git a/charts.d/tomcat.chart.sh b/charts.d/tomcat.chart.sh
index 44a92c86e..44a92c86e 100755..100644
--- a/charts.d/tomcat.chart.sh
+++ b/charts.d/tomcat.chart.sh
diff --git a/compile b/compile
deleted file mode 100755
index a85b723c7..000000000
--- a/compile
+++ /dev/null
@@ -1,347 +0,0 @@
-#! /bin/sh
-# Wrapper for compilers which do not understand '-c -o'.
-
-scriptversion=2012-10-14.11; # UTC
-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-# Written by Tom Tromey <tromey@cygnus.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# This file is maintained in Automake, please report
-# bugs to <bug-automake@gnu.org> or send patches to
-# <automake-patches@gnu.org>.
-
-nl='
-'
-
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent tools from complaining about whitespace usage.
-IFS=" "" $nl"
-
-file_conv=
-
-# func_file_conv build_file lazy
-# Convert a $build file to $host form and store it in $file
-# Currently only supports Windows hosts. If the determined conversion
-# type is listed in (the comma separated) LAZY, no conversion will
-# take place.
-func_file_conv ()
-{
- file=$1
- case $file in
- / | /[!/]*) # absolute file, and not a UNC file
- if test -z "$file_conv"; then
- # lazily determine how to convert abs files
- case `uname -s` in
- MINGW*)
- file_conv=mingw
- ;;
- CYGWIN*)
- file_conv=cygwin
- ;;
- *)
- file_conv=wine
- ;;
- esac
- fi
- case $file_conv/,$2, in
- *,$file_conv,*)
- ;;
- mingw/*)
- file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
- ;;
- cygwin/*)
- file=`cygpath -m "$file" || echo "$file"`
- ;;
- wine/*)
- file=`winepath -w "$file" || echo "$file"`
- ;;
- esac
- ;;
- esac
-}
-
-# func_cl_dashL linkdir
-# Make cl look for libraries in LINKDIR
-func_cl_dashL ()
-{
- func_file_conv "$1"
- if test -z "$lib_path"; then
- lib_path=$file
- else
- lib_path="$lib_path;$file"
- fi
- linker_opts="$linker_opts -LIBPATH:$file"
-}
-
-# func_cl_dashl library
-# Do a library search-path lookup for cl
-func_cl_dashl ()
-{
- lib=$1
- found=no
- save_IFS=$IFS
- IFS=';'
- for dir in $lib_path $LIB
- do
- IFS=$save_IFS
- if $shared && test -f "$dir/$lib.dll.lib"; then
- found=yes
- lib=$dir/$lib.dll.lib
- break
- fi
- if test -f "$dir/$lib.lib"; then
- found=yes
- lib=$dir/$lib.lib
- break
- fi
- if test -f "$dir/lib$lib.a"; then
- found=yes
- lib=$dir/lib$lib.a
- break
- fi
- done
- IFS=$save_IFS
-
- if test "$found" != yes; then
- lib=$lib.lib
- fi
-}
-
-# func_cl_wrapper cl arg...
-# Adjust compile command to suit cl
-func_cl_wrapper ()
-{
- # Assume a capable shell
- lib_path=
- shared=:
- linker_opts=
- for arg
- do
- if test -n "$eat"; then
- eat=
- else
- case $1 in
- -o)
- # configure might choose to run compile as 'compile cc -o foo foo.c'.
- eat=1
- case $2 in
- *.o | *.[oO][bB][jJ])
- func_file_conv "$2"
- set x "$@" -Fo"$file"
- shift
- ;;
- *)
- func_file_conv "$2"
- set x "$@" -Fe"$file"
- shift
- ;;
- esac
- ;;
- -I)
- eat=1
- func_file_conv "$2" mingw
- set x "$@" -I"$file"
- shift
- ;;
- -I*)
- func_file_conv "${1#-I}" mingw
- set x "$@" -I"$file"
- shift
- ;;
- -l)
- eat=1
- func_cl_dashl "$2"
- set x "$@" "$lib"
- shift
- ;;
- -l*)
- func_cl_dashl "${1#-l}"
- set x "$@" "$lib"
- shift
- ;;
- -L)
- eat=1
- func_cl_dashL "$2"
- ;;
- -L*)
- func_cl_dashL "${1#-L}"
- ;;
- -static)
- shared=false
- ;;
- -Wl,*)
- arg=${1#-Wl,}
- save_ifs="$IFS"; IFS=','
- for flag in $arg; do
- IFS="$save_ifs"
- linker_opts="$linker_opts $flag"
- done
- IFS="$save_ifs"
- ;;
- -Xlinker)
- eat=1
- linker_opts="$linker_opts $2"
- ;;
- -*)
- set x "$@" "$1"
- shift
- ;;
- *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
- func_file_conv "$1"
- set x "$@" -Tp"$file"
- shift
- ;;
- *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
- func_file_conv "$1" mingw
- set x "$@" "$file"
- shift
- ;;
- *)
- set x "$@" "$1"
- shift
- ;;
- esac
- fi
- shift
- done
- if test -n "$linker_opts"; then
- linker_opts="-link$linker_opts"
- fi
- exec "$@" $linker_opts
- exit 1
-}
-
-eat=
-
-case $1 in
- '')
- echo "$0: No command. Try '$0 --help' for more information." 1>&2
- exit 1;
- ;;
- -h | --h*)
- cat <<\EOF
-Usage: compile [--help] [--version] PROGRAM [ARGS]
-
-Wrapper for compilers which do not understand '-c -o'.
-Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
-arguments, and rename the output as expected.
-
-If you are trying to build a whole package this is not the
-right script to run: please start by reading the file 'INSTALL'.
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
- exit $?
- ;;
- -v | --v*)
- echo "compile $scriptversion"
- exit $?
- ;;
- cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
- func_cl_wrapper "$@" # Doesn't return...
- ;;
-esac
-
-ofile=
-cfile=
-
-for arg
-do
- if test -n "$eat"; then
- eat=
- else
- case $1 in
- -o)
- # configure might choose to run compile as 'compile cc -o foo foo.c'.
- # So we strip '-o arg' only if arg is an object.
- eat=1
- case $2 in
- *.o | *.obj)
- ofile=$2
- ;;
- *)
- set x "$@" -o "$2"
- shift
- ;;
- esac
- ;;
- *.c)
- cfile=$1
- set x "$@" "$1"
- shift
- ;;
- *)
- set x "$@" "$1"
- shift
- ;;
- esac
- fi
- shift
-done
-
-if test -z "$ofile" || test -z "$cfile"; then
- # If no '-o' option was seen then we might have been invoked from a
- # pattern rule where we don't need one. That is ok -- this is a
- # normal compilation that the losing compiler can handle. If no
- # '.c' file was seen then we are probably linking. That is also
- # ok.
- exec "$@"
-fi
-
-# Name of file we expect compiler to create.
-cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
-
-# Create the lock directory.
-# Note: use '[/\\:.-]' here to ensure that we don't use the same name
-# that we are using for the .o file. Also, base the name on the expected
-# object file name, since that is what matters with a parallel build.
-lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
-while true; do
- if mkdir "$lockdir" >/dev/null 2>&1; then
- break
- fi
- sleep 1
-done
-# FIXME: race condition here if user kills between mkdir and trap.
-trap "rmdir '$lockdir'; exit 1" 1 2 15
-
-# Run the compile.
-"$@"
-ret=$?
-
-if test -f "$cofile"; then
- test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
-elif test -f "${cofile}bj"; then
- test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
-fi
-
-rmdir "$lockdir"
-exit $ret
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/conf.d/Makefile.am b/conf.d/Makefile.am
index b725e249e..efe1f2a6e 100644
--- a/conf.d/Makefile.am
+++ b/conf.d/Makefile.am
@@ -11,6 +11,7 @@ dist_config_DATA = \
python.d.conf \
health_alarm_notify.conf \
health_email_recipients.conf \
+ stream.conf \
$(NULL)
nodeconfigdir=$(configdir)/node.d
@@ -33,16 +34,16 @@ dist_pythonconfig_DATA = \
python.d/exim.conf \
python.d/fail2ban.conf \
python.d/freeradius.conf \
- python.d/gunicorn_log.conf \
python.d/haproxy.conf \
python.d/hddtemp.conf \
python.d/ipfs.conf \
python.d/isc_dhcpd.conf \
python.d/mdstat.conf \
python.d/memcached.conf \
+ python.d/mongodb.conf \
python.d/mysql.conf \
python.d/nginx.conf \
- python.d/nginx_log.conf \
+ python.d/nsd.conf \
python.d/ovpn_status_log.conf \
python.d/phpfpm.conf \
python.d/postfix.conf \
@@ -51,43 +52,54 @@ dist_pythonconfig_DATA = \
python.d/retroshare.conf \
python.d/sensors.conf \
python.d/squid.conf \
+ python.d/smartd_log.conf \
python.d/tomcat.conf \
python.d/varnish.conf \
+ python.d/web_log.conf \
$(NULL)
healthconfigdir=$(configdir)/health.d
+
dist_healthconfig_DATA = \
health.d/apache.conf \
health.d/backend.conf \
health.d/bind_rndc.conf \
- health.d/cpu.conf \
- health.d/disks.conf \
health.d/elasticsearch.conf \
- health.d/entropy.conf \
+ health.d/fping.conf \
health.d/haproxy.conf \
- health.d/ipc.conf \
health.d/ipfs.conf \
+ health.d/ipmi.conf \
health.d/isc_dhcpd.conf \
health.d/mdstat.conf \
health.d/memcached.conf \
- health.d/memory.conf \
health.d/mysql.conf \
health.d/named.conf \
- health.d/net.conf \
- health.d/netfilter.conf \
health.d/nginx.conf \
health.d/postgres.conf \
- health.d/qos.conf \
- health.d/ram.conf \
health.d/redis.conf \
health.d/retroshare.conf \
- health.d/softnet.conf \
health.d/squid.conf \
+ health.d/varnish.conf \
+ health.d/web_log.conf \
+ $(NULL)
+
+if LINUX
+dist_healthconfig_DATA += \
+ health.d/cpu.conf \
+ health.d/disks.conf \
+ health.d/entropy.conf \
+ health.d/ipc.conf \
+ health.d/memory.conf \
+ health.d/net.conf \
+ health.d/netfilter.conf \
+ health.d/qos.conf \
+ health.d/ram.conf \
+ health.d/softnet.conf \
health.d/swap.conf \
health.d/tcp_resets.conf \
health.d/udp_errors.conf \
- health.d/varnish.conf \
$(NULL)
+endif LINUX
chartsconfigdir=$(configdir)/charts.d
dist_chartsconfig_DATA = \
diff --git a/conf.d/Makefile.in b/conf.d/Makefile.in
index 344f1c416..fb05396fb 100644
--- a/conf.d/Makefile.in
+++ b/conf.d/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -15,61 +16,6 @@
@SET_MAKE@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -88,10 +34,30 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+@LINUX_TRUE@am__append_1 = \
+@LINUX_TRUE@ health.d/cpu.conf \
+@LINUX_TRUE@ health.d/disks.conf \
+@LINUX_TRUE@ health.d/entropy.conf \
+@LINUX_TRUE@ health.d/ipc.conf \
+@LINUX_TRUE@ health.d/memory.conf \
+@LINUX_TRUE@ health.d/net.conf \
+@LINUX_TRUE@ health.d/netfilter.conf \
+@LINUX_TRUE@ health.d/qos.conf \
+@LINUX_TRUE@ health.d/ram.conf \
+@LINUX_TRUE@ health.d/softnet.conf \
+@LINUX_TRUE@ health.d/swap.conf \
+@LINUX_TRUE@ health.d/tcp_resets.conf \
+@LINUX_TRUE@ health.d/udp_errors.conf \
+@LINUX_TRUE@ $(NULL)
+
subdir = conf.d
+DIST_COMMON = $(am__dist_healthconfig_DATA_DIST) \
+ $(dist_chartsconfig_DATA) $(dist_config_DATA) \
+ $(dist_nodeconfig_DATA) $(dist_pythonconfig_DATA) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -100,33 +66,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_chartsconfig_DATA) \
- $(dist_config_DATA) $(dist_healthconfig_DATA) \
- $(dist_nodeconfig_DATA) $(dist_pythonconfig_DATA) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-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 =
SOURCES =
DIST_SOURCES =
-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/||"`;; \
@@ -157,15 +102,26 @@ am__uninstall_files_from_dir = { \
am__installdirs = "$(DESTDIR)$(chartsconfigdir)" \
"$(DESTDIR)$(configdir)" "$(DESTDIR)$(healthconfigdir)" \
"$(DESTDIR)$(nodeconfigdir)" "$(DESTDIR)$(pythonconfigdir)"
+am__dist_healthconfig_DATA_DIST = health.d/apache.conf \
+ health.d/backend.conf health.d/bind_rndc.conf \
+ health.d/elasticsearch.conf health.d/fping.conf \
+ health.d/haproxy.conf health.d/ipfs.conf health.d/ipmi.conf \
+ health.d/isc_dhcpd.conf health.d/mdstat.conf \
+ health.d/memcached.conf health.d/mysql.conf \
+ health.d/named.conf health.d/nginx.conf health.d/postgres.conf \
+ health.d/redis.conf health.d/retroshare.conf \
+ health.d/squid.conf health.d/varnish.conf \
+ health.d/web_log.conf health.d/cpu.conf health.d/disks.conf \
+ health.d/entropy.conf health.d/ipc.conf health.d/memory.conf \
+ health.d/net.conf health.d/netfilter.conf health.d/qos.conf \
+ health.d/ram.conf health.d/softnet.conf health.d/swap.conf \
+ health.d/tcp_resets.conf health.d/udp_errors.conf
DATA = $(dist_chartsconfig_DATA) $(dist_config_DATA) \
$(dist_healthconfig_DATA) $(dist_nodeconfig_DATA) \
$(dist_pythonconfig_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -189,7 +145,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -203,6 +163,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -312,6 +276,7 @@ dist_config_DATA = \
python.d.conf \
health_alarm_notify.conf \
health_email_recipients.conf \
+ stream.conf \
$(NULL)
nodeconfigdir = $(configdir)/node.d
@@ -334,16 +299,16 @@ dist_pythonconfig_DATA = \
python.d/exim.conf \
python.d/fail2ban.conf \
python.d/freeradius.conf \
- python.d/gunicorn_log.conf \
python.d/haproxy.conf \
python.d/hddtemp.conf \
python.d/ipfs.conf \
python.d/isc_dhcpd.conf \
python.d/mdstat.conf \
python.d/memcached.conf \
+ python.d/mongodb.conf \
python.d/mysql.conf \
python.d/nginx.conf \
- python.d/nginx_log.conf \
+ python.d/nsd.conf \
python.d/ovpn_status_log.conf \
python.d/phpfpm.conf \
python.d/postfix.conf \
@@ -352,44 +317,23 @@ dist_pythonconfig_DATA = \
python.d/retroshare.conf \
python.d/sensors.conf \
python.d/squid.conf \
+ python.d/smartd_log.conf \
python.d/tomcat.conf \
python.d/varnish.conf \
+ python.d/web_log.conf \
$(NULL)
healthconfigdir = $(configdir)/health.d
-dist_healthconfig_DATA = \
- health.d/apache.conf \
- health.d/backend.conf \
- health.d/bind_rndc.conf \
- health.d/cpu.conf \
- health.d/disks.conf \
- health.d/elasticsearch.conf \
- health.d/entropy.conf \
- health.d/haproxy.conf \
- health.d/ipc.conf \
- health.d/ipfs.conf \
- health.d/isc_dhcpd.conf \
- health.d/mdstat.conf \
- health.d/memcached.conf \
- health.d/memory.conf \
- health.d/mysql.conf \
- health.d/named.conf \
- health.d/net.conf \
- health.d/netfilter.conf \
- health.d/nginx.conf \
- health.d/postgres.conf \
- health.d/qos.conf \
- health.d/ram.conf \
- health.d/redis.conf \
- health.d/retroshare.conf \
- health.d/softnet.conf \
- health.d/squid.conf \
- health.d/swap.conf \
- health.d/tcp_resets.conf \
- health.d/udp_errors.conf \
- health.d/varnish.conf \
- $(NULL)
-
+dist_healthconfig_DATA = health.d/apache.conf health.d/backend.conf \
+ health.d/bind_rndc.conf health.d/elasticsearch.conf \
+ health.d/fping.conf health.d/haproxy.conf health.d/ipfs.conf \
+ health.d/ipmi.conf health.d/isc_dhcpd.conf \
+ health.d/mdstat.conf health.d/memcached.conf \
+ health.d/mysql.conf health.d/named.conf health.d/nginx.conf \
+ health.d/postgres.conf health.d/redis.conf \
+ health.d/retroshare.conf health.d/squid.conf \
+ health.d/varnish.conf health.d/web_log.conf $(NULL) \
+ $(am__append_1)
chartsconfigdir = $(configdir)/charts.d
dist_chartsconfig_DATA = \
charts.d/apache.conf \
@@ -428,6 +372,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu conf.d/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu conf.d/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -447,11 +392,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_chartsconfigDATA: $(dist_chartsconfig_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(chartsconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(chartsconfigdir)"
@list='$(dist_chartsconfig_DATA)'; test -n "$(chartsconfigdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(chartsconfigdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(chartsconfigdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -468,11 +410,8 @@ uninstall-dist_chartsconfigDATA:
dir='$(DESTDIR)$(chartsconfigdir)'; $(am__uninstall_files_from_dir)
install-dist_configDATA: $(dist_config_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(configdir)" || $(MKDIR_P) "$(DESTDIR)$(configdir)"
@list='$(dist_config_DATA)'; test -n "$(configdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(configdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(configdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -489,11 +428,8 @@ uninstall-dist_configDATA:
dir='$(DESTDIR)$(configdir)'; $(am__uninstall_files_from_dir)
install-dist_healthconfigDATA: $(dist_healthconfig_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(healthconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(healthconfigdir)"
@list='$(dist_healthconfig_DATA)'; test -n "$(healthconfigdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(healthconfigdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(healthconfigdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -510,11 +446,8 @@ uninstall-dist_healthconfigDATA:
dir='$(DESTDIR)$(healthconfigdir)'; $(am__uninstall_files_from_dir)
install-dist_nodeconfigDATA: $(dist_nodeconfig_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(nodeconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(nodeconfigdir)"
@list='$(dist_nodeconfig_DATA)'; test -n "$(nodeconfigdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodeconfigdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodeconfigdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -531,11 +464,8 @@ uninstall-dist_nodeconfigDATA:
dir='$(DESTDIR)$(nodeconfigdir)'; $(am__uninstall_files_from_dir)
install-dist_pythonconfigDATA: $(dist_pythonconfig_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(pythonconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pythonconfigdir)"
@list='$(dist_pythonconfig_DATA)'; test -n "$(pythonconfigdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pythonconfigdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pythonconfigdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -550,11 +480,11 @@ uninstall-dist_pythonconfigDATA:
@list='$(dist_pythonconfig_DATA)'; test -n "$(pythonconfigdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pythonconfigdir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
+tags: TAGS
+TAGS:
-ctags CTAGS:
-
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -697,23 +627,21 @@ uninstall-am: uninstall-dist_chartsconfigDATA \
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-dist_chartsconfigDATA \
- install-dist_configDATA install-dist_healthconfigDATA \
- install-dist_nodeconfigDATA install-dist_pythonconfigDATA \
- 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-ps \
- install-ps-am install-strip installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
- uninstall uninstall-am uninstall-dist_chartsconfigDATA \
- uninstall-dist_configDATA uninstall-dist_healthconfigDATA \
- uninstall-dist_nodeconfigDATA uninstall-dist_pythonconfigDATA
-
-.PRECIOUS: Makefile
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_chartsconfigDATA install-dist_configDATA \
+ install-dist_healthconfigDATA install-dist_nodeconfigDATA \
+ install-dist_pythonconfigDATA 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-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-dist_chartsconfigDATA uninstall-dist_configDATA \
+ uninstall-dist_healthconfigDATA uninstall-dist_nodeconfigDATA \
+ uninstall-dist_pythonconfigDATA
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/conf.d/apps_groups.conf b/conf.d/apps_groups.conf
index e2836877c..4c5171b3d 100644
--- a/conf.d/apps_groups.conf
+++ b/conf.d/apps_groups.conf
@@ -73,10 +73,12 @@ netdata: netdata
# netdata known plugins
# plugins not defined here will be accumulated in netdata, above
apps.plugin: apps.plugin
+freeipmi.plugin: freeipmi.plugin
charts.d.plugin: *charts.d.plugin*
node.d.plugin: *node.d.plugin*
python.d.plugin: *python.d.plugin*
tc-qos-helper: *tc-qos-helper.sh*
+fping: fping
# -----------------------------------------------------------------------------
# authentication/authorization related servers
@@ -106,11 +108,12 @@ nosql: mongod redis* memcached
email: dovecot imapd pop3d amavis* master zmstat* zmmailboxdmgr qmgr oqmgr
# -----------------------------------------------------------------------------
-# networking and VPN servers
+# network, routing, VPN
ppp: ppp*
vpn: openvpn pptp* cjdroute
wifi: hostapd wpa_supplicant
+routing: ospfd* ospf6d* bgpd isisd ripd ripngd pimd ldpd zebra vtysh bird*
# -----------------------------------------------------------------------------
# high availability and balancers
diff --git a/conf.d/charts.d/nut.conf b/conf.d/charts.d/nut.conf
index 2844849de..a836692d8 100644
--- a/conf.d/charts.d/nut.conf
+++ b/conf.d/charts.d/nut.conf
@@ -2,7 +2,7 @@
# netdata
# real-time performance and health monitoring, done right!
-# (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
+# (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
# GPL v3+
# a space separated list of UPS names
@@ -12,6 +12,10 @@
# how much time in seconds, to wait for nut to respond
#nut_timeout=2
+# set this to 1, to enable another chart showing the number
+# of UPS clients connected to upsd
+#nut_clients_chart=1
+
# the data collection frequency
# if unset, will inherit the netdata update frequency
#nut_update_every=2
diff --git a/conf.d/health.d/cpu.conf b/conf.d/health.d/cpu.conf
index 60f494d70..30a714097 100644
--- a/conf.d/health.d/cpu.conf
+++ b/conf.d/health.d/cpu.conf
@@ -1,13 +1,13 @@
template: 10min_cpu_usage
on: system.cpu
- lookup: average -10m unaligned of user,system,nice,softirq,irq,guest,guest_nice
+ lookup: average -10m unaligned of user,system,softirq,irq,guest
units: %
every: 1m
warn: $this > (($status >= $WARNING) ? (75) : (85))
crit: $this > (($status == $CRITICAL) ? (85) : (95))
delay: down 15m multiplier 1.5 max 1h
- info: average cpu utilization for the last 10 minutes
+ info: average cpu utilization for the last 10 minutes (excluding iowait, nice and steal)
to: sysadmin
template: 10min_cpu_iowait
diff --git a/conf.d/health.d/disks.conf b/conf.d/health.d/disks.conf
index 0549bac26..9548f9ee0 100644
--- a/conf.d/health.d/disks.conf
+++ b/conf.d/health.d/disks.conf
@@ -1,34 +1,4 @@
# -----------------------------------------------------------------------------
-# make sure we collect values for each disk
-
-# for mount points
-template: disk_space_last_collected_secs
- on: disk.space
-families: *
- calc: $now - $last_collected_t
- units: seconds ago
- every: 10s
- warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
- crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
- delay: down 5m multiplier 1.5 max 1h
- info: number of seconds since the last successful data collection of the mount point
- to: sysadmin
-
-# for block devices
-template: disk_last_collected_secs
- on: disk.io
-families: *
- calc: $now - $last_collected_t
- units: seconds ago
- every: 10s
- warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
- crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
- delay: down 5m multiplier 1.5 max 1h
- info: number of seconds since the last successful data collection of the block device
- to: sysadmin
-
-
-# -----------------------------------------------------------------------------
# low disk space
# checking the latest collected values
@@ -88,7 +58,7 @@ families: *
template: out_of_disk_space_time
on: disk.space
families: *
- calc: ($disk_fill_rate > 0) ? ($avail / $disk_fill_rate) : (0)
+ calc: ($disk_fill_rate > 0) ? ($avail / $disk_fill_rate) : (inf)
units: hours
every: 10s
warn: $this > 0 and $this < (($status >= $WARNING) ? (48) : (8))
diff --git a/conf.d/health.d/fping.conf b/conf.d/health.d/fping.conf
new file mode 100644
index 000000000..69251b182
--- /dev/null
+++ b/conf.d/health.d/fping.conf
@@ -0,0 +1,53 @@
+
+template: fping_last_collected_secs
+families: *
+ on: fping.latency
+ calc: $now - $last_collected_t
+ units: seconds ago
+ every: 10s
+ warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
+ crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
+ delay: down 5m multiplier 1.5 max 1h
+ info: number of seconds since the last successful data collection
+ to: sysadmin
+
+template: host_reachable
+families: *
+ on: fping.latency
+ calc: $average != nan
+ units: up/down
+ every: 10s
+ crit: $this == 0
+ info: states if the remote host is reachable
+ delay: down 30m multiplier 1.5 max 2h
+ to: sysadmin
+
+template: host_latency
+families: *
+ on: fping.latency
+ lookup: average -10s unaligned of average
+ units: ms
+ every: 10s
+ green: 300
+ red: 1000
+ warn: $this > $green OR $max > $red
+ crit: $this > $red
+ info: average round trip delay during the last 10 seconds
+ delay: down 30m multiplier 1.5 max 2h
+ to: sysadmin
+
+template: packet_loss
+families: *
+ on: fping.quality
+ lookup: average -10m unaligned of returned
+ calc: 100 - $this
+ green: 1
+ red: 10
+ units: %
+ every: 10s
+ warn: $this > $green
+ crit: $this > $red
+ info: packet loss percentage
+ delay: down 30m multiplier 1.5 max 2h
+ to: sysadmin
+
diff --git a/conf.d/health.d/ipmi.conf b/conf.d/health.d/ipmi.conf
new file mode 100644
index 000000000..c25581964
--- /dev/null
+++ b/conf.d/health.d/ipmi.conf
@@ -0,0 +1,20 @@
+ alarm: ipmi_sensors_states
+ on: ipmi.sensors_states
+ calc: $warning + $critical
+ units: sensors
+ every: 10s
+ warn: $this > 0
+ crit: $critical > 0
+ delay: up 5m down 15m multiplier 1.5 max 1h
+ info: the number IPMI sensors in non-nominal state
+ to: sysadmin
+
+ alarm: ipmi_events
+ on: ipmi.events
+ calc: $events
+ units: events
+ every: 10s
+ warn: $this > 0
+ delay: up 5m down 15m multiplier 1.5 max 1h
+ info: the number of events in the IPMI System Event Log (SEL)
+ to: sysadmin
diff --git a/conf.d/health.d/memcached.conf b/conf.d/health.d/memcached.conf
index 7917e36af..d248ef57a 100644
--- a/conf.d/health.d/memcached.conf
+++ b/conf.d/health.d/memcached.conf
@@ -42,7 +42,7 @@ template: cache_fill_rate
template: out_of_cache_space_time
on: memcached.cache
- calc: ($cache_fill_rate > 0) ? ($available / $cache_fill_rate) : (0)
+ calc: ($cache_fill_rate > 0) ? ($available / $cache_fill_rate) : (inf)
units: hours
every: 10s
warn: $this > 0 and $this < (($status >= $WARNING) ? (48) : (8))
diff --git a/conf.d/health.d/mysql.conf b/conf.d/health.d/mysql.conf
index 78773e5b5..1eeb993f0 100644
--- a/conf.d/health.d/mysql.conf
+++ b/conf.d/health.d/mysql.conf
@@ -49,7 +49,7 @@ template: mysql_10s_table_locks_waited
template: mysql_10s_waited_locks_ratio
on: mysql.table_locks
- calc: ($mysql_10s_table_locks_waited * 100) / ($mysql_10s_table_locks_waited + $mysql_10s_table_locks_immediate)
+ calc: ( ($mysql_10s_table_locks_waited + $mysql_10s_table_locks_immediate) > 0 ) ? (($mysql_10s_table_locks_waited * 100) / ($mysql_10s_table_locks_waited + $mysql_10s_table_locks_immediate)) : 0
units: %
every: 10s
warn: $this > (($status >= $WARNING) ? (10) : (25))
@@ -65,7 +65,7 @@ template: mysql_10s_waited_locks_ratio
template: mysql_replication
on: mysql.slave_status
calc: ($sql_running == -1 OR $io_running == -1)?0:1
- units: status
+ units: ok/failed
every: 10s
crit: $this == 0
delay: down 5m multiplier 1.5 max 1h
diff --git a/conf.d/health.d/net.conf b/conf.d/health.d/net.conf
index 924acccc3..0232395ac 100644
--- a/conf.d/health.d/net.conf
+++ b/conf.d/health.d/net.conf
@@ -1,18 +1,3 @@
-# -----------------------------------------------------------------------------
-# make sure we collect values for each interface
-
-template: interface_last_collected_secs
- on: net.net
-families: *
- calc: $now - $last_collected_t
- units: seconds ago
- every: 10s
- warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
- crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
- delay: down 5m multiplier 1.5 max 1h
- info: number of seconds since the last successful data collection
- to: sysadmin
-
# -----------------------------------------------------------------------------
# dropped packets
@@ -116,6 +101,7 @@ families: *
units: %
warn: $this > (($status >= $WARNING)?(200):(1000))
crit: $this > (($status >= $WARNING)?(1000):(2000))
+options: no-clear-notification
info: the % of the rate of received packets in the last 10 seconds, compared to the rate of the last minute
- to: silent
+ to: sysadmin
diff --git a/conf.d/health.d/tcp_resets.conf b/conf.d/health.d/tcp_resets.conf
index daf24a1cd..49fb1b924 100644
--- a/conf.d/health.d/tcp_resets.conf
+++ b/conf.d/health.d/tcp_resets.conf
@@ -28,8 +28,9 @@
every: 10s
warn: $this > ((($1m_ipv4_tcp_resets_sent < 5)?(5):($1m_ipv4_tcp_resets_sent)) * (($status >= $WARNING) ? (1) : (4)))
delay: up 0 down 60m multiplier 1.2 max 2h
+options: no-clear-notification
info: average TCP RESETS this host is sending, over the last 10 seconds (this can be an indication that a port scan is made, or that a service running on this host has crashed)
- to: silent
+ to: sysadmin
# -----------------------------------------------------------------------------
# tcp resets this host receives
@@ -48,5 +49,6 @@
every: 10s
warn: $this > ((($1m_ipv4_tcp_resets_received < 5)?(5):($1m_ipv4_tcp_resets_received)) * (($status >= $WARNING) ? (1) : (4)))
delay: up 0 down 60m multiplier 1.2 max 2h
+options: no-clear-notification
info: average TCP RESETS this host is receiving, over the last 10 seconds (this can be an indication that a service this host needs, has crashed)
- to: silent
+ to: sysadmin
diff --git a/conf.d/health.d/web_log.conf b/conf.d/health.d/web_log.conf
new file mode 100644
index 000000000..c668959f5
--- /dev/null
+++ b/conf.d/health.d/web_log.conf
@@ -0,0 +1,161 @@
+
+# make sure we can collect web log data
+
+template: last_collected_secs
+ on: web_log.response_codes
+families: *
+ calc: $now - $last_collected_t
+ units: seconds ago
+ every: 10s
+ warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
+ crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
+ delay: down 5m multiplier 1.5 max 1h
+ info: number of seconds since the last successful data collection
+ to: webmaster
+
+
+# -----------------------------------------------------------------------------
+# high level response code alarms
+
+# the following alarms trigger only when there are enough data.
+# we assume there are enough data when:
+#
+# $1m_requests > 120
+#
+# i.e. when there are at least 120 requests during the last minute
+
+template: 1m_requests
+ on: web_log.response_statuses
+families: *
+ lookup: sum -1m unaligned
+ calc: ($this == 0)?(1):($this)
+ units: requests
+ every: 10s
+ info: the sum of all HTTP requests over the last minute
+
+template: 1m_successful
+ on: web_log.response_statuses
+families: *
+ lookup: sum -1m unaligned of successful_requests
+ calc: $this * 100 / $1m_requests
+ units: %
+ every: 10s
+ warn: ($1m_requests > 120) ? ($this < (($status >= $WARNING ) ? ( 95 ) : ( 85 )) ) : ( 0 )
+ crit: ($1m_requests > 120) ? ($this < (($status == $CRITICAL) ? ( 85 ) : ( 75 )) ) : ( 0 )
+ delay: up 2m down 15m multiplier 1.5 max 1h
+ info: the ratio of successful HTTP responses (1xx, 2xx, 304) over the last minute
+ to: webmaster
+
+template: 1m_redirects
+ on: web_log.response_statuses
+families: *
+ lookup: sum -1m unaligned of redirects
+ calc: $this * 100 / $1m_requests
+ units: %
+ every: 10s
+ warn: ($1m_requests > 120) ? ($this > (($status >= $WARNING ) ? ( 1 ) : ( 20 )) ) : ( 0 )
+ crit: ($1m_requests > 120) ? ($this > (($status == $CRITICAL) ? ( 20 ) : ( 30 )) ) : ( 0 )
+ delay: up 2m down 15m multiplier 1.5 max 1h
+ info: the ratio of HTTP redirects (3xx except 304) over the last minute
+ to: webmaster
+
+template: 1m_bad_requests
+ on: web_log.response_statuses
+families: *
+ lookup: sum -1m unaligned of bad_requests
+ calc: $this * 100 / $1m_requests
+ units: %
+ every: 10s
+ warn: ($1m_requests > 120) ? ($this > (($status >= $WARNING) ? ( 10 ) : ( 30 )) ) : ( 0 )
+ crit: ($1m_requests > 120) ? ($this > (($status == $CRITICAL) ? ( 30 ) : ( 50 )) ) : ( 0 )
+ delay: up 2m down 15m multiplier 1.5 max 1h
+ info: the ratio of HTTP bad requests (4xx) over the last minute
+ to: webmaster
+
+template: 1m_internal_errors
+ on: web_log.response_statuses
+families: *
+ lookup: sum -1m unaligned of server_errors
+ calc: $this * 100 / $1m_requests
+ units: %
+ every: 10s
+ warn: ($1m_requests > 120) ? ($this > (($status >= $WARNING) ? ( 1 ) : ( 2 )) ) : ( 0 )
+ crit: ($1m_requests > 120) ? ($this > (($status == $CRITICAL) ? ( 2 ) : ( 5 )) ) : ( 0 )
+ delay: up 2m down 15m multiplier 1.5 max 1h
+ info: the ratio of HTTP internal server errors (5xx), over the last minute
+ to: webmaster
+
+
+# -----------------------------------------------------------------------------
+# web slow
+
+# the following alarms trigger only when there are enough data.
+# we assume there are enough data when:
+#
+# $1m_requests > 120
+#
+# i.e. when there are at least 120 requests during the last minute
+
+template: 10m_response_time
+ on: web_log.response_time
+families: *
+ lookup: average -10m unaligned of avg
+ units: ms
+ every: 30s
+ info: the average time to respond to HTTP requests, over the last 10 minutes
+
+template: web_slow
+ on: web_log.response_time
+families: *
+ lookup: average -1m unaligned of avg
+ units: ms
+ every: 10s
+ green: 500
+ red: 1000
+ warn: ($1m_requests > 120) ? ($this > $green && $this > ($10m_response_time * 2) ) : ( 0 )
+ crit: ($1m_requests > 120) ? ($this > $red && $this > ($10m_response_time * 4) ) : ( 0 )
+ delay: down 15m multiplier 1.5 max 1h
+ info: the average time to respond to HTTP requests, over the last 1 minute
+ to: webmaster
+
+# -----------------------------------------------------------------------------
+# web too many or too few requests
+
+# the following alarms trigger only when there are enough data.
+# we assume there are enough data when:
+#
+# $5m_successful_old > 120
+#
+# i.e. when there were at least 120 requests during the 5 minutes starting
+# at -10m and ending at -5m
+
+template: 5m_successful_old
+ on: web_log.response_statuses
+families: *
+ lookup: average -5m at -5m unaligned of successful_requests
+ units: requests/s
+ every: 30s
+ info: average rate of successful HTTP requests over the last 5 minutes
+
+template: 5m_successful
+ on: web_log.response_statuses
+families: *
+ lookup: average -5m unaligned of successful_requests
+ units: requests/s
+ every: 30s
+ info: average successful HTTP requests over the last 5 minutes
+
+template: 5m_requests_ratio
+ on: web_log.response_codes
+families: *
+ calc: ($5m_successful_old > 0)?($5m_successful * 100 / $5m_successful_old):(100)
+ units: %
+ every: 30s
+ warn: ($5m_successful_old > 120) ? ($this > 200 OR $this < 50) : (0)
+ crit: ($5m_successful_old > 120) ? ($this > 400 OR $this < 25) : (0)
+ delay: down 15m multiplier 1.5 max 1h
+options: no-clear-notification
+ info: the percentage of successful web requests over the last 5 minutes, \
+ compared with the previous 5 minutes
+ to: webmaster
+
diff --git a/conf.d/health_alarm_notify.conf b/conf.d/health_alarm_notify.conf
index b838e8024..23776b96a 100644
--- a/conf.d/health_alarm_notify.conf
+++ b/conf.d/health_alarm_notify.conf
@@ -7,6 +7,7 @@
# - e-mails (using the sendmail command),
# - push notifications to your mobile phone (pushover.net),
# - messages to your slack team (slack.com),
+# - messages to your discord guild (discordapp.com),
# - messages to your telegram chat / group chat (telegram.org)
# - sms messages to your cell phone or any sms enabled device (twilio.com)
# - sms messages to your cell phone or any sms enabled device (messagebird.com)
@@ -22,7 +23,7 @@
# proxy configuration
#
# If you need to send curl based notifications (pushover, pushbullet, slack,
-# telegram) via a proxy, set these to your proxy address:
+# discord, telegram) via a proxy, set these to your proxy address:
#export http_proxy="http://10.0.0.1:3128/"
#export https_proxy="http://10.0.0.1:3128/"
@@ -62,6 +63,7 @@ curl=""
# - pushover user tokens
# - telegram chat ids
# - slack channels
+# - discord channels
# - hipchat rooms
# - sms phone numbers
# - pagerduty.com (pd) services
@@ -75,6 +77,7 @@ curl=""
# pushover : "2987343...9437837 8756278...2362736|critical"
# telegram : "111827421 112746832|critical"
# slack : "alarms disasters|critical"
+# discord : "alarms disasters|critical"
# twilio : "+15555555555 +17777777777|critical"
# messagebird: "+15555555555 +17777777777|critical"
# pd : "<pd_service_key_1> <pd_service_key_2>|critical"
@@ -228,6 +231,25 @@ DEFAULT_RECIPIENT_SLACK=""
#------------------------------------------------------------------------------
+# discord (discordapp.com) global notification options
+
+# multiple recipients can be given like this:
+# "CHANNEL1 CHANNEL2 ..."
+
+# enable/disable sending discord notifications
+SEND_DISCORD="YES"
+
+# Create a webhook by following the official documentation -
+# https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks
+DISCORD_WEBHOOK_URL=""
+
+# if a role's recipients are not configured, a notification will be send to
+# this discord channel (empty = do not send a notification for unconfigured
+# roles):
+DEFAULT_RECIPIENT_DISCORD=""
+
+
+#------------------------------------------------------------------------------
# hipchat global notification options
# multiple recipients can be given like this:
@@ -236,6 +258,9 @@ DEFAULT_RECIPIENT_SLACK=""
# enable/disable sending hipchat notifications
SEND_HIPCHAT="YES"
+# define hipchat server
+HIPCHAT_SERVER="api.hipchat.com"
+
# api.hipchat.com authorization token
# Without this, netdata cannot send hipchat notifications.
HIPCHAT_AUTH_TOKEN=""
@@ -295,6 +320,8 @@ role_recipients_telegram[sysadmin]="${DEFAULT_RECIPIENT_TELEGRAM}"
role_recipients_slack[sysadmin]="${DEFAULT_RECIPIENT_SLACK}"
+role_recipients_discord[sysadmin]="${DEFAULT_RECIPIENT_DISCORD}"
+
role_recipients_hipchat[sysadmin]="${DEFAULT_RECIPIENT_HIPCHAT}"
role_recipients_twilio[sysadmin]="${DEFAULT_RECIPIENT_TWILIO}"
@@ -316,6 +343,8 @@ role_recipients_telegram[domainadmin]="${DEFAULT_RECIPIENT_TELEGRAM}"
role_recipients_slack[domainadmin]="${DEFAULT_RECIPIENT_SLACK}"
+role_recipients_discord[domainadmin]="${DEFAULT_RECIPIENT_DISCORD}"
+
role_recipients_hipchat[domainadmin]="${DEFAULT_RECIPIENT_HIPCHAT}"
role_recipients_twilio[domainadmin]="${DEFAULT_RECIPIENT_TWILIO}"
@@ -338,6 +367,8 @@ role_recipients_telegram[dba]="${DEFAULT_RECIPIENT_TELEGRAM}"
role_recipients_slack[dba]="${DEFAULT_RECIPIENT_SLACK}"
+role_recipients_discord[dba]="${DEFAULT_RECIPIENT_DISCORD}"
+
role_recipients_hipchat[dba]="${DEFAULT_RECIPIENT_HIPCHAT}"
role_recipients_twilio[dba]="${DEFAULT_RECIPIENT_TWILIO}"
@@ -360,6 +391,8 @@ role_recipients_telegram[webmaster]="${DEFAULT_RECIPIENT_TELEGRAM}"
role_recipients_slack[webmaster]="${DEFAULT_RECIPIENT_SLACK}"
+role_recipients_discord[webmaster]="${DEFAULT_RECIPIENT_DISCORD}"
+
role_recipients_hipchat[webmaster]="${DEFAULT_RECIPIENT_HIPCHAT}"
role_recipients_twilio[webmaster]="${DEFAULT_RECIPIENT_TWILIO}"
@@ -382,6 +415,8 @@ role_recipients_telegram[proxyadmin]="${DEFAULT_RECIPIENT_TELEGRAM}"
role_recipients_slack[proxyadmin]="${DEFAULT_RECIPIENT_SLACK}"
+role_recipients_discord[proxyadmin]="${DEFAULT_RECIPIENT_DISCORD}"
+
role_recipients_hipchat[proxyadmin]="${DEFAULT_RECIPIENT_HIPCHAT}"
role_recipients_twilio[proxyadmin]="${DEFAULT_RECIPIENT_TWILIO}"
diff --git a/conf.d/node.d/snmp.conf.md b/conf.d/node.d/snmp.conf.md
index bae5bf207..6b496f7a8 100644
--- a/conf.d/node.d/snmp.conf.md
+++ b/conf.d/node.d/snmp.conf.md
@@ -1,341 +1,359 @@
-# SNMP Data Collector
-
-Using this collector, netdata can collect data from any SNMP device.
-
-This collector supports:
-
-- any number of SNMP devices
-- each SNMP device can be used to collect data for any number of charts
-- each chart may have any number of dimensions
-- each SNMP device may have a different update frequency
-- each SNMP device will accept one or more batches to report values (you can set `max_request_size` per SNMP server, to control the size of batches).
-
-The source code of the plugin is [here](https://github.com/firehol/netdata/blob/master/node.d/snmp.node.js).
-
-## Configuration
-
-You will need to create the file `/etc/netdata/node.d/snmp.conf` with data like the following.
-
-In this example:
-
- - the SNMP device is `10.11.12.8`.
- - the SNMP community is `public`.
- - we will update the values every 10 seconds (`update_every: 10` under the server `10.11.12.8`).
- - we define 2 charts `snmp_switch.bandwidth_port1` and `snmp_switch.bandwidth_port2`, each having 2 dimensions: `in` and `out`.
-
-```js
-{
- "enable_autodetect": false,
- "update_every": 5,
- "max_request_size": 100,
- "servers": [
- {
- "hostname": "10.11.12.8",
- "community": "public",
- "update_every": 10,
- "max_request_size": 50,
- "options": { "timeout": 10000 },
- "charts": {
- "snmp_switch.bandwidth_port1": {
- "title": "Switch Bandwidth for port 1",
- "units": "kilobits/s",
- "type": "area",
- "priority": 1,
- "family": "ports",
- "dimensions": {
- "in": {
- "oid": "1.3.6.1.2.1.2.2.1.10.1",
- "algorithm": "incremental",
- "multiplier": 8,
- "divisor": 1024
- },
- "out": {
- "oid": "1.3.6.1.2.1.2.2.1.16.1",
- "algorithm": "incremental",
- "multiplier": -8,
- "divisor": 1024
- }
- }
- },
- "snmp_switch.bandwidth_port2": {
- "title": "Switch Bandwidth for port 2",
- "units": "kilobits/s",
- "type": "area",
- "priority": 1,
- "family": "ports",
- "dimensions": {
- "in": {
- "oid": "1.3.6.1.2.1.2.2.1.10.2",
- "algorithm": "incremental",
- "multiplier": 8,
- "divisor": 1024
- },
- "out": {
- "oid": "1.3.6.1.2.1.2.2.1.16.2",
- "algorithm": "incremental",
- "multiplier": -8,
- "divisor": 1024
- }
- }
- }
- }
- }
- ]
-}
-```
-
-`update_every` is the update frequency for each server, in seconds.
-
-`max_request_size` limits the maximum number of OIDs that will be requested in a single call. The default is 50. Lower this number of you get `TooBig` errors in netdata error.log.
-
-`family` sets the name of the submenu of the dashboard each chart will appear under.
-
-If you need to define many charts using incremental OIDs, you can use something like this:
-
-This is like the previous, but the option `multiply_range` given, will multiply the current chart from `1` to `24` inclusive, producing 24 charts in total for the 24 ports of the switch `10.11.12.8`.
-
-Each of the 24 new charts will have its id (1-24) appended at:
-
-1. its chart unique id, i.e. `snmp_switch.bandwidth_port1` to `snmp_switch.bandwidth_port24`
-2. its `title`, i.e. `Switch Bandwidth for port 1` to `Switch Bandwidth for port 24`
-3. its `oid` (for all dimensions), i.e. dimension `in` will be `1.3.6.1.2.1.2.2.1.10.1` to `1.3.6.1.2.1.2.2.1.10.24`
-3. its priority (which will be incremented for each chart so that the charts will appear on the dashboard in this order)
-
-```js
-{
- "enable_autodetect": false,
- "update_every": 10,
- "servers": [
- {
- "hostname": "10.11.12.8",
- "community": "public",
- "update_every": 10,
- "options": { "timeout": 20000 },
- "charts": {
- "snmp_switch.bandwidth_port": {
- "title": "Switch Bandwidth for port ",
- "units": "kilobits/s",
- "type": "area",
- "priority": 1,
- "family": "ports",
- "multiply_range": [ 1, 24 ],
- "dimensions": {
- "in": {
- "oid": "1.3.6.1.2.1.2.2.1.10.",
- "algorithm": "incremental",
- "multiplier": 8,
- "divisor": 1024
- },
- "out": {
- "oid": "1.3.6.1.2.1.2.2.1.16.",
- "algorithm": "incremental",
- "multiplier": -8,
- "divisor": 1024
- }
- }
- }
- }
- }
- ]
-}
-```
-
-The `options` given for each server, are:
-
- - `timeout`, the time to wait for the SNMP device to respond. The default is 5000 ms.
- - `version`, the SNMP version to use. `0` is Version 1, `1` is Version 2c. The default is Version 1 (`0`).
- - `transport`, the default is `udp4`.
- - `port`, the port of the SNMP device to connect to. The default is `161`.
- - `retries`, the number of attempts to make to fetch the data. The default is `1`.
-
-## Retreiving names from snmp
-
-You can append a value retrieved from SNMP to the title, by adding `titleoid` to the chart.
-
-You can set a dimension name to a value retrieved from SNMP, by adding `oidname` to the dimension.
-
-Both of the above will participate in `multiply_range`.
-
-
-## Testing the configuration
-
-To test it, you can run:
-
-```sh
-/usr/libexec/netdata/plugins.d/node.d.plugin 1 snmp
-```
-
-The above will run it on your console and you will be able to see what netdata sees, but also errors. You can get a very detailed output by appending `debug` to the command line.
-
-If it works, restart netdata to activate the snmp collector and refresh the dashboard (if your SNMP device responds with a delay, you may need to refresh the dashboard in a few seconds).
-
-## Data collection speed
-
-Keep in mind that many SNMP switches are routers are very slow. They may not be able to report values per second. If you run `node.d.plugin` in `debug` mode, it will report the time it took for the SNMP device to respond. My switch, for example, needs 7-8 seconds to respond for the traffic on 24 ports (48 OIDs, in/out).
-
-Also, if you use many SNMP clients on the same SNMP device at the same time, values may be skipped. This is a problem of the SNMP device, not this collector.
-
-## Finding OIDs
-
-Use `snmpwalk`, like this:
-
-```sh
-snmpwalk -t 20 -v 1 -O fn -c public 10.11.12.8
-```
-
-- `-t 20` is the timeout in seconds
-- `-v 1` is the SNMP version
-- `-O fn` will display full OIDs in numeric format (you may want to run it also without this option to see human readable output of OIDs)
-- `-c public` is the SNMP community
-- `10.11.12.8` is the SNMP device
-
-Keep in mind that `snmpwalk` outputs the OIDs with a dot in front them. You should remove this dot when adding OIDs to the configuration file of this collector.
-
-## Example: Linksys SRW2024P
-
-This is what I use for my Linksys SRW2024P. It creates:
-
-1. A chart for power consumption (it is a PoE switch)
-2. Two charts for packets received (total packets received and packets received with errors)
-3. One chart for packets output
-4. 24 charts, one for each port of the switch. It also appends the port names, as defined at the switch, to the chart titles.
-
-This switch also reports various other metrics, like snmp, packets per port, etc. Unfortunately it does not report CPU utilization or backplane utilization.
-
-This switch has a very slow SNMP processors. To respond, it needs about 8 seconds, so I have set the refresh frequency (`update_every`) to 15 seconds.
-
-```js
-{
- "enable_autodetect": false,
- "update_every": 5,
- "servers": [
- {
- "hostname": "10.11.12.8",
- "community": "public",
- "update_every": 15,
- "options": { "timeout": 20000, "version": 1 },
- "charts": {
- "snmp_switch.power": {
- "title": "Switch Power Supply",
- "units": "watts",
- "type": "line",
- "priority": 10,
- "family": "power",
- "dimensions": {
- "supply": {
- "oid": ".1.3.6.1.2.1.105.1.3.1.1.2.1",
- "algorithm": "absolute",
- "multiplier": 1,
- "divisor": 1
- },
- "used": {
- "oid": ".1.3.6.1.2.1.105.1.3.1.1.4.1",
- "algorithm": "absolute",
- "multiplier": 1,
- "divisor": 1
- }
- }
- }
- , "snmp_switch.input": {
- "title": "Switch Packets Input",
- "units": "packets/s",
- "type": "area",
- "priority": 20,
- "family": "IP",
- "dimensions": {
- "receives": {
- "oid": ".1.3.6.1.2.1.4.3.0",
- "algorithm": "incremental",
- "multiplier": 1,
- "divisor": 1
- }
- , "discards": {
- "oid": ".1.3.6.1.2.1.4.8.0",
- "algorithm": "incremental",
- "multiplier": 1,
- "divisor": 1
- }
- }
- }
- , "snmp_switch.input_errors": {
- "title": "Switch Received Packets with Errors",
- "units": "packets/s",
- "type": "line",
- "priority": 30,
- "family": "IP",
- "dimensions": {
- "bad_header": {
- "oid": ".1.3.6.1.2.1.4.4.0",
- "algorithm": "incremental",
- "multiplier": 1,
- "divisor": 1
- }
- , "bad_address": {
- "oid": ".1.3.6.1.2.1.4.5.0",
- "algorithm": "incremental",
- "multiplier": 1,
- "divisor": 1
- }
- , "unknown_protocol": {
- "oid": ".1.3.6.1.2.1.4.7.0",
- "algorithm": "incremental",
- "multiplier": 1,
- "divisor": 1
- }
- }
- }
- , "snmp_switch.output": {
- "title": "Switch Output Packets",
- "units": "packets/s",
- "type": "line",
- "priority": 40,
- "family": "IP",
- "dimensions": {
- "requests": {
- "oid": ".1.3.6.1.2.1.4.10.0",
- "algorithm": "incremental",
- "multiplier": 1,
- "divisor": 1
- }
- , "discards": {
- "oid": ".1.3.6.1.2.1.4.11.0",
- "algorithm": "incremental",
- "multiplier": -1,
- "divisor": 1
- }
- , "no_route": {
- "oid": ".1.3.6.1.2.1.4.12.0",
- "algorithm": "incremental",
- "multiplier": -1,
- "divisor": 1
- }
- }
- }
- , "snmp_switch.bandwidth_port": {
- "title": "Switch Bandwidth for port ",
- "titleoid": ".1.3.6.1.2.1.31.1.1.1.18.",
- "units": "kilobits/s",
- "type": "area",
- "priority": 100,
- "family": "ports",
- "multiply_range": [ 1, 24 ],
- "dimensions": {
- "in": {
- "oid": ".1.3.6.1.2.1.2.2.1.10.",
- "algorithm": "incremental",
- "multiplier": 8,
- "divisor": 1024
- }
- , "out": {
- "oid": ".1.3.6.1.2.1.2.2.1.16.",
- "algorithm": "incremental",
- "multiplier": -8,
- "divisor": 1024
- }
- }
- }
- }
- }
- ]
-}
-```
+# SNMP Data Collector
+
+Using this collector, netdata can collect data from any SNMP device.
+
+This collector supports:
+
+- any number of SNMP devices
+- each SNMP device can be used to collect data for any number of charts
+- each chart may have any number of dimensions
+- each SNMP device may have a different update frequency
+- each SNMP device will accept one or more batches to report values (you can set `max_request_size` per SNMP server, to control the size of batches).
+
+The source code of the plugin is [here](https://github.com/firehol/netdata/blob/master/node.d/snmp.node.js).
+
+## Configuration
+
+You will need to create the file `/etc/netdata/node.d/snmp.conf` with data like the following.
+
+In this example:
+
+ - the SNMP device is `10.11.12.8`.
+ - the SNMP community is `public`.
+ - we will update the values every 10 seconds (`update_every: 10` under the server `10.11.12.8`).
+ - we define 2 charts `snmp_switch.bandwidth_port1` and `snmp_switch.bandwidth_port2`, each having 2 dimensions: `in` and `out`.
+
+```js
+{
+ "enable_autodetect": false,
+ "update_every": 5,
+ "max_request_size": 100,
+ "servers": [
+ {
+ "hostname": "10.11.12.8",
+ "community": "public",
+ "update_every": 10,
+ "max_request_size": 50,
+ "options": { "timeout": 10000 },
+ "charts": {
+ "snmp_switch.bandwidth_port1": {
+ "title": "Switch Bandwidth for port 1",
+ "units": "kilobits/s",
+ "type": "area",
+ "priority": 1,
+ "family": "ports",
+ "dimensions": {
+ "in": {
+ "oid": "1.3.6.1.2.1.2.2.1.10.1",
+ "algorithm": "incremental",
+ "multiplier": 8,
+ "divisor": 1024,
+ "offset": 0
+ },
+ "out": {
+ "oid": "1.3.6.1.2.1.2.2.1.16.1",
+ "algorithm": "incremental",
+ "multiplier": -8,
+ "divisor": 1024,
+ "offset": 0
+ }
+ }
+ },
+ "snmp_switch.bandwidth_port2": {
+ "title": "Switch Bandwidth for port 2",
+ "units": "kilobits/s",
+ "type": "area",
+ "priority": 1,
+ "family": "ports",
+ "dimensions": {
+ "in": {
+ "oid": "1.3.6.1.2.1.2.2.1.10.2",
+ "algorithm": "incremental",
+ "multiplier": 8,
+ "divisor": 1024,
+ "offset": 0
+ },
+ "out": {
+ "oid": "1.3.6.1.2.1.2.2.1.16.2",
+ "algorithm": "incremental",
+ "multiplier": -8,
+ "divisor": 1024,
+ "offset": 0
+ }
+ }
+ }
+ }
+ }
+ ]
+}
+```
+
+`update_every` is the update frequency for each server, in seconds.
+
+`max_request_size` limits the maximum number of OIDs that will be requested in a single call. The default is 50. Lower this number of you get `TooBig` errors in netdata error.log.
+
+`family` sets the name of the submenu of the dashboard each chart will appear under.
+
+If you need to define many charts using incremental OIDs, you can use something like this:
+
+This is like the previous, but the option `multiply_range` given, will multiply the current chart from `1` to `24` inclusive, producing 24 charts in total for the 24 ports of the switch `10.11.12.8`.
+
+Each of the 24 new charts will have its id (1-24) appended at:
+
+1. its chart unique id, i.e. `snmp_switch.bandwidth_port1` to `snmp_switch.bandwidth_port24`
+2. its `title`, i.e. `Switch Bandwidth for port 1` to `Switch Bandwidth for port 24`
+3. its `oid` (for all dimensions), i.e. dimension `in` will be `1.3.6.1.2.1.2.2.1.10.1` to `1.3.6.1.2.1.2.2.1.10.24`
+3. its priority (which will be incremented for each chart so that the charts will appear on the dashboard in this order)
+
+```js
+{
+ "enable_autodetect": false,
+ "update_every": 10,
+ "servers": [
+ {
+ "hostname": "10.11.12.8",
+ "community": "public",
+ "update_every": 10,
+ "options": { "timeout": 20000 },
+ "charts": {
+ "snmp_switch.bandwidth_port": {
+ "title": "Switch Bandwidth for port ",
+ "units": "kilobits/s",
+ "type": "area",
+ "priority": 1,
+ "family": "ports",
+ "multiply_range": [ 1, 24 ],
+ "dimensions": {
+ "in": {
+ "oid": "1.3.6.1.2.1.2.2.1.10.",
+ "algorithm": "incremental",
+ "multiplier": 8,
+ "divisor": 1024,
+ "offset": 0
+ },
+ "out": {
+ "oid": "1.3.6.1.2.1.2.2.1.16.",
+ "algorithm": "incremental",
+ "multiplier": -8,
+ "divisor": 1024,
+ "offset": 0
+ }
+ }
+ }
+ }
+ }
+ ]
+}
+```
+
+The `options` given for each server, are:
+
+ - `timeout`, the time to wait for the SNMP device to respond. The default is 5000 ms.
+ - `version`, the SNMP version to use. `0` is Version 1, `1` is Version 2c. The default is Version 1 (`0`).
+ - `transport`, the default is `udp4`.
+ - `port`, the port of the SNMP device to connect to. The default is `161`.
+ - `retries`, the number of attempts to make to fetch the data. The default is `1`.
+
+## Retreiving names from snmp
+
+You can append a value retrieved from SNMP to the title, by adding `titleoid` to the chart.
+
+You can set a dimension name to a value retrieved from SNMP, by adding `oidname` to the dimension.
+
+Both of the above will participate in `multiply_range`.
+
+
+## Testing the configuration
+
+To test it, you can run:
+
+```sh
+/usr/libexec/netdata/plugins.d/node.d.plugin 1 snmp
+```
+
+The above will run it on your console and you will be able to see what netdata sees, but also errors. You can get a very detailed output by appending `debug` to the command line.
+
+If it works, restart netdata to activate the snmp collector and refresh the dashboard (if your SNMP device responds with a delay, you may need to refresh the dashboard in a few seconds).
+
+## Data collection speed
+
+Keep in mind that many SNMP switches are routers are very slow. They may not be able to report values per second. If you run `node.d.plugin` in `debug` mode, it will report the time it took for the SNMP device to respond. My switch, for example, needs 7-8 seconds to respond for the traffic on 24 ports (48 OIDs, in/out).
+
+Also, if you use many SNMP clients on the same SNMP device at the same time, values may be skipped. This is a problem of the SNMP device, not this collector.
+
+## Finding OIDs
+
+Use `snmpwalk`, like this:
+
+```sh
+snmpwalk -t 20 -v 1 -O fn -c public 10.11.12.8
+```
+
+- `-t 20` is the timeout in seconds
+- `-v 1` is the SNMP version
+- `-O fn` will display full OIDs in numeric format (you may want to run it also without this option to see human readable output of OIDs)
+- `-c public` is the SNMP community
+- `10.11.12.8` is the SNMP device
+
+Keep in mind that `snmpwalk` outputs the OIDs with a dot in front them. You should remove this dot when adding OIDs to the configuration file of this collector.
+
+## Example: Linksys SRW2024P
+
+This is what I use for my Linksys SRW2024P. It creates:
+
+1. A chart for power consumption (it is a PoE switch)
+2. Two charts for packets received (total packets received and packets received with errors)
+3. One chart for packets output
+4. 24 charts, one for each port of the switch. It also appends the port names, as defined at the switch, to the chart titles.
+
+This switch also reports various other metrics, like snmp, packets per port, etc. Unfortunately it does not report CPU utilization or backplane utilization.
+
+This switch has a very slow SNMP processors. To respond, it needs about 8 seconds, so I have set the refresh frequency (`update_every`) to 15 seconds.
+
+```js
+{
+ "enable_autodetect": false,
+ "update_every": 5,
+ "servers": [
+ {
+ "hostname": "10.11.12.8",
+ "community": "public",
+ "update_every": 15,
+ "options": { "timeout": 20000, "version": 1 },
+ "charts": {
+ "snmp_switch.power": {
+ "title": "Switch Power Supply",
+ "units": "watts",
+ "type": "line",
+ "priority": 10,
+ "family": "power",
+ "dimensions": {
+ "supply": {
+ "oid": ".1.3.6.1.2.1.105.1.3.1.1.2.1",
+ "algorithm": "absolute",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ },
+ "used": {
+ "oid": ".1.3.6.1.2.1.105.1.3.1.1.4.1",
+ "algorithm": "absolute",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ }
+ }
+ , "snmp_switch.input": {
+ "title": "Switch Packets Input",
+ "units": "packets/s",
+ "type": "area",
+ "priority": 20,
+ "family": "IP",
+ "dimensions": {
+ "receives": {
+ "oid": ".1.3.6.1.2.1.4.3.0",
+ "algorithm": "incremental",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ , "discards": {
+ "oid": ".1.3.6.1.2.1.4.8.0",
+ "algorithm": "incremental",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ }
+ }
+ , "snmp_switch.input_errors": {
+ "title": "Switch Received Packets with Errors",
+ "units": "packets/s",
+ "type": "line",
+ "priority": 30,
+ "family": "IP",
+ "dimensions": {
+ "bad_header": {
+ "oid": ".1.3.6.1.2.1.4.4.0",
+ "algorithm": "incremental",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ , "bad_address": {
+ "oid": ".1.3.6.1.2.1.4.5.0",
+ "algorithm": "incremental",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ , "unknown_protocol": {
+ "oid": ".1.3.6.1.2.1.4.7.0",
+ "algorithm": "incremental",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ }
+ }
+ , "snmp_switch.output": {
+ "title": "Switch Output Packets",
+ "units": "packets/s",
+ "type": "line",
+ "priority": 40,
+ "family": "IP",
+ "dimensions": {
+ "requests": {
+ "oid": ".1.3.6.1.2.1.4.10.0",
+ "algorithm": "incremental",
+ "multiplier": 1,
+ "divisor": 1,
+ "offset": 0
+ }
+ , "discards": {
+ "oid": ".1.3.6.1.2.1.4.11.0",
+ "algorithm": "incremental",
+ "multiplier": -1,
+ "divisor": 1,
+ "offset": 0
+ }
+ , "no_route": {
+ "oid": ".1.3.6.1.2.1.4.12.0",
+ "algorithm": "incremental",
+ "multiplier": -1,
+ "divisor": 1,
+ "offset": 0
+ }
+ }
+ }
+ , "snmp_switch.bandwidth_port": {
+ "title": "Switch Bandwidth for port ",
+ "titleoid": ".1.3.6.1.2.1.31.1.1.1.18.",
+ "units": "kilobits/s",
+ "type": "area",
+ "priority": 100,
+ "family": "ports",
+ "multiply_range": [ 1, 24 ],
+ "dimensions": {
+ "in": {
+ "oid": ".1.3.6.1.2.1.2.2.1.10.",
+ "algorithm": "incremental",
+ "multiplier": 8,
+ "divisor": 1024,
+ "offset": 0
+ }
+ , "out": {
+ "oid": ".1.3.6.1.2.1.2.2.1.16.",
+ "algorithm": "incremental",
+ "multiplier": -8,
+ "divisor": 1024,
+ "offset": 0
+ }
+ }
+ }
+ }
+ }
+ ]
+}
+```
diff --git a/conf.d/python.d.conf b/conf.d/python.d.conf
index 7e4fa801f..9ed346cdc 100644
--- a/conf.d/python.d.conf
+++ b/conf.d/python.d.conf
@@ -18,28 +18,53 @@ log_interval: 3600
# ----------------------------------------------------------------------
# Enable / Disable python.d.plugin modules
+#default_run: yes
#
-# The default for all modules is enabled (yes).
-# Setting any of these to no will disable it.
+# If "default_run" = "yes" the default for all modules is enabled (yes).
+# Setting any of these to "no" will disable it.
+#
+# If "default_run" = "no" the default for all modules is disabled (no).
+# Setting any of these to "yes" will enable it.
-# apache: yes
# apache_cache: yes
+# apache: yes
+# bind_rndc: yes
# cpufreq: yes
+# cpuidle: yes
# dovecot: yes
+# elasticsearch: yes
+
+# this is just an example
example: no
+
# exim: yes
+# fail2ban: yes
+# freeradius: yes
+
+# gunicorn_log has been replaced by web_log
+gunicorn_log: no
+
+# haproxy: yes
# hddtemp: yes
# ipfs: yes
# isc_dhcpd: yes
+# mdstat: yes
# memcached: yes
# mysql: yes
# nginx: yes
-# nginx_log: yes
+
+# nginx_log has been replaced by web_log
+nginx_log: no
+
+# ovpn_status_log: yes
# phpfpm: yes
# postfix: yes
+# postgres: yes
# redis: yes
+# retroshare: yes
# sensors: yes
+# smartd_log: yes
# squid: yes
# tomcat: yes
-# freeradius: yes
-# ovpn_status_log: yes
+# varnish: yes
+# web_log: yes
diff --git a/conf.d/python.d/elasticsearch.conf b/conf.d/python.d/elasticsearch.conf
index 1faee8582..f98aaeced 100644
--- a/conf.d/python.d/elasticsearch.conf
+++ b/conf.d/python.d/elasticsearch.conf
@@ -62,6 +62,13 @@
# cluster_stats: False/True # Calls to cluster stats elasticsearch API. Enabled by default.
#
# ----------------------------------------------------------------------
+# IMPORTANT Information
+#
+# Module uses python `requests` package
+#
+# You need to install it manually. (python-requests or python3-requests depending on the version of python).
+#
+#
# AUTO-DETECTION JOBS
# only one of them will run (they have the same name)
#
diff --git a/conf.d/python.d/fail2ban.conf b/conf.d/python.d/fail2ban.conf
index cd805be8d..d9664e353 100644
--- a/conf.d/python.d/fail2ban.conf
+++ b/conf.d/python.d/fail2ban.conf
@@ -56,22 +56,17 @@
#
# Additionally to the above, fail2ban also supports the following:
#
-# log_path: 'path to fail2ban.log' # Default: '/var/log/fail2ban.log'
+# log_path: 'path to fail2ban.log' # Default: '/var/log/fail2ban.log'
# conf_path: 'path to jail.local/jail.conf' # Default: '/etc/fail2ban/jail.local'
-# exclude: 'jails you want to exclude from autodetection' # Default: '[]' empty list
+# conf_dir: 'path to jail.d/' # Default: '' empty
+# exclude: 'jails you want to exclude from autodetection' # Default: '[]' empty list
#------------------------------------------------------------------------------------------------------------------
-# IMPORTANT Information
-#
-# fail2ban.log file MUST BE readable by netdata.
-# A good idea is to do this by adding the
-# # create 0640 root netdata
-# to fail2ban conf at logrotate.d
-#
# ------------------------------------------------------------------------------------------------------------------
# AUTO-DETECTION JOBS
# only one of them will run (they have the same name)
-#local:
-# log_path: '/var/log/fail2ban.log'
-# conf_path: '/etc/fail2ban/jail.local'
+local:
+ log_path: '/var/log/fail2ban.log'
+ conf_path: '/etc/fail2ban/jail.local'
+# conf_dir: '/etc/fail2ban/jail.d/'
# exclude: 'dropbear apache'
diff --git a/conf.d/python.d/gunicorn_log.conf b/conf.d/python.d/mongodb.conf
index 8fea483f0..a19b6570b 100644
--- a/conf.d/python.d/gunicorn_log.conf
+++ b/conf.d/python.d/mongodb.conf
@@ -1,4 +1,4 @@
-# netdata python.d.plugin configuration for nginx gunicorn log
+# netdata python.d.plugin configuration for mongodb
#
# This file is in YaML format. Generally the format is:
#
@@ -54,20 +54,24 @@
# priority: 60000 # the JOB's order on the dashboard
# retries: 5 # the JOB's number of restoration attempts
#
-# Additionally to the above, gunicorn_log also supports the following:
+# Additionally to the above, mongodb also supports the following:
#
-# path: 'PATH' # the path to gunicorn's access.log
+# host: 'IP or HOSTNAME' # type <str> the host to connect to
+# port: PORT # type <int> the port to connect to
+#
+# in all cases, the following can also be set:
+#
+# user: 'username' # the mongodb username to use
+# pass: 'password' # the mongodb password to use
#
# ----------------------------------------------------------------------
+# to connect to the mongodb on localhost, without a password:
+# ----------------------------------------------------------------------
# AUTO-DETECTION JOBS
# only one of them will run (they have the same name)
-gunicorn_log:
- name: 'local'
- path: '/var/log/gunicorn/access.log'
-
-gunicorn_log2:
- name: 'local'
- path: '/var/log/gunicorn/gunicorn-access.log'
-
+local:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 27017
diff --git a/conf.d/python.d/nginx_log.conf b/conf.d/python.d/nsd.conf
index 6a53c5204..7566fe85e 100644
--- a/conf.d/python.d/nginx_log.conf
+++ b/conf.d/python.d/nsd.conf
@@ -1,4 +1,4 @@
-# netdata python.d.plugin configuration for nginx log
+# netdata python.d.plugin configuration for nsd
#
# This file is in YaML format. Generally the format is:
#
@@ -20,7 +20,8 @@
# update_every sets the default data collection frequency.
# If unset, the python.d.plugin default is used.
-# update_every: 1
+# nsd-control is slow, so once every 30 seconds
+# update_every: 30
# priority controls the order of charts at the netdata dashboard.
# Lower numbers move the charts towards the top of the page.
@@ -54,19 +55,32 @@
# priority: 60000 # the JOB's order on the dashboard
# retries: 5 # the JOB's number of restoration attempts
#
-# Additionally to the above, nginx_log also supports the following:
+# Additionally to the above, nsd also supports the following:
#
-# path: 'PATH' # the path to nginx's access.log
+# command: 'nsd-control stats_noreset' # the command to run
#
# ----------------------------------------------------------------------
-# AUTO-DETECTION JOBS
-# only one of them will run (they have the same name)
+# IMPORTANT Information
+#
+# Netdata must have permissions to run `nsd-control stats_noreset` command
+#
+# - Example-1 (use "sudo")
+# 1. sudoers (e.g. visudo -f /etc/sudoers.d/netdata)
+# Defaults:netdata !requiretty
+# netdata ALL=(ALL) NOPASSWD: /usr/sbin/nsd-control stats_noreset
+# 2. etc/netdata/python.d/nsd.conf
+# local:
+# update_every: 30
+# command: 'sudo /usr/sbin/nsd-control stats_noreset'
+#
+# - Example-2 (add "netdata" user to "nsd" group)
+# usermod -aG nsd netdata
+#
-nginx_log:
- name: 'local'
- path: '/var/log/nginx/access.log'
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
-nginx_log2:
- name: 'local'
- path: '/var/log/nginx/nginx-access.log'
+local:
+ update_every: 30
+ command: 'nsd-control stats_noreset'
diff --git a/conf.d/python.d/smartd_log.conf b/conf.d/python.d/smartd_log.conf
new file mode 100644
index 000000000..e16454dfb
--- /dev/null
+++ b/conf.d/python.d/smartd_log.conf
@@ -0,0 +1,85 @@
+# netdata python.d.plugin configuration for smartd log
+#
+# This file is in YaML format. Generally the format is:
+#
+# name: value
+#
+# There are 2 sections:
+# - global variables
+# - one or more JOBS
+#
+# JOBS allow you to collect values from multiple sources.
+# Each source will have its own set of charts.
+#
+# JOB parameters have to be indented (using spaces only, example below).
+
+# ----------------------------------------------------------------------
+# Global Variables
+# These variables set the defaults for all JOBs, however each JOB
+# may define its own, overriding the defaults.
+
+# update_every sets the default data collection frequency.
+# If unset, the python.d.plugin default is used.
+# update_every: 1
+
+# priority controls the order of charts at the netdata dashboard.
+# Lower numbers move the charts towards the top of the page.
+# If unset, the default for python.d.plugin is used.
+# priority: 60000
+
+# retries sets the number of retries to be made in case of failures.
+# If unset, the default for python.d.plugin is used.
+# Attempts to restore the service are made once every update_every
+# and only if the module has collected values in the past.
+# retries: 5
+
+# ----------------------------------------------------------------------
+# JOBS (data collection sources)
+#
+# The default JOBS share the same *name*. JOBS with the same name
+# are mutually exclusive. Only one of them will be allowed running at
+# any time. This allows autodetection to try several alternatives and
+# pick the one that works.
+#
+# Any number of jobs is supported.
+#
+# All python.d.plugin JOBS (for all its modules) support a set of
+# predefined parameters. These are:
+#
+# job_name:
+# name: myname # the JOB's name as it will appear at the
+# # dashboard (by default is the job_name)
+# # JOBs sharing a name are mutually exclusive
+# update_every: 1 # the JOB's data collection frequency
+# priority: 60000 # the JOB's order on the dashboard
+# retries: 5 # the JOB's number of restoration attempts
+#
+# Additionally to the above, smartd_log also supports the following:
+#
+# log_path: '/path/to/smartdlogs' # path to smartd log files. Default is /var/log/smartd
+# raw_values: no # raw or normalized values on charts. Default is normalized.
+# smart_attributes: '1 2 3 4 44' # add additional smart attributes charts. Default are ['1', '4', '5', '7', '9', '12', '193', '194', '197', '198', '200'].
+#
+# ----------------------------------------------------------------------
+# Additional information
+# Plugin reads smartd log files (-A option).
+# You need to add (man smartd) to /etc/default/smartmontools '-i 600 -A /var/log/smartd/' to pass additional options to smartd on startup
+# Then restart smartd service and check /path/log/smartdlogs
+# ls /var/log/smartd/
+# CDC_WD10EZEX_00BN5A0-WD_WCC3F7FLVZS9.ata.csv WDC_WD10EZEX_00BN5A0-WD_WCC3F7FLVZS9.ata.csv ZDC_WD10EZEX_00BN5A0-WD_WCC3F7FLVZS9.ata.csv
+#
+# Smartd APPEND logs at every run. Its NOT RECOMMENDED to set '-i' option below 60 sec.
+# STRONGLY RECOMMENDED to create smartd conf file for logrotate
+#
+# RAW vs NORMALIZED values
+# "Normalized value", commonly referred to as just "value". This is a most universal measurement, on the scale from 0 (bad) to some maximum (good) value.
+# Maximum values are typically 100, 200 or 253. Rule of thumb is: high values are good, low values are bad.
+#
+# "Raw value" - the value of the attribute as it is tracked by the device, before any normalization takes place.
+# Some raw numbers provide valuable insight when properly interpreted. These cases will be discussed later on.
+# Raw values are typically listed in hexadecimal numbers. The raw value has different structure for different vendors and is often not meaningful as a decimal number.
+#
+#
+# JOB configuration
+#
+log_path: '/var/log/smartd'
diff --git a/conf.d/python.d/varnish.conf b/conf.d/python.d/varnish.conf
index 56dc6334d..c25f3010f 100644
--- a/conf.d/python.d/varnish.conf
+++ b/conf.d/python.d/varnish.conf
@@ -55,11 +55,3 @@
# retries: 5 # the JOB's number of restoration attempts
#
#
-#
-# The only you need is to add netdata to 'varnish' group
-#
-# Check it from cmd
-# id netdata
-#
-# uid=999(netdata) gid=999(netdata) группы=999(netdata),118(varnish)
-#
diff --git a/conf.d/python.d/web_log.conf b/conf.d/python.d/web_log.conf
new file mode 100644
index 000000000..06656285f
--- /dev/null
+++ b/conf.d/python.d/web_log.conf
@@ -0,0 +1,147 @@
+# netdata python.d.plugin configuration for web log
+#
+# This file is in YaML format. Generally the format is:
+#
+# name: value
+#
+# There are 2 sections:
+# - global variables
+# - one or more JOBS
+#
+# JOBS allow you to collect values from multiple sources.
+# Each source will have its own set of charts.
+#
+# JOB parameters have to be indented (using spaces only, example below).
+
+# ----------------------------------------------------------------------
+# Global Variables
+# These variables set the defaults for all JOBs, however each JOB
+# may define its own, overriding the defaults.
+
+# update_every sets the default data collection frequency.
+# If unset, the python.d.plugin default is used.
+# update_every: 1
+
+# priority controls the order of charts at the netdata dashboard.
+# Lower numbers move the charts towards the top of the page.
+# If unset, the default for python.d.plugin is used.
+# priority: 60000
+
+# retries sets the number of retries to be made in case of failures.
+# If unset, the default for python.d.plugin is used.
+# Attempts to restore the service are made once every update_every
+# and only if the module has collected values in the past.
+# retries: 5
+
+# ----------------------------------------------------------------------
+# JOBS (data collection sources)
+#
+# The default JOBS share the same *name*. JOBS with the same name
+# are mutually exclusive. Only one of them will be allowed running at
+# any time. This allows autodetection to try several alternatives and
+# pick the one that works.
+#
+# Any number of jobs is supported.
+
+# ----------------------------------------------------------------------
+# PLUGIN CONFIGURATION
+#
+# All python.d.plugin JOBS (for all its modules) support a set of
+# predefined parameters. These are:
+#
+# job_name:
+# name: myname # the JOB's name as it will appear at the
+# # dashboard (by default is the job_name)
+# # JOBs sharing a name are mutually exclusive
+# update_every: 1 # the JOB's data collection frequency
+# priority: 60000 # the JOB's order on the dashboard
+# retries: 5 # the JOB's number of restoration attempts
+#
+# Additionally to the above, web_log also supports the following:
+#
+# path: 'PATH' # the path to web server log file
+# detailed_response_codes: yes/no # Default: yes. Additional chart where response codes are not grouped
+# detailed_response_aggregate: yes/no # Default: yes. Not aggregated detailed response codes charts
+# all_time : yes/no # Default: yes. All time unique client IPs chart (50000 addresses ~ 400KB)
+# categories: # requests per url chart configuration
+# cacti: 'cacti.*' # name(dimension): REGEX to match
+# observium: 'observium.*' # name(dimension): REGEX to match
+# stub_status: 'stub_status' # name(dimension): REGEX to match
+# custom_log_format: # define a custom log format
+# pattern: '(?P<address>[\da-f.:]+) -.*?"(?P<method>[A-Z]+) (?P<url>.*?)" (?P<code>[1-9]\d{2}) (?P<bytes_sent>\d+) (?P<resp_length>\d+) (?P<resp_time>\d\.\d+) '
+# time_multiplier: 1000000 # type <int> - convert time to microseconds
+
+# ----------------------------------------------------------------------
+# WEB SERVER CONFIGURATION
+#
+# Make sure the web server log directory and the web server log files
+# can be read by user 'netdata'.
+#
+# To enable the timings chart and the requests size dimension, the
+# web server needs to log them. This is how to add them:
+#
+# nginx:
+# log_format netdata '$remote_addr - $remote_user [$time_local] '
+# '"$request" $status $body_bytes_sent '
+# '$request_length $request_time '
+# '"$http_referer" "$http_user_agent"';
+# access_log /var/log/nginx/access.log netdata;
+#
+# apache (you need mod_logio enabled):
+# LogFormat "%h %l %u %t \"%r\" %>s %O %I %D \"%{Referer}i\" \"%{User-Agent}i\"" vhost_netdata
+# LogFormat "%h %l %u %t \"%r\" %>s %O %I %D \"%{Referer}i\" \"%{User-Agent}i\"" netdata
+# CustomLog "/var/log/apache2/access.log" netdata
+
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them per web server will run (when they have the same name)
+
+
+# -------------------------------------------
+# nginx log on various distros
+
+# debian, arch
+nginx_log:
+ name: 'nginx'
+ path: '/var/log/nginx/access.log'
+
+# gentoo
+nginx_log2:
+ name: 'nginx'
+ path: '/var/log/nginx/localhost.access_log'
+
+
+# -------------------------------------------
+# apache log on various distros
+
+# debian
+apache_log:
+ name: 'apache'
+ path: '/var/log/apache2/access.log'
+
+# gentoo
+apache_log2:
+ name: 'apache'
+ path: '/var/log/apache2/access_log'
+
+# arch
+apache_log3:
+ name: 'apache'
+ path: '/var/log/httpd/access_log'
+
+# debian
+apache_vhosts_log:
+ name: 'apache_vhosts'
+ path: '/var/log/apache2/other_vhosts_access.log'
+
+
+# -------------------------------------------
+# gunicorn log on various distros
+
+gunicorn_log:
+ name: 'gunicorn'
+ path: '/var/log/gunicorn/access.log'
+
+gunicorn_log2:
+ name: 'gunicorn'
+ path: '/var/log/gunicorn/gunicorn-access.log'
diff --git a/conf.d/stream.conf b/conf.d/stream.conf
new file mode 100644
index 000000000..0ebdccb8a
--- /dev/null
+++ b/conf.d/stream.conf
@@ -0,0 +1,143 @@
+# netdata configuration for aggregating data from remote hosts
+#
+# API keys authorize a pair of sending-receiving netdata servers.
+# Once their communication is authorized, they can exchange metrics for any
+# number of hosts.
+#
+# You can generate API keys, with the linux command: uuidgen
+#
+# -----------------------------------------------------------------------------
+# 1. ON SLAVE NETDATA - THE ONE THAT WILL BE SENDING METRICS
+
+[stream]
+ # Enable this on slaves, to have them send metrics.
+ enabled = no
+
+ # The destination to send metrics to.
+ # A space separated list of:
+ # [PROTOCOL:]HOST[%INTERFACE][:PORT]
+ # The first available will get the metrics.
+ # PROTOCOL = tcp or udp (only tcp is supported by masters)
+ # HOST = an IPv4, IPv6 IP, or a hostname.
+ # IPv6 IPs should be given with brackets [ip:address]
+ # INTERFACE = the network interface to use
+ # PORT = the port number or service name (/etc/services)
+ # This communication is not HTTP (cannot be proxied by web proxies).
+ destination =
+
+ # The API_KEY to use (as the sender)
+ api key =
+
+ # The timeout to connect and send metrics
+ timeout seconds = 60
+
+ # If the destination line above does specify a port, use this
+ default port = 19999
+
+ # The buffer to use for sending metrics.
+ # 1MB by default is good for 2-3 seconds of data, so increase this
+ # if you expect latencies.
+ buffer size bytes = 1048576
+
+ # If the connection fails, or it disconnects,
+ # retry after that many seconds.
+ reconnect delay seconds = 5
+
+ # Attempt to sync the clock the of the master with the clock of the
+ # slave for that many iterations, when starting.
+ initial clock resync iterations = 60
+
+
+# -----------------------------------------------------------------------------
+# 2. ON MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS
+#
+# You can have one API key per slave, or the same API key for all slaves.
+#
+# All options below are used in this order:
+#
+# a) MACHINE_GUID (settings for each machine)
+# b) API_KEY (settings for the API key)
+# c) this netdata defaults (as in netdata.conf)
+#
+# You can combine the above (the more specific setting will be used).
+
+# API key authentication
+# If the key is not listed here, it will not be able to connect.
+
+[API_KEY]
+ # Default settings for the API key
+
+ # You can disable the API key, by setting this to: no
+ # The default (for unknown API keys) is also: no
+ enabled = no
+
+ # The default history in entries, for all hosts using this API key.
+ # You can also set it per host below.
+ # If you don't set it here, the history size of the central netdata
+ # will be used
+ default history = 3600
+
+ # The default memory mode to be used for all hosts using this API key.
+ # You can also set it per host below.
+ # If you don't set it here, the memory mode of netdata.conf will be used.
+ # Valid modes:
+ # save save on exit, load on start
+ # map like swap (continuously syncing to disks)
+ # ram keep it in RAM, don't touch the disk
+ # none no database (passing through this netdata)
+ default memory mode = ram
+
+ # Shall we enable health monitoring for the hosts using this API key?
+ # 3 values:
+ # yes enable alarms
+ # no do not enable alarms
+ # auto enable alarms, only when the sending netdata is connected
+ # You can also set it per host, below.
+ # The default is the same as to netdata.conf
+ health enabled by default = auto
+
+ # postpone alarms for a short period after the sender is connected
+ default postpone alarms on connect seconds = 60
+
+ # need to route metrics differently? set these.
+ # the defaults are the ones at the [stream] section
+ #default proxy enabled = yes | no
+ #default proxy destination = IP:PORT IP:PORT ...
+ #default proxy api key = API_KEY
+
+
+# -----------------------------------------------------------------------------
+# 3. ON MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS
+#
+# THIS IS OPTIONAL - YOU DON'T NEED IT BY DEFAULT
+# It only exists to give you finer control of the master settings for each
+# slave host, when the same API key is used by many netdata slaves / proxies.
+#
+# Each netdata has a unique GUID - generated the first time netdata starts.
+# You can find it at /var/lib/netdata/registry/netdata.public.unique.id
+# The host sending data will have one. If the host is not ephemeral,
+# you can give settings for each specific host here.
+
+[MACHINE_GUID]
+ # enable this host: yes | no
+ # When disabled, the master will not receive metrics for this host.
+ # THIS IS NOT A SECURITY MECHANISM - AN ATTACKER CAN SET ANY OTHER GUID.
+ # Use only the API key for security.
+ enabled = no
+
+ # The number of entries in the database
+ history = 3600
+
+ # The memory mode of the database: save | map | ram | none
+ memory mode = save
+
+ # Health / alarms control: yes | no | auto
+ health enabled = yes
+
+ # postpone alarms when the sender connects
+ postpone alarms on connect seconds = 60
+
+ # need to route metrics differently?
+ #proxy enabled = yes | no
+ #proxy destination = IP:PORT IP:PORT ...
+ #proxy api key = API_KEY
diff --git a/config.guess b/config.guess
index a2eeec38e..d622a44e5 100755
--- a/config.guess
+++ b/config.guess
@@ -1,12 +1,14 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
-timestamp='2016-04-02'
+timestamp='2012-02-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -20,17 +22,19 @@ timestamp='2016-04-02'
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program. This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
#
-# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
#
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
-#
-# Please send patches to <config-patches@gnu.org>.
-
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
me=`echo "$0" | sed -e 's,.*/,,'`
@@ -50,7 +54,9 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -132,27 +138,6 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-case "${UNAME_SYSTEM}" in
-Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
-
- eval $set_cc_for_build
- cat <<-EOF > $dummy.c
- #include <features.h>
- #if defined(__UCLIBC__)
- LIBC=uclibc
- #elif defined(__dietlibc__)
- LIBC=dietlibc
- #else
- LIBC=gnu
- #endif
- EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
- ;;
-esac
-
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
@@ -168,27 +153,20 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
- /sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || \
- echo unknown)`
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
- earmv*)
- arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
- endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
- machine=${arch}${endian}-unknown
- ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
- arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
@@ -204,13 +182,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd
;;
esac
- # Determine ABI tags.
- case "${UNAME_MACHINE_ARCH}" in
- earm*)
- expr='s/^earmv[0-9]/-eabi/;s/eb$//'
- abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
- ;;
- esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
@@ -221,26 +192,18 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu'
;;
*)
- release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}${abi}"
- exit ;;
- *:Bitrig:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ echo "${machine}-${os}${release}"
exit ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;;
- *:LibertyBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
- exit ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
@@ -253,9 +216,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;;
- *:Sortix:*:*)
- echo ${UNAME_MACHINE}-unknown-sortix
- exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
@@ -272,42 +232,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
- UNAME_MACHINE=alpha ;;
+ UNAME_MACHINE="alpha" ;;
"EV4.5 (21064)")
- UNAME_MACHINE=alpha ;;
+ UNAME_MACHINE="alpha" ;;
"LCA4 (21066/21068)")
- UNAME_MACHINE=alpha ;;
+ UNAME_MACHINE="alpha" ;;
"EV5 (21164)")
- UNAME_MACHINE=alphaev5 ;;
+ UNAME_MACHINE="alphaev5" ;;
"EV5.6 (21164A)")
- UNAME_MACHINE=alphaev56 ;;
+ UNAME_MACHINE="alphaev56" ;;
"EV5.6 (21164PC)")
- UNAME_MACHINE=alphapca56 ;;
+ UNAME_MACHINE="alphapca56" ;;
"EV5.7 (21164PC)")
- UNAME_MACHINE=alphapca57 ;;
+ UNAME_MACHINE="alphapca57" ;;
"EV6 (21264)")
- UNAME_MACHINE=alphaev6 ;;
+ UNAME_MACHINE="alphaev6" ;;
"EV6.7 (21264A)")
- UNAME_MACHINE=alphaev67 ;;
+ UNAME_MACHINE="alphaev67" ;;
"EV6.8CB (21264C)")
- UNAME_MACHINE=alphaev68 ;;
+ UNAME_MACHINE="alphaev68" ;;
"EV6.8AL (21264B)")
- UNAME_MACHINE=alphaev68 ;;
+ UNAME_MACHINE="alphaev68" ;;
"EV6.8CX (21264D)")
- UNAME_MACHINE=alphaev68 ;;
+ UNAME_MACHINE="alphaev68" ;;
"EV6.9A (21264/EV69A)")
- UNAME_MACHINE=alphaev69 ;;
+ UNAME_MACHINE="alphaev69" ;;
"EV7 (21364)")
- UNAME_MACHINE=alphaev7 ;;
+ UNAME_MACHINE="alphaev7" ;;
"EV7.9 (21364A)")
- UNAME_MACHINE=alphaev79 ;;
+ UNAME_MACHINE="alphaev79" ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@@ -342,7 +302,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit ;;
- arm*:riscos:*:*|arm*:RISCOS:*:*)
+ arm:riscos:*:*|arm:RISCOS:*:*)
echo arm-unknown-riscos
exit ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
@@ -380,16 +340,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
- SUN_ARCH=i386
+ SUN_ARCH="i386"
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
- SUN_ARCH=x86_64
+ SUN_ARCH="x86_64"
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -414,7 +374,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
@@ -600,9 +560,8 @@ EOF
else
IBM_ARCH=powerpc
fi
- if [ -x /usr/bin/lslpp ] ; then
- IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
- awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
@@ -639,13 +598,13 @@ EOF
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
- 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
- 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
- 32) HP_ARCH=hppa2.0n ;;
- 64) HP_ARCH=hppa2.0w ;;
- '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
esac ;;
esac
fi
@@ -684,11 +643,11 @@ EOF
exit (0);
}
EOF
- (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ ${HP_ARCH} = hppa2.0w ]
+ if [ ${HP_ARCH} = "hppa2.0w" ]
then
eval $set_cc_for_build
@@ -701,12 +660,12 @@ EOF
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23
- if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
- HP_ARCH=hppa2.0w
+ HP_ARCH="hppa2.0w"
else
- HP_ARCH=hppa64
+ HP_ARCH="hppa64"
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -811,14 +770,14 @@ EOF
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -842,13 +801,10 @@ EOF
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
- *:MINGW64*:*)
- echo ${UNAME_MACHINE}-pc-mingw64
- exit ;;
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
- *:MSYS*:*)
+ i*:MSYS*:*)
echo ${UNAME_MACHINE}-pc-msys
exit ;;
i*:windows32*:*)
@@ -896,21 +852,21 @@ EOF
exit ;;
*:GNU:*:*)
# the GNU system
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
aarch64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -923,60 +879,59 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
- if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- arc:Linux:*:* | arceb:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;;
arm*:Linux:*:*)
eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
else
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
fi
fi
exit ;;
avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
cris:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
crisv32:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
- exit ;;
- e2k:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
frv:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
hexagon:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
i*86:Linux:*:*)
- echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit ;;
ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- k1om:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
@@ -995,74 +950,54 @@ EOF
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
- openrisc*:Linux:*:*)
- echo or1k-unknown-linux-${LIBC}
- exit ;;
- or32:Linux:*:* | or1k*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ or32:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
padre:Linux:*:*)
- echo sparc-unknown-linux-${LIBC}
+ echo sparc-unknown-linux-gnu
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-${LIBC}
+ echo hppa64-unknown-linux-gnu
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
- PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
- *) echo hppa-unknown-linux-${LIBC} ;;
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-${LIBC}
+ echo powerpc64-unknown-linux-gnu
exit ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-${LIBC}
- exit ;;
- ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-${LIBC}
- exit ;;
- ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-${LIBC}
+ echo powerpc-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ echo ${UNAME_MACHINE}-ibm-linux
exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
tile*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
- eval $set_cc_for_build
- X86_64_ABI=
- # If there is a compiler, see if it is configured for 32-bit objects.
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
- if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_X32 >/dev/null
- then
- X86_64_ABI=x32
- fi
- fi
- echo ${UNAME_MACHINE}-pc-linux-${LIBC}${X86_64_ABI}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
xtensa*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
@@ -1138,7 +1073,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
- # prints for the "djgpp" host, or else GDB configure will decide that
+ # prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
@@ -1266,9 +1201,6 @@ EOF
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
echo i586-pc-haiku
exit ;;
- x86_64:Haiku:*:*)
- echo x86_64-unknown-haiku
- exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
@@ -1287,9 +1219,6 @@ EOF
SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE}
exit ;;
- SX-ACE:SUPER-UX:*:*)
- echo sxace-nec-superux${UNAME_RELEASE}
- exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;;
@@ -1298,36 +1227,24 @@ EOF
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval $set_cc_for_build
- if test "$UNAME_PROCESSOR" = unknown ; then
- UNAME_PROCESSOR=powerpc
- fi
- if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- case $UNAME_PROCESSOR in
- i386) UNAME_PROCESSOR=x86_64 ;;
- powerpc) UNAME_PROCESSOR=powerpc64 ;;
- esac
- fi
- fi
- elif test "$UNAME_PROCESSOR" = i386 ; then
- # Avoid executing cc on OS X 10.9, as it ships with a stub
- # that puts up a graphical alert prompting to install
- # developer tools. Any system running Mac OS X 10.7 or
- # later (Darwin 11 and later) is required to have a 64-bit
- # processor. This is not true of the ARM version of Darwin
- # that Apple uses in portable devices.
- UNAME_PROCESSOR=x86_64
- fi
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = x86; then
+ if test "$UNAME_PROCESSOR" = "x86"; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
@@ -1339,7 +1256,7 @@ EOF
NEO-?:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
- NSE-*:NONSTOP_KERNEL:*:*)
+ NSE-?:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
@@ -1358,7 +1275,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
- if test "$cputype" = 386; then
+ if test "$cputype" = "386"; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
@@ -1400,7 +1317,7 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
exit ;;
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
@@ -1411,11 +1328,159 @@ EOF
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
- amd64:Isilon\ OneFS:*:*)
- echo x86_64-unknown-onefs
- exit ;;
esac
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
cat >&2 <<EOF
$0: unable to guess system type
@@ -1423,9 +1488,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
diff --git a/config.h.in b/config.h.in
index 0ac78cf26..8feeefb57 100644
--- a/config.h.in
+++ b/config.h.in
@@ -12,6 +12,9 @@
/* Define to 1 if you have the <arpa/nameser.h> header file. */
#undef HAVE_ARPA_NAMESER_H
+/* libcap usability */
+#undef HAVE_CAPABILITY
+
/* Define to 1 if the system has the type `clockid_t'. */
#undef HAVE_CLOCKID_T
@@ -34,6 +37,9 @@
don't. */
#undef HAVE_DECL_STRERROR_R
+/* ipmimonitoring usability */
+#undef HAVE_FREEIPMI
+
/* Define to 1 if the system has the `format' function attribute */
#undef HAVE_FUNC_ATTRIBUTE_FORMAT
@@ -56,6 +62,19 @@
/* Define to 1 if you have the <jemalloc/jemalloc.h> header file. */
#undef HAVE_JEMALLOC_JEMALLOC_H
+/* libmnl usability */
+#undef HAVE_LIBMNL
+
+/* libnetfilter_acct usability */
+#undef HAVE_LIBNETFILTER_ACCT
+
+/* Define to 1 if you have the <linux/netfilter/nfnetlink_conntrack.h> header
+ file. */
+#undef HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
+
+/* Define to 1 if -flto works. */
+#undef HAVE_LTO
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
@@ -65,6 +84,9 @@
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
+/* Define to 1 if you have the `nice' function. */
+#undef HAVE_NICE
+
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
@@ -74,6 +96,15 @@
/* Define to 1 if you have the <resolv.h> header file. */
#undef HAVE_RESOLV_H
+/* Define to 1 if you have the `sched_get_priority_max' function. */
+#undef HAVE_SCHED_GET_PRIORITY_MAX
+
+/* Define to 1 if you have the `sched_get_priority_min' function. */
+#undef HAVE_SCHED_GET_PRIORITY_MIN
+
+/* Define to 1 if you have the `sched_setscheduler' function. */
+#undef HAVE_SCHED_SETSCHEDULER
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
@@ -92,6 +123,9 @@
/* Define to 1 if the system has the type `struct timespec'. */
#undef HAVE_STRUCT_TIMESPEC
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#undef HAVE_SYS_PRCTL_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
@@ -101,7 +135,7 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
-/* nfacct plugin settings */
+/* nfacct plugin usability */
#undef INTERNAL_PLUGIN_NFACCT
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
@@ -115,10 +149,10 @@
/* use this user to drop privileged */
#undef NETDATA_USER
-/* uuid settings */
+/* uuid usability */
#undef NETDATA_WITH_UUID
-/* zlib settings */
+/* zlib usability */
#undef NETDATA_WITH_ZLIB
/* Name of package */
@@ -152,7 +186,7 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
-/* math settings */
+/* math usability */
#undef STORAGE_WITH_MATH
/* Define to 1 if strerror_r returns char *. */
@@ -198,6 +232,11 @@
#define below would cause a syntax error. */
#undef _UINT32_T
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT64_T
+
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
@@ -215,6 +254,22 @@
#undef inline
#endif
+/* Define to the type of a signed integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+#undef int16_t
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef int32_t
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+#undef int64_t
+
+/* Define to the type of a signed integer type of width exactly 8 bits if such
+ a type exists and the standard includes do not define it. */
+#undef int8_t
+
/* gcc branch optimization */
#undef likely
@@ -229,6 +284,10 @@
such a type exists and the standard includes do not define it. */
#undef uint32_t
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint64_t
+
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
#undef uint8_t
diff --git a/config.sub b/config.sub
index b01fff0b6..c894da455 100755
--- a/config.sub
+++ b/config.sub
@@ -1,18 +1,24 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
-timestamp='2016-03-30'
+timestamp='2012-02-10'
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
@@ -20,12 +26,11 @@ timestamp='2016-03-30'
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program. This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
+# the same distribution terms that you use for the rest of that program.
-# Please send patches to <config-patches@gnu.org>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
@@ -33,7 +38,7 @@ timestamp='2016-03-30'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -53,7 +58,8 @@ timestamp='2016-03-30'
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
Canonicalize a configuration name.
@@ -67,7 +73,9 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -115,8 +123,8 @@ esac
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
- linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
@@ -148,7 +156,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray | -microblaze*)
+ -apple | -axis | -knuth | -cray | -microblaze)
os=
basic_machine=$1
;;
@@ -217,12 +225,6 @@ case $os in
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
- -lynx*178)
- os=-lynxos178
- ;;
- -lynx*5)
- os=-lynxos5
- ;;
-lynx*)
os=-lynxos
;;
@@ -251,25 +253,21 @@ case $basic_machine in
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
- | arc | arceb \
- | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
- | avr | avr32 \
- | ba \
- | be32 | be64 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | be32 | be64 \
| bfin \
- | c4x | c8051 | clipper \
- | d10v | d30v | dlx | dsp16xx | dvp \
- | e2k | epiphany \
- | fido | fr30 | frv | ft32 \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
- | k1om \
| le32 | le64 \
| lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | maxq | mb | microblaze | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
@@ -283,29 +281,26 @@ case $basic_machine in
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
- | mipsisa32r6 | mipsisa32r6el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r6 | mipsisa64r6el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nds32 | nds32le | nds32be \
- | nios | nios2 | nios2eb | nios2el \
+ | nios | nios2 \
| ns16k | ns32k \
- | open8 | or1k | or1knd | or32 \
+ | open8 \
+ | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
- | riscv32 | riscv64 \
| rl78 | rx \
| score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -313,7 +308,6 @@ case $basic_machine in
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
- | visium \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
@@ -328,10 +322,7 @@ case $basic_machine in
c6x)
basic_machine=tic6x-unknown
;;
- leon|leon[3-9])
- basic_machine=sparc-$basic_machine
- ;;
- m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -373,29 +364,26 @@ case $basic_machine in
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
- | ba-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
- | c8051-* | clipper-* | craynv-* | cydra-* \
+ | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
- | e2k-* | elxsi-* \
+ | elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
- | k1om-* \
| le32-* | le64-* \
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
- | microblaze-* | microblazeel-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
@@ -409,33 +397,28 @@ case $basic_machine in
| mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa32r6-* | mipsisa32r6el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64r6-* | mipsisa64r6el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nds32-* | nds32le-* | nds32be-* \
- | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | nios-* | nios2-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| open8-* \
- | or1k*-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
- | riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
@@ -443,7 +426,6 @@ case $basic_machine in
| ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
- | visium-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
@@ -520,9 +502,6 @@ case $basic_machine in
basic_machine=i386-pc
os=-aros
;;
- asmjs)
- basic_machine=asmjs-unknown
- ;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -784,9 +763,6 @@ case $basic_machine in
basic_machine=m68k-isi
os=-sysv
;;
- leon-*|leon[3-9]-*)
- basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
- ;;
m68knommu)
basic_machine=m68k-unknown
os=-linux
@@ -806,15 +782,11 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
- microblaze*)
+ microblaze)
basic_machine=microblaze-xilinx
;;
- mingw64)
- basic_machine=x86_64-pc
- os=-mingw64
- ;;
mingw32)
- basic_machine=i686-pc
+ basic_machine=i386-pc
os=-mingw32
;;
mingw32ce)
@@ -828,24 +800,6 @@ case $basic_machine in
basic_machine=m68k-atari
os=-mint
;;
- mipsEE* | ee | ps2)
- basic_machine=mips64r5900el-scei
- case $os in
- -linux*)
- ;;
- *)
- os=-elf
- ;;
- esac
- ;;
- iop)
- basic_machine=mipsel-scei
- os=-irx
- ;;
- dvp)
- basic_machine=dvp-scei
- os=-elf
- ;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
@@ -860,10 +814,6 @@ case $basic_machine in
basic_machine=powerpc-unknown
os=-morphos
;;
- moxiebox)
- basic_machine=moxie-unknown
- os=-moxiebox
- ;;
msdos)
basic_machine=i386-pc
os=-msdos
@@ -872,7 +822,7 @@ case $basic_machine in
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
msys)
- basic_machine=i686-pc
+ basic_machine=i386-pc
os=-msys
;;
mvs)
@@ -1063,11 +1013,7 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
- rdos | rdos64)
- basic_machine=x86_64-pc
- os=-rdos
- ;;
- rdos32)
+ rdos)
basic_machine=i386-pc
os=-rdos
;;
@@ -1394,30 +1340,29 @@ case $os in
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
- | -sym* | -kopensolaris* | -plan9* \
+ | -sym* | -kopensolaris* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* | -cloudabi* | -sortix* \
+ | -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+ | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
- | -linux-newlib* | -linux-musl* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -mingw32* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -irx* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
- | -onefs* | -tirtos*)
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1541,6 +1486,9 @@ case $os in
-aros*)
os=-aros
;;
+ -kaos*)
+ os=-kaos
+ ;;
-zvmoe)
os=-zvmoe
;;
@@ -1549,8 +1497,6 @@ case $os in
;;
-nacl*)
;;
- -ios)
- ;;
-none)
;;
*)
@@ -1591,12 +1537,6 @@ case $basic_machine in
c4x-* | tic4x-*)
os=-coff
;;
- c8051-*)
- os=-elf
- ;;
- hexagon-*)
- os=-elf
- ;;
tic54x-*)
os=-coff
;;
diff --git a/configs.signatures b/configs.signatures
index fbae919c4..713a1d323 100644
--- a/configs.signatures
+++ b/configs.signatures
@@ -1,6 +1,7 @@
declare -A configs_signatures=(
['0056936ce99788ed9ae1c611c87aa6d8']='apps_groups.conf'
['0102351817595a85d01ebd54a5f2f36b']='python.d/ovpn_status_log.conf'
+ ['01302e01162d465614276de43fad7546']='python.d.conf'
['02fa10fa85ab88e9723998de48d1aca0']='health.d/disks.conf'
['036dc300bd7b0e0ef229b9822686d63e']='python.d/isc_dhcpd.conf'
['0388b873d0d7e47c19005b7241db77d8']='python.d/tomcat.conf'
@@ -9,6 +10,8 @@ declare -A configs_signatures=(
['043f0a35dde85837fabeb85b990a41c1']='health.d/swap.conf'
['0529b679d3c0e7e6332753c7f6484731']='health.d/net.conf'
['057d12aaff0467e64529e839a258806b']='health.d/entropy.conf'
+ ['059d98d0c562e1c81653d1e64673deab']='python.d/web_log.conf'
+ ['05a8f39f134850c1e8d6267dbe706273']='health.d/web_log.conf'
['061c45b0e34170d357e47883166ecf40']='python.d/nginx.conf'
['074df527cc70b5f38c0714f08f20e57c']='health.d/apache.conf'
['08042325ab27256b938575deafee8ecf']='python.d/nginx.conf'
@@ -19,9 +22,11 @@ declare -A configs_signatures=(
['091572888425bc3b8b559c3c53367ec7']='apps_groups.conf'
['09264cec953ae1c4c2985e6446abb386']='health.d/mysql.conf'
['093540fdc2a228e976ce5d48a3adf9fc']='health.d/disks.conf'
+ ['0ad10fa896346202aee99384b0ec968d']='health.d/cpu.conf'
['0c5e0fa364d7bdf7c16e8459a0544572']='health.d/netfilter.conf'
['0cd4e1fb57497e4d4c2451a9e58f724d']='python.d/redis.conf'
['0d29fe9919a2975107db1f2583344e7a']='health.d/mdstat.conf'
+ ['0dd38dcd2473ddb9f8b1b41147432d10']='health_alarm_notify.conf'
['0e59bc11d0a869ea0247c04c08c8d72e']='python.d/ipfs.conf'
['0ef8af1f358741afa7fd5d0ffabefaac']='charts.d/mysql.conf'
['10c3b525850a1cb9de760a8ee96fbc6e']='charts.d/opensips.conf'
@@ -32,11 +37,13 @@ declare -A configs_signatures=(
['15d8401b56a74120f9f832873ec9c578']='health.d/postgres.conf'
['15e32114994b92be7853b88091e7c6fb']='python.d/exim.conf'
['174c21a6ce5de97bda83d502aa47a9f8']='health.d/apache.conf'
+ ['17555c7418c801ceb6c93adbe485d6f9']='apps_groups.conf'
['178281aa2241d4a3e6b798bb9c4ae577']='python.d/haproxy.conf'
['18710ef6523cef8630d644ab270bfe02']='health.d/varnish.conf'
['18ee1c6197a4381b1c1631ef6129824f']='apps_groups.conf'
['1972e48345e6c3f0d65f94a03317622b']='health_alarm_notify.conf'
['1c12b678ab65f271a96da1bbd0a1ab1c']='health.d/softnet.conf'
+ ['1c3168c95b53e999df3d45162b3f50b8']='health.d/fping.conf'
['1ea8e8ef1fa8a3a0fcdfba236f4cb195']='python.d/mysql.conf'
['1ef0fd38e7969c023bc3fa6d89eaf6d6']='python.d/mdstat.conf'
['1f5545b3ff52b3eb75ee05401f67a9bc']='fping.conf'
@@ -56,6 +63,7 @@ declare -A configs_signatures=(
['2827de41cf34a91b7a8e4d8724f59668']='health.d/net.conf'
['28df44a90e8ea4c6156314c03e88bf44']='health.d/softnet.conf'
['297160ae7ee01a547ed14f857b4f2c8d']='health.d/memcached.conf'
+ ['298504f331c55dff4055321ff3a7b5cc']='health.d/web_log.conf'
['29f97e10b92333790fbe0d2a3617b736']='health_alarm_notify.conf'
['2a0794fd43eadf30a51805bc9ba2c64d']='python.d/hddtemp.conf'
['2ad55a5d1e885cf142849a78d4b00401']='health.d/net.conf'
@@ -67,14 +75,19 @@ declare -A configs_signatures=(
['312b4b8e2805e19cf9be554b319567d6']='health.d/softnet.conf'
['318bb45755726a25120bb33413d4b582']='health.d/net.conf'
['325617412a628e3bc776e3fbb777a2a6']='health.d/redis.conf'
+ ['326e1477131e0f73304711135f70a2a5']='health.d/memcached.conf'
['32fde0057c790964f2c743cb3c9aad29']='health.d/nginx.conf'
['33b135e28aeaef2b8224ba69a0fde245']='health.d/cpu.conf'
+ ['343bc919a2fbc93f687f9d1339ec5f79']='health.d/net.conf'
+ ['35024ebd94542484c0866e6ee6b950cb']='health.d/net.conf'
['3634d5eddc46fb0d50cf47f370670c2c']='health.d/redis.conf'
['364b6e0081b116c9ec073b4d329a6dcc']='health_alarm_notify.conf'
['367d1463e520eb9dc89223bab161c6d1']='python.d/postgres.conf'
['36fdd55665cf10b0db164c2a0cca5e57']='health.d/qos.conf'
['373160658e7d5f1a129de397b9347365']='health.d/entropy.conf'
['373c1276dc9e65884ff2b26e1f08afe7']='health.d/named.conf'
+ ['3798445a7faaf45c7a8047908678e690']='python.d/varnish.conf'
+ ['37bc2b50ade9f334da4775dfea59f785']='python.d.conf'
['3848172053221b95279ba9bf789cd4e0']='health.d/apache.conf'
['3866efafd38e161136428d0f818cac43']='health.d/net.conf'
['38d1bf04fe9901481dd6febcc0404a86']='python.d.conf'
@@ -89,6 +102,7 @@ declare -A configs_signatures=(
['3c9c47163e9d4dbcb0079b6232398f2f']='apps_groups.conf'
['3ca696189911fb38a0319ddd71e9a395']='python.d/phpfpm.conf'
['3cc6255457d4cba881ae0554ae5d9190']='health.d/squid.conf'
+ ['3d974ac9fdaa44d4527d6503bec35e34']='stream.conf'
['3f170e3343cd784983b019163393f5af']='health.d/nginx.conf'
['3fc45cc18e884c22482524dff6d27833']='python.d/hddtemp.conf'
['3fcc3c449ce8e0388f9c23ca07cab608']='health.d/backend.conf'
@@ -111,6 +125,7 @@ declare -A configs_signatures=(
['4b775fb31342f1478b3773d041a72911']='python.d.conf'
['4ccb06fff1ce06dc5bc80e0a9f568f6e']='charts.d.conf'
['4d13684cadfa90e73ab465409bf7263b']='health.d/mysql.conf'
+ ['4d91ee6fe4c887ea3865ef36ac63da3c']='health.d/mysql.conf'
['4e995acb0d6fd77403a2a9dca984b55b']='charts.d.conf'
['4f6a5b47a13f5912cc89e9286701dd08']='health.d/redis.conf'
['4f6f4d39c19d7d954f769d3f9d3b4da5']='health.d/memcached.conf'
@@ -135,16 +150,20 @@ declare -A configs_signatures=(
['573398335c0c71c075fa57f702bce287']='health.d/disks.conf'
['5829812db29598db5857c9f433e96fef']='python.d/apache.conf'
['58e835b7176865ec5a6f59f7aba832bf']='health.d/named.conf'
+ ['598f9814966a9e2fe48e8218151d3fa6']='stream.conf'
['5b917d894bb6a755d59264e9d48e9d56']='fping.conf'
+ ['5bbef0708f5eff4d4a53aaf35fc48a62']='health.d/disks.conf'
['5bf51bb24fb41db9b1e448bd060d3f8c']='apps_groups.conf'
['5da15d6e17a15213a720749045e5d419']='health.d/disks.conf'
['5e6fd588ef6934cf04ddb5e662aa02ea']='health.d/postgres.conf'
['5eb670b6fe39da5fec2523d910b0dd1e']='health.d/cpu.conf'
['5f05d4b248ab2637ada319b4e8c4e4c3']='python.d/varnish.conf'
+ ['5f109df927d5f20409c81f4bfca0c83e']='python.d/web_log.conf'
['5ff1bcaa58695754e2f6980bfe19f579']='health.d/entropy.conf'
['61b7ed36f35e7bd930f5f7f91694a112']='charts.d/postfix.conf'
['621f10b257a11add5ff5aff41e9662e3']='health.d/memcached.conf'
['623771eecb3c277fc728b5304793f93b']='health.d/cpu.conf'
+ ['632c28d714c87a4969d11cf36a5edaa8']='health.d/web_log.conf'
['636d032928ea0f4741eab264fb49c099']='apps_groups.conf'
['6398ef37a15cb6a0bc921f58948d2b39']='health.d/softnet.conf'
['64070d856ab1b47a18ec871e49bbc13b']='python.d/squid.conf'
@@ -153,6 +172,7 @@ declare -A configs_signatures=(
['64c48f9726ab987baec9c617a9fef7a6']='health.d/nginx.conf'
['64ffc1b6878c81b87564b0f48642c790']='health.d/elasticsearch.conf'
['650b5fc9da23b25ee7ee1481e4aa2851']='health_alarm_notify.conf'
+ ['653e0c014c8fcfb4db6cd3351d87d720']='python.d.conf'
['6546909d10cc5efcef9dd873bea85956']='python.d/mysql.conf'
['65c6933a17fb6b7f8e6baeab73431c17']='charts.d/apcupsd.conf'
['6608c6546b3c6bde084fc1d34b1163c1']='health.d/retroshare.conf'
@@ -163,20 +183,25 @@ declare -A configs_signatures=(
['6a47af861ad3dd112124c37fbf09672b']='apps_groups.conf'
['6b39de5d85db45115db236347a6896d4']='health.d/named.conf'
['6b917300747e7e8314844237e2462261']='python.d/apache_cache.conf'
+ ['6bb278bd9e171c4cb5c0fe639231288b']='python.d/web_log.conf'
['6bf0de6e3b251b765b10a71d8c5c319d']='python.d/apache.conf'
+ ['6c9f2f0abe49a6f1a69db052ebcef1bf']='python.d/elasticsearch.conf'
['6ca08ea2a238cad26578b8b85edae160']='health.d/udp_errors.conf'
- ['6cba40e32a7e98a98c31a209913839cc']='python.d/nginx_log.conf'
['6d02c2dd0863e09ad9dbba53e3b58116']='health.d/mysql.conf'
['6ea958ca521e0514af57c08b518d8c5c']='health.d/backend.conf'
+ ['6f303ccfdc21c7b122758cea8c15e249']='python.d.conf'
['70105b1744a8e13f49083d7f1981aea2']='python.d/ipfs.conf'
['707a63f53f4b32e01d134ae90ba94aad']='health_alarm_notify.conf'
['707a63f53f4b32e01d134ae90ba94aad']='health_email_recipients.conf'
['70d82dabecb09a1da4684f293abef0c9']='health_alarm_notify.conf'
+ ['7120cba2f55b1c0a97a0e10d4f6ef751']='health.d/ipmi.conf'
+ ['729b3e24a72f7d566fd429617d51a21b']='health.d/web_log.conf'
['73125ae64d5c6e9361944cd9bd14844e']='python.d/exim.conf'
['731a1fcfe9b2da1b9d685056a59541b8']='python.d/hddtemp.conf'
['73a8e10dfe4183aca751e9e2a80dabe3']='node.d.conf'
['7454ed74511d7b9819dfe173f9020786']='python.d/redis.conf'
['749fe31362969d75f1ea66d15231d98d']='python.d/retroshare.conf'
+ ['7502c931aa9acbb92f54c67978d75983']='stream.conf'
['7596ae54d46ce199ac599429ef753caf']='health.d/cpu.conf'
['75a9c4b0b1c73956df55585eb0619f6c']='charts.d/ap.conf'
['769aa4cdcdc3d78d0328d1f9e4edcdf9']='python.d/mysql.conf'
@@ -208,6 +233,8 @@ declare -A configs_signatures=(
['845023f9b4a526aa0e6493756dbe6034']='health.d/squid.conf'
['846ce94bfeeb90c0dc6a89e8d25f1a68']='health.d/named.conf'
['8490f690d97adacc4e2096df82e7e8a5']='charts.d/cpufreq.conf'
+ ['871bbeea33b83ea9755600b6d574919c']='python.d/web_log.conf'
+ ['87224d2f2b87646f3c0d38cc1eb30112']='python.d/nsd.conf'
['8810140ce9c09af1d18b9602c4003904']='health_alarm_notify.conf'
['88f77865f75c9fb61c97d700bd4561ee']='python.d/mysql.conf'
['8989b5e2f4ef9cd278ef58be0fae4074']='health.d/disks.conf'
@@ -218,6 +245,8 @@ declare -A configs_signatures=(
['8c1d41e2c88aeca78bc319ed74c8748c']='python.d/phpfpm.conf'
['8d0552371a7c9725a04196fa560813d1']='health.d/cpu.conf'
['8dc0bd0a70b5117454bd5f5b98f91c2c']='health.d/disks.conf'
+ ['8f4f925c1e97dd164007495ec5135ffc']='health.d/fping.conf'
+ ['8f7b734ea0f89abf8acbb47c50234477']='health.d/web_log.conf'
['8fd472a854b0996327e8ed3562161182']='health_alarm_notify.conf'
['919911d13901d60a7580f5dfd7fc87bb']='health.d/ram.conf'
['91c757ef6be3abdb86906d9dbb9c217a']='fping.conf'
@@ -230,15 +259,19 @@ declare -A configs_signatures=(
['99b6030ce25c8fee4598179c0f95fb0b']='health.d/redis.conf'
['99c1617448abbdc493976ab9bda5ce02']='apps_groups.conf'
['9a8a459a3841b78d4c6ef07428ad2fe1']='health.d/entropy.conf'
+ ['9b6eee7f2febb29efac2b7ea9fcab9be']='charts.d/nut.conf'
['9c0185ceff15415bc59b2ce2c1f04367']='apps_groups.conf'
+ ['9c8ddfa810d83ae58c8614ee5229e66b']='health.d/disks.conf'
['9c981c75bdf4b1637f7113e7e45eb2bf']='health.d/memcached.conf'
['9e0553ebdc21b64295873fc104cfa79d']='python.d.conf'
['9eb3326ae2ee9badeaad31d8dd2eaa2b']='python.d/isc_dhcpd.conf'
['a02d14124b19c635c1426cee2e98bac5']='charts.d.conf'
+ ['a03f3e38378385bf87d4c0f81eb1f108']='health.d/tcp_resets.conf'
['a09714b5942cf25a89ec3da1dbc18063']='health.d/ram.conf'
['a0b3a12389c9c56dfe35964b20b59836']='health.d/bind_rndc.conf'
['a0ee8f351f213c0e8af9eb7a4a09cb95']='apps_groups.conf'
['a2944a309f8ce1a3195451856478d6ae']='python.d.conf'
+ ['a2a647dc492dc2d6ed1f5c0fdc97a96e']='python.d/mongodb.conf'
['a305b400378d6492efd15f9940c2779b']='health.d/softnet.conf'
['a4407787e4beb23a701a8a614dca461d']='health.d/disks.conf'
['a44899a5795bed2863c1d11aa3e85586']='health.d/swap.conf'
@@ -262,6 +295,7 @@ declare -A configs_signatures=(
['a9cd91675467c5426f5b51c47602c889']='apps_groups.conf'
['aa4bee249bfc0c4a88ac8c2ffb97aa0d']='health.d/squid.conf'
['aa8b57a733c2035917acf81a8ebdfbe7']='health.d/haproxy.conf'
+ ['aac44691a1cf95fa8f8990a79bab4ce1']='python.d/web_log.conf'
['abaf2e021f9f6ee5d1c4e4726f47348e']='health.d/ipc.conf'
['acaa6731a272f6d251afb357e99b518f']='apps_groups.conf'
['ade389c1b6efe0cff47c33e662731f0a']='python.d/squid.conf'
@@ -285,9 +319,11 @@ declare -A configs_signatures=(
['b8969be5b3ceb4a99477937119bd4323']='python.d.conf'
['b8b87574fd496a66ede884c5336493bd']='python.d/phpfpm.conf'
['b915126262d08aa9da81de539a58a3fb']='python.d/redis.conf'
+ ['ba11ea2d2f632b2de4b1224bcdc54f07']='python.d/smartd_log.conf'
['bb51112d01ff20053196a57632df8962']='apps_groups.conf'
['bba2f3886587f137ea08a6e63dd3d376']='python.d.conf'
['bda5517ea01640cfdfa0a27549619d6a']='health.d/memcached.conf'
+ ['bf66f113b2dd8d8fb444cbd5650f284c']='health_alarm_notify.conf'
['c004430f55310ae9ed489c4905ed02cb']='charts.d/apache.conf'
['c080e006f544c949baca33cc24a9c126']='health_alarm_notify.conf'
['c1a7e634b5b8aad523a0d115a93379cd']='health.d/memcached.conf'
@@ -323,6 +359,7 @@ declare -A configs_signatures=(
['d8dc489e32f7114c6298fce94e86a8ef']='health.d/entropy.conf'
['d9036091e2232fc2b8bfa8c7484dea28']='apps_groups.conf'
['d9258e671d0d0b6498af1ce16ef030d2']='apps_groups.conf'
+ ['d9fa0290cdfe4153188bb52dd31191df']='apps_groups.conf'
['da29d2ab1ab7b8fda189960c840e5144']='health.d/swap.conf'
['dad303c5cca7a69345811a01a74f5892']='health.d/net.conf'
['dc0d2b96378f290eec3fcf98b89ad824']='python.d/cpufreq.conf'
@@ -334,11 +371,14 @@ declare -A configs_signatures=(
['de02f899a61f21b86adb646940f0bcae']='health.d/net.conf'
['def883f35986c9d25de63b1a8e7d0f46']='health.d/entropy.conf'
['df381f3a7ca9fb2b4b43ae7cb7a4c492']='python.d/mysql.conf'
+ ['df7e8044902b5e155fad8430c2ddcfa8']='health.d/fping.conf'
['dfd5431b11cf2f3852a40d390c1d5a92']='python.d/varnish.conf'
['e0242003fd2e3f9ac1b9314e802ada79']='python.d/hddtemp.conf'
+ ['e0ba3bc216ffc9933b4741dbb6b1f8c8']='health.d/web_log.conf'
['e0e96cc47ed61d6492416be5236cd4d3']='python.d/apache_cache.conf'
['e2f3388c06726154c10ec22bad5bc7ec']='fping.conf'
['e3023092e3b2bbb5351e0fe6682f4fe9']='health_alarm_notify.conf'
+ ['e3d100c2d0347c08efbf6245e05620c6']='python.d/fail2ban.conf'
['e3e5bc57335c489f01b8559f5c70e112']='python.d/squid.conf'
['e40947d22f7ed5359f12fc89e3512963']='python.d/dovecot.conf'
['e449e5582279742496550df14b6fca95']='health.d/entropy.conf'
@@ -346,24 +386,28 @@ declare -A configs_signatures=(
['e734c5951a8764d4d9de046dd7cf7407']='health.d/softnet.conf'
['e7bc22a1942cffbd2b1b0cfd119ee328']='health.d/ipfs.conf'
['e8ec8046c7007af6ca3e8c51e62c99f8']='health.d/disks.conf'
+ ['ea1a96c42ad464c354fb250e3408c3e8']='stream.conf'
+ ['eaa7beb935cae9c48a40fb934eb105a7']='health.d/web_log.conf'
['eb5168f0b516bc982aac45e59da6e52e']='health.d/nginx.conf'
['eb748d6fb69d11b0d29c5794657e206c']='health.d/qos.conf'
['ebd0612ccc5807524ebb2b647e3e56c9']='apps_groups.conf'
- ['ec490e037c1e53daa44a55a941381d6d']='python.d/gunicorn_log.conf'
['ecd3aa97e2581f88eb466d6612690ef2']='charts.d/nginx.conf'
['ee5343881744e6a97e6ee5cdd329cfb8']='health.d/retroshare.conf'
['ef1861bf5725d91e773cbdba05687597']='python.d.conf'
['ef9916ea144878a9f37cbb6b1b29da10']='health.d/squid.conf'
+ ['f1446cb3f1a905ee06defa2aa15ee806']='python.d/web_log.conf'
['f2f1b8656f5011e965ac45b818cf668d']='apps_groups.conf'
['f42df9f13abfae2426519c6728b34882']='charts.d/example.conf'
['f4c5d88c34d3fb853498124177cc77f1']='python.d.conf'
['f5736e0b2945182cb659cb0713eff923']='apps_groups.conf'
['f66e5236ba1245bb2e5fd99191f114c6']='charts.d/hddtemp.conf'
['f6c6656f900ff52d159dca12d624016a']='python.d/postgres.conf'
+ ['f7401a6e7c7d4fe2e0e2be7f7f523275']='health.d/web_log.conf'
['f7a99e94231beda85c6254912d8d31c1']='python.d/tomcat.conf'
['f82924563e41d99cdae5431f0af69155']='python.d.conf'
['f8c30f22df92765e2c0fab3c8174e2fc']='health.d/memcached.conf'
['f8dade4484f1b6a48655388502df7d5a']='health_alarm_notify.conf'
+ ['f96acba4b14b0c1b50d0187a04416151']='health_alarm_notify.conf'
['f9be549a849d023595d19d5d74263e0f']='health.d/tcp_resets.conf'
['fa4396513b358d6ec6a7f5bfb08439b8']='health.d/net.conf'
['fd3164e6e8cb6726706267eae49aa082']='health_alarm_notify.conf'
diff --git a/configure b/configure
index 39644b13a..f638780b4 100755
--- a/configure
+++ b/configure
@@ -1,9 +1,11 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for netdata 1.5.0.
+# Generated by GNU Autoconf 2.68 for netdata 1.6.0.
#
#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -132,31 +134,6 @@ export LANGUAGE
# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
@@ -190,8 +167,7 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
else
exitcode=1; echo positional parameters were not saved.
fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
+test x\$exitcode = x0 || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -236,25 +212,21 @@ IFS=$as_save_IFS
if test "x$CONFIG_SHELL" != x; then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ # Preserve -v and -x to the replacement shell.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+ esac
+ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
fi
if test x$as_have_required = xno; then :
@@ -356,14 +328,6 @@ $as_echo X"$as_dir" |
} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -485,10 +449,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
chmod +x "$as_me.lineno" ||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this).
@@ -523,16 +483,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
+ # In both cases, we have to default to `cp -p'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@@ -544,8 +504,28 @@ else
as_mkdir_p=false
fi
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -577,8 +557,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='netdata'
PACKAGE_TARNAME='netdata'
-PACKAGE_VERSION='1.5.0'
-PACKAGE_STRING='netdata 1.5.0'
+PACKAGE_VERSION='1.6.0'
+PACKAGE_STRING='netdata 1.6.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -620,10 +600,15 @@ ac_includes_default="\
#endif"
ac_func_list=
+ac_header_list=
ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
+OPTIONAL_IPMIMONITORING_LIBS
+OPTIONAL_IPMIMONITORING_CFLAGS
+OPTIONAL_LIBCAP_LIBS
+OPTIONAL_LIBCAP_CFLAGS
OPTIONAL_UUID_LIBS
OPTIONAL_UUID_CLFAGS
OPTIONAL_ZLIB_LIBS
@@ -642,23 +627,37 @@ chartsdir
cachedir
registrydir
varlibdir
-ZLIB_LIBS
-ZLIB_CFLAGS
+ENABLE_PLUGIN_NFACCT_FALSE
+ENABLE_PLUGIN_NFACCT_TRUE
LIBMNL_LIBS
LIBMNL_CFLAGS
NFACCT_LIBS
NFACCT_CFLAGS
+ENABLE_PLUGIN_FREEIPMI_FALSE
+ENABLE_PLUGIN_FREEIPMI_TRUE
+IPMIMONITORING_LIBS
+IPMIMONITORING_CFLAGS
+ENABLE_PLUGIN_APPS_FALSE
+ENABLE_PLUGIN_APPS_TRUE
+ENABLE_CAPABILITY_FALSE
+ENABLE_CAPABILITY_TRUE
+LIBCAP_LIBS
+LIBCAP_CFLAGS
+has_tcmalloc
+has_jemalloc
+SSE_CANDIDATE
UUID_LIBS
UUID_CFLAGS
+ZLIB_LIBS
+ZLIB_CFLAGS
MATH_LIBS
MATH_CFLAGS
-SSE_CANDIDATE
-has_tcmalloc
-has_jemalloc
PTHREAD_CFLAGS
PTHREAD_LIBS
PTHREAD_CC
ax_pthread_config
+LINUX_FALSE
+LINUX_TRUE
MACOS_FALSE
MACOS_TRUE
FREEBSD_FALSE
@@ -669,18 +668,6 @@ CPP
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
-AM_BACKSLASH
-AM_DEFAULT_VERBOSITY
-AM_DEFAULT_V
-AM_V
am__fastdepCC_FALSE
am__fastdepCC_TRUE
CCDEPMODE
@@ -691,6 +678,21 @@ AMDEP_TRUE
am__quote
am__include
DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
am__untar
am__tar
AMTAR
@@ -714,13 +716,6 @@ am__isrc
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
-OBJEXT
-EXEEXT
-ac_ct_CC
-CPPFLAGS
-LDFLAGS
-CFLAGS
-CC
PACKAGE_RPM_RELEASE
PACKAGE_RPM_VERSION
MAINT
@@ -769,14 +764,16 @@ ac_user_opts='
enable_option_checking
enable_maintainer_mode
enable_dependency_tracking
-enable_silent_rules
enable_plugin_nfacct
+enable_plugin_freeipmi
enable_pedantic
with_webdir
+with_libcap
with_zlib
with_math
with_user
enable_x86_sse
+enable_lto
with_jemalloc_prefix
with_jemalloc
with_tcmalloc_lib
@@ -794,17 +791,21 @@ PKG_CONFIG
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
CPP
-SSE_CANDIDATE
MATH_CFLAGS
MATH_LIBS
+ZLIB_CFLAGS
+ZLIB_LIBS
UUID_CFLAGS
UUID_LIBS
+SSE_CANDIDATE
+LIBCAP_CFLAGS
+LIBCAP_LIBS
+IPMIMONITORING_CFLAGS
+IPMIMONITORING_LIBS
NFACCT_CFLAGS
NFACCT_LIBS
LIBMNL_CFLAGS
-LIBMNL_LIBS
-ZLIB_CFLAGS
-ZLIB_LIBS'
+LIBMNL_LIBS'
# Initialize some variables set by options.
@@ -1260,6 +1261,8 @@ target=$target_alias
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
@@ -1345,7 +1348,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures netdata 1.5.0 to adapt to many kinds of systems.
+\`configure' configures netdata 1.6.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1415,7 +1418,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of netdata 1.5.0:";;
+ short | recursive ) echo "Configuration of netdata 1.6.0:";;
esac
cat <<\_ACEOF
@@ -1423,23 +1426,22 @@ Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --enable-maintainer-mode
- enable make rules and dependencies not useful (and
- sometimes confusing) to the casual installer
- --enable-dependency-tracking
- do not reject slow dependency extractors
- --disable-dependency-tracking
- speeds up one-time build
- --enable-silent-rules less verbose build output (undo: "make V=1")
- --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
--enable-plugin-nfacct enable nfacct plugin, requires root
+ --enable-plugin-freeipmi
+ enable freeipmi plugin
--enable-pedantic enable pedantic compiler warnings
--disable-x86-sse SSE/SS2 optimizations on x86 [default enabled]
+ --disable-lto Link Time Optimizations [default enabled]
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-webdir location of webdir [PKGDATADIR/web]
+ --with-libcap build with libcap
--with-zlib build with zlib
--with-math build with math
--with-user use this user to drop privilege
@@ -1464,20 +1466,27 @@ Some influential environment variables:
PKG_CONFIG_LIBDIR
path overriding pkg-config's built-in search path
CPP C preprocessor
- SSE_CANDIDATE
- C compiler flags for SSE
MATH_CFLAGS C compiler flags for math
MATH_LIBS linker flags for math
+ ZLIB_CFLAGS C compiler flags for ZLIB, overriding pkg-config
+ ZLIB_LIBS linker flags for ZLIB, overriding pkg-config
UUID_CFLAGS C compiler flags for UUID, overriding pkg-config
UUID_LIBS linker flags for UUID, overriding pkg-config
+ SSE_CANDIDATE
+ C compiler flags for SSE
+ LIBCAP_CFLAGS
+ C compiler flags for LIBCAP, overriding pkg-config
+ LIBCAP_LIBS linker flags for LIBCAP, overriding pkg-config
+ IPMIMONITORING_CFLAGS
+ C compiler flags for IPMIMONITORING, overriding pkg-config
+ IPMIMONITORING_LIBS
+ linker flags for IPMIMONITORING, overriding pkg-config
NFACCT_CFLAGS
C compiler flags for NFACCT, overriding pkg-config
NFACCT_LIBS linker flags for NFACCT, overriding pkg-config
LIBMNL_CFLAGS
C compiler flags for LIBMNL, overriding pkg-config
LIBMNL_LIBS linker flags for LIBMNL, overriding pkg-config
- ZLIB_CFLAGS C compiler flags for ZLIB, overriding pkg-config
- ZLIB_LIBS linker flags for ZLIB, overriding pkg-config
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -1545,10 +1554,10 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-netdata configure 1.5.0
-generated by GNU Autoconf 2.69
+netdata configure 1.6.0
+generated by GNU Autoconf 2.68
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1597,52 +1606,6 @@ fi
} # ac_fn_c_try_compile
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest$ac_exeext
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest$ac_exeext && {
- test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
- }; then :
- ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
- # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
- # interfere with the next link command; also delete a directory that is
- # left behind by Apple's compiler. We do this before executing the actions.
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-
# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
@@ -1840,6 +1803,52 @@ $as_echo "$ac_res" >&6; }
} # ac_fn_c_check_header_compile
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
@@ -1961,6 +1970,80 @@ $as_echo "$ac_res" >&6; }
} # ac_fn_c_check_type
+# ac_fn_c_find_intX_t LINENO BITS VAR
+# -----------------------------------
+# Finds a signed integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_intX_t ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5
+$as_echo_n "checking for int$2_t... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ # Order is important - never check a type that is potentially smaller
+ # than half of the expected target width.
+ for ac_type in int$2_t 'int' 'long int' \
+ 'long long int' 'short int' 'signed char'; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+ enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+ enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1)
+ < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ case $ac_type in #(
+ int$2_t) :
+ eval "$3=yes" ;; #(
+ *) :
+ eval "$3=\$ac_type" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if eval test \"x\$"$3"\" = x"no"; then :
+
+else
+ break
+fi
+ done
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_find_intX_t
+
# ac_fn_c_find_uintX_t LINENO BITS VAR
# ------------------------------------
# Finds an unsigned integer type with width BITS, setting cache variable VAR
@@ -1985,8 +2068,7 @@ int
main ()
{
static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2078,8 +2160,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) >= 0)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2095,8 +2176,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) <= $ac_mid)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2122,8 +2202,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) < 0)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2139,8 +2218,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) >= $ac_mid)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2174,8 +2252,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) <= $ac_mid)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2247,8 +2324,8 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by netdata $as_me 1.5.0, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+It was created by netdata $as_me 1.6.0, which was
+generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -2528,6 +2605,8 @@ $as_echo "$as_me: creating cache $cache_file" >&6;}
fi
as_fn_append ac_func_list " accept4"
+as_fn_append ac_header_list " sys/prctl.h"
+as_fn_append ac_header_list " linux/netfilter/nfnetlink_conntrack.h"
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
@@ -2626,1144 +2705,13 @@ $as_echo "$as_me: ***************** MAINTAINER MODE *****************" >&6;}
PACKAGE_BUILT_DATE=$(date '+%d %b %Y')
fi
-PACKAGE_RPM_VERSION="1.5.0"
+PACKAGE_RPM_VERSION="1.6.0"
-# fails on centos6
-#AX_CHECK_ENABLE_DEBUG()
-
-ac_aux_dir=
-for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
- if test -f "$ac_dir/install-sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f "$ac_dir/install.sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f "$ac_dir/shtool"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
-fi
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
-
-
-# Expand $ac_aux_dir to an absolute path.
-am_aux_dir=`cd "$ac_aux_dir" && pwd`
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- fi
-fi
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl.exe
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl.exe
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-
-
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
-
-# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
- { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- sed '10a\
-... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
- cat conftest.er1 >&5
- fi
- rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- * ) ac_rmfiles="$ac_rmfiles $ac_file";;
- esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link_default") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile. We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
- ;;
- [ab].out )
- # We found the default executable, but exeext='' is most
- # certainly right.
- break;;
- *.* )
- if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
- then :; else
- ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- fi
- # We set ac_cv_exeext here because the later test for it is not
- # safe: cross compilers may not add the suffix if given an `-o'
- # argument, so we may need to know it at that point already.
- # Even if this section looks crufty: it has the advantage of
- # actually working.
- break;;
- * )
- break;;
- esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else
- ac_file=''
-fi
-if test -z "$ac_file"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
- # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- break;;
- * ) break;;
- esac
-done
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdio.h>
-int
-main ()
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
- { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if { ac_try='./conftest$ac_cv_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
- fi
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
- for ac_file in conftest.o conftest.obj conftest.*; do
- test -f "$ac_file" || continue;
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
- *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
- break;;
- esac
-done
-else
- $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_compiler_gnu=yes
-else
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_save_c_werror_flag=$ac_c_werror_flag
- ac_c_werror_flag=yes
- ac_cv_prog_cc_g=no
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-else
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-else
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
-}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
- *)
- CC="$CC $ac_cv_prog_cc_c89"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
-if ${am_cv_prog_cc_c_o+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
- # Make sure it works both with $CC and with simple cc.
- # Following AC_PROG_CC_C_O, we do the test twice because some
- # compilers refuse to overwrite an existing .o file with -o,
- # though they will create one.
- am_cv_prog_cc_c_o=yes
- for am_i in 1 2; do
- if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
- ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } \
- && test -f conftest2.$ac_objext; then
- : OK
- else
- am_cv_prog_cc_c_o=no
- break
- fi
- done
- rm -f core conftest*
- unset am_i
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-$as_echo "$am_cv_prog_cc_c_o" >&6; }
-if test "$am_cv_prog_cc_c_o" != yes; then
- # Losing compiler, so override with the script.
- # FIXME: It is wrong to rewrite CC.
- # But if we don't then we get into trouble of one sort or another.
- # A longer-term fix would be to have automake use am__CC in this case,
- # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
- CC="$am_aux_dir/compile $CC"
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((returns_nonnull))" >&5
-$as_echo_n "checking for __attribute__((returns_nonnull))... " >&6; }
-if ${ax_cv_have_func_attribute_returns_nonnull+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- void *foo( void ) __attribute__((returns_nonnull));
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- if test -s conftest.err; then :
- ax_cv_have_func_attribute_returns_nonnull=no
-else
- ax_cv_have_func_attribute_returns_nonnull=yes
-fi
-else
- ax_cv_have_func_attribute_returns_nonnull=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_returns_nonnull" >&5
-$as_echo "$ax_cv_have_func_attribute_returns_nonnull" >&6; }
-
- if test yes = $ax_cv_have_func_attribute_returns_nonnull; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL 1
-_ACEOF
-
-fi
-
-
-
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((malloc))" >&5
-$as_echo_n "checking for __attribute__((malloc))... " >&6; }
-if ${ax_cv_have_func_attribute_malloc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- void *foo( void ) __attribute__((malloc));
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- if test -s conftest.err; then :
- ax_cv_have_func_attribute_malloc=no
-else
- ax_cv_have_func_attribute_malloc=yes
-fi
-else
- ax_cv_have_func_attribute_malloc=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_malloc" >&5
-$as_echo "$ax_cv_have_func_attribute_malloc" >&6; }
-
- if test yes = $ax_cv_have_func_attribute_malloc; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FUNC_ATTRIBUTE_MALLOC 1
-_ACEOF
-
-fi
-
-
-
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((noreturn))" >&5
-$as_echo_n "checking for __attribute__((noreturn))... " >&6; }
-if ${ax_cv_have_func_attribute_noreturn+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- void foo( void ) __attribute__((noreturn));
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- if test -s conftest.err; then :
- ax_cv_have_func_attribute_noreturn=no
-else
- ax_cv_have_func_attribute_noreturn=yes
-fi
-else
- ax_cv_have_func_attribute_noreturn=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_noreturn" >&5
-$as_echo "$ax_cv_have_func_attribute_noreturn" >&6; }
-
- if test yes = $ax_cv_have_func_attribute_noreturn; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FUNC_ATTRIBUTE_NORETURN 1
-_ACEOF
-
-fi
-
-
-
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((format))" >&5
-$as_echo_n "checking for __attribute__((format))... " >&6; }
-if ${ax_cv_have_func_attribute_format+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- int foo(const char *p, ...) __attribute__((format(printf, 1, 2)));
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- if test -s conftest.err; then :
- ax_cv_have_func_attribute_format=no
-else
- ax_cv_have_func_attribute_format=yes
-fi
-else
- ax_cv_have_func_attribute_format=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_format" >&5
-$as_echo "$ax_cv_have_func_attribute_format" >&6; }
-
- if test yes = $ax_cv_have_func_attribute_format; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FUNC_ATTRIBUTE_FORMAT 1
-_ACEOF
-
-fi
-
-
-
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((warn_unused_result))" >&5
-$as_echo_n "checking for __attribute__((warn_unused_result))... " >&6; }
-if ${ax_cv_have_func_attribute_warn_unused_result+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- int foo( void ) __attribute__((warn_unused_result));
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- if test -s conftest.err; then :
- ax_cv_have_func_attribute_warn_unused_result=no
-else
- ax_cv_have_func_attribute_warn_unused_result=yes
-fi
-else
- ax_cv_have_func_attribute_warn_unused_result=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_warn_unused_result" >&5
-$as_echo "$ax_cv_have_func_attribute_warn_unused_result" >&6; }
-
- if test yes = $ax_cv_have_func_attribute_warn_unused_result; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT 1
-_ACEOF
-
-fi
-
-
+# -----------------------------------------------------------------------------
+# autoconf initialization
ac_aux_dir=
for ac_dir in . "$srcdir"/.; do
@@ -3798,7 +2746,7 @@ ac_config_headers="$ac_config_headers config.h"
-am__api_version='1.15'
+am__api_version='1.11'
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -3837,7 +2785,7 @@ case $as_dir/ in #((
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
if test $ac_prog = install &&
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
@@ -3895,6 +2843,9 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
# Reject unsafe characters in $srcdir or the absolute working directory
# name. Accept space and tab only in the latter.
am_lf='
@@ -3905,40 +2856,32 @@ case `pwd` in
esac
case $srcdir in
*[\\\"\#\$\&\'\`$am_lf\ \ ]*)
- as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+ as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
esac
-# Do 'set' in a subshell so we don't clobber the current shell's
+# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
- am_has_slept=no
- for am_try in 1 2; do
- echo "timestamp, slept: $am_has_slept" > conftest.file
- set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
- if test "$*" = "X"; then
- # -L didn't work.
- set X `ls -t "$srcdir/configure" conftest.file`
- fi
- if test "$*" != "X $srcdir/configure conftest.file" \
- && test "$*" != "X conftest.file $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
- alias in your environment" "$LINENO" 5
- fi
- if test "$2" = conftest.file || test $am_try -eq 2; then
- break
- fi
- # Just in case.
- sleep 1
- am_has_slept=yes
- done
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+ fi
+
test "$2" = conftest.file
)
then
@@ -3950,16 +2893,6 @@ Check your system clock" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
-# If we didn't sleep, we still need to ensure time stamps of config.status and
-# generated files are strictly newer.
-am_sleep_pid=
-if grep 'slept: no' conftest.file >/dev/null 2>&1; then
- ( sleep 1 ) &
- am_sleep_pid=$!
-fi
-
-rm -f conftest.file
-
test "$program_prefix" != NONE &&
program_transform_name="s&^&$program_prefix&;$program_transform_name"
# Use a double $ so make ignores it.
@@ -3970,6 +2903,9 @@ test "$program_suffix" != NONE &&
ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
if test x"${MISSING+set}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
@@ -3979,15 +2915,15 @@ if test x"${MISSING+set}" != xset; then
esac
fi
# Use eval to expand $SHELL
-if eval "$MISSING --is-lightweight"; then
- am_missing_run="$MISSING "
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
else
am_missing_run=
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
-$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
fi
-if test x"${install_sh+set}" != xset; then
+if test x"${install_sh}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -3996,10 +2932,10 @@ if test x"${install_sh+set}" != xset; then
esac
fi
-# Installed binaries are usually stripped using 'strip' when the user
-# run "make install-strip". However 'strip' might not be the right
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
-# will honor the 'STRIP' environment variable to overrule this program.
+# will honor the `STRIP' environment variable to overrule this program.
if test "$cross_compiling" != no; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
@@ -4018,7 +2954,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_STRIP="${ac_tool_prefix}strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4058,7 +2994,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_STRIP="strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4109,7 +3045,7 @@ do
test -z "$as_dir" && as_dir=.
for ac_prog in mkdir gmkdir; do
for ac_exec_ext in '' $ac_executable_extensions; do
- as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
'mkdir (GNU coreutils) '* | \
'mkdir (coreutils) '* | \
@@ -4138,6 +3074,12 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
$as_echo "$MKDIR_P" >&6; }
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+ [\\/$]* | ?:[\\/]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
for ac_prog in gawk mawk nawk awk
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
@@ -4156,7 +3098,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4220,108 +3162,6 @@ else
fi
rmdir .tst 2>/dev/null
-DEPDIR="${am__leading_dot}deps"
-
-ac_config_commands="$ac_config_commands depfiles"
-
-
-am_make=${MAKE-make}
-cat > confinc << 'END'
-am__doit:
- @echo this is the am__doit target
-.PHONY: am__doit
-END
-# If we don't find an include directive, just comment out the code.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
-$as_echo_n "checking for style of include used by $am_make... " >&6; }
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# Ignore all kinds of additional output from 'make'.
-case `$am_make -s -f confmf 2> /dev/null` in #(
-*the\ am__doit\ target*)
- am__include=include
- am__quote=
- _am_result=GNU
- ;;
-esac
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
- echo '.include "confinc"' > confmf
- case `$am_make -s -f confmf 2> /dev/null` in #(
- *the\ am__doit\ target*)
- am__include=.include
- am__quote="\""
- _am_result=BSD
- ;;
- esac
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
-$as_echo "$_am_result" >&6; }
-rm -f confinc confmf
-
-# Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then :
- enableval=$enable_dependency_tracking;
-fi
-
-if test "x$enable_dependency_tracking" != xno; then
- am_depcomp="$ac_aux_dir/depcomp"
- AMDEPBACKSLASH='\'
- am__nodep='_no'
-fi
- if test "x$enable_dependency_tracking" != xno; then
- AMDEP_TRUE=
- AMDEP_FALSE='#'
-else
- AMDEP_TRUE='#'
- AMDEP_FALSE=
-fi
-
-
-# Check whether --enable-silent-rules was given.
-if test "${enable_silent_rules+set}" = set; then :
- enableval=$enable_silent_rules;
-fi
-
-case $enable_silent_rules in # (((
- yes) AM_DEFAULT_VERBOSITY=0;;
- no) AM_DEFAULT_VERBOSITY=1;;
- *) AM_DEFAULT_VERBOSITY=1;;
-esac
-am_make=${MAKE-make}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
-$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
-if ${am_cv_make_support_nested_variables+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if $as_echo 'TRUE=$(BAR$(V))
-BAR0=false
-BAR1=true
-V=1
-am__doit:
- @$(TRUE)
-.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
- am_cv_make_support_nested_variables=yes
-else
- am_cv_make_support_nested_variables=no
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
-$as_echo "$am_cv_make_support_nested_variables" >&6; }
-if test $am_cv_make_support_nested_variables = yes; then
- AM_V='$(V)'
- AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
-else
- AM_V=$AM_DEFAULT_VERBOSITY
- AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
-fi
-AM_BACKSLASH='\'
-
if test "`cd $srcdir && pwd`" != "`pwd`"; then
# Use -I$(srcdir) only when $(srcdir) != ., so that make's output
# is not polluted with repeated "-I."
@@ -4344,7 +3184,7 @@ fi
# Define the identity of the package.
PACKAGE='netdata'
- VERSION='1.5.0'
+ VERSION='1.6.0'
cat >>confdefs.h <<_ACEOF
@@ -4372,199 +3212,18 @@ AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
-# For better backward compatibility. To be removed once Automake 1.9.x
-# dies out for good. For more background, see:
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
-mkdir_p='$(MKDIR_P)'
-
-# We need awk for the "check" target (and possibly the TAP driver). The
-# system "awk" is bad on some platforms.
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AMTAR='$${TAR-tar}'
-
-# We'll loop over all known methods to create a tar archive until one works.
-_am_tools='gnutar pax cpio none'
-
am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
-depcc="$CC" am_compiler_list=
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-$as_echo_n "checking dependency style of $depcc... " >&6; }
-if ${am_cv_CC_dependencies_compiler_type+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
- # We make a subdir and do the tests there. Otherwise we can end up
- # making bogus files that we don't know about and never remove. For
- # instance it was reported that on HP-UX the gcc test will end up
- # making a dummy file named 'D' -- because '-MD' means "put the output
- # in D".
- rm -rf conftest.dir
- mkdir conftest.dir
- # Copy depcomp to subdir because otherwise we won't find it if we're
- # using a relative directory.
- cp "$am_depcomp" conftest.dir
- cd conftest.dir
- # We will build objects and dependencies in a subdirectory because
- # it helps to detect inapplicable dependency modes. For instance
- # both Tru64's cc and ICC support -MD to output dependencies as a
- # side effect of compilation, but ICC will put the dependencies in
- # the current directory while Tru64 will put them in the object
- # directory.
- mkdir sub
-
- am_cv_CC_dependencies_compiler_type=none
- if test "$am_compiler_list" = ""; then
- am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
- fi
- am__universal=false
- case " $depcc " in #(
- *\ -arch\ *\ -arch\ *) am__universal=true ;;
- esac
-
- for depmode in $am_compiler_list; do
- # Setup a source with many dependencies, because some compilers
- # like to wrap large dependency lists on column 80 (with \), and
- # we should not choose a depcomp mode which is confused by this.
- #
- # We need to recreate these files for each test, as the compiler may
- # overwrite some of them when testing with obscure command lines.
- # This happens at least with the AIX C compiler.
- : > sub/conftest.c
- for i in 1 2 3 4 5 6; do
- echo '#include "conftst'$i'.h"' >> sub/conftest.c
- # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
- # Solaris 10 /bin/sh.
- echo '/* dummy */' > sub/conftst$i.h
- done
- echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
-
- # We check with '-c' and '-o' for the sake of the "dashmstdout"
- # mode. It turns out that the SunPro C++ compiler does not properly
- # handle '-M -o', and we need to detect this. Also, some Intel
- # versions had trouble with output in subdirs.
- am__obj=sub/conftest.${OBJEXT-o}
- am__minus_obj="-o $am__obj"
- case $depmode in
- gcc)
- # This depmode causes a compiler race in universal mode.
- test "$am__universal" = false || continue
- ;;
- nosideeffect)
- # After this tag, mechanisms are not by side-effect, so they'll
- # only be used when explicitly requested.
- if test "x$enable_dependency_tracking" = xyes; then
- continue
- else
- break
- fi
- ;;
- msvc7 | msvc7msys | msvisualcpp | msvcmsys)
- # This compiler won't grok '-c -o', but also, the minuso test has
- # not run yet. These depmodes are late enough in the game, and
- # so weak that their functioning should not be impacted.
- am__obj=conftest.${OBJEXT-o}
- am__minus_obj=
- ;;
- none) break ;;
- esac
- if depmode=$depmode \
- source=sub/conftest.c object=$am__obj \
- depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
- $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
- >/dev/null 2>conftest.err &&
- grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
- grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
- grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
- ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
- # icc doesn't choke on unknown options, it will just issue warnings
- # or remarks (even with -Werror). So we grep stderr for any message
- # that says an option was ignored or not supported.
- # When given -MP, icc 7.0 and 7.1 complain thusly:
- # icc: Command line warning: ignoring option '-M'; no argument required
- # The diagnosis changed in icc 8.0:
- # icc: Command line remark: option '-MP' not supported
- if (grep 'ignoring option' conftest.err ||
- grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
- am_cv_CC_dependencies_compiler_type=$depmode
- break
- fi
- fi
- done
-
- cd ..
- rm -rf conftest.dir
-else
- am_cv_CC_dependencies_compiler_type=none
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
-$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
-CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
-
- if
- test "x$enable_dependency_tracking" != xno \
- && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
- am__fastdepCC_TRUE=
- am__fastdepCC_FALSE='#'
-else
- am__fastdepCC_TRUE='#'
- am__fastdepCC_FALSE=
-fi
-
-
-
-# POSIX will say in a future version that running "rm -f" with no argument
-# is OK; and we want to be able to make that assumption in our Makefile
-# recipes. So use an aggressive probe to check that the usage we want is
-# actually supported "in the wild" to an acceptable degree.
-# See automake bug#10828.
-# To make any issue more visible, cause the running configure to be aborted
-# by default if the 'rm' program in use doesn't match our expectations; the
-# user can still override this though.
-if rm -f && rm -fr && rm -rf; then : OK; else
- cat >&2 <<'END'
-Oops!
-
-Your 'rm' program seems unable to run without file operands specified
-on the command line, even when the '-f' option is present. This is contrary
-to the behaviour of most rm programs out there, and not conforming with
-the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
-
-Please tell bug-automake@gnu.org about your system, including the value
-of your $PATH and any error possibly output before this message. This
-can help us improve future automake versions.
-
-END
- if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
- echo 'Configuration will proceed anyway, since you have set the' >&2
- echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
- echo >&2
- else
- cat >&2 <<'END'
-Aborting the configuration process, to ensure you take notice of the issue.
-
-You can download and install GNU coreutils to get an 'rm' implementation
-that behaves properly: <http://www.gnu.org/software/coreutils/>.
-
-If you want to complete the configuration process using your problematic
-'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
-to "yes", and re-run configure.
-
-END
- as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
- fi
-fi
-
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
@@ -4658,7 +3317,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4698,7 +3357,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4751,7 +3410,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4792,7 +3451,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
@@ -4850,7 +3509,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4894,7 +3553,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4964,6 +3623,256 @@ $as_echo "$ac_try_echo"; } >&5
test $ac_status = 0; }
done
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
if ${ac_cv_c_compiler_gnu+:} false; then :
@@ -5090,7 +3999,8 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdio.h>
-struct stat;
+#include <sys/types.h>
+#include <sys/stat.h>
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -5174,64 +4084,196 @@ ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
-if ${am_cv_prog_cc_c_o+:} false; then :
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
$as_echo_n "(cached) " >&6
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
-int
-main ()
-{
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
- ;
- return 0;
-}
-_ACEOF
- # Make sure it works both with $CC and with simple cc.
- # Following AC_PROG_CC_C_O, we do the test twice because some
- # compilers refuse to overwrite an existing .o file with -o,
- # though they will create one.
- am_cv_prog_cc_c_o=yes
- for am_i in 1 2; do
- if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
- ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } \
- && test -f conftest2.$ac_objext; then
- : OK
- else
- am_cv_prog_cc_c_o=no
- break
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
fi
done
- rm -f core conftest*
- unset am_i
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-$as_echo "$am_cv_prog_cc_c_o" >&6; }
-if test "$am_cv_prog_cc_c_o" != yes; then
- # Losing compiler, so override with the script.
- # FIXME: It is wrong to rewrite CC.
- # But if we don't then we get into trouble of one sort or another.
- # A longer-term fix would be to have automake use am__CC in this case,
- # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
- CC="$am_aux_dir/compile $CC"
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
@@ -5262,7 +4304,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5305,7 +4347,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5355,6 +4397,7 @@ $as_echo "no" >&6; }
PKG_CONFIG=""
fi
fi
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -5509,7 +4552,7 @@ do
for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
# Check for GNU ac_path_GREP and select it if it is found.
# Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
@@ -5575,7 +4618,7 @@ do
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
@@ -5782,8 +4825,8 @@ else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-# define __EXTENSIONS__ 1
- $ac_includes_default
+# define __EXTENSIONS__ 1
+ $ac_includes_default
int
main ()
{
@@ -5815,6 +4858,355 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+# -----------------------------------------------------------------------------
+# configurable options
+
+# Check whether --enable-plugin-nfacct was given.
+if test "${enable_plugin_nfacct+set}" = set; then :
+ enableval=$enable_plugin_nfacct;
+else
+ enable_plugin_nfacct="no"
+
+fi
+
+# Check whether --enable-plugin-freeipmi was given.
+if test "${enable_plugin_freeipmi+set}" = set; then :
+ enableval=$enable_plugin_freeipmi;
+else
+ enable_plugin_freeipmi="detect"
+
+fi
+
+# Check whether --enable-pedantic was given.
+if test "${enable_pedantic+set}" = set; then :
+ enableval=$enable_pedantic;
+else
+ enable_pedantic="no"
+
+fi
+
+
+# Check whether --with-webdir was given.
+if test "${with_webdir+set}" = set; then :
+ withval=$with_webdir; webdir="${withval}"
+else
+ webdir="\$(pkgdatadir)/web"
+
+fi
+
+
+# Check whether --with-libcap was given.
+if test "${with_libcap+set}" = set; then :
+ withval=$with_libcap;
+else
+ with_libcap="detect"
+
+fi
+
+
+# Check whether --with-zlib was given.
+if test "${with_zlib+set}" = set; then :
+ withval=$with_zlib;
+else
+ with_zlib="yes"
+
+fi
+
+
+# Check whether --with-math was given.
+if test "${with_math+set}" = set; then :
+ withval=$with_math;
+else
+ with_math="yes"
+
+fi
+
+
+# Check whether --with-user was given.
+if test "${with_user+set}" = set; then :
+ withval=$with_user;
+else
+ with_user="nobody"
+
+fi
+
+# Check whether --enable-x86-sse was given.
+if test "${enable_x86_sse+set}" = set; then :
+ enableval=$enable_x86_sse;
+else
+ enable_x86_sse="yes"
+
+fi
+
+# Check whether --enable-lto was given.
+if test "${enable_lto+set}" = set; then :
+ enableval=$enable_lto;
+else
+ enable_lto="detect"
+
+fi
+
+
+
+# -----------------------------------------------------------------------------
+# netdata required checks
+
+# fails on centos6
+#AX_CHECK_ENABLE_DEBUG()
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((returns_nonnull))" >&5
+$as_echo_n "checking for __attribute__((returns_nonnull))... " >&6; }
+if ${ax_cv_have_func_attribute_returns_nonnull+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ void *foo( void ) __attribute__((returns_nonnull));
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if test -s conftest.err; then :
+ ax_cv_have_func_attribute_returns_nonnull=no
+else
+ ax_cv_have_func_attribute_returns_nonnull=yes
+fi
+else
+ ax_cv_have_func_attribute_returns_nonnull=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_returns_nonnull" >&5
+$as_echo "$ax_cv_have_func_attribute_returns_nonnull" >&6; }
+
+ if test yes = $ax_cv_have_func_attribute_returns_nonnull; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((malloc))" >&5
+$as_echo_n "checking for __attribute__((malloc))... " >&6; }
+if ${ax_cv_have_func_attribute_malloc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ void *foo( void ) __attribute__((malloc));
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if test -s conftest.err; then :
+ ax_cv_have_func_attribute_malloc=no
+else
+ ax_cv_have_func_attribute_malloc=yes
+fi
+else
+ ax_cv_have_func_attribute_malloc=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_malloc" >&5
+$as_echo "$ax_cv_have_func_attribute_malloc" >&6; }
+
+ if test yes = $ax_cv_have_func_attribute_malloc; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FUNC_ATTRIBUTE_MALLOC 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((noreturn))" >&5
+$as_echo_n "checking for __attribute__((noreturn))... " >&6; }
+if ${ax_cv_have_func_attribute_noreturn+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ void foo( void ) __attribute__((noreturn));
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if test -s conftest.err; then :
+ ax_cv_have_func_attribute_noreturn=no
+else
+ ax_cv_have_func_attribute_noreturn=yes
+fi
+else
+ ax_cv_have_func_attribute_noreturn=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_noreturn" >&5
+$as_echo "$ax_cv_have_func_attribute_noreturn" >&6; }
+
+ if test yes = $ax_cv_have_func_attribute_noreturn; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FUNC_ATTRIBUTE_NORETURN 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((format))" >&5
+$as_echo_n "checking for __attribute__((format))... " >&6; }
+if ${ax_cv_have_func_attribute_format+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ int foo(const char *p, ...) __attribute__((format(printf, 1, 2)));
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if test -s conftest.err; then :
+ ax_cv_have_func_attribute_format=no
+else
+ ax_cv_have_func_attribute_format=yes
+fi
+else
+ ax_cv_have_func_attribute_format=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_format" >&5
+$as_echo "$ax_cv_have_func_attribute_format" >&6; }
+
+ if test yes = $ax_cv_have_func_attribute_format; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FUNC_ATTRIBUTE_FORMAT 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((warn_unused_result))" >&5
+$as_echo_n "checking for __attribute__((warn_unused_result))... " >&6; }
+if ${ax_cv_have_func_attribute_warn_unused_result+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ int foo( void ) __attribute__((warn_unused_result));
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if test -s conftest.err; then :
+ ax_cv_have_func_attribute_warn_unused_result=no
+else
+ ax_cv_have_func_attribute_warn_unused_result=yes
+fi
+else
+ ax_cv_have_func_attribute_warn_unused_result=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_func_attribute_warn_unused_result" >&5
+$as_echo "$ax_cv_have_func_attribute_warn_unused_result" >&6; }
+
+ if test yes = $ax_cv_have_func_attribute_warn_unused_result; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT 1
+_ACEOF
+
+fi
+
+
+
+
+
+
for ac_func in $ac_func_list
do :
@@ -5919,97 +5311,505 @@ _ACEOF
fi
done
+for ac_func in sched_setscheduler sched_get_priority_min sched_get_priority_max nice
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
-# Check system type
-case "$host_os" in
-freebsd*)
- build_target=freebsd
- ;;
-darwin*)
- build_target=macos
- LDFLAGS="${LDFLAGS} -framework CoreFoundation -framework IOKit"
- ;;
-*)
- ;;
+fi
+done
+
+
+ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t"
+case $ac_cv_c_int8_t in #(
+ no|yes) ;; #(
+ *)
+
+cat >>confdefs.h <<_ACEOF
+#define int8_t $ac_cv_c_int8_t
+_ACEOF
+;;
esac
- if test x$build_target = xfreebsd; then
- FREEBSD_TRUE=
- FREEBSD_FALSE='#'
+ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t"
+case $ac_cv_c_int16_t in #(
+ no|yes) ;; #(
+ *)
+
+cat >>confdefs.h <<_ACEOF
+#define int16_t $ac_cv_c_int16_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t"
+case $ac_cv_c_int32_t in #(
+ no|yes) ;; #(
+ *)
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t $ac_cv_c_int32_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t"
+case $ac_cv_c_int64_t in #(
+ no|yes) ;; #(
+ *)
+
+cat >>confdefs.h <<_ACEOF
+#define int64_t $ac_cv_c_int64_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
+case $ac_cv_c_uint8_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT8_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint8_t $ac_cv_c_uint8_t
+_ACEOF
+;;
+ esac
+
+ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
+case $ac_cv_c_uint16_t in #(
+ no|yes) ;; #(
+ *)
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t $ac_cv_c_uint16_t
+_ACEOF
+;;
+ esac
+
+ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
+case $ac_cv_c_uint32_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT32_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t $ac_cv_c_uint32_t
+_ACEOF
+;;
+ esac
+
+ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t"
+case $ac_cv_c_uint64_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT64_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint64_t $ac_cv_c_uint64_t
+_ACEOF
+;;
+ esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- FREEBSD_TRUE='#'
- FREEBSD_FALSE=
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
- if test x$build_target = xmacos; then
- MACOS_TRUE=
- MACOS_FALSE='#'
-else
- MACOS_TRUE='#'
- MACOS_FALSE=
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
-# Check whether --enable-plugin-nfacct was given.
-if test "${enable_plugin_nfacct+set}" = set; then :
- enableval=$enable_plugin_nfacct;
+ac_fn_c_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default"
+if test "x$ac_cv_have_decl_strerror_r" = xyes; then :
+ ac_have_decl=1
else
- enable_plugin_nfacct="no"
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRERROR_R $ac_have_decl
+_ACEOF
+
+for ac_func in strerror_r
+do :
+ ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r"
+if test "x$ac_cv_func_strerror_r" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRERROR_R 1
+_ACEOF
fi
+done
-# Check whether --enable-pedantic was given.
-if test "${enable_pedantic+set}" = set; then :
- enableval=$enable_pedantic;
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
+$as_echo_n "checking whether strerror_r returns char *... " >&6; }
+if ${ac_cv_func_strerror_r_char_p+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- enable_pedantic="no"
+
+ ac_cv_func_strerror_r_char_p=no
+ if test $ac_cv_have_decl_strerror_r = yes; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ char buf[100];
+ char x = *strerror_r (0, buf, sizeof buf);
+ char *p = strerror_r (0, buf, sizeof buf);
+ return !p || x;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_func_strerror_r_char_p=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ else
+ # strerror_r is not declared. Choose between
+ # systems that have relatively inaccessible declarations for the
+ # function. BeOS and DEC UNIX 4.0 fall in this category, but the
+ # former has a strerror_r that returns char*, while the latter
+ # has a strerror_r that returns `int'.
+ # This test should segfault on the DEC system.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+ extern char *strerror_r ();
+int
+main ()
+{
+char buf[100];
+ char x = *strerror_r (0, buf, sizeof buf);
+ return ! isalpha (x);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_strerror_r_char_p=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5
+$as_echo "$ac_cv_func_strerror_r_char_p" >&6; }
+if test $ac_cv_func_strerror_r_char_p = yes; then
+$as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h
-# Check whether --with-webdir was given.
-if test "${with_webdir+set}" = set; then :
- withval=$with_webdir; webdir="${withval}"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Generic" >&5
+$as_echo_n "checking for _Generic... " >&6; }
+if ${ac_cv_c__Generic+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- webdir="\$(pkgdatadir)/web"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int
+ main (int argc, char **argv)
+ {
+ int a = _Generic (argc, int: argc = 1);
+ int *b = &_Generic (argc, default: argc);
+ char ***c = _Generic (argv, int: argc, default: argv ? &argv : 0);
+ _Generic (1 ? 0 : b, int: a, default: b) = &argc;
+ _Generic (a = 1, default: a) = 3;
+ return a + !b + !c;
+ }
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c__Generic=yes
+else
+ ac_cv_c__Generic=no
fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c__Generic" >&5
+$as_echo "$ac_cv_c__Generic" >&6; }
+if test $ac_cv_c__Generic = yes; then
+$as_echo "#define HAVE_C__GENERIC 1" >>confdefs.h
-# Check whether --with-zlib was given.
-if test "${with_zlib+set}" = set; then :
- withval=$with_zlib;
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic" >&5
+$as_echo_n "checking for __atomic... " >&6; }
+if ${ac_cv_c___atomic+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- with_zlib="yes"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int
+ main (int argc, char **argv)
+ {
+ volatile unsigned long ul1 = 1, ul2 = 0, ul3 = 2;
+ __atomic_compare_exchange(&ul1, &ul2, &ul3, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&ul1, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_sub(&ul3, 1, __ATOMIC_SEQ_CST);
+ volatile unsigned long long ull1 = 1, ull2 = 0, ull3 = 2;
+ __atomic_compare_exchange(&ull1, &ull2, &ull3, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&ull1, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_sub(&ull3, 1, __ATOMIC_SEQ_CST);
+ return 0;
+ }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_c___atomic=yes
+else
+ ac_cv_c___atomic=no
fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c___atomic" >&5
+$as_echo "$ac_cv_c___atomic" >&6; }
+if test $ac_cv_c___atomic = yes; then
+$as_echo "#define HAVE_C___ATOMIC 1" >>confdefs.h
-# Check whether --with-math was given.
-if test "${with_math+set}" = set; then :
- withval=$with_math;
+fi
+
+# AC_C_STMT_EXPR
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
+$as_echo_n "checking size of void *... " >&6; }
+if ${ac_cv_sizeof_void_p+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- with_math="yes"
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then :
+else
+ if test "$ac_cv_type_void_p" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (void *)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_void_p=0
+ fi
fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
+$as_echo "$ac_cv_sizeof_void_p" >&6; }
-# Check whether --with-user was given.
-if test "${with_user+set}" = set; then :
- withval=$with_user;
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5
+$as_echo_n "checking whether sys/types.h defines makedev... " >&6; }
+if ${ac_cv_header_sys_types_h_makedev+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- with_user="nobody"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main ()
+{
+return makedev(0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_header_sys_types_h_makedev=yes
+else
+ ac_cv_header_sys_types_h_makedev=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5
+$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; }
-# Check whether --enable-x86-sse was given.
-if test "${enable_x86_sse+set}" = set; then :
- enableval=$enable_x86_sse;
+if test $ac_cv_header_sys_types_h_makedev = no; then
+ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mkdev_h" = xyes; then :
+
+$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h
+
+fi
+
+
+
+ if test $ac_cv_header_sys_mkdev_h = no; then
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then :
+
+$as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h
+
+fi
+
+
+ fi
+fi
+
+for ac_header in sys/types.h netinet/in.h arpa/nameser.h netdb.h resolv.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h> /* inet_ functions / structs */
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h> /* DNS HEADER struct */
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+ for ac_header in $ac_header_list
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+# -----------------------------------------------------------------------------
+# operating system detection
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking operating system" >&5
+$as_echo_n "checking operating system... " >&6; }
+case "$host_os" in
+freebsd*)
+ build_target=freebsd
+ ;;
+darwin*)
+ build_target=macos
+ LDFLAGS="${LDFLAGS} -framework CoreFoundation -framework IOKit"
+ ;;
+*)
+ build_target=linux
+ ;;
+esac
+
+ if test "${build_target}" = "freebsd"; then
+ FREEBSD_TRUE=
+ FREEBSD_FALSE='#'
else
- enable_x86_sse="yes"
+ FREEBSD_TRUE='#'
+ FREEBSD_FALSE=
+fi
+ if test "${build_target}" = "macos"; then
+ MACOS_TRUE=
+ MACOS_FALSE='#'
+else
+ MACOS_TRUE='#'
+ MACOS_FALSE=
+fi
+
+ if test "${build_target}" = "linux"; then
+ LINUX_TRUE=
+ LINUX_FALSE='#'
+else
+ LINUX_TRUE='#'
+ LINUX_FALSE=
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${build_target}" >&5
+$as_echo "${build_target}" >&6; }
+
+
+# -----------------------------------------------------------------------------
+# pthreads
@@ -6182,7 +5982,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ax_pthread_config="yes"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6374,7 +6174,7 @@ fi
#handle absolute path differently from PATH based program lookup
case "x$CC" in #(
x/*) :
- if as_fn_executable_p ${CC}_r; then :
+ if { test -f ${CC}_r && $as_test_x ${CC}_r; }; then :
PTHREAD_CC="${CC}_r"
fi ;; #(
*) :
@@ -6396,7 +6196,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_PTHREAD_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6458,6 +6258,338 @@ CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}"
CC="${PTHREAD_CC}"
+# -----------------------------------------------------------------------------
+# libm
+
+
+
+if test -z "${MATH_LIBS}"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5
+$as_echo_n "checking for sin in -lm... " >&6; }
+if ${ac_cv_lib_m_sin+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sin ();
+int
+main ()
+{
+return sin ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_sin=yes
+else
+ ac_cv_lib_m_sin=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5
+$as_echo "$ac_cv_lib_m_sin" >&6; }
+if test "x$ac_cv_lib_m_sin" = xyes; then :
+ MATH_LIBS="-lm"
+
+fi
+
+fi
+test "${with_math}" = "yes" -a -z "${MATH_LIBS}" && as_fn_error $? "math required but not found" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libm should be used" >&5
+$as_echo_n "checking if libm should be used... " >&6; }
+if test "${with_math}" != "no" -a ! -z "${MATH_LIBS}"; then
+ with_math="yes"
+
+$as_echo "#define STORAGE_WITH_MATH 1" >>confdefs.h
+
+ OPTIONAL_MATH_CFLAGS="${MATH_CFLAGS}"
+ OPTIONAL_MATH_LIBS="${MATH_LIBS}"
+else
+ with_math="no"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_math}" >&5
+$as_echo "${with_math}" >&6; }
+
+
+# -----------------------------------------------------------------------------
+# zlib
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZLIB" >&5
+$as_echo_n "checking for ZLIB... " >&6; }
+
+if test -n "$ZLIB_CFLAGS"; then
+ pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "zlib") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$ZLIB_LIBS"; then
+ pkg_cv_ZLIB_LIBS="$ZLIB_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "zlib") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1`
+ else
+ ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$ZLIB_PKG_ERRORS" >&5
+
+ have_zlib=no
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_zlib=no
+
+else
+ ZLIB_CFLAGS=$pkg_cv_ZLIB_CFLAGS
+ ZLIB_LIBS=$pkg_cv_ZLIB_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ have_zlib=yes
+fi
+test "${with_zlib}" = "yes" -a "${have_zlib}" != "yes" && as_fn_error $? "zlib required but not found. Try installing 'zlib1g-dev' or 'zlib-devel'." "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if zlib should be used" >&5
+$as_echo_n "checking if zlib should be used... " >&6; }
+if test "${with_zlib}" != "no" -a "${have_zlib}" = "yes"; then
+ with_zlib="yes"
+
+$as_echo "#define NETDATA_WITH_ZLIB 1" >>confdefs.h
+
+ OPTIONAL_ZLIB_CLFAGS="${ZLIB_CFLAGS}"
+ OPTIONAL_ZLIB_LIBS="${ZLIB_LIBS}"
+else
+ with_zlib="no"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_zlib}" >&5
+$as_echo "${with_zlib}" >&6; }
+
+
+# -----------------------------------------------------------------------------
+# libuuid
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UUID" >&5
+$as_echo_n "checking for UUID... " >&6; }
+
+if test -n "$UUID_CFLAGS"; then
+ pkg_cv_UUID_CFLAGS="$UUID_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "uuid") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_UUID_CFLAGS=`$PKG_CONFIG --cflags "uuid" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$UUID_LIBS"; then
+ pkg_cv_UUID_LIBS="$UUID_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "uuid") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_UUID_LIBS=`$PKG_CONFIG --libs "uuid" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ UUID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "uuid" 2>&1`
+ else
+ UUID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "uuid" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$UUID_PKG_ERRORS" >&5
+
+ as_fn_error $? "libuuid required but not found. Try installing 'uuid-dev' or 'libuuid-devel'." "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "libuuid required but not found. Try installing 'uuid-dev' or 'libuuid-devel'." "$LINENO" 5
+
+else
+ UUID_CFLAGS=$pkg_cv_UUID_CFLAGS
+ UUID_LIBS=$pkg_cv_UUID_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ have_uuid=yes
+fi
+
+$as_echo "#define NETDATA_WITH_UUID 1" >>confdefs.h
+
+OPTIONAL_UUID_CLFAGS="${UUID_CFLAGS}"
+OPTIONAL_UUID_LIBS="${UUID_LIBS}"
+
+
+# -----------------------------------------------------------------------------
+# compiler options
+
+
+case $host_cpu in #(
+ i?86) :
+ SSE_CANDIDATE="yes"
+ ;; #(
+ *) :
+ ;;
+esac
+
+if test "${SSE_CANDIDATE}" = "yes" -a "${enable_x86_sse}" = "yes"; then
+ opt="-msse2 -mfpmath=sse"
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__${opt}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts ${opt}" >&5
+$as_echo_n "checking whether C compiler accepts ${opt}... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS ${opt}"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then :
+ CFLAGS="${CFLAGS} ${opt}"
+else
+ :
+fi
+
+fi
+
+if test "${GCC}" = "yes"; then
+
+cat >>confdefs.h <<_ACEOF
+#define likely(x) __builtin_expect(!!(x), 1)
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define unlikely(x) __builtin_expect(!!(x), 0)
+_ACEOF
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define likely(x) (x)
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define unlikely(x) (x)
+_ACEOF
+
+fi
+
+if test "${enable_pedantic}" = "yes"; then
+ enable_strict="yes"
+ CFLAGS="${CFLAGS} -pedantic -Wall -Wextra -Wno-long-long"
+fi
+
+
+# -----------------------------------------------------------------------------
+# memory allocation library
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for memory allocator" >&5
+$as_echo_n "checking for memory allocator... " >&6; }
+
# Check whether --with-jemalloc-prefix was given.
if test "${with_jemalloc_prefix+set}" = set; then :
@@ -6598,6 +6730,8 @@ if test "$has_jemalloc" = "1"; then
$as_echo "#define ENABLE_JEMALLOC 1" >>confdefs.h
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: jemalloc" >&5
+$as_echo "jemalloc" >&6; }
else
@@ -6686,12 +6820,16 @@ fi
- if test "$has_tcmalloc" = "1"; then
+ if test "$has_tcmalloc" = "1"; then
$as_echo "#define ENABLE_TCMALLOC 1" >>confdefs.h
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mallopt" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: tcmalloc" >&5
+$as_echo "tcmalloc" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5
+$as_echo "system" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mallopt" >&5
$as_echo_n "checking for mallopt... " >&6; }
if ${ac_cv_c_mallopt+:} false; then :
$as_echo_n "(cached) " >&6
@@ -6720,7 +6858,7 @@ $as_echo "#define HAVE_C_MALLOPT 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mallinfo" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mallinfo" >&5
$as_echo_n "checking for mallinfo... " >&6; }
if ${ac_cv_c_mallinfo+:} false; then :
$as_echo_n "(cached) " >&6
@@ -6759,478 +6897,202 @@ $as_echo "#define HAVE_C_MALLINFO 1" >>confdefs.h
fi
- fi
+ fi
fi
-ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
-case $ac_cv_c_uint8_t in #(
- no|yes) ;; #(
- *)
-
-$as_echo "#define _UINT8_T 1" >>confdefs.h
-
-
-cat >>confdefs.h <<_ACEOF
-#define uint8_t $ac_cv_c_uint8_t
-_ACEOF
-;;
- esac
-
-ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
-case $ac_cv_c_uint16_t in #(
- no|yes) ;; #(
- *)
-
-
-cat >>confdefs.h <<_ACEOF
-#define uint16_t $ac_cv_c_uint16_t
-_ACEOF
-;;
- esac
-ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
-case $ac_cv_c_uint32_t in #(
- no|yes) ;; #(
- *)
-
-$as_echo "#define _UINT32_T 1" >>confdefs.h
+# -----------------------------------------------------------------------------
+# libcap
-cat >>confdefs.h <<_ACEOF
-#define uint32_t $ac_cv_c_uint32_t
-_ACEOF
-;;
- esac
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBCAP" >&5
+$as_echo_n "checking for LIBCAP... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
-$as_echo_n "checking for inline... " >&6; }
-if ${ac_cv_c_inline+:} false; then :
- $as_echo_n "(cached) " >&6
+if test -n "$LIBCAP_CFLAGS"; then
+ pkg_cv_LIBCAP_CFLAGS="$LIBCAP_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcap\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libcap") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBCAP_CFLAGS=`$PKG_CONFIG --cflags "libcap" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
else
- ac_cv_c_inline=no
-for ac_kw in inline __inline__ __inline; do
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifndef __cplusplus
-typedef int foo_t;
-static $ac_kw foo_t static_foo () {return 0; }
-$ac_kw foo_t foo () {return 0; }
-#endif
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_c_inline=$ac_kw
+ pkg_failed=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- test "$ac_cv_c_inline" != no && break
-done
-
+ else
+ pkg_failed=untried
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
-$as_echo "$ac_cv_c_inline" >&6; }
-
-case $ac_cv_c_inline in
- inline | yes) ;;
- *)
- case $ac_cv_c_inline in
- no) ac_val=;;
- *) ac_val=$ac_cv_c_inline;;
- esac
- cat >>confdefs.h <<_ACEOF
-#ifndef __cplusplus
-#define inline $ac_val
-#endif
-_ACEOF
- ;;
-esac
-
-ac_fn_c_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default"
-if test "x$ac_cv_have_decl_strerror_r" = xyes; then :
- ac_have_decl=1
+if test -n "$LIBCAP_LIBS"; then
+ pkg_cv_LIBCAP_LIBS="$LIBCAP_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcap\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libcap") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBCAP_LIBS=`$PKG_CONFIG --libs "libcap" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
else
- ac_have_decl=0
+ pkg_failed=yes
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_STRERROR_R $ac_have_decl
-_ACEOF
-
-for ac_func in strerror_r
-do :
- ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r"
-if test "x$ac_cv_func_strerror_r" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STRERROR_R 1
-_ACEOF
-
+ else
+ pkg_failed=untried
fi
-done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
-$as_echo_n "checking whether strerror_r returns char *... " >&6; }
-if ${ac_cv_func_strerror_r_char_p+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_func_strerror_r_char_p=no
- if test $ac_cv_have_decl_strerror_r = yes; then
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_includes_default
-int
-main ()
-{
- char buf[100];
- char x = *strerror_r (0, buf, sizeof buf);
- char *p = strerror_r (0, buf, sizeof buf);
- return !p || x;
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_func_strerror_r_char_p=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- else
- # strerror_r is not declared. Choose between
- # systems that have relatively inaccessible declarations for the
- # function. BeOS and DEC UNIX 4.0 fall in this category, but the
- # former has a strerror_r that returns char*, while the latter
- # has a strerror_r that returns `int'.
- # This test should segfault on the DEC system.
- if test "$cross_compiling" = yes; then :
- :
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_includes_default
- extern char *strerror_r ();
-int
-main ()
-{
-char buf[100];
- char x = *strerror_r (0, buf, sizeof buf);
- return ! isalpha (x);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- ac_cv_func_strerror_r_char_p=yes
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- fi
-
+ _pkg_short_errors_supported=no
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5
-$as_echo "$ac_cv_func_strerror_r_char_p" >&6; }
-if test $ac_cv_func_strerror_r_char_p = yes; then
-
-$as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h
+ if test $_pkg_short_errors_supported = yes; then
+ LIBCAP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcap" 2>&1`
+ else
+ LIBCAP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcap" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBCAP_PKG_ERRORS" >&5
-fi
+ have_libcap=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Generic" >&5
-$as_echo_n "checking for _Generic... " >&6; }
-if ${ac_cv_c__Generic+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int
- main (int argc, char **argv)
- {
- int a = _Generic (argc, int: argc = 1);
- int *b = &_Generic (argc, default: argc);
- char ***c = _Generic (argv, int: argc, default: argv ? &argv : 0);
- _Generic (1 ? 0 : b, int: a, default: b) = &argc;
- _Generic (a = 1, default: a) = 3;
- return a + !b + !c;
- }
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_libcap=no
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_c__Generic=yes
else
- ac_cv_c__Generic=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c__Generic" >&5
-$as_echo "$ac_cv_c__Generic" >&6; }
-if test $ac_cv_c__Generic = yes; then
-
-$as_echo "#define HAVE_C__GENERIC 1" >>confdefs.h
-
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic" >&5
-$as_echo_n "checking for __atomic... " >&6; }
-if ${ac_cv_c___atomic+:} false; then :
+ LIBCAP_CFLAGS=$pkg_cv_LIBCAP_CFLAGS
+ LIBCAP_LIBS=$pkg_cv_LIBCAP_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc, cap_set_proc in -lcap" >&5
+$as_echo_n "checking for cap_get_proc, cap_set_proc in -lcap... " >&6; }
+if ${ac_cv_lib_cap_cap_get_proc__cap_set_proc+:} false; then :
$as_echo_n "(cached) " >&6
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-int
- main (int argc, char **argv)
- {
- volatile unsigned long ul1 = 1, ul2 = 0, ul3 = 2;
- __atomic_compare_exchange(&ul1, &ul2, &ul3, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
- __atomic_fetch_add(&ul1, 1, __ATOMIC_SEQ_CST);
- __atomic_fetch_sub(&ul3, 1, __ATOMIC_SEQ_CST);
- volatile unsigned long long ull1 = 1, ull2 = 0, ull3 = 2;
- __atomic_compare_exchange(&ull1, &ull2, &ull3, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
- __atomic_fetch_add(&ull1, 1, __ATOMIC_SEQ_CST);
- __atomic_fetch_sub(&ull3, 1, __ATOMIC_SEQ_CST);
- return 0;
- }
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_c___atomic=yes
-else
- ac_cv_c___atomic=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c___atomic" >&5
-$as_echo "$ac_cv_c___atomic" >&6; }
-if test $ac_cv_c___atomic = yes; then
-
-$as_echo "#define HAVE_C___ATOMIC 1" >>confdefs.h
-
-fi
-
-# AC_C_STMT_EXPR
-# The cast to long int works around a bug in the HP C Compiler
-# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
-# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
-$as_echo_n "checking size of void *... " >&6; }
-if ${ac_cv_sizeof_void_p+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then :
-
-else
- if test "$ac_cv_type_void_p" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (void *)
-See \`config.log' for more details" "$LINENO" 5; }
- else
- ac_cv_sizeof_void_p=0
- fi
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
-$as_echo "$ac_cv_sizeof_void_p" >&6; }
-
-
-
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
-_ACEOF
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5
-$as_echo_n "checking whether sys/types.h defines makedev... " >&6; }
-if ${ac_cv_header_sys_types_h_makedev+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cap_get_proc, cap_set_proc ();
int
main ()
{
-return makedev(0, 0);
+return cap_get_proc, cap_set_proc ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_header_sys_types_h_makedev=yes
+ ac_cv_lib_cap_cap_get_proc__cap_set_proc=yes
else
- ac_cv_header_sys_types_h_makedev=no
+ ac_cv_lib_cap_cap_get_proc__cap_set_proc=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
-
+LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5
-$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; }
-
-if test $ac_cv_header_sys_types_h_makedev = no; then
-ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_mkdev_h" = xyes; then :
-
-$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_get_proc__cap_set_proc" >&5
+$as_echo "$ac_cv_lib_cap_cap_get_proc__cap_set_proc" >&6; }
+if test "x$ac_cv_lib_cap_cap_get_proc__cap_set_proc" = xyes; then :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_capability_h" = xyes; then :
+ have_libcap=yes
+else
+ have_libcap=no
fi
+else
+ have_libcap=no
- if test $ac_cv_header_sys_mkdev_h = no; then
- ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then :
-
-$as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h
-
-fi
-
-
- fi
fi
-for ac_header in sys/types.h netinet/in.h arpa/nameser.h netdb.h resolv.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h> /* inet_ functions / structs */
-#endif
-#ifdef HAVE_ARPA_NAMESER_H
-# include <arpa/nameser.h> /* DNS HEADER struct */
-#endif
-#ifdef HAVE_NETDB_H
-# include <netdb.h>
-#endif
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
fi
+test "${with_libcap}" = "yes" -a "${have_libcap}" != "yes" && as_fn_error $? "libcap required but not found." "$LINENO" 5
-done
-
-
-
-
-case $host_cpu in #(
- i?86) :
- SSE_CANDIDATE="yes"
- ;; #(
- *) :
- ;;
-esac
-
-if test "${SSE_CANDIDATE}" = "yes" -a "${enable_x86_sse}" = "yes"; then
- opt="-msse2 -mfpmath=sse"
- as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$opt" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $opt" >&5
-$as_echo_n "checking whether C compiler accepts $opt... " >&6; }
-if eval \${$as_CACHEVAR+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- ax_check_save_flags=$CFLAGS
- CFLAGS="$CFLAGS $opt"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libcap should be used" >&5
+$as_echo_n "checking if libcap should be used... " >&6; }
+if test "${with_libcap}" != "no" -a "${have_libcap}" = "yes"; then
+ with_libcap="yes"
-int
-main ()
-{
+$as_echo "#define HAVE_CAPABILITY 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- eval "$as_CACHEVAR=yes"
+ OPTIONAL_LIBCAP_CLFAGS="${LIBCAP_CFLAGS}"
+ OPTIONAL_LIBCAP_LIBS="${LIBCAP_LIBS}"
else
- eval "$as_CACHEVAR=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- CFLAGS=$ax_check_save_flags
+ with_libcap="no"
fi
-eval ac_res=\$$as_CACHEVAR
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then :
- CFLAGS="$CFLAGS $opt"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_libcap}" >&5
+$as_echo "${with_libcap}" >&6; }
+ if test "${with_libcap}" = "yes"; then
+ ENABLE_CAPABILITY_TRUE=
+ ENABLE_CAPABILITY_FALSE='#'
else
- :
-fi
-
+ ENABLE_CAPABILITY_TRUE='#'
+ ENABLE_CAPABILITY_FALSE=
fi
-if test -z "${MATH_LIBS}"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5
-$as_echo_n "checking for sin in -lm... " >&6; }
-if ${ac_cv_lib_m_sin+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lm $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+# -----------------------------------------------------------------------------
+# apps.plugin
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sin ();
-int
-main ()
-{
-return sin ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_m_sin=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if apps.plugin should be enabled" >&5
+$as_echo_n "checking if apps.plugin should be enabled... " >&6; }
+if test "${build_target}" != "macos"; then
+ enable_plugin_apps="yes"
else
- ac_cv_lib_m_sin=no
+ enable_plugin_apps="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_plugin_apps}" >&5
+$as_echo "${enable_plugin_apps}" >&6; }
+ if test "${enable_plugin_apps}" = "yes"; then
+ ENABLE_PLUGIN_APPS_TRUE=
+ ENABLE_PLUGIN_APPS_FALSE='#'
+else
+ ENABLE_PLUGIN_APPS_TRUE='#'
+ ENABLE_PLUGIN_APPS_FALSE=
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5
-$as_echo "$ac_cv_lib_m_sin" >&6; }
-if test "x$ac_cv_lib_m_sin" = xyes; then :
- MATH_LIBS="-lm"
-fi
-fi
+
+# -----------------------------------------------------------------------------
+# freeipmi.plugin - libipmimonitoring
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UUID" >&5
-$as_echo_n "checking for UUID... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for IPMIMONITORING" >&5
+$as_echo_n "checking for IPMIMONITORING... " >&6; }
-if test -n "$UUID_CFLAGS"; then
- pkg_cv_UUID_CFLAGS="$UUID_CFLAGS"
+if test -n "$IPMIMONITORING_CFLAGS"; then
+ pkg_cv_IPMIMONITORING_CFLAGS="$IPMIMONITORING_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5
- ($PKG_CONFIG --exists --print-errors "uuid") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libipmimonitoring\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libipmimonitoring") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_UUID_CFLAGS=`$PKG_CONFIG --cflags "uuid" 2>/dev/null`
+ pkg_cv_IPMIMONITORING_CFLAGS=`$PKG_CONFIG --cflags "libipmimonitoring" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -7238,16 +7100,16 @@ fi
else
pkg_failed=untried
fi
-if test -n "$UUID_LIBS"; then
- pkg_cv_UUID_LIBS="$UUID_LIBS"
+if test -n "$IPMIMONITORING_LIBS"; then
+ pkg_cv_IPMIMONITORING_LIBS="$IPMIMONITORING_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5
- ($PKG_CONFIG --exists --print-errors "uuid") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libipmimonitoring\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libipmimonitoring") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_UUID_LIBS=`$PKG_CONFIG --libs "uuid" 2>/dev/null`
+ pkg_cv_IPMIMONITORING_LIBS=`$PKG_CONFIG --libs "libipmimonitoring" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -7268,53 +7130,61 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- UUID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "uuid" 2>&1`
+ IPMIMONITORING_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libipmimonitoring" 2>&1`
else
- UUID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "uuid" 2>&1`
+ IPMIMONITORING_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libipmimonitoring" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
- echo "$UUID_PKG_ERRORS" >&5
-
- as_fn_error $? "Package requirements (uuid) were not met:
+ echo "$IPMIMONITORING_PKG_ERRORS" >&5
-$UUID_PKG_ERRORS
+ have_ipmimonitoring=no
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables UUID_CFLAGS
-and UUID_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables UUID_CFLAGS
-and UUID_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
+ have_ipmimonitoring=no
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details" "$LINENO" 5; }
else
- UUID_CFLAGS=$pkg_cv_UUID_CFLAGS
- UUID_LIBS=$pkg_cv_UUID_LIBS
+ IPMIMONITORING_CFLAGS=$pkg_cv_IPMIMONITORING_CFLAGS
+ IPMIMONITORING_LIBS=$pkg_cv_IPMIMONITORING_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ have_ipmimonitoring=yes
+fi
+test "${enable_plugin_freeipmi}" = "yes" -a "${have_ipmimonitoring}" != "yes" && \
+ as_fn_error $? "ipmimonitoring required but not found. Try installing 'libipmimonitoring-dev' or 'libipmimonitoring-devel'" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if freeipmi.plugin should be enabled" >&5
+$as_echo_n "checking if freeipmi.plugin should be enabled... " >&6; }
+if test "${enable_plugin_freeipmi}" != "no" -a "${have_ipmimonitoring}" = "yes"; then
+ enable_plugin_freeipmi="yes"
+$as_echo "#define HAVE_FREEIPMI 1" >>confdefs.h
+
+ OPTIONAL_IPMIMONITORING_CLFAGS="${IPMIMONITORING_CFLAGS}"
+ OPTIONAL_IPMIMONITORING_LIBS="${IPMIMONITORING_LIBS}"
+else
+ enable_plugin_freeipmi="no"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_plugin_freeipmi}" >&5
+$as_echo "${enable_plugin_freeipmi}" >&6; }
+ if test "${enable_plugin_freeipmi}" = "yes"; then
+ ENABLE_PLUGIN_FREEIPMI_TRUE=
+ ENABLE_PLUGIN_FREEIPMI_FALSE='#'
+else
+ ENABLE_PLUGIN_FREEIPMI_TRUE='#'
+ ENABLE_PLUGIN_FREEIPMI_FALSE=
fi
-test -z "${UUID_LIBS}" && as_fn_error $? "libuuid required but not found. Try installing 'uuid-dev' or 'libuuid-devel'." "$LINENO" 5
-$as_echo "#define NETDATA_WITH_UUID 1" >>confdefs.h
-OPTIONAL_UUID_CLFAGS="${UUID_CFLAGS}"
-OPTIONAL_UUID_LIBS="${UUID_LIBS}"
-if test "${enable_plugin_nfacct}" = "yes"; then
+# -----------------------------------------------------------------------------
+# nfacct.plugin - libmnl, libnetfilter_acct
+
+
+
+
+
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for NFACCT" >&5
@@ -7374,39 +7244,22 @@ fi
# Put the nasty error message in config.log where it belongs
echo "$NFACCT_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements (libnetfilter_acct) were not met:
-
-$NFACCT_PKG_ERRORS
+ have_libnetfilter_acct=no
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables NFACCT_CFLAGS
-and NFACCT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables NFACCT_CFLAGS
-and NFACCT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
+ have_libnetfilter_acct=no
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details" "$LINENO" 5; }
else
NFACCT_CFLAGS=$pkg_cv_NFACCT_CFLAGS
NFACCT_LIBS=$pkg_cv_NFACCT_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
-
+ have_libnetfilter_acct=yes
fi
+
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBMNL" >&5
$as_echo_n "checking for LIBMNL... " >&6; }
@@ -7465,182 +7318,157 @@ fi
# Put the nasty error message in config.log where it belongs
echo "$LIBMNL_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements (libmnl) were not met:
+ have_libmnl=no
-$LIBMNL_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables LIBMNL_CFLAGS
-and LIBMNL_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
+ have_libmnl=no
-Alternatively, you may set the environment variables LIBMNL_CFLAGS
-and LIBMNL_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details" "$LINENO" 5; }
else
LIBMNL_CFLAGS=$pkg_cv_LIBMNL_CFLAGS
LIBMNL_LIBS=$pkg_cv_LIBMNL_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
-
+ have_libmnl=yes
fi
- test -z "${NFACCT_LIBS}" && as_fn_error $? "netfilter_acct required but not found" "$LINENO" 5
- test -z "${LIBMNL_LIBS}" && as_fn_error $? "libmnl required but not found. Try installing 'libmnl-dev' or 'libmnl-devel'" "$LINENO" 5
-$as_echo "#define INTERNAL_PLUGIN_NFACCT 1" >>confdefs.h
+test "${enable_plugin_nfacct}" = "yes" -a "${have_libnetfilter_acct}" != "yes" && \
+ as_fn_error $? "netfilter_acct required but not found" "$LINENO" 5
- OPTIONAL_NFACCT_CLFAGS="${NFACCT_CFLAGS} ${LIBMNL_CFLAGS}"
- OPTIONAL_NFACCT_LIBS="${NFACCT_LIBS} ${LIBMNL_LIBS}"
-fi
-if test "${with_zlib}" = "yes"; then
+test "${enable_plugin_nfacct}" = "yes" -a "${have_libmnl}" != "yes" && \
+ as_fn_error $? "libmnl required but not found. Try installing 'libmnl-dev' or 'libmnl-devel'" "$LINENO" 5
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZLIB" >&5
-$as_echo_n "checking for ZLIB... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if nfacct.plugin should be enabled" >&5
+$as_echo_n "checking if nfacct.plugin should be enabled... " >&6; }
+if test "${enable_plugin_nfacct}" != "no" -a "${have_libnetfilter_acct}" = "yes" -a "${have_libmnl}" = "yes"; then
+ enable_plugin_nfacct="yes"
-if test -n "$ZLIB_CFLAGS"; then
- pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5
- ($PKG_CONFIG --exists --print-errors "zlib") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
-else
- pkg_failed=yes
-fi
- else
- pkg_failed=untried
-fi
-if test -n "$ZLIB_LIBS"; then
- pkg_cv_ZLIB_LIBS="$ZLIB_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5
- ($PKG_CONFIG --exists --print-errors "zlib") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
-else
- pkg_failed=yes
-fi
- else
- pkg_failed=untried
-fi
+$as_echo "#define HAVE_LIBMNL 1" >>confdefs.h
+$as_echo "#define HAVE_LIBNETFILTER_ACCT 1" >>confdefs.h
-if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
+$as_echo "#define INTERNAL_PLUGIN_NFACCT 1" >>confdefs.h
+
+ OPTIONAL_NFACCT_CLFAGS="${NFACCT_CFLAGS} ${LIBMNL_CFLAGS}"
+ OPTIONAL_NFACCT_LIBS="${NFACCT_LIBS} ${LIBMNL_LIBS}"
else
- _pkg_short_errors_supported=no
+ enable_plugin_nfacct="no"
fi
- if test $_pkg_short_errors_supported = yes; then
- ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1`
- else
- ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
- echo "$ZLIB_PKG_ERRORS" >&5
-
- as_fn_error $? "Package requirements (zlib) were not met:
-
-$ZLIB_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables ZLIB_CFLAGS
-and ZLIB_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details." "$LINENO" 5
-elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables ZLIB_CFLAGS
-and ZLIB_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details" "$LINENO" 5; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_plugin_nfacct}" >&5
+$as_echo "${enable_plugin_nfacct}" >&6; }
+ if test "${enable_plugin_nfacct}" = "yes"; then
+ ENABLE_PLUGIN_NFACCT_TRUE=
+ ENABLE_PLUGIN_NFACCT_FALSE='#'
else
- ZLIB_CFLAGS=$pkg_cv_ZLIB_CFLAGS
- ZLIB_LIBS=$pkg_cv_ZLIB_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
+ ENABLE_PLUGIN_NFACCT_TRUE='#'
+ ENABLE_PLUGIN_NFACCT_FALSE=
fi
- test -z "${ZLIB_LIBS}" && as_fn_error $? "zlib required but not found. Try installing 'zlib1g-dev' or 'zlib-devel'." "$LINENO" 5
-$as_echo "#define NETDATA_WITH_ZLIB 1" >>confdefs.h
- OPTIONAL_ZLIB_CLFAGS="${ZLIB_CFLAGS}"
- OPTIONAL_ZLIB_LIBS="${ZLIB_LIBS}"
-fi
-if test "${with_math}" = "yes"; then
- test -z "${MATH_LIBS}" && as_fn_error $? "math required but not found" "$LINENO" 5
-$as_echo "#define STORAGE_WITH_MATH 1" >>confdefs.h
-
- OPTIONAL_MATH_CFLAGS="${MATH_CFLAGS}"
- OPTIONAL_MATH_LIBS="${MATH_LIBS}"
-fi
+# -----------------------------------------------------------------------------
+# Link-Time-Optimization
-if test "${GCC}" = "yes"; then
+if test "${enable_lto}" != "no"; then
+ opt="-flto"
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__${opt}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts ${opt}" >&5
+$as_echo_n "checking whether C compiler accepts ${opt}... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
-cat >>confdefs.h <<_ACEOF
-#define likely(x) __builtin_expect(!!(x), 1)
-_ACEOF
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS ${opt}"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int
+main ()
+{
-cat >>confdefs.h <<_ACEOF
-#define unlikely(x) __builtin_expect(!!(x), 0)
+ ;
+ return 0;
+}
_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then :
+ have_lto=yes
+else
+ have_lto=no
+fi
+fi
+if test "${have_lto}" = "yes"; then
+ oCFLAGS="${CFLAGS}"
+ CFLAGS="${CFLAGS} -flto ${OPTIONAL_MATH_CLFAGS} ${OPTIONAL_NFACCT_CLFAGS} ${OPTIONAL_ZLIB_CLFAGS} ${OPTIONAL_UUID_CLFAGS} ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS}"
+ ac_cv_c_lto_cross_compile="${enable_lto}"
+ test "${ac_cv_c_lto_cross_compile}" != "yes" && ac_cv_c_lto_cross_compile="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -flto builds executables" >&5
+$as_echo_n "checking if -flto builds executables... " >&6; }
+if ${ac_cv_c_lto+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_c_lto=${ac_cv_c_lto_cross_compile}
else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+ int main(int argc, char **argv) {
+ return 0;
+ }
-cat >>confdefs.h <<_ACEOF
-#define likely(x) (x)
_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_lto=yes
+else
+ ac_cv_c_lto=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_lto" >&5
+$as_echo "$ac_cv_c_lto" >&6; }
+if test "${ac_cv_c_lto}" = "yes"; then
-cat >>confdefs.h <<_ACEOF
-#define unlikely(x) (x)
-_ACEOF
+$as_echo "#define HAVE_LTO 1" >>confdefs.h
fi
-if test "${enable_pedantic}" = "yes"; then
- enable_strict="yes"
- CFLAGS="${CFLAGS} -pedantic -Wall -Wextra -Wno-long-long"
+ CFLAGS="${oCFLAGS}"
+ test "${ac_cv_c_lto}" != "yes" && have_lto="no"
fi
+test "${enable_lto}" = "yes" -a "${have_lto}" != "yes" && \
+ as_fn_error $? "LTO is required but is not available." "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if LTO should be enabled" >&5
+$as_echo_n "checking if LTO should be enabled... " >&6; }
+if test "${enable_lto}" != "no" -a "${have_lto}" = "yes"; then
+ enable_lto="yes"
+ CFLAGS="${CFLAGS} -flto"
+else
+ enable_lto="no"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_lto}" >&5
+$as_echo "${enable_lto}" >&6; }
+
+
+# -----------------------------------------------------------------------------
cat >>confdefs.h <<_ACEOF
@@ -7677,6 +7505,10 @@ pluginsdir="\$(libexecdir)/netdata/plugins.d"
+
+
+
+
ac_config_files="$ac_config_files Makefile charts.d/Makefile conf.d/Makefile netdata.spec python.d/Makefile node.d/Makefile plugins.d/Makefile src/Makefile system/Makefile web/Makefile contrib/Makefile"
cat >confcache <<\_ACEOF
@@ -7792,22 +7624,6 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
-$as_echo_n "checking that generated files are newer than configure... " >&6; }
- if test -n "$am_sleep_pid"; then
- # Hide warnings about reused PIDs.
- wait $am_sleep_pid 2>/dev/null
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
-$as_echo "done" >&6; }
-if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
- as_fn_error $? "conditional \"AMDEP\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
- as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
if test -n "$EXEEXT"; then
am__EXEEXT_TRUE=
am__EXEEXT_FALSE='#'
@@ -7816,6 +7632,14 @@ else
am__EXEEXT_FALSE=
fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${FREEBSD_TRUE}" && test -z "${FREEBSD_FALSE}"; then
as_fn_error $? "conditional \"FREEBSD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -7824,6 +7648,26 @@ if test -z "${MACOS_TRUE}" && test -z "${MACOS_FALSE}"; then
as_fn_error $? "conditional \"MACOS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${LINUX_TRUE}" && test -z "${LINUX_FALSE}"; then
+ as_fn_error $? "conditional \"LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_CAPABILITY_TRUE}" && test -z "${ENABLE_CAPABILITY_FALSE}"; then
+ as_fn_error $? "conditional \"ENABLE_CAPABILITY\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_PLUGIN_APPS_TRUE}" && test -z "${ENABLE_PLUGIN_APPS_FALSE}"; then
+ as_fn_error $? "conditional \"ENABLE_PLUGIN_APPS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_PLUGIN_FREEIPMI_TRUE}" && test -z "${ENABLE_PLUGIN_FREEIPMI_FALSE}"; then
+ as_fn_error $? "conditional \"ENABLE_PLUGIN_FREEIPMI\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_PLUGIN_NFACCT_TRUE}" && test -z "${ENABLE_PLUGIN_NFACCT_FALSE}"; then
+ as_fn_error $? "conditional \"ENABLE_PLUGIN_NFACCT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
@@ -8122,16 +7966,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
+ # In both cases, we have to default to `cp -p'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@@ -8191,16 +8035,28 @@ else
as_mkdir_p=false
fi
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -8221,8 +8077,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by netdata $as_me 1.5.0, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+This file was extended by netdata $as_me 1.6.0, which was
+generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -8287,11 +8143,11 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-netdata config.status 1.5.0
-configured by $0, generated by GNU Autoconf 2.69,
+netdata config.status 1.6.0
+configured by $0, generated by GNU Autoconf 2.68,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -8382,7 +8238,7 @@ fi
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
@@ -9025,7 +8881,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
case $ac_file$ac_mode in
"depfiles":C) test x"$AMDEP_TRUE" != x"" || {
- # Older Autoconf quotes --file arguments for eval, but not when files
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
# are listed without --file. Let's play safe and only enable the eval
# if we detect the quoting.
case $CONFIG_FILES in
@@ -9038,7 +8894,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
# Strip MF so we end up with the name of the file.
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
- # We used to match only the files named 'Makefile.in', but
+ # We used to match only the files named `Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
@@ -9072,19 +8928,21 @@ $as_echo X"$mf" |
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
- # from the Makefile without running 'make'.
+ # from the Makefile without running `make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
- test -z "$am__include" && continue
+ test -z "am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
- sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`$as_dirname -- "$file" ||
@@ -9158,5 +9016,5 @@ fi
test "${with_math}" != "yes" && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You are building without math. math allows accurate calculations. It should be enabled." >&5
$as_echo "$as_me: WARNING: You are building without math. math allows accurate calculations. It should be enabled." >&2;} || :
-test "${with_zlib}" != "yes" && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You are building without zlib. zlib allows netdata to trasnfer a lot less data with web clients. It should be enabled." >&5
-$as_echo "$as_me: WARNING: You are building without zlib. zlib allows netdata to trasnfer a lot less data with web clients. It should be enabled." >&2;} || :
+test "${with_zlib}" != "yes" && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You are building without zlib. zlib allows netdata to transfer a lot less data with web clients. It should be enabled." >&5
+$as_echo "$as_me: WARNING: You are building without zlib. zlib allows netdata to transfer a lot less data with web clients. It should be enabled." >&2;} || :
diff --git a/configure.ac b/configure.ac
index d0a6ebd6f..2c83830ca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
AC_PREREQ(2.60)
define([VERSION_MAJOR], [1])
-define([VERSION_MINOR], [5])
+define([VERSION_MINOR], [6])
define([VERSION_FIX], [0])
define([VERSION_NUMBER], VERSION_MAJOR[.]VERSION_MINOR[.]VERSION_FIX)
define([VERSION_SUFFIX], [])
@@ -12,7 +12,11 @@ define([VERSION_SUFFIX], [])
dnl Set to "1" for a first RPM release of a new version
PACKAGE_RPM_RELEASE="1"
-AC_INIT([netdata], VERSION_NUMBER[]VERSION_SUFFIX)
+# We do not use m4_esyscmd_s to support older autoconf.
+define([VERSION_STRING], m4_esyscmd(git describe 2>/dev/null | sed 's/^v//' | tr -d '\n'))
+m4_ifval(VERSION_STRING, [], [define([VERSION_STRING], VERSION_NUMBER)])
+
+AC_INIT([netdata], VERSION_STRING[]VERSION_SUFFIX)
AM_MAINTAINER_MODE([disable])
if test x"$USE_MAINTAINER_MODE" = xyes; then
@@ -24,14 +28,9 @@ PACKAGE_RPM_VERSION="VERSION_NUMBER"
AC_SUBST([PACKAGE_RPM_VERSION])
AC_SUBST([PACKAGE_RPM_RELEASE])
-# fails on centos6
-#AX_CHECK_ENABLE_DEBUG()
-AX_GCC_FUNC_ATTRIBUTE(returns_nonnull)
-AX_GCC_FUNC_ATTRIBUTE(malloc)
-AX_GCC_FUNC_ATTRIBUTE(noreturn)
-AX_GCC_FUNC_ATTRIBUTE(format)
-AX_GCC_FUNC_ATTRIBUTE(warn_unused_result)
+# -----------------------------------------------------------------------------
+# autoconf initialization
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_HEADERS([config.h])
@@ -43,91 +42,99 @@ AC_PROG_CC
AC_PROG_INSTALL
PKG_PROG_PKG_CONFIG
AC_USE_SYSTEM_EXTENSIONS
-AC_CHECK_FUNCS_ONCE(accept4)
-AC_CHECK_TYPES([struct timespec, clockid_t], [], [], [[#include <time.h>]])
-AC_SEARCH_LIBS([clock_gettime], [rt posix4])
-AC_CHECK_FUNCS([clock_gettime])
-# Check system type
-case "$host_os" in
-freebsd*)
- build_target=freebsd
- ;;
-darwin*)
- build_target=macos
- LDFLAGS="${LDFLAGS} -framework CoreFoundation -framework IOKit"
- ;;
-*)
- ;;
-esac
-AM_CONDITIONAL([FREEBSD], [test x$build_target = xfreebsd])
-AM_CONDITIONAL([MACOS], [test x$build_target = xmacos])
+# -----------------------------------------------------------------------------
+# configurable options
AC_ARG_ENABLE(
- [plugin-nfacct],
- [AS_HELP_STRING([--enable-plugin-nfacct], [enable nfacct plugin, requires root])],
- ,
- [enable_plugin_nfacct="no"]
+ [plugin-nfacct],
+ [AS_HELP_STRING([--enable-plugin-nfacct], [enable nfacct plugin, requires root])],
+ ,
+ [enable_plugin_nfacct="no"]
+)
+AC_ARG_ENABLE(
+ [plugin-freeipmi],
+ [AS_HELP_STRING([--enable-plugin-freeipmi], [enable freeipmi plugin])],
+ ,
+ [enable_plugin_freeipmi="detect"]
)
AC_ARG_ENABLE(
- [pedantic],
- [AS_HELP_STRING([--enable-pedantic], [enable pedantic compiler warnings])],
- ,
- [enable_pedantic="no"]
+ [pedantic],
+ [AS_HELP_STRING([--enable-pedantic], [enable pedantic compiler warnings])],
+ ,
+ [enable_pedantic="no"]
+)
+AC_ARG_WITH(
+ [webdir],
+ [AS_HELP_STRING([--with-webdir], [location of webdir @<:@PKGDATADIR/web@:>@])],
+ [webdir="${withval}"],
+ [webdir="\$(pkgdatadir)/web"]
)
AC_ARG_WITH(
- [webdir],
- [AS_HELP_STRING([--with-webdir], [location of webdir @<:@PKGDATADIR/web@:>@])],
- [webdir="${withval}"],
- [webdir="\$(pkgdatadir)/web"]
+ [libcap],
+ [AS_HELP_STRING([--with-libcap], [build with libcap])],
+ ,
+ [with_libcap="detect"]
)
AC_ARG_WITH(
- [zlib],
- [AS_HELP_STRING([--with-zlib], [build with zlib])],
- ,
- [with_zlib="yes"]
+ [zlib],
+ [AS_HELP_STRING([--with-zlib], [build with zlib])],
+ ,
+ [with_zlib="yes"]
)
AC_ARG_WITH(
- [math],
- [AS_HELP_STRING([--with-math], [build with math])],
- ,
- [with_math="yes"]
+ [math],
+ [AS_HELP_STRING([--with-math], [build with math])],
+ ,
+ [with_math="yes"]
)
AC_ARG_WITH(
- [user],
- [AS_HELP_STRING([--with-user], [use this user to drop privilege])],
- ,
- [with_user="nobody"]
+ [user],
+ [AS_HELP_STRING([--with-user], [use this user to drop privilege])],
+ ,
+ [with_user="nobody"]
)
AC_ARG_ENABLE(
- [x86-sse],
- [AS_HELP_STRING([--disable-x86-sse], [SSE/SS2 optimizations on x86 @<:@default enabled@:>@])],
- ,
- [enable_x86_sse="yes"]
+ [x86-sse],
+ [AS_HELP_STRING([--disable-x86-sse], [SSE/SS2 optimizations on x86 @<:@default enabled@:>@])],
+ ,
+ [enable_x86_sse="yes"]
+)
+AC_ARG_ENABLE(
+ [lto],
+ [AS_HELP_STRING([--disable-lto], [Link Time Optimizations @<:@default enabled@:>@])],
+ ,
+ [enable_lto="detect"]
)
-ACX_PTHREAD(, [AC_MSG_ERROR([Cannot initialize pthread environment])])
-LIBS="${PTHREAD_LIBS} ${LIBS}"
-CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}"
-CC="${PTHREAD_CC}"
-TS_CHECK_JEMALLOC
-if test "$has_jemalloc" = "1"; then
- AC_DEFINE([ENABLE_JEMALLOC], [1], [compile and link with jemalloc])
-else
- TS_CHECK_TCMALLOC
- if test "$has_tcmalloc" = "1"; then
- AC_DEFINE([ENABLE_TCMALLOC], [1], [compile and link with tcmalloc])
- else
- AC_C_MALLOPT
- AC_C_MALLINFO
- fi
-fi
+# -----------------------------------------------------------------------------
+# netdata required checks
+
+# fails on centos6
+#AX_CHECK_ENABLE_DEBUG()
+AX_GCC_FUNC_ATTRIBUTE([returns_nonnull])
+AX_GCC_FUNC_ATTRIBUTE([malloc])
+AX_GCC_FUNC_ATTRIBUTE([noreturn])
+AX_GCC_FUNC_ATTRIBUTE([format])
+AX_GCC_FUNC_ATTRIBUTE([warn_unused_result])
+
+AC_CHECK_FUNCS_ONCE(accept4)
+AC_CHECK_TYPES([struct timespec, clockid_t], [], [], [[#include <time.h>]])
+AC_SEARCH_LIBS([clock_gettime], [rt posix4])
+AC_CHECK_FUNCS([clock_gettime])
+AC_CHECK_FUNCS([sched_setscheduler sched_get_priority_min sched_get_priority_max nice])
+
+AC_TYPE_INT8_T
+AC_TYPE_INT16_T
+AC_TYPE_INT32_T
+AC_TYPE_INT64_T
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
AC_C_INLINE
AC_FUNC_STRERROR_R
AC_C__GENERIC
@@ -138,79 +145,290 @@ AC_CANONICAL_HOST
AC_HEADER_MAJOR
AC_HEADER_RESOLV
+AC_CHECK_HEADERS_ONCE([sys/prctl.h])
+
+
+# -----------------------------------------------------------------------------
+# operating system detection
+
+AC_MSG_CHECKING([operating system])
+case "$host_os" in
+freebsd*)
+ build_target=freebsd
+ ;;
+darwin*)
+ build_target=macos
+ LDFLAGS="${LDFLAGS} -framework CoreFoundation -framework IOKit"
+ ;;
+*)
+ build_target=linux
+ ;;
+esac
+
+AM_CONDITIONAL([FREEBSD], [test "${build_target}" = "freebsd"])
+AM_CONDITIONAL([MACOS], [test "${build_target}" = "macos"])
+AM_CONDITIONAL([LINUX], [test "${build_target}" = "linux"])
+AC_MSG_RESULT([${build_target}])
+
+
+# -----------------------------------------------------------------------------
+# pthreads
+
+ACX_PTHREAD(, [AC_MSG_ERROR([Cannot initialize pthread environment])])
+LIBS="${PTHREAD_LIBS} ${LIBS}"
+CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}"
+CC="${PTHREAD_CC}"
+
+
+# -----------------------------------------------------------------------------
+# libm
+
+AC_ARG_VAR([MATH_CFLAGS], [C compiler flags for math])
+AC_ARG_VAR([MATH_LIBS], [linker flags for math])
+if test -z "${MATH_LIBS}"; then
+ AC_CHECK_LIB(
+ [m],
+ [sin],
+ [MATH_LIBS="-lm"]
+ )
+fi
+test "${with_math}" = "yes" -a -z "${MATH_LIBS}" && AC_MSG_ERROR([math required but not found])
+
+AC_MSG_CHECKING([if libm should be used])
+if test "${with_math}" != "no" -a ! -z "${MATH_LIBS}"; then
+ with_math="yes"
+ AC_DEFINE([STORAGE_WITH_MATH], [1], [math usability])
+ OPTIONAL_MATH_CFLAGS="${MATH_CFLAGS}"
+ OPTIONAL_MATH_LIBS="${MATH_LIBS}"
+else
+ with_math="no"
+fi
+AC_MSG_RESULT([${with_math}])
+
+
+# -----------------------------------------------------------------------------
+# zlib
+
+PKG_CHECK_MODULES(
+ [ZLIB],
+ [zlib],
+ [have_zlib=yes],
+ [have_zlib=no]
+)
+test "${with_zlib}" = "yes" -a "${have_zlib}" != "yes" && AC_MSG_ERROR([zlib required but not found. Try installing 'zlib1g-dev' or 'zlib-devel'.])
+
+AC_MSG_CHECKING([if zlib should be used])
+if test "${with_zlib}" != "no" -a "${have_zlib}" = "yes"; then
+ with_zlib="yes"
+ AC_DEFINE([NETDATA_WITH_ZLIB], [1], [zlib usability])
+ OPTIONAL_ZLIB_CLFAGS="${ZLIB_CFLAGS}"
+ OPTIONAL_ZLIB_LIBS="${ZLIB_LIBS}"
+else
+ with_zlib="no"
+fi
+AC_MSG_RESULT([${with_zlib}])
+
+
+# -----------------------------------------------------------------------------
+# libuuid
+
+PKG_CHECK_MODULES(
+ [UUID],
+ [uuid],
+ [have_uuid=yes],
+ [AC_MSG_ERROR([libuuid required but not found. Try installing 'uuid-dev' or 'libuuid-devel'.])]
+)
+AC_DEFINE([NETDATA_WITH_UUID], [1], [uuid usability])
+OPTIONAL_UUID_CLFAGS="${UUID_CFLAGS}"
+OPTIONAL_UUID_LIBS="${UUID_LIBS}"
+
+
+# -----------------------------------------------------------------------------
+# compiler options
+
AC_ARG_VAR([SSE_CANDIDATE], [C compiler flags for SSE])
AS_CASE([$host_cpu],
- [i?86], [SSE_CANDIDATE="yes"]
+ [i?86], [SSE_CANDIDATE="yes"]
)
AC_SUBST([SSE_CANDIDATE])
if test "${SSE_CANDIDATE}" = "yes" -a "${enable_x86_sse}" = "yes"; then
- opt="-msse2 -mfpmath=sse"
- AX_CHECK_COMPILE_FLAG($opt, [CFLAGS="$CFLAGS $opt"], [])
+ opt="-msse2 -mfpmath=sse"
+ AX_CHECK_COMPILE_FLAG(${opt}, [CFLAGS="${CFLAGS} ${opt}"], [])
fi
-AC_ARG_VAR([MATH_CFLAGS], [C compiler flags for math])
-AC_ARG_VAR([MATH_LIBS], [linker flags for math])
-if test -z "${MATH_LIBS}"; then
- AC_CHECK_LIB(
- [m],
- [sin],
- [MATH_LIBS="-lm"]
- )
+if test "${GCC}" = "yes"; then
+ AC_DEFINE_UNQUOTED([likely(x)], [__builtin_expect(!!(x), 1)], [gcc branch optimization])
+ AC_DEFINE_UNQUOTED([unlikely(x)], [__builtin_expect(!!(x), 0)], [gcc branch optimization])
+else
+ AC_DEFINE_UNQUOTED([likely(x)], [(x)], [gcc branch optimization])
+ AC_DEFINE_UNQUOTED([unlikely(x)], [(x)], [gcc branch optimization])
+fi
+
+if test "${enable_pedantic}" = "yes"; then
+ enable_strict="yes"
+ CFLAGS="${CFLAGS} -pedantic -Wall -Wextra -Wno-long-long"
+fi
+
+
+# -----------------------------------------------------------------------------
+# memory allocation library
+
+AC_MSG_CHECKING([for memory allocator])
+TS_CHECK_JEMALLOC
+if test "$has_jemalloc" = "1"; then
+ AC_DEFINE([ENABLE_JEMALLOC], [1], [compile and link with jemalloc])
+ AC_MSG_RESULT([jemalloc])
+else
+ TS_CHECK_TCMALLOC
+ if test "$has_tcmalloc" = "1"; then
+ AC_DEFINE([ENABLE_TCMALLOC], [1], [compile and link with tcmalloc])
+ AC_MSG_RESULT([tcmalloc])
+ else
+ AC_MSG_RESULT([system])
+ AC_C_MALLOPT
+ AC_C_MALLINFO
+ fi
fi
+
+# -----------------------------------------------------------------------------
+# libcap
+
PKG_CHECK_MODULES(
- [UUID],
- [uuid],
+ [LIBCAP],
+ [libcap],
+ [AC_CHECK_LIB([cap], [cap_get_proc, cap_set_proc],
+ [AC_CHECK_HEADER(
+ [sys/capability.h],
+ [have_libcap=yes],
+ [have_libcap=no]
+ )],
+ [have_libcap=no]
+ )],
+ [have_libcap=no]
)
-test -z "${UUID_LIBS}" && AC_MSG_ERROR([libuuid required but not found. Try installing 'uuid-dev' or 'libuuid-devel'.])
-AC_DEFINE([NETDATA_WITH_UUID], [1], [uuid settings])
-OPTIONAL_UUID_CLFAGS="${UUID_CFLAGS}"
-OPTIONAL_UUID_LIBS="${UUID_LIBS}"
+test "${with_libcap}" = "yes" -a "${have_libcap}" != "yes" && AC_MSG_ERROR([libcap required but not found.])
-if test "${enable_plugin_nfacct}" = "yes"; then
- PKG_CHECK_MODULES(
- [NFACCT],
- [libnetfilter_acct],
- )
- PKG_CHECK_MODULES(
- [LIBMNL],
- [libmnl],
- )
- test -z "${NFACCT_LIBS}" && AC_MSG_ERROR([netfilter_acct required but not found])
- test -z "${LIBMNL_LIBS}" && AC_MSG_ERROR([libmnl required but not found. Try installing 'libmnl-dev' or 'libmnl-devel'])
- AC_DEFINE([INTERNAL_PLUGIN_NFACCT], [1], [nfacct plugin settings])
- OPTIONAL_NFACCT_CLFAGS="${NFACCT_CFLAGS} ${LIBMNL_CFLAGS}"
- OPTIONAL_NFACCT_LIBS="${NFACCT_LIBS} ${LIBMNL_LIBS}"
+AC_MSG_CHECKING([if libcap should be used])
+if test "${with_libcap}" != "no" -a "${have_libcap}" = "yes"; then
+ with_libcap="yes"
+ AC_DEFINE([HAVE_CAPABILITY], [1], [libcap usability])
+ OPTIONAL_LIBCAP_CLFAGS="${LIBCAP_CFLAGS}"
+ OPTIONAL_LIBCAP_LIBS="${LIBCAP_LIBS}"
+else
+ with_libcap="no"
fi
-if test "${with_zlib}" = "yes"; then
- PKG_CHECK_MODULES(
- [ZLIB],
- [zlib],
- )
- test -z "${ZLIB_LIBS}" && AC_MSG_ERROR([zlib required but not found. Try installing 'zlib1g-dev' or 'zlib-devel'.])
- AC_DEFINE([NETDATA_WITH_ZLIB], [1], [zlib settings])
- OPTIONAL_ZLIB_CLFAGS="${ZLIB_CFLAGS}"
- OPTIONAL_ZLIB_LIBS="${ZLIB_LIBS}"
+AC_MSG_RESULT([${with_libcap}])
+AM_CONDITIONAL([ENABLE_CAPABILITY], [test "${with_libcap}" = "yes"])
+
+
+# -----------------------------------------------------------------------------
+# apps.plugin
+
+AC_MSG_CHECKING([if apps.plugin should be enabled])
+if test "${build_target}" != "macos"; then
+ enable_plugin_apps="yes"
+else
+ enable_plugin_apps="no"
fi
-if test "${with_math}" = "yes"; then
- test -z "${MATH_LIBS}" && AC_MSG_ERROR([math required but not found])
- AC_DEFINE([STORAGE_WITH_MATH], [1], [math settings])
- OPTIONAL_MATH_CFLAGS="${MATH_CFLAGS}"
- OPTIONAL_MATH_LIBS="${MATH_LIBS}"
+AC_MSG_RESULT([${enable_plugin_apps}])
+AM_CONDITIONAL([ENABLE_PLUGIN_APPS], [test "${enable_plugin_apps}" = "yes"])
+
+
+# -----------------------------------------------------------------------------
+# freeipmi.plugin - libipmimonitoring
+
+PKG_CHECK_MODULES(
+ [IPMIMONITORING],
+ [libipmimonitoring],
+ [have_ipmimonitoring=yes],
+ [have_ipmimonitoring=no]
+)
+test "${enable_plugin_freeipmi}" = "yes" -a "${have_ipmimonitoring}" != "yes" && \
+ AC_MSG_ERROR([ipmimonitoring required but not found. Try installing 'libipmimonitoring-dev' or 'libipmimonitoring-devel'])
+
+AC_MSG_CHECKING([if freeipmi.plugin should be enabled])
+if test "${enable_plugin_freeipmi}" != "no" -a "${have_ipmimonitoring}" = "yes"; then
+ enable_plugin_freeipmi="yes"
+ AC_DEFINE([HAVE_FREEIPMI], [1], [ipmimonitoring usability])
+ OPTIONAL_IPMIMONITORING_CLFAGS="${IPMIMONITORING_CFLAGS}"
+ OPTIONAL_IPMIMONITORING_LIBS="${IPMIMONITORING_LIBS}"
+else
+ enable_plugin_freeipmi="no"
fi
+AC_MSG_RESULT([${enable_plugin_freeipmi}])
+AM_CONDITIONAL([ENABLE_PLUGIN_FREEIPMI], [test "${enable_plugin_freeipmi}" = "yes"])
-if test "${GCC}" = "yes"; then
- AC_DEFINE_UNQUOTED([likely(x)], [__builtin_expect(!!(x), 1)], [gcc branch optimization])
- AC_DEFINE_UNQUOTED([unlikely(x)], [__builtin_expect(!!(x), 0)], [gcc branch optimization])
+
+# -----------------------------------------------------------------------------
+# nfacct.plugin - libmnl, libnetfilter_acct
+
+AC_CHECK_HEADERS_ONCE([linux/netfilter/nfnetlink_conntrack.h])
+
+PKG_CHECK_MODULES(
+ [NFACCT],
+ [libnetfilter_acct],
+ [have_libnetfilter_acct=yes],
+ [have_libnetfilter_acct=no]
+)
+
+PKG_CHECK_MODULES(
+ [LIBMNL],
+ [libmnl],
+ [have_libmnl=yes],
+ [have_libmnl=no]
+)
+
+test "${enable_plugin_nfacct}" = "yes" -a "${have_libnetfilter_acct}" != "yes" && \
+ AC_MSG_ERROR([netfilter_acct required but not found])
+
+test "${enable_plugin_nfacct}" = "yes" -a "${have_libmnl}" != "yes" && \
+ AC_MSG_ERROR([libmnl required but not found. Try installing 'libmnl-dev' or 'libmnl-devel'])
+
+AC_MSG_CHECKING([if nfacct.plugin should be enabled])
+if test "${enable_plugin_nfacct}" != "no" -a "${have_libnetfilter_acct}" = "yes" -a "${have_libmnl}" = "yes"; then
+ enable_plugin_nfacct="yes"
+ AC_DEFINE([HAVE_LIBMNL], [1], [libmnl usability])
+ AC_DEFINE([HAVE_LIBNETFILTER_ACCT], [1], [libnetfilter_acct usability])
+ AC_DEFINE([INTERNAL_PLUGIN_NFACCT], [1], [nfacct plugin usability])
+ OPTIONAL_NFACCT_CLFAGS="${NFACCT_CFLAGS} ${LIBMNL_CFLAGS}"
+ OPTIONAL_NFACCT_LIBS="${NFACCT_LIBS} ${LIBMNL_LIBS}"
else
- AC_DEFINE_UNQUOTED([likely(x)], [(x)], [gcc branch optimization])
- AC_DEFINE_UNQUOTED([unlikely(x)], [(x)], [gcc branch optimization])
+ enable_plugin_nfacct="no"
fi
+AC_MSG_RESULT([${enable_plugin_nfacct}])
+AM_CONDITIONAL([ENABLE_PLUGIN_NFACCT], [test "${enable_plugin_nfacct}" = "yes"])
-if test "${enable_pedantic}" = "yes"; then
- enable_strict="yes"
- CFLAGS="${CFLAGS} -pedantic -Wall -Wextra -Wno-long-long"
+
+# -----------------------------------------------------------------------------
+# Link-Time-Optimization
+
+if test "${enable_lto}" != "no"; then
+ opt="-flto"
+ AX_CHECK_COMPILE_FLAG(${opt}, [have_lto=yes], [have_lto=no])
+fi
+if test "${have_lto}" = "yes"; then
+ oCFLAGS="${CFLAGS}"
+ CFLAGS="${CFLAGS} -flto ${OPTIONAL_MATH_CLFAGS} ${OPTIONAL_NFACCT_CLFAGS} ${OPTIONAL_ZLIB_CLFAGS} ${OPTIONAL_UUID_CLFAGS} ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS}"
+ ac_cv_c_lto_cross_compile="${enable_lto}"
+ test "${ac_cv_c_lto_cross_compile}" != "yes" && ac_cv_c_lto_cross_compile="no"
+ AC_C_LTO
+ CFLAGS="${oCFLAGS}"
+ test "${ac_cv_c_lto}" != "yes" && have_lto="no"
fi
+test "${enable_lto}" = "yes" -a "${have_lto}" != "yes" && \
+ AC_MSG_ERROR([LTO is required but is not available.])
+AC_MSG_CHECKING([if LTO should be enabled])
+if test "${enable_lto}" != "no" -a "${have_lto}" = "yes"; then
+ enable_lto="yes"
+ CFLAGS="${CFLAGS} -flto"
+else
+ enable_lto="no"
+fi
+AC_MSG_RESULT([${enable_lto}])
+
+
+# -----------------------------------------------------------------------------
AC_DEFINE_UNQUOTED([NETDATA_USER], ["${with_user}"], [use this user to drop privileged])
@@ -233,21 +451,25 @@ AC_SUBST([OPTIONAL_ZLIB_CLFAGS])
AC_SUBST([OPTIONAL_ZLIB_LIBS])
AC_SUBST([OPTIONAL_UUID_CLFAGS])
AC_SUBST([OPTIONAL_UUID_LIBS])
+AC_SUBST([OPTIONAL_LIBCAP_CFLAGS])
+AC_SUBST([OPTIONAL_LIBCAP_LIBS])
+AC_SUBST([OPTIONAL_IPMIMONITORING_CFLAGS])
+AC_SUBST([OPTIONAL_IPMIMONITORING_LIBS])
AC_CONFIG_FILES([
- Makefile
- charts.d/Makefile
- conf.d/Makefile
- netdata.spec
- python.d/Makefile
- node.d/Makefile
- plugins.d/Makefile
- src/Makefile
- system/Makefile
- web/Makefile
- contrib/Makefile
+ Makefile
+ charts.d/Makefile
+ conf.d/Makefile
+ netdata.spec
+ python.d/Makefile
+ node.d/Makefile
+ plugins.d/Makefile
+ src/Makefile
+ system/Makefile
+ web/Makefile
+ contrib/Makefile
])
AC_OUTPUT
test "${with_math}" != "yes" && AC_MSG_WARN([You are building without math. math allows accurate calculations. It should be enabled.]) || :
-test "${with_zlib}" != "yes" && AC_MSG_WARN([You are building without zlib. zlib allows netdata to trasnfer a lot less data with web clients. It should be enabled.]) || :
+test "${with_zlib}" != "yes" && AC_MSG_WARN([You are building without zlib. zlib allows netdata to transfer a lot less data with web clients. It should be enabled.]) || :
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
index eed37f4d9..29db296aa 100644
--- a/contrib/Makefile.in
+++ b/contrib/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,9 +36,11 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = contrib
+DIST_COMMON = $(dist_noinst_DATA) $(dist_noinst_SCRIPTS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -101,39 +49,17 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_noinst_SCRIPTS) \
- $(dist_noinst_DATA) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
SCRIPTS = $(dist_noinst_SCRIPTS)
-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 =
SOURCES =
DIST_SOURCES =
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
DATA = $(dist_noinst_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -157,7 +83,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -171,6 +101,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -306,6 +240,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu contrib/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -323,11 +258,11 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
-tags TAGS:
-
-ctags CTAGS:
+tags: TAGS
+TAGS:
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -463,18 +398,15 @@ uninstall-am:
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am 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-ps install-ps-am install-strip installcheck \
- installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
- pdf-am ps ps-am tags-am uninstall uninstall-am
-
-.PRECIOUS: Makefile
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am 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-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am
debian/changelog:
diff --git a/contrib/debian/changelog b/contrib/debian/changelog
deleted file mode 100644
index bc8f48cd5..000000000
--- a/contrib/debian/changelog
+++ /dev/null
@@ -1,3 +0,0 @@
-netdata (1.5.0) UNRELEASED; urgency=medium
- * Latest release
- -- Netdata Team <> Mon, 23 Jan 2017 21:57:01 +0200
diff --git a/contrib/debian/compat b/contrib/debian/compat
deleted file mode 100644
index ec635144f..000000000
--- a/contrib/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/contrib/debian/control b/contrib/debian/control
deleted file mode 100644
index 24c5f4c4b..000000000
--- a/contrib/debian/control
+++ /dev/null
@@ -1,25 +0,0 @@
-Source: netdata
-Build-Depends: debhelper (>= 9),
- dh-autoreconf,
- dh-systemd (>= 1.5),
- dpkg-dev (>= 1.13.19),
- zlib1g-dev,
- uuid-dev
-Section: net
-Priority: optional
-Maintainer: Costa Tsaousis <costa@tsaousis.gr>
-Standards-Version: 3.9.6
-Homepage: https://github.com/firehol/netdata/wiki
-
-Package: netdata
-Architecture: any
-Depends: adduser,
- libcap2-bin (>= 1:2.0),
- lsb-base (>= 3.1-23.2),
- ${misc:Depends},
- ${shlibs:Depends}
-Description: real-time charts for system monitoring
- Netdata is a daemon that collects data in realtime (per second)
- and presents a web site to view and analyze them. The presentation
- is also real-time and full of interactive charts that precisely
- render all collected values.
diff --git a/contrib/debian/control.wheezy b/contrib/debian/control.wheezy
deleted file mode 100644
index 4103908a2..000000000
--- a/contrib/debian/control.wheezy
+++ /dev/null
@@ -1,25 +0,0 @@
-Source: netdata
-Build-Depends: debhelper (>= 9),
- dh-autoreconf,
- pkg-config,
- dpkg-dev (>= 1.13.19),
- zlib1g-dev,
- uuid-dev
-Section: net
-Priority: optional
-Maintainer: Costa Tsaousis <costa@tsaousis.gr>
-Standards-Version: 3.9.6
-Homepage: https://github.com/firehol/netdata/wiki
-
-Package: netdata
-Architecture: any
-Depends: adduser,
- libcap2-bin (>= 1:2.0),
- lsb-base (>= 3.1-23.2),
- ${misc:Depends},
- ${shlibs:Depends}
-Description: real-time charts for system monitoring
- Netdata is a daemon that collects data in realtime (per second)
- and presents a web site to view and analyze them. The presentation
- is also real-time and full of interactive charts that precisely
- render all collected values.
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
deleted file mode 100644
index 11a3d6390..000000000
--- a/contrib/debian/copyright
+++ /dev/null
@@ -1,10 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: Netdata
-Upstream-Contact: Costa Tsaousis <costa@tsaousis.gr>
-Source: https://github.com/firehol/netdata
-
-Files: *
-Copyright: 2014-2016, Costa Tsaousis
-License: GPL-3+
- On Debian systems, the complete text of the GNU General Public
- License version 3 can be found in /usr/share/common-licenses/GPL-3.
diff --git a/contrib/debian/netdata.conf b/contrib/debian/netdata.conf
deleted file mode 100644
index a963d80b7..000000000
--- a/contrib/debian/netdata.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-# NetData Configuration
-
-# The current full configuration can be retrieved from the running
-# server at the URL
-#
-# http://localhost:19999/netdata.conf
-#
-# for example:
-#
-# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
-#
-
-[global]
- run as user = netdata
- web files owner = root
- web files group = netdata
diff --git a/contrib/debian/netdata.default b/contrib/debian/netdata.default
deleted file mode 100644
index 9e7f8ae6e..000000000
--- a/contrib/debian/netdata.default
+++ /dev/null
@@ -1,5 +0,0 @@
-# Extra arguments to pass to netdata
-#
-#EXTRA_OPTS=""
-#uncomment following line if you are building a wheezy-package
-#EXTRA_OPTS="-P /var/run/netdata.pid"
diff --git a/contrib/debian/netdata.docs b/contrib/debian/netdata.docs
deleted file mode 100644
index 56631abf1..000000000
--- a/contrib/debian/netdata.docs
+++ /dev/null
@@ -1 +0,0 @@
-ChangeLog
diff --git a/contrib/debian/netdata.init b/contrib/debian/netdata.init
deleted file mode 100755
index c1b2b74de..000000000
--- a/contrib/debian/netdata.init
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-# Start/stop the netdata daemon.
-#
-### BEGIN INIT INFO
-# Provides: netdata
-# Required-Start: $remote_fs
-# Required-Stop: $remote_fs
-# Should-Start: $network
-# Should-Stop: $network
-# Default-Start: 2 3 4 5
-# Default-Stop:
-# Short-Description: Real-time charts for system monitoring
-# Description: Netdata is a daemon that collects data in realtime (per second)
-# and presents a web site to view and analyze them. The presentation
-# is also real-time and full of interactive charts that precisely
-# render all collected values.
-### END INIT INFO
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-DESC="netdata daemon"
-NAME=netdata
-DAEMON=/usr/sbin/netdata
-PIDFILE=/var/run/netdata/netdata.pid
-SCRIPTNAME=/etc/init.d/"$NAME"
-
-test -f $DAEMON || exit 0
-
-. /lib/lsb/init-functions
-
-[ -r /etc/default/netdata ] && . /etc/default/netdata
-
-case "$1" in
-start) log_daemon_msg "Starting real-time system monitoring" "netdata"
- start_daemon -p $PIDFILE $DAEMON $EXTRA_OPTS
- log_end_msg $?
- ;;
-stop) log_daemon_msg "Stopping real-time system monitoring" "netdata"
- killproc -p $PIDFILE $DAEMON
- RETVAL=$?
- [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE
- log_end_msg $RETVAL
- # wait for plugins to exit
- sleep 1
- ;;
-restart|force-reload) log_daemon_msg "Restarting real-time system monitoring" "netdata"
- $0 stop
- $0 start
- ;;
-status)
- status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $?
- ;;
-*) log_action_msg "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}"
- exit 2
- ;;
-esac
-exit 0
diff --git a/contrib/debian/netdata.install b/contrib/debian/netdata.install
deleted file mode 100644
index 45d42b635..000000000
--- a/contrib/debian/netdata.install
+++ /dev/null
@@ -1 +0,0 @@
-debian/netdata.conf /etc/netdata/
diff --git a/contrib/debian/netdata.lintian-overrides b/contrib/debian/netdata.lintian-overrides
deleted file mode 100644
index 45b2d868f..000000000
--- a/contrib/debian/netdata.lintian-overrides
+++ /dev/null
@@ -1,16 +0,0 @@
-
-# See Debian policy 10.9. apps.plugin has extra capabilities, so don't let
-# normal users run it.
-netdata: non-standard-executable-perm usr/lib/*/netdata/plugins.d/apps.plugin 0754 != 0755
-
-
-# FontAwesome is at least in the fonts-font-awesome package, but this is
-# not available in wheezy. glyphicons-halflings-regular isn't currently in
-# a Debian package. Therefore don't complain about shipping them with netdata
-# for the time being.
-netdata: duplicate-font-file usr/share/netdata/fonts/*
-netdata: font-in-non-font-package usr/share/netdata/fonts/*
-
-# Files here are marked as conffiles so that local updates to the html files
-# isn't clobbered on upgrade.
-netdata: non-etc-file-marked-as-conffile var/lib/netdata/www/*
diff --git a/contrib/debian/netdata.postinst.in b/contrib/debian/netdata.postinst.in
deleted file mode 100644
index 29615f541..000000000
--- a/contrib/debian/netdata.postinst.in
+++ /dev/null
@@ -1,41 +0,0 @@
-#! /bin/sh
-
-set -e
-
-case "$1" in
- configure)
- if [ -z "$2" ]; then
- if ! getent group netdata >/dev/null; then
- addgroup --quiet --system netdata
- fi
-
- if ! getent passwd netdata >/dev/null; then
- adduser --quiet --system --ingroup netdata --home /var/lib/netdata --no-create-home netdata
- fi
-
- if ! dpkg-statoverride --list /var/lib/netdata >/dev/null 2>&1; then
- dpkg-statoverride --update --add netdata netdata 0755 /var/lib/netdata
- fi
-
- if ! dpkg-statoverride --list /var/lib/netdata/www >/dev/null 2>&1; then
- dpkg-statoverride --update --add root netdata 0755 /var/lib/netdata/www
- fi
-
- if ! dpkg-statoverride --list /var/cache/netdata >/dev/null 2>&1; then
- dpkg-statoverride --update --add netdata netdata 0755 /var/cache/netdata
- fi
-
- fi
-
- dpkg-statoverride --update --add --force root netdata 0775 /var/lib/netdata/registry
- chown -R root:netdata /usr/share/netdata/*
- chown -R root:netdata /usr/lib/@DEB_HOST_MULTIARCH@/netdata/plugins.d
- setcap cap_dac_read_search,cap_sys_ptrace+ep /usr/lib/@DEB_HOST_MULTIARCH@/netdata/plugins.d/apps.plugin
-
-#PERMS#
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
diff --git a/contrib/debian/netdata.postrm b/contrib/debian/netdata.postrm
deleted file mode 100644
index 4ab4eeadd..000000000
--- a/contrib/debian/netdata.postrm
+++ /dev/null
@@ -1,43 +0,0 @@
-#! /bin/sh
-
-set -e
-
-case "$1" in
- remove)
- ;;
-
- purge)
- if dpkg-statoverride --list | grep -qw /var/cache/netdata; then
- dpkg-statoverride --remove /var/cache/netdata
- fi
-
- if dpkg-statoverride --list | grep -qw /var/lib/netdata/www; then
- dpkg-statoverride --remove /var/lib/netdata/www
- fi
-
- if dpkg-statoverride --list | grep -qw /var/lib/netdata; then
- dpkg-statoverride --remove /var/lib/netdata
- fi
-
- if getent passwd netdata >/dev/null; then
- if [ -x /usr/sbin/deluser ]; then
- deluser --quiet --system netdata || echo "Unable to remove netdata user"
- fi
- fi
-
- if getent group netdata >/dev/null; then
- if [ -x /usr/sbin/delgroup ]; then
- delgroup --quiet --system netdata || echo "Unable to remove netdata group"
- fi
- fi
-
- ;;
-
- *)
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
-
diff --git a/contrib/debian/netdata.service b/contrib/debian/netdata.service
deleted file mode 100644
index e5d3a3863..000000000
--- a/contrib/debian/netdata.service
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-Description=netdata real-time system monitoring
-After=network.target
-
-[Service]
-Type=simple
-EnvironmentFile=-/etc/default/netdata
-ExecStart=/usr/sbin/netdata -D $EXTRA_OPTS
-TimeoutStopSec=30
-Restart=always
-RestartSec=5
-
-[Install]
-WantedBy=multi-user.target
diff --git a/contrib/debian/rules b/contrib/debian/rules
deleted file mode 100755
index ec4ec4182..000000000
--- a/contrib/debian/rules
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/make -f
-
-# Find the arch we are building for, as this determines
-# the location of plugins in /usr/lib
-DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
-TOP = $(CURDIR)/debian/netdata
-
-%:
- # For jessie and beyond
- #
- dh $@ --with autoreconf,systemd
-
- # For wheezy or other non-systemd distributions use the following. You
- # should also see contrib/README.md which gives details of updates to
- # make to debian/control.
- #
- #dh $@ --with autoreconf
-
-override_dh_auto_configure:
- dh_auto_configure -- --with-math --with-webdir=/var/lib/netdata/www
-
-debian/%.postinst: debian/%.postinst.in
- sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' $< > $@
-
-override_dh_install: debian/netdata.postinst
- dh_install
-
- # Remove unneeded .keep files
- #
- find "$(TOP)" -name .keep -exec rm '{}' ';'
-
- # Move files that local user shouldn't be editing to /usr/share/netdata
- #
- mkdir -p "$(TOP)/usr/share/netdata"
- for D in $$(find "$(TOP)/var/lib/netdata/www/" -maxdepth 1 -type d -printf '%f '); do \
- echo Relocating $$D; \
- mv "$(TOP)/var/lib/netdata/www/$$D" "$(TOP)/usr/share/netdata/$$D"; \
- ln -s "/usr/share/netdata/$$D" "$(TOP)/var/lib/netdata/www/$$D"; \
- done
-
- # Update postinst to set correct group for www files on installation.
- # Should probably be dpkg-statoverride really, but that gets *really*
- # messy. We also set all web files in /var as conffiles so an upgrade
- # doesn't splat them.
- #
- for D in $$(find "$(TOP)/var/lib/netdata/www/" -maxdepth 1 -type f -printf '%f '); do \
- echo Updating postinst for $$D; \
- sed -i "s/^#PERMS#/chgrp netdata \/var\/lib\/netdata\/www\/$$D\n#PERMS#/g" \
- $(CURDIR)/debian/netdata.postinst; \
- echo "/var/lib/netdata/www/$$D" >> $(CURDIR)/debian/netdata.conffiles; \
- done
- sed -i "/^#PERMS#/d" $(CURDIR)/debian/netdata.postinst
-
-override_dh_installdocs:
- dh_installdocs
-
- # Docs should not be under /usr/lib
- #
- mv $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/plugins.d/README.md \
- $(TOP)/usr/share/doc/netdata/README.plugins.md
- mv $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/charts.d/README.md \
- $(TOP)/usr/share/doc/netdata/README.charts.md
-
- # This doc is currently empty, so no point installing it.
- #
- rm $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/node.d/README.md
-
-override_dh_fixperms:
- dh_fixperms
-
- # apps.plugin should only be runnable by the netdata user. It will be
- # given extra capabilities in the postinst script.
- #
- chmod 0754 $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/plugins.d/apps.plugin
-
-override_dh_installlogrotate:
- cp system/netdata.logrotate debian/netdata.logrotate
- dh_installlogrotate
-
-override_dh_clean:
- dh_clean
-
- # Tidy up copied/generated files
- #
- -[ -r $(CURDIR)/debian/netdata.logrotate ] && rm $(CURDIR)/debian/netdata.logrotate
- -[ -r $(CURDIR)/debian/netdata.postinst ] && rm $(CURDIR)/debian/netdata.postinst
- -[ -r $(CURDIR)/debian/netdata.conffiles ] && rm $(CURDIR)/debian/netdata.conffiles
diff --git a/contrib/debian/source/format b/contrib/debian/source/format
deleted file mode 100644
index 89ae9db8f..000000000
--- a/contrib/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (native)
diff --git a/coverity-scan.sh b/coverity-scan.sh
index a690fead7..8ea433453 100755
--- a/coverity-scan.sh
+++ b/coverity-scan.sh
@@ -18,6 +18,9 @@ covbuild="$(which cov-build 2>/dev/null || command -v cov-build 2>/dev/null)"
echo "The command ${covbuild} is not executable. Save command the full filename of cov-build in .coverity-build" && \
exit 1
+version="$(cat config.h | grep "^#define PACKAGE_VERSION" | cut -d '"' -f 2)"
+echo >&2 "Working on netdata version: ${version}"
+
echo >&2 "Cleaning up old builds..."
make clean || exit 1
@@ -34,6 +37,6 @@ tar czvf netdata-coverity-analysis.tgz cov-int || exit 1
curl --form token="${token}" \
--form email=costa@tsaousis.gr \
--form file=@netdata-coverity-analysis.tgz \
- --form version="1.5.0rc1" \
- --form description="Description" \
+ --form version="${version}" \
+ --form description="netdata, real-time performance monitoring, done right." \
https://scan.coverity.com/builds?project=firehol%2Fnetdata
diff --git a/depcomp b/depcomp
index fc98710e2..bd0ac0895 100755
--- a/depcomp
+++ b/depcomp
@@ -1,9 +1,10 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
-scriptversion=2013-05-30.07; # UTC
+scriptversion=2011-12-04.11; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
+# 2011 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -27,9 +28,9 @@ scriptversion=2013-05-30.07; # UTC
case $1 in
'')
- echo "$0: No command. Try '$0 --help' for more information." 1>&2
- exit 1;
- ;;
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
@@ -39,8 +40,8 @@ as side-effects.
Environment variables:
depmode Dependency tracking mode.
- source Source file read by 'PROGRAMS ARGS'.
- object Object file output by 'PROGRAMS ARGS'.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
@@ -56,66 +57,6 @@ EOF
;;
esac
-# Get the directory component of the given path, and save it in the
-# global variables '$dir'. Note that this directory component will
-# be either empty or ending with a '/' character. This is deliberate.
-set_dir_from ()
-{
- case $1 in
- */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
- *) dir=;;
- esac
-}
-
-# Get the suffix-stripped basename of the given path, and save it the
-# global variable '$base'.
-set_base_from ()
-{
- base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
-}
-
-# If no dependency file was actually created by the compiler invocation,
-# we still have to create a dummy depfile, to avoid errors with the
-# Makefile "include basename.Plo" scheme.
-make_dummy_depfile ()
-{
- echo "#dummy" > "$depfile"
-}
-
-# Factor out some common post-processing of the generated depfile.
-# Requires the auxiliary global variable '$tmpdepfile' to be set.
-aix_post_process_depfile ()
-{
- # If the compiler actually managed to produce a dependency file,
- # post-process it.
- if test -f "$tmpdepfile"; then
- # Each line is of the form 'foo.o: dependency.h'.
- # Do two passes, one to just change these to
- # $object: dependency.h
- # and one to simply output
- # dependency.h:
- # which is needed to avoid the deleted-header problem.
- { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
- sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
- } > "$depfile"
- rm -f "$tmpdepfile"
- else
- make_dummy_depfile
- fi
-}
-
-# A tabulation character.
-tab=' '
-# A newline character.
-nl='
-'
-# Character ranges might be problematic outside the C locale.
-# These definitions help.
-upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
-lower=abcdefghijklmnopqrstuvwxyz
-digits=0123456789
-alpha=${upper}${lower}
-
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
@@ -128,9 +69,6 @@ tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
-# Avoid interferences from the environment.
-gccflag= dashmflag=
-
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
@@ -142,32 +80,26 @@ if test "$depmode" = hp; then
fi
if test "$depmode" = dashXmstdout; then
- # This is just like dashmstdout with a different argument.
- dashmflag=-xM
- depmode=dashmstdout
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
- # This is just like msvisualcpp but w/o cygpath translation.
- # Just convert the backslash-escaped backslashes to single forward
- # slashes to satisfy depend.m4
- cygpath_u='sed s,\\\\,/,g'
- depmode=msvisualcpp
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
- # This is just like msvc7 but w/o cygpath translation.
- # Just convert the backslash-escaped backslashes to single forward
- # slashes to satisfy depend.m4
- cygpath_u='sed s,\\\\,/,g'
- depmode=msvc7
-fi
-
-if test "$depmode" = xlc; then
- # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
- gccflag=-qmakedep=gcc,-MF
- depmode=gcc
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
fi
case "$depmode" in
@@ -190,7 +122,8 @@ gcc3)
done
"$@"
stat=$?
- if test $stat -ne 0; then
+ if test $stat -eq 0; then :
+ else
rm -f "$tmpdepfile"
exit $stat
fi
@@ -198,17 +131,13 @@ gcc3)
;;
gcc)
-## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
-## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
-## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
-## -MM, not -M (despite what the docs say). Also, it might not be
-## supported by the other compilers which use the 'gcc' depmode.
+## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
@@ -216,31 +145,33 @@ gcc)
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
- if test $stat -ne 0; then
+ if test $stat -eq 0; then :
+ else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
- # The second -e expression handles DOS-style file names with drive
- # letters.
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the "deleted header file" problem.
+## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
-## Some versions of gcc put a space before the ':'. On the theory
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
- | sed -e 's/$/ :/' >> "$depfile"
+ sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@@ -258,7 +189,8 @@ sgi)
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
- if test $stat -ne 0; then
+ if test $stat -eq 0; then :
+ else
rm -f "$tmpdepfile"
exit $stat
fi
@@ -266,41 +198,43 @@ sgi)
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
+
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
- # the IRIX cc adds comments like '#:fec' to the end of the
+ # the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
- | tr "$nl" ' ' >> "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> "$depfile"
echo >> "$depfile"
+
# The second pass generates a dummy entry for each header file.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
- >> "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
else
- make_dummy_depfile
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
-xlc)
- # This case exists only to let depend.m4 do its work. It works by
- # looking at the text of this script. This case will never be run,
- # since it is checked for above.
- exit 1
- ;;
-
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
- # current directory. Also, the AIX compiler puts '$object:' at the
+ # current directory. Also, the AIX compiler puts `$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
- set_dir_from "$object"
- set_base_from "$object"
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
@@ -313,7 +247,9 @@ aix)
"$@" -M
fi
stat=$?
- if test $stat -ne 0; then
+
+ if test $stat -eq 0; then :
+ else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
@@ -322,100 +258,44 @@ aix)
do
test -f "$tmpdepfile" && break
done
- aix_post_process_depfile
- ;;
-
-tcc)
- # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
- # FIXME: That version still under development at the moment of writing.
- # Make that this statement remains true also for stable, released
- # versions.
- # It will wrap lines (doesn't matter whether long or short) with a
- # trailing '\', as in:
- #
- # foo.o : \
- # foo.c \
- # foo.h \
- #
- # It will put a trailing '\' even on the last line, and will use leading
- # spaces rather than leading tabs (at least since its commit 0394caf7
- # "Emit spaces for -MD").
- "$@" -MD -MF "$tmpdepfile"
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
fi
- rm -f "$depfile"
- # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
- # We have to change lines of the first kind to '$object: \'.
- sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
- # And for each line of the second kind, we have to emit a 'dep.h:'
- # dummy dependency, to avoid the deleted-header problem.
- sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
-## The order of this option in the case statement is important, since the
-## shell code in configure will try each of these formats in the order
-## listed in this file. A plain '-MD' option would be understood by many
-## compilers, so we must ensure this comes after the gcc and icc options.
-pgcc)
- # Portland's C compiler understands '-MD'.
- # Will always output deps to 'file.d' where file is the root name of the
- # source file under compilation, even if file resides in a subdirectory.
- # The object file name does not affect the name of the '.d' file.
- # pgcc 10.2 will output
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
- # and will wrap long lines using '\' :
+ # and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
- set_dir_from "$object"
- # Use the source, not the object, to determine the base name, since
- # that's sadly what pgcc will do too.
- set_base_from "$source"
- tmpdepfile=$base.d
-
- # For projects that build the same source file twice into different object
- # files, the pgcc approach of using the *source* file root name can cause
- # problems in parallel builds. Use a locking strategy to avoid stomping on
- # the same $tmpdepfile.
- lockdir=$base.d-lock
- trap "
- echo '$0: caught signal, cleaning up...' >&2
- rmdir '$lockdir'
- exit 1
- " 1 2 13 15
- numtries=100
- i=$numtries
- while test $i -gt 0; do
- # mkdir is a portable test-and-set.
- if mkdir "$lockdir" 2>/dev/null; then
- # This process acquired the lock.
- "$@" -MD
- stat=$?
- # Release the lock.
- rmdir "$lockdir"
- break
- else
- # If the lock is being held by a different process, wait
- # until the winning process is done or we timeout.
- while test -d "$lockdir" && test $i -gt 0; do
- sleep 1
- i=`expr $i - 1`
- done
- fi
- i=`expr $i - 1`
- done
- trap - 1 2 13 15
- if test $i -le 0; then
- echo "$0: failed to acquire lock after $numtries attempts" >&2
- echo "$0: check lockdir '$lockdir'" >&2
- exit 1
- fi
- if test $stat -ne 0; then
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
rm -f "$tmpdepfile"
exit $stat
fi
@@ -427,8 +307,8 @@ pgcc)
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
- sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
- | sed -e 's/$/ :/' >> "$depfile"
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@@ -439,8 +319,9 @@ hp2)
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
- set_dir_from "$object"
- set_base_from "$object"
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
@@ -451,7 +332,8 @@ hp2)
"$@" +Maked
fi
stat=$?
- if test $stat -ne 0; then
+ if test $stat -eq 0; then :
+ else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
@@ -461,61 +343,77 @@ hp2)
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
- sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
- # Add 'dependent.h:' lines.
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
sed -ne '2,${
- s/^ *//
- s/ \\*$//
- s/$/:/
- p
- }' "$tmpdepfile" >> "$depfile"
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
else
- make_dummy_depfile
+ echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
- # The Tru64 compiler uses -MD to generate dependencies as a side
- # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
- # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
- # dependencies in 'foo.d' instead, so we check for that too.
- # Subdirectories are respected.
- set_dir_from "$object"
- set_base_from "$object"
-
- if test "$libtool" = yes; then
- # Libtool generates 2 separate objects for the 2 libraries. These
- # two compilations output dependencies in $dir.libs/$base.o.d and
- # in $dir$base.o.d. We have to check for both files, because
- # one of the two compilations can be disabled. We should prefer
- # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
- # automatically cleaned when .libs/ is deleted, while ignoring
- # the former would cause a distcleancheck panic.
- tmpdepfile1=$dir$base.o.d # libtool 1.5
- tmpdepfile2=$dir.libs/$base.o.d # Likewise.
- tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
- "$@" -Wc,-MD
- else
- tmpdepfile1=$dir$base.d
- tmpdepfile2=$dir$base.d
- tmpdepfile3=$dir$base.d
- "$@" -MD
- fi
-
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
- exit $stat
- fi
-
- for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
- do
- test -f "$tmpdepfile" && break
- done
- # Same post-processing that is required for AIX mode.
- aix_post_process_depfile
- ;;
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
msvc7)
if test "$libtool" = yes; then
@@ -526,7 +424,8 @@ msvc7)
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
- if test $stat -ne 0; then
+ if test "$stat" = 0; then :
+ else
rm -f "$tmpdepfile"
exit $stat
fi
@@ -544,15 +443,14 @@ msvc7)
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
-s/\(.*\)/'"$tab"'\1 \\/p
+s/\(.*\)/ \1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
- s/.*/'"$tab"'/
+ s/.*/ /
G
p
}' >> "$depfile"
- echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
@@ -580,7 +478,7 @@ dashmstdout)
shift
fi
- # Remove '-o $object'.
+ # Remove `-o $object'.
IFS=" "
for arg
do
@@ -600,18 +498,18 @@ dashmstdout)
done
test -z "$dashmflag" && dashmflag=-M
- # Require at least two characters before searching for ':'
+ # Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
- # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
- sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
- # Some versions of the HPUX 10.20 sed can't process this sed invocation
- # correctly. Breaking it into two sed invocations is a workaround.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
- | sed -e 's/$/ :/' >> "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@@ -664,12 +562,11 @@ makedepend)
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
- # Some versions of the HPUX 10.20 sed can't process the last invocation
- # correctly. Breaking it into two sed invocations is a workaround.
- sed '1,2d' "$tmpdepfile" \
- | tr ' ' "$nl" \
- | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
- | sed -e 's/$/ :/' >> "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
@@ -686,7 +583,7 @@ cpp)
shift
fi
- # Remove '-o $object'.
+ # Remove `-o $object'.
IFS=" "
for arg
do
@@ -705,10 +602,10 @@ cpp)
esac
done
- "$@" -E \
- | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
- -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
- | sed '$ s: \\$::' > "$tmpdepfile"
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
@@ -740,23 +637,23 @@ msvisualcpp)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
- set fnord "$@"
- shift
- shift
- ;;
+ set fnord "$@"
+ shift
+ shift
+ ;;
*)
- set fnord "$@" "$arg"
- shift
- shift
- ;;
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
- sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
- echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
diff --git a/diagrams/netdata-for-ephemeral-nodes.xml b/diagrams/netdata-for-ephemeral-nodes.xml
new file mode 100644
index 000000000..8606170e5
--- /dev/null
+++ b/diagrams/netdata-for-ephemeral-nodes.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" version="6.2.4" editor="www.draw.io" type="github"><diagram name="Page-1">jLzH0qNMti58NT39A2+GeIRwwggzw3vvufpDqurr3n12nIi/BnpRCkGSudZjVqbqXyjXndIcjaU2pFn7LwRKz3+h/L+Q5x9JPH9Ay/WnBaYJ+k9LMVfp37b/NNjVnf1thP62blWaLf914joM7VqN/92YDH2fJet/tUXzPBz/fVo+tP991zEqsv/VYCdR+79bvSpdyz+tFA79p13OqqL8584w9PeTLvrn5L8NSxmlw/E/mlDhXyg3D8P656g7uawFo/fPuPzzvfX6pzP/Qtly7drnDfwc/j4W/x9fhv//fPnp/pz16/+83f/regSK/a8rZukzVH/fDvNaDsXQR63wn1Y22eY9S//ech62Pv29g/67L9lZrf7fZnAcgOP/Dwfv+nW+/P9+G/z9Vhot5b+vDd6Y0bpmc/9rQSDQuqzRvDIgCp7GpI2WpUr+aRar9t/379N/TuqHPvvT8vdz0Kc6W9frb2hG2zo8Tf95XHUYxr/XWdZ5aP4dJsi/RxmM0/8VTf8Z9n8matjmJPtnrP9O/dPPIvt7Hk7B/w6aJ92yocuewXhOmrM2Wqv9v+8Q/Q374t/n/Wdun4O/0/v/muq/t9+jdvsneP7vuX+ieQSHVfdLIHbP5rV60kaN4qw1h6VaqwFMRTys69A9J7TgAzZKmuIXB9zQDvPvUmj++/c/rsG0VQG+u4KRZaNl/JPYeXWC+WZ/t2T+aYX+aXmO02iN/oUyf94i4tgX/0K46ssa1gG9pWJgnn+67ZaCWzxHQfK88B3HBKD9Xwh7uA38HBWM0Aqfr4Ux2fWAFRtQre2rffhcUd5Mbpu3fXiaw7pGk7lo0ut7pmSjfpI1VTl+UY+XwFjvwoTAN+qCZQsOZ4o3m7NMIVjHZ7ArBQ3vot+IjBzJydhNMxUSVb5Vajc5M7+I7doG/LmHv/v2QaP6raE6mqAU99xYrPbnBQUv+z49Jxl1UC3vBXuBTn2/fntj9lz1HG7LBmM8p5W83EWWT80IP1XPSVnlIM+DifmaP68XeOly8vkANFLnRq5orIFwQcQN/F3r5wUHL6SwzhE6c7P6xcCF44uVrWhtyyOT6dUAV0qt50JUmTyHS9ZCUf8cYBZKD+DDCbyjD6kgCRjdPtJzau27KY06L1Lvnnd8sFRCNMOxapp/epDk+9vpaXB3+k6f1wCOwMBmHbhgbZLLDTqmXcnc+7FjcuT0kZ3KidqE76nz+R6bOwvx7n1lLc8veNYNHpFCm96/G7DXnz/PO3a67783ndrzY7KN+1aFhjlgrAfhoXCNWsM6Vc17ITpfQiv6Txtq1jV4+XikyTDKJWtpsJyK8dEe1cfqOYoVLRwSy2LAIhexbnMinrE2+u+00ZFYqFlKaCc7ExHOMKn73CU+CXQmMkxwwFTZW8+H1W5XKpi30e5uYgop30rZK/9ayjOAYl+s4W3OKbxtBBE9D8A+Y88ubxiu9hnTWvr9zvzx9Rb6pISCrJpPLOJ9zFnm/W1I+kulo+d8pywEOFSZtje53FKZGN9sjJxvEwwH2mWDQJIkzGJ5yS1ipuPj0PpI+UbEVmBdtGtV7u2bHXtEldyv/JbWnf7ZEkeeGf+5elEk2jdC3YKsj2eaRRGHW1k6Jj4mYju1cEI5MVl1nk+ajwXiRE20+X6eMoPIg+SieyY8vJGiqR8bL0Cs+vrGz2VnFwdxNnnUDRkjYtDxmHYQ0ufDEuOtkXAG6/dBOvS4bj7x+sAxS+4wpdk21XEJVFiS+cyyJhsEdQzwYc/jKxZ8bamfYILufFqP2VYu9YHLTdZtKSLxebfXZr2WkREoLJK/U9jN9eetVgKGwxuM5MGeDa3ea06DG3Nqrp66f9c2iBnaQPInW8XZMtKWSOb8/FZBnaS1hKESvD2fwDEf5Qh6PL30sKtpw0RIfZDlfQcvvATa1RvJCd/p6kjOQWT3dMYr5xigVflAHavZz1SKfnIHfd/GUcjP8LkmOc3BknCiMbpOkD/TPQsSW3bmX5hs6Zwhu4pvfnJuhkIdNY2G8EqQHzLtFSQcMrmE8PgYXSre9lwM0Rh/vilKG44J8P6FTKdNRWisvy8ogezkTzYtMko+aXerJEX1IB6Ht7sPR94td/O+pORlRdsxTbeWuuMXWcks93d0z9MlRXP/z0wFfo/SW3kk8hJPVqfIm1Qc0loLASJ/kDVtl4ee4u4OIie9iuZhEpGIlEPjuUV+kCAOJxwdy0SqVlaAHJwiLtSXn+uaFsIQZg3dRMKPtSZtW02N+Fssj52/b6h3G2tCYyKtw0RyhvcuKTVsYugMp4BTtnU9jpROH8xG87S6nfe7iB/xq7QX48mxwaR9kG08P29jlnN6nSCkgcg8Amd3hhaUVkZi54UOl2wEheq8tRjW8wQ1DslBkhy5I+Au6qwBJEdkGKisJBGuudIJ4qdBZT0dYJuSSlDTMTbEc6Lwjsg0gjf0ucu9wKyPQrl0vgFrpb0HkdJBruTrAJDsN6qyyAu5YUGimiHKLE+jNCA/oI6lstgzPoGPUDNPhFsPkiY2Eau4l39KPGu70ifBmlt+50uOkBuN46mGZeQjCtj2aOo17nA8r+srrYx6IFfM4F/oDMI9vO3l3glWh9hmYKZFiXUQ381aqIEU2wsP21Fa0/oK8F0D+B4JALLN2VRC42wIJV8OWvYlk0llnAq44hBvjd8oo8QC68hIAw7zmz8AELZULt+GIZXdUfE3FmhyWWC44SDnc0V0JfWxN3jD0+eiSOFZrZtTQ+U9RUi6HUxV6X9xJ65IKv+wt3J3mRwekt3pfkQQbtz1kcJ7N7YSC5ETSf1cgRaWkH4EvQKHG22ccwLpX0BjcUMKqVxicVaL6C2EAZzXDQY4c/FwmnrobbxldzRGI/zW25qZtTYl6PSbKJz2x1+sKRCKk6sMKJ/xHLvd/nQwR0kzB1AGm7IZoT0KpM5WZvXlMsGL9NAN2UkWyhFcb50nLGJuRTadwdgqdCeUeft4ehF7iJexVeE3EtQTNXMd4FQjrKPUeaNfEl3KAIs/FxF2yMb8aKl+fY4hIO4kc/wDqjH/yThW4b1oQOiELfSZ++jTikqSxH3GOkj4FQlcWRbqJLnVu4oruCysAnA2lJS9un0H4oXwyAc/HVE6v1/yXTTDLtvEQjWKR2AZzOqBvTGaMhhFEL1fLylC6o+KmNqlbit/6UWKhkjYfjH6JeeP2rB68auPsJYzDNZBx26mDluo9/fdX26dRGGL+70Xf0h4m6Bd02/soVzN29Ba9NSDMDzZQvLtJXEjEcWO9PK08jgZBuIhg4Zjnck9NfdTV4MIyWwgvtHMIpPuxj4FiM4eiojNtnwwKm/LD3kfXlmuM0KTzud0BAKdyojH3pM2egCnA5VGiXoM9CehWgvupAlpRhj1yDiI9W3manDWLmFmz6sy9leUqEDnzI+hFk1t79lOrxu567zOhSfOhTu8PLwXfoXpCZXjdzZlMS+0m4UIxnknjnrUJHeUX10DUyDe93mVemIVaMP7aPUCt1j5wKnULfuKZA3koDi+itfAtHAvX0kXun535phwbBBmfjCzTIS9oC0sJkhsw4+wEWutROnP1ZPwp8v5QlP6Ah7omYuOR4pBypMZlWA7hOlDSpnHmfEH5jHG4xpyRc6q/9Ip0xBF6jJf4ggaifTTpPboOaAzk/N4CDcdCmTQFZpy2g82EMMHbgwcUHE3PrkPmQ7gskSpCfX7wTB/pWWKipdS8sJVjc2Y8cV7uTgoz0Mkqe/Rdw4bKGl/qROiDAUy+ERXKcPfSoU0e5TfzIucaz9WacvEtxCbbXpPkP7Fn9TxMqOGggQq0I44k5hXMl3McuZ5EELNLSBBs3mmwjmIyC8Oy2OBKk+CLg+B6VlYFuTlosUbq2A/dC5bPMKpLzpREF++te4lBCZ+CAPvoBA8lVBvBgnKhgxbDtdXKGTF73h7VyFiY2yBZgSTtWPsDUQy78euOOtADnBfCG2AdL9E8/XFIGqvYQoefhOiBrL7/WifMWlsO9of5oFcSXuixhmKJ8TY9Yw4H96zuoO7WY5femhSkwF/llFnG1nkcFpsfCBK62MG0zjzAO1H7K2LyFAm77LG9vOD5IbxbjjCor60pH1alKoOgWdpokSpmw/v7ZFMqom1F+Ci99iUHDAx6Vu8e/PjTq/SzjVplyD0cpiUPhX/zRAAzEdTStrx28CYd6FK+rEEW7Dce8ysMjgLGO9W9fZNFUpOzyrMF2Umg8gYaMQkxiUQRPeM9lU902Z/Bh6/z85aICWU6clr+wbIKmEtYleIq4e3VPaZYcAuApXmNHAJrljPPBk4M1+kb9+C+INrWsNy5qGg5iczG9caSYkVyq2ADv5+RT3A/bp822506kb+mo2pv+JMgw6rEBMo2Z3iiuq8zVEcreWLd+HUibp7aZZ+dOUsIm2g/T6tZEOfO7rrYyTFZqBeW9qz0fTChNuaCxSvXkADVWfUNSf/iJHIMzCuYOByU53NPZcugeTDNauFweJWfT8gonRFQEd64Hlo8yrrqwpU76t8IEDA8hMMoZFn70+SMC4AHXnDI+sIf7DfkhHVPmTOTJfH+oJsLJPh98IJAYNmGu6Xzsbd21z8/Bg1SWKsmC6tzftD7r3Hirwr0/LOChVFAjiyWMEkh6T4cruAs5bCN1SELP2BxIzj1LrERWX5xox9rosXIVi4T8NJ+wfb3hoYWnhooWM678XLPyRQAokhs1WhQgK0tDKRV4mqKG2BiODi1lxnxn2OguEIML8ECD/aLA30NSUvXteQX4o+ga6xE02cYdRJVdMHaLh3uq2ZY9tXryjEsUrSzlpl58z0hLZUMSOwAw6M3B7P3aWhx2232SmwfmnjjWVg6v0hXBxdrAj1tPTNFF0ni8CViPmoNxqKf8BNXztMD1YCxpi+G3KKltV4zZY5DwIHe/Zdu+9HsV4l7hTaGTWpEiP0LiVZbe77otG0wmKULmPoxOVazXOEAWhd5Xw8ykRodtSO563E58enlSsfcTwGnqMFvSaZ7KB1t7Xh2m2zYzqcDVf07Rs33Bv3gS/9cH69zrZ3tAvXCl017V6MuZs1K/MY2ZQeucpcRriCk4kULfMjojR+GtirTUQ5EmHoAxOBWY2hw7Tl6JeHM6/vUvgGlD4qlTVyXqKrEpB+PzDw9XSIvUo8r181gTVUrksf0zge0+aG1AtANhUXL7pWiNShqoSMfAhoSvlJP+52bp+/IY08EdSOg/BG+BzOvl3YUt/U38mFzzpVumx8GL/2aVVJP5LRw3HKfb1cFQay9W2f+ZPw8IzpqOge9251G0+Xj3VbYFQEGNo94c8mzFarEC+VNijErPhayF5AnkGn1LVCmSmoafjOPa0pS+BqZycU7E6Ufcx+Fjbu237hNtDh4wGlZ65psUJsiYLn/URiYUlUb3p8A+q//z6dBLMi4bL6ID5PVltxbOHa5W98SSDXiCXkfEU3BwURMTOE/5aAnL5lYOHZvaq9nW4dKG/p8D4eWAjaKu2AnoSh4D35KSrSkyzYEu/ZW5MwgECU3ZReocuVn205ijGQuRdEv8yORKnsJeifmKNOQL5e0am8V+6WV2KVifCvGkmQau3Vi0E4qNMc44vlKD0nSXlmTZaKhgDs+JJm5XP/D/F9opRFdiXmvOMZWxUaOKg1hyMuuQ+9l2UGrw8JmOtK3Jd/NiGu1xIFgEJ/dLpolef9ib4bimbea4TQPgDpSla8rX1AlYCMUti7odjRADrNqzp6SyZmSTM4u0Lq19gBDJJOo2hQNWP7LUs2HOaroeHKwtmJYjK7kpRcRmOubVCM9nWSslLLb3/mKKmiRb5F7SLz4UzEP12C4CcouglJpm4CjJs4+aLVfQA90ZqWeEkqhrdQ9Cg/AWi5AHxALxlezNpc3KyhM6bMXIGhmhWo5oi7+bJdGdmD3kp74iEFDH9aPUv5dJRtguOPt5YuQkhkvCcwinKl+/WkVCwzRRv5dgMGQjYq2E086U624Z3Xd71oqAZoHtIJ0iLgbV0yVSTImNBx+AxPQygonpnw+XMYWs4rdzDjN0YKDnBSbZLa2MVVb0kx2KS3gq/8rpqMpW6M1w6zHF43PoRVe/GCezMxJgQZr9ZZjk2suusqg1MvKlJenQJMDsM5uVnQjbi+ZAfQq2WrK8N890s5V4BTuu194HNJphVzVQL7fue5AimKR8yv+snqr6vCO31EUkSXzwn6kbW1ao5/sRzk5iSexmEmdDqrA4i9ipW6Oaeq58lb0zU9gfGJAaLcQ9z1d9Mm8iYRgmKvWzzA9yTnlooHEXt0fmg1rlr2lpR3ZSkLg6+Qt27I5RsmTbvQzBR/bStIHPv9OjgqpklaKs4L5cS8dDgxwAebFw7sYvKcPY+q0hbjyTdy9fyPTkqSyBc5w9lttY4K/Wlp9yJ9dXtyHmu5FKisMU85GuUt1p/u1URuCw2w3FCXZb8B9xegWgvtJ8fLnL6eCrd9MzG4MCNRHkdFChiyUKrsussk2KAsK730EU+qHtYwG4P52/0MnvyNqPFdKQ1pnq/kaIHIhlol5gMLCfldWNnky6tEPnJBizRXXuKmrBumso7D3iE9DSsJYytzaml1HSLYPkN4kwZ7FW7xC8oeuYQz3wD+o/1n78d/X43E4kWBxDX7ALgP7gWTmk2RFPJs3Y4pJENY3CyY7MHnkoSgrKGj+a1+GXGrBQyRCcAZF76NIfx7dLVk8X7AoveHv5Sn7Gadg6hRlMWX537NSABh8GWzzD+cb98rIP3nKL/d9iOi10ASQeso5EsDtVThE7F/bPeGvzo5ZAz1q+pSNP0kAvu2eklFzamtjPAIPnfr0WD+1207UT+ZHHYFVQVSWbN43iyaVMA1T6NrZe6TRr7CgwFwHnUC3amYXDv9wZpX856Z+05MYqGNnXiixz+/sEQS8dHSYjSSMMVFAJ495xXxdcN5ZqEVOTTm9UZuKDlKtfY+Ypya1ySZOfcjtFxMC6LRlSLmi8J+oGb9HowsHXISBaVvhs9zQ8t4q5lhJyIuISMZa8SNGrAvvw8NsekMjjZJF53twMG4y/RBR7Mpyd0nlJI/GjExOjIJqqWE8f0RgiqE8FNibA9+bRe6JKKzNfi9gNHxy01uYYgH8Hf4QsvIh8UsCfVRw7YnjA5bi2+aMsvx2TjTIM1jdM1nPlk4nVGkrihiQscH+3IEs9WUDnbiLq6XtNbU44RfoPglel6353KnOxd7kKxVH/ELEPSBU7tRfpNurylBmQoM/VLHJgAbs0CxXVu1kj905VEC0yYVUXac+UqnmJtI648FDyMs3W97es29ngAsND5EUkPOyx5VaCqbF2ClfDt90niU9XLrVVbz9UvyJ48Amg5U2jWfHgXSMvPt6Y7emvuW1xb5nh/mUGkOebeEO7SrIyB1sQjJrA/rO8RQ/aUzb4OfrFddPd1upor/1IVsKjcb2YElfN7L6faTgpiGXn4AKyDwg+nSiwMgSTy8kJNLanbnDG9tBAdUTuWEPbqkTgVoiqX1Qmj2tIBq+l3b051r05Y0i6FSs0nBn+xaNxWZShRH0NM6a5PEFtNPS2bt8JjKge7tbya4tXVq11hNNWoHCxarNemrEMbmeLMuR/90rbTkuJEJTWesVm6KHzAm+hGdvUy+mPdoaVdQbYEa14Ya3WJKEeQYu0SCL7oBxwYSsBH/+tDwUc0THf9WbYJFtSxeGvsmiMkOJn073cxOtPZznUBB3Lb6fg49/0YdYa/UHWoeVM4oWT1sVkvreMnmlYVBPyg8DskpDh/6+naHMbM1cvtr8uaF5OKXLxYt7m7OZvZbcso24CeybbnCdsndXcZzZaObi3uZKOw9Pcr6OS48DUyGyHqbBThG1SO65rPks0oiqITWzZyOedT3+iiG1uohUfQ92/Rr9der3wwn8hS2dZwY59DAe5vJh1FdxC+uxRcpfAnOyl++aDpgppitMBNVqEeCQLVLcef9DDnREO63Hl6pGFmEXV5nbJDoW76541xq4lWgVVwuYm3fGZibmjC8YaPKwR19uAG2d/HhoE9BhgTIdAzxd3DpeZ2RR2b5eQsjcUyDAPNSRyXpnSYbQfxOL2fhZTijVw/odNZAwh0l86n/pB6aLjByzgL5luPlM/GFIRcCAdJm9mXnunl1q//k2px/uzFBgsi25STiF29OwIClQZ5aauLneyMFBr9JtR4f59AhECXps8dCuYfc252sEwCvyFoHzMh6B13BAjg7AvwNnbkeg5ozsop4BFgntPMCfTnyxK/DC8sU2sM95qMOdGTiq9Nsk/P7ctOvh5LDdgc3NW35d0TIRwjmXfUQgFJQ4tHmqvGJALHSfkefMevRiRMkqkdUmfJ9g7HIji/WzV+88i0vhyJ/Lck43upkkovQ+1LU2DWUEg1kbEpbSfeyYJgkgcruqHUwg4LVC7nb1dK2zdQXPaL4lHRdcqEYJuk3iJG3FzjhOnoIYs9rHFqyET/sCqPkBvd5PU1efU3pHW9TcX8oKxN9Gs3Wo+JAVY0MvzKJr3THm9MIrf0lPqBAaOHHTsIQfwymXupgXQE2LTjqMFobvTUhpIOQKSzVkBtEwfdDo6nbHocs5oqd4z5XW1STeOMLBxmD7ZKjLnuZtd9vR+pkisyks+HrgcgDviTrdS5EEqd7hMW0cTvt3FRp3ztWGZ5FKh3J/tr8eXtfy9xfTeahp9PHoOoUo2YchTmSeOvU48njeljID1dQiP/61uqrfJ72oLAUU+aplxMork7sku+yS+6VpOtdBRt3kPQxDRbdW8+C6AHzVa37qq2rabSrLRN7256ruZNy2+4IRJHULLPJO/YaSXCse+4UGi8M5cHamLFLyC2FFBTmIWAO8rx96g34QuPlKRFPFpfc0ayYFhVDBIyceszEoWar13qQGxZ0BJZltkaP3b8rIuLSo6FEL/oU1g9KxNQOxHPUxOa+HE1mz5t4DWiiBBTSnMDwiWPWmLM8zjc177mntulNXb8VLNYDoFgP8LLHmAILc1vavB2alvPK+ekuOoPRzt5lFF4zSljCVb/EExeXPkOR4E0LrTnSzbWbEbmT5p1zbt8Bd+5tHRsqXvcQCwg4O3eP8LQgnOMTXmwELfvw3lf+CZMAMeSuLeHfUojsQOisNGHXXPNb0/JX6cfnByxonC4Ne6E69U00xDiqkEfc1NYCzBIcR79KePS+VngFCQ3hcwT45jDjeE+JHCF9pctvbCbD/O5L2FfDrV+R6wvfIAzgXkBbiqv8VdNaWuJP3LfoMx/1K6ePmnuDjQVfUBXuUJjwstyIjP01aPtsfFBFOVFxsxsSQj/cV+S0YoJ5WVvFY/T0F6Pglup/QBlWAoHAi98GlrVMUsvudbomy5lCwOZ9mR1qxznQEiyiHaz29kS7HI1jS4+3d+b061HOILABAj+2WALi/kRuJ291OFjkWQdhX19Xzbxe84LOcZiCcQCaFCyiU0Xa82a0gO0B3+Kyi2/gudhX48AJ67e0jbpCdvCYPyJ7YIIkoLef3nNY6K4cJPs2ycaoJN9NwKER8NZQZGBEnueCWVoW1Kbzm7j0xd6mXxnP+bxDjNb25uNMWtsY/fXmyBGl9zF4EUAhIk9/LhtFZk9WEtciThbIxjcDDFgNjlm1+LQ7soVXlH5o4dynvd0FebVN4zRJUMmOX2jX6yRYIQ5jvc2fEVk6n9Zfkt3vCnh0BKxq06wywi2s2xt6f3ETlu7yol7tNfrsDazHAoqEM97OZqM55a1u6d6/Xfgg6wdcFTIdWB7XvxeoNM8xxzSuWHqfua07tR/R87rNMyScT9OyDkahlvrOE+Odwndq+AVwIp5l/B6m9aG7gx+mh8fyQPsnuSbPtPGYbvK1ylDI2UAW9B4ZgU6naXe7CCQDW672UIdCZHyB+hEd066ZA4qcYpAagw2NoFT4PHnAkWLa4tbk9o3a7aDukHcSLd7xFK0jrkAa7naBEIedMHfatzXwjnmn/kDP7WRueRBJ2kBMt2ebj41lGGnTbilZO4yaO+wBtfphzRk2nQ4l0UikKVCeyxDjx89gvioI7BpCxgJO75VIPM3FbmysLkjyz05lBxd/FQZH6OcVJSY3Mv2XRPRpjFJv2Y2wgsnvHK/8PYKtDCQbI1a2XiMJrv/GZBVathO/ETihYTT6ltdHbdcd3j8ZA+cEb3SGUHkXLC6NlBI4649BuVey/JIQbVlt67uLoDhEt9m8Ma5XWgkfAQLFIh7bvgWUOp9Rso/u9vzLrXi75WiNHIvXnEs8B9b8s1rgWPYjlt1u34ZZsJEnD/6LiPK2kRKcO+6BVX7lkJrI3850tuZFk2lbwbOYgcSNGHoBITnzBpjnt7gjyPvnJJPX29ia/ZAOI0YQIchrmoR7nATAoZPPaC8rgyOsyz75HY8vowrzNIrDhx1C5EnQ7U6pDZmx9ca2gXCWQTf8tldBOUQkQs/YRMvjoxfO8/bHyFeJghvaOywwaakzXN9heNXudfJavmZwg6hyuEhoO6s8id7duaL4QRgumcUWe9o0YNMzeVJxOXjeze0288jRKH1pRllJkkXm4CVaMWcDlYK03rw0jXQQzg0fzAkLch7/dvcSV0veJn04JReIXvGra6U9ydSoATZWZMfm6stDG/ULQOtjApjWC+xligf0uRomf53sCY3kdntXkUC0qfrcvUxIHwZrd5ZPKM9mztH7pD+ejSiG8st84m9ySJs3Q1u3bOHrE1POfb/oevzyWoszARgPAZGYXhIaaRGxdfP31HgR0M1gW+x0pvvyS0wAGyYFLLNUc5j4Go950Qy/cAzKanEycg39QyYgCdYWpAPYy5N6VAxM0SOVPbtTcvXi9cMUE04WTBouUiAGB8Dx6zbXNHUTu7fE7Jar73J11XxnkD1UJiQ3r7FfW8qGycSoIsAJkWxtj7ZAdbhSb9inWgEJI0OJz5BjXr/KoOdSfTsWuL7n+o1EXxpEKY9VLkhWnofA2CLBToN1x2OgjMzMUXzuchQGfsaI5dhbl1Y5iZjnW5rgGd1YIMyQVmteNcmgcP5usmSVza6Z3SlvvSi/H9juLN/Die2hYEPZSTde6UfykHZk9hc+oEIjb1L27qdDi7MVHS4euqN0RQ4KWLizQVXVql8/swbWuTlHRL7WbZrwLS1a9drbyuTPnLQ+Q7R7mph5P/PNnQ67XM3CJsRjn+ZlbtDVRy2T1EzvsYUpmBT2kRhG7tT5utA940zoal9XYkSZruNejk28ST1o0BxE+D7jr3Ibb4QtNfusHM8wN9rf1LdtSoUXnl2NG4p4D5/fRpwhMKvjK0u7KIqGZ3ofdcQEC6Yy/Q4k7vLAPrfXPNfCQDFlGlZlUhyQvj02AkGxS6arYjLOPAXam0IMna18WV0Vm8HtvMWE1EAuZN73TWkBT2MyXpaSqtZjAbYt3u8cUIwER0H2K6g8Uvo2Y3WL0TxaV9SrIbKz0OjymM9OGwNE7YPq/pyVVlgMJIeN626g6i4M6jZlbzzAU5bJpUQBO8400qiXxc4kbrDPxghkXqBcuCSKuC6Mo9d3WSfeQEsiqs+i6wdBz9/22FRSzBxHafoA3kvrypmBGe7HtYygUJrKMU9OPx8lxmOnwQbPz7udPXJmXGlf4zcXs8wr0cA+tO/3Ll3hSvf1UR7uYDizc1qoTfUmL1dq8V22N3VYv12sEnisJz7D2A9V48S+a00vSELlwK4cPoDgETGlJiyL9mETKsJ1MDWDQmWxfkwq26p98fMRjAQBkWOmILcPtIRSGV3rb/dMkHvneo/h7K9gaYA8y763ZE6/Any8wH2c11CKgB2tnYSGn3S68/cGk3so0rBC/hZwIVJVH2fwCjeU/zz59C1So3JTASP00Zdrkpla9QQOJHhwRHRLlWhYsQy13aSPxK6t4+c67MWi1dGK01CBZW+uluRtqwqHzlRhyhRUnaJdfLB+8xkcyvECrM+si66BB5R/+LECUbF+Lj75xpJ0Mj4eagMUL6Rqb3+s9wXNfzi+kM3+YT4nELKhDQVr73O1jlUNRfDB1ZESnb+KRwNVOUc/1xWHRaYtrwQx+e1eSKPEbr9NMDwQS+ZRlQPvuUVmL/RH3J0wgBQpSxG1Ho418LHBRz4RbXUtmNUzAAU70Bk3Lrl6PmawSymcjEfbH9hqksj9ApGEkMpVz1cp0tdL75DPNrgmpbV8GpEIVqgoHEOH0HgTQjAWnVXHakhLbvEyj9be+aZqiax4tb7hVBy3BBSCP+iLkFofyERIjc2aHhFdwuMVQRE0SIGHg6hq2g6G4RjGdi32qwukgE8Pi96iyilYBAaPvT+r4xTRS/5ggAd4pUVQGALP4+serWa2oiQ+GQj+w0zFPXFSFelPuLcjFhudWaDfhJoIeEMn6eo7vY/xFJTGieBe0PxnCicWjXakWlpaA2WRayAfzPH0zxicjIdSUAdqNtXknqp0ZWmN6bpSm7bCUCT+9kx3e7HzmyGr32bhsXkGH1pfg2jN3AsUSt52OL+7KSVDY17q5wP2ANF3jK/4pkaH1kQ5R4RH+fdTiPim2c06aW7r5EDrgDeLnEnll62++24y1/q3ntO6+Y5QCCH2JYD4TgHGd8cPi5rep1Pfwhy/12eiLLqaidN5tGEIFvIWGzXdoR/y94UNy5hW8VUeSyaIBhUBrQyi4ONEKQectlLSdkQ0dooTYnWWsiEQAGb0+hE2EoWrzTkYZxxDJFUZGwX1rhA7bOVMqjHd5wDBEz1l1Gha4+AN9aFwRkGEWDnG2GvBTX/252XUNpPJtbDKhRM7wFYZUQ17F/8+6lV+mPuapJx2Og90PX0AmbpXjETCPC7Q5fyzkqCTkR53YCs82cr5Xv9qJ8IWHEF6PZBEha83NQkZzWqpsnZlHltbK/6wevXYfC2sDDy39hkuyW2VCASGUSAb2kB5OfW9mAi1k4qFrLtpBg/w7Jthj5J5nw45XZArAMSpzyuAXECKmU/eNIL/ir6uUBsNC33Nd4HtpTU5tZ04YjWbJmqbhNszxOTcmqWENyWF8+RzxdaPHnBjr0oStSW2Sy2/GgoSlWBXIg6EjGxQh7I9Hfj91uBxQUD0mNvkI7seAxmkMgA6ZDHyhth+zhiYC3qMwhh9wcwN9HTjOIqc8+vA2Et7bcVve+sLyMROmh6a/k5iHc12WaEZoZAh5ZdLn8uBtRinE+XwFBFAaBHrzTHl0bC79PFV6bxkv5Fzxi1TC9DBV9G0JpF5PN+WScGn8clyGVQbouuAwEIFAa9dgGyEDIaM4FD51K4DfpwvTlkqhqgmI/x2as5EH373BcXeoIeL5HKmTqE3Hi1J338Sg5divsbg7hQWIkMg6r5CkB1xM0tf05l3hECybx5/0J93oOEV1GUxHoAI0n2Qng2RW9uqfbbiFu4gtPjkWcYMsqM07cKpVSnvLjTm/qpPrMNz2bdvcwLRPsjkq/WHsFaEURHs82pZWAZx55bGpe+3QyKe49TLBtxXsul5vpaPLpV6fSw/dxCW88khGsXUFCAoL/g+UBU7HhyfGKuYFpLomdWsV2NQtfhxwrJPTZ1ubwhKkJrvRwfbESiuM5Fzn3h8PzYwIuS1mRKuIOG0/Kp/MMKPzRXR2axdaBijD8zzQIS8sxhZuHqBpADpmhssUqzSmec3NDkoQYtmbN5l8h5/QgPsxH9lS/OR37MfwcX4Lv02Rp28UferdR4rY0LXV5rXPMj0Cq7zxXnfdpXYbvKgJz0vnZxp5Qiuxqp5C21QRRbB+xoQVAH06IRkmMoZy60E/moThd2Vuq/PhjLeKa0E3x2GdsSQDwQl4ZvCluzPRoWV8tcKxD4S82PXmJ/6ZdVOroxgAS7nPV15sm4P/Th7cTUdhkCGrc7LCPwUKKtHep5jgq59R7HJctcOn/dvrXat1p6KKgzpaP6tYytmOKKkTUugq7HJHjkCRD0R5o48I2fr83lt0VYVfsIkFy0ffdno+H33SKF2q4AQ98cuFnNnRuBkOBD/j+Ez+dyZj6nu9Y7PvuMJL+syXNV6It/S3DkFAhzCsUP82/318zZbQX43eJPubCmLMf7o98CE+KkRj43kBvKNBAjmOGosTWtxmUBtbNhs3CDKaWf4ki/oul6cWGPvmT17+EnVYCfvraWOd4Op+sXhEtgCnX8TJrYg+Zy0Re/NbPlVgADzDRLa+UfDP8R4ai/xCWeL3h4Qn97II0JsfKtgMMSCrxWCQ0hMztpugMshoTz3gFxOyjZNLDCePLtVAjbiEuewnWokOQwLCf+E67YA6oX+FEMyBJj+B2WbHb2jNaXSlD4ZXRxDsCq/+8Z2XTa18zCjw7L5MrqvguBasEMtnSVfasYIzoCNWfBqhmvfinsigjtAkQIJTV8Dr2aU2+xj9yua2xnpHi+T1zWoejYxjODImDvxiAQXaomaWgbhQMBjCuXv6bHa3e/3JWjsrzOExPcGVAyfoSGCF2OdorkMqPM0+xuPU5NLnB17YkDDIlN0+slpg8R3DD9DHrcGSev2GsPSOCltETPedZ02Nq0DoEb6MahgozwRGjhgNZ0ST6nsmxB0q8AknxlA1dbjKJLmtSeZt/tKhkr8tOVHLlMfA4qklHyM9nKFF4v7PHPLej0At8gRmJrjVGnoCmcZlXVeih8GI2yq+UJtGDPH0vNkUG7RRsyeC9c1RAtnvoFP3W/dQWNQOc7QFUe35fHUy+YJWfFCejL8/QjCcbbF824f3av6+s4DTLPFF9SYm5ekO/lxNGmj1wGSy0ZQfO610dD2DiAdoxkltG6IRXGCSLs7j2jyASPu9c0J+w4+1Y7bLU4d5nnSYFkINpNsJJ9Ys9lXsrAZfX49KZdRf/1SNLED63H8/IWc1taG5FjI3ktCBigxkHEl0SCuzSDDyCHk3zRmTC4gWFvjnnxqvq906bOy5zIJ0QrMVhupevXvKag9c/UsOJL9K3zJOgUVRk+ZSZrXcbqqsBE+4WMGkMdnPCQcKHedx77cCPazT19tmZhqT8YU8ZD0b6DvuMEk30py8IPwRsy87/ocpFwU6ODWlCPKcr4oQDJ8HmCkiSUuez/PEtdjULUQodKXY4kw935uEh7UTtr33ShpVy1TKioEidJDNGtdXksebuARUReImYdEhejEXeWV4XY9WIkSHUqdRmMUI+NEvHJhk3S5qDmyIHMmwXaBcMyM8BL699v4Pcvcf7VGR9zuDatKJ0ILUYlvqYkQbTFkvgwQer/P722EewzvkQfSWoO4JhUk62CSP9Iteyw5+edw70NFQ8e0fdQQllFRDE2Wu9Zy35CID6mBGNmeQSVFomVXRRr3hqxJl/q/vUvbZ2xX1SDJ3Nfwq8Gz+XFLyKMpriRrafMIzzKStBJAN245yYAhX4XurtUccmTmh2Yjeqn44GUfU8nWm+kStmbMp1SM6ODyCOoAapCCGfR1XypNfzSlhZPl9XBhpfz2Ch1aD0Ae/apY7J58qWgc3wltnVAOlFkTtLV+lZf2yjNW5n8wxsS+pK4TZ36SAf9WtoQAsK2KPmwdcNu5/AJhkPWOMejKJQdJe+UmLln8g5QUz1/gblDS3xXNGubjAWlojHCMkzxojzfS7zOM6oPWeqfZyu8bLIpRhm7xurNYIlza1rVrAjKARNQYvcqeZSk8G43vXb828KsK8bc6SYdU7nymjaaDPeId4iIeQfH4fxjsNAVyzo1d9tO5JaydDd6HA5V6uRl9Vwujl2weTuNcyLd5xECe89fWa3V6Qnqvi92LJkBNR0naltp0qnljOLQXLtNjwuusIOKxEDV+Ka5l3MaJeXXDjRM6KR3e+CEo2si/iuO5AZ3i+HjpkzYok6Qdqw31j4tmZ3zP2eeJJwWdJbZKGiahZBbLELtVp8w4LwQmM2S3HmvtzJB5fPrV21w37+ZPi78DKHB8/uSoGYgX/gSP0EppCkiigPGWPqKWdqbv7dRYwxj0C+jiF0jpr9l/Wfk6oas+HcXple/j7DI0AcUlfQlYJmrLYUTd5NX1izsxvdD3Anppw1a2J5XLZjtHEnNXr3NbMi/Yc0SiR+yEJjyEN47kePdMP2nyNeLrNDVRja+0H9HweOSwzNQ9f0sgYXUWx/HTzlXyXe0fybAqYdd71+RRyKlZobUPatGytp1Fvx1QIJxqDyJQziEldS723LSrIa3fNzA2oe6zQ9qB3RoXwFQgDdiFkMPyD4hd1xs6QGkKXCaoTfLEY+L3q+gwcf2aODCz9nlXZoiazV/rHK3IiQarYekI2cQc+yGoDUe2GdeSFsZf/aO4DP7+wE9CClA0TbvaMXlH8w7yedQWRcVE9hyP1j31ToRtjnxIn09MxOlpAPJ9mVlncIT1IdjaeMblFDQRg9YotPL6grYoI70TTCNOxG1PbYLUCrjc93bymWe7QzsRBWszd7DEuVApzbbxwvzSsbxXdH2QJj8iZ83y13G5iyyj1jvrpXyqxK4Ne2w778dsN3Blvtv17tx174LTV000X+BEjxW+4MFPbdgyq7v5shhX7xEdDbnOODSf4Y+xrcb9MzSDyX9QSinzhCn07Cr+0IV4k3bqZoa9v7umYKhakfHLlcsyNOPmsoDHy16Z1yB1A0to0sugOgUSxcGGqbmELUJvRqhLNyTUIn/Ty+Wr22sNDC4z+7V7P0pwpgp2650C8/kmH3GZYgWovjmACY13R+ELuAuTKbvAYvuEqW1op+pfPKw+3cCZ3n97FEL4bM6AQmfXOqz19125fEhwPyN/idOfglh6vUFWoZI3/mLFDyli27Mg+uC5yAYG7dEwZCB3gew5n9Ue6lOnrRQJ3DTqjFCHNgTY22gqw5AFnKSArSoWtKycBTNV1bii3q9+VbhvJ/SE96JC41QH7SSgZ3zxj5BClkWvjl+JWaIpJUkvRDuyyuxgfkOFAJBXxNjhKJprVwuBJWD7qDRbTXHeBe98wJzkr9px3tU0cXuP8Ixik31r9e6eQimKFxlvjshjhAeGtOX4pqC2tUxn7XgXpbsxZg5es7CzEpydoK30DBDP39YDf41GMfKVLxe8H0g6fqI83hEfFSYhezin2Q6T8rWbtjrPtEGLjyYYGubTO5beB/PgiWZ/sqD8L9Wpbzschx11aorQN/nKr5ulOeA65b41Tem+tVSVs8rK3MtuNPYN4UdcFa7NQhNHhTVcSPXgfuRr1x2TRfxMJps2S+UAnxohmu2pFwG1G6Fd6MrtLwUw2JNdGr1FlD6XfIBhK4dbIocp529qDYJ6wNZtUk84pOk38QWLsFhhbsTD6QhiRBwHmeAHoy3C9i9kp7EarICJ8e/Hak/7+0Yxrxw+D6s0cvTFGH/uPEalJpUHBPBgsSS9aRIJLT3Ymcc7Ekm6iYpmFQJleAXb0Ca8VDh+QxZ2taB7aYpDE00W4kAWp52+i9s5X071Pmymq88kHwbBNBmNn79R0i9v59HSY7jo5SXYEB5sBtVwkqG93wwafePypRnGRSZ5WYFfFre0hSmH/5PGKZLKNjUoe3/nyw2ecZNkQwVEiht+C0+vdVjPiiebPlirhCZ5mohqx11sIyarh8+AGCkb+ZGiRuC4sXqAOTb5CSFCC2XjaUP4Ai9WVUpiLJDZaaZMGc51bIHfGqH7GFE7U4ftvMijTtOq2IvC2QK7Rdj//Yw4KBwDdT5EGXmW9YZeRyDumcBZurYU3TYHhk2DQq6rbE/mgaPvh1JhlFWhIVqPY1PvLToobchLB8OCZucJGZqAqM7W/UXKD2VSg5Bn+Xf//Siq/+43kTwzfAM5CLayGqcVcXTbb5MfyPjixS+/02YRD/yvwj2qTe1L1i+liy3FfuhrBS+7LQSeRAXVIftDYeB/ymDdXdoV0SHJQd8bN0/8/iHkNxrKuVaX2dI5BQNfTo0fhvkqTMpNQUWqurHQF0FiXK880sUlSocFj8PoBYa9ZWyIxki9yfyRwCs9I9u+EvAKivDoYfB1l2CgvSPL+6bp9qWdLRPl3hqzaVPkOOcAdOO3kcPZQWwd/X7pMvhpHAR9/DHQR5t+nOwlaTD1wiCjdl3V9wcmCjmsl+5dVWJ5bgjignQBVPfACmRnP1wOKk5Ov4UJBREtgYY4jKCvCOeVgOZBnbi3X70B4Dp3R4NaB8kpeXjO7DD4fCypatXGeExhIkTBcr+Y4GVTM2AQXtAQWKwyy7CrXA4ISwGN7x6P0i/hQsnbiasdVPf5H9/UMg5HWjgGVFaF4H+SEKk4OcDjyRjEbdmjX2YE97R5qde2W3RHx6tFvz7iiN53MpcL1BICNgrnbpoqAe8jxMpgVVUt2zBy7xTdYcpFW4ATttXSxPkJZflrFydHaJsnKwI6LYmpsXGCBn1mlKWsVfJS+zEQJ1xx+GKXyVKvJB/owyk04h6yJ1X2XJ/XFvxk9JkZ2CTre7E+xm1kx/qx0CEMSuG+jnVFWXPByW9EuejSjgujPuxgPZJ9rEbq4jkkgtkN9NdRZkRIwR4dOaup7Q6G06j/xlX34ItKYIfwgOzZopTIbKT6ExsM87qPaOJG6aj8VIyLfARUbdhR5lXkUbHs+dA/m3JT3tnf2vALx9ZKgTW0zg+xwjGpUbZrVopMd/hig2qAUWsb53iXJEP0SP0WYVS59v5ljZ6QJKzy7SdJb5bwLURf+Vufwlix1aWyb0OdSyUeGCMlhXqKsnqCsI1/Tc0f1UFr6IQN2z6zpRm0VVTbIZB6ohgn/4eqq1hwllmir4TLEie4B9jh7gR7+kvP92/uNjMh0FRXnXNK2puGv5LcrGgT3mHTsxLN/Dy3PySSy6JaoEJ0byv44BN3hY7roDDDWhldXxT+ws7du/ISmwboAizXCc/F09YzE8drcsnENUjGcfCfvncrGVtc9asy5AHaf4ZyQ1daYmhF5qh3L1JtzEUhsvWrS384XDIuVNANgnZx+6djqvAQSoKghb5wCWljf92xYCsp/PeJnvJEeZAYEOGHkcS/Usg1oL7VQzcQDE/INsjndbOnwT7JENKlua8MDKMbTE0YxNZXMtRQ119Oh8Vnn71e1VaKtXP42xCYX4QnIZKqYjQlm/nymnudh5O0YYg+G1oE+fbg1zsrDnZtscxB8ICY9xBxqV/fygh7v+hdEWtDtZ4/jaVE6QOcFosjXrAoFZGYeg9UI1YdLYvvO2n4lYwiLUVOJ4JYXpPoY+xIa4fyYm3Gvj8GKpJYBkBdgFkQdlM+zrstbZm+Zke/WJTbS5O8oJ5yUVewy5PA+7OjTP+bqsOgFSlXrAdKKVPPBcom1D3OUXTMtb38POI1nh7WfWYCdlQadOL7px2Bchcgz4xMVmVb2gMUrGGUwEoXPsVhOeVGf+kAj6i6XHfQ4RNrRcg7KzyBrIL+tQ7ZnveHcfdoIkZ9TGAlrlxwXdwGO1ke4pOxT7NYbEVZpoH4lfQYD/T+/B7nznLzWuC/XD+LwEdpqOW9wI/OW408Wq2sP7zfZ78in9NiQ8am2RKN7qkUw14Izqr1VkjNhsz5zmKsi1dQyXXE5Q+VIfIgmOvfPm5aGy9+NGbwbBY6XZ7NttxJjqmLwqP7Gn051hvd/A5keTbFMdGk79mfISsYAm/p5gosGnaykFpAeAhrBsv1zhlU7WdnVHZMC3N3jPNTgeOH+y+THqIPelcM+TINAj4h05c9qkllJBCOddSBl6oW8B+f4JqKoue9WbMsY+6tPzEDxfXA1K0/cY69GkBQI0mWSY39qnz2nLTviPTfgBqV7TB90AfjPJtzT0FFYodnpBhUn4cGNhGc1Q9KNBMbORzK+gkfv6GFq+GNeRbJNQY2VsVwGk/SDGYchND64BtExSRZLTJQug2WPMK4t9CaTEC7Ufa+NcsCIik0asgEbcBaZNLcSqecaMsbtlgJuwoUoU2R/e6hOKxjPET29mMKl17HbdgHzBVuyRCk6kUtdUb46gUK8aSa6jnmrrOSTeeJfm1QpLDFIkBFvHhX/QiT91ZOkHl+UBBDTPxZDijPYXuU/9pZf5D7Yo+geN3D88wwKY++8yD0LyDdKPbLn3qiK+yo/hhFcYbUkZ9e7tW0D7vU3V9TyG+5eiXEbyTqoK1CW2nSpX6uTa/DKB4n4JlzQPTJuS40+G7SjS0fxcO2OjXGhxK+ZUuV2+X1bQwSeCj+N5dAQx9spPAG3vX9N+JG+cFR2SMrDUAiHmjsyZwp9pOoPKc76wgqArQ2jG4UtvWj0MveYEZ+ua6Zo7GFQszVQq8x+u9djMpsBqh6wvPfyKmqm5XuA3ABzbb01BUkjE0+RvTcjXfv8tkLbhT+YoKiwQRkzCrMExYmrqGZiS3X8MfBhN7Y7rLKqUlf+YsFDd8OPSQxSZ9404bFOmDosfBjMMHFv9bTmt4bWNRTaqFFcBS6lJpGlj6CxMJKYfMFrkuz0uKYWNPUbh9iq6uLicadKvciYV0l5StbK+LtVbE5ZEtSAqx9oTqmLBR7sbbolo7xfqmsPI6OUixTm+h6mP1YWZKxDrBIs198S7u7MytN4Yy4hbybOXau3wKsQhSBKj24z1aZR9d4dp3RZ15mMNASGtt+8MjxTqz4UYekz3M3aJs+MdaHCJdE+0VEVFldvWLtzsEHJi5P/DEPrVJgIs1t2vD28HVa35HXK64w5b5wf9bNH4kQ5BTlIDL5IBkClEiS3nnzdbnkQlEghbr4GF2jGH1HRPyRKZ05M8B5oMagA09t1dvR4ku+frNGF3Swxaw7zbAvf5e0zYGnlG1iSpooiK+j58TqCjuehmZOyj84cen78ky+KDR8fXx665nQ0d7L0TVKD4G/a1FrhB/K5/p+MRD45Kf1USlYpKAoCmfw3w2WU6d+Sh7R+PY5hRuDVNeqAx+nuCoWp1xozc9c1iEdWFb70iyweWT59cxi+cdgZcMi1D8GEGNih1IWCOnZaimCtmB+QQh+5cvF9dGBC2Ov8KF5xs0Jn0PbIvnrH4s+nkeLX+nLarzP+PQYYN6Y7ZjvEO5aLK/LzGNW1usS1bpZ1kAe42TM0poY4AL5tt8GdrBjkivoH/jkSVMIzU2Ray30yDaSJlHLfPdIZiz4nnf4CwinixJHhW1vJ//UNF+KA31ED3cMqYSl94dgbs/Nz1DAEOoqk/J4w+CkGpzPtU7EjGR88Z7SFFKtg3KJRfMeHFQlCadezAItzBKP1sIF6sn8N9ZnrpxgeuzAcQz/dikmFL6TH72gwh8t+G+0j+PkVjJHkc+qfuo++FDM5RWUe5PM5PKMHZEn4yB9eL/rX7UOA3QbzKXYn8z5BaXKe9atcoEHSER8YrshLE2e68L6YJZ/FHPmy+XMoHiRve8QKwfna1GLUMfRTWXJTI7VVy4vKDwU91oCAsCR+TOSAQ9XDLVDGfowBngSCn/ekC5+9RezgLQXeM2TLlq5T8QGqzf8PL2Et9127kjJDQUoakv18nh+7844n90rG4ssSxKfD3RNdCTyID87wKzC0HAFa9zMkrlGyzcO38e/ZQuSmSGizh6ye7Zp8IvQ6Lp1ZbFmDygoSDrGH8E2HONjxjBkiIx25QtMcO/XqP+agU1DFmbM8oTE7giXo8MW4hghxlSmrLmTzqQojeZ1J8pAhkaxJV73AGVcV5Hji07b1LxASeaucrac6VWJZIIVhQT+fakwkXFOPSnd6kyEA+UycLFNdg3IixCBPFLPhoAKWz8nJjTQn2AcW+smxJu539gsY4VC1xm6Awy+VZyZWzBoQxclN6c98nL639/MluLAsWNWy36URQRWImSxrttaOGd8loYscglztQ32DSyT7Aqb6h0VcCZcPuh6zmSBgumTAErLx5g3JHIBhNaVQJot07k+0NbdkJLfO5jeahGfXWLAVvyFRgF3eBYc/diPh+10jZGWvP4N5IL0m3EygkB8FUt9iK9qXY74MVHdGnsDAlHZkLFJ81Z82vLj96XJ/bDTHktDaKzZfrhGHVCY3c5KOkIcKvkkMsMyn4N8qJ4Lor4rFaSF1itM2RRKDDK6DljMd6OcE9uykE0nBiFeUghPWagOg+H8TZJox+lvLCnRg8bkOH3A2mWf0DojUA6q13bdD41jRpuUthrPJGfhwX+Nd9QAQDOn8O8ulJ/RYGNgjSBUy/LKvnYiJ7gs5NeCPmzTprjfe8T4c21x92hKl+NZU8ty/z7hg+8ILU1pQOVAQoGrwUizw8NDvPSGSzTC+/NjQSElhW8vI7NdzjzjUdNypDGvR2wzwqWon3sO+yqzbKStz/RS8VkETPTml2/vNU55buQlhnkekhXueXN66eXdlw7Nb+YzSrXwfeHxERMlBDN/qcHLRoReqnqB6MXyyUJgzC9IaOPWTOoKoq+ANrDw84EieUidMMK9jgqR1ZTxYsTK+zPDRc1Loc4GqPmNYY1ctMtS7k89VI0KiA/pKB7E2meoGm8c+qWjL0zjG5lKMO9EBKDNyhRU4IVyDg8QBuvtl6re99v/U57J3+/JloKG6CmjsFoG87PEtI+Pl3PDYuDbzPliOG6U6OtPWRKUu4wHsVwQw4aN8+fz7XkN8LkErmsWI36Dt5lmmko9l0F2gfN5asuIgLMCCrdGTd+gp6gkUt2yz/qciji26FnT0jDgTjLaMHBaaXvuelc8/oNm92G2YMwri5419H1UjgoercH2712hyBbnv/gE1VPslsJ/ZHgRe/ONFtK7QaZ1BBrRUdTVaY02tPaE6wd2mQEwh7gBGWEXrw2nEpCE4LENJovxXy/nT4tby1J6lL3BKxsshMbsMLvsvjf9kL97SN/bKzA34hFUBMLxeQsWxCctSuLrtJHWEXb0WcsGNHR5M4M/ykmR41Bk6KpRR9jDf2Xc+q702W67QssXsaiUTkh+vFTjHyQgpAwKuzKVpE+emRztTRz1kPAp8Tpc0Ca/9e64/iKQABw/LEhgQj4QuNhZLK5wwcWwwpy/sbz9zPqWHbFlOhlVSl9eCOm6rCg+7mBHw320XL6wh8K9ZDLoD1aqLyPc8O1vKgyYlCd8uD2T/W0ws0B49xw05n1NN79vpRufH1MKaNtsz0+1erP1jaJTD4DYyUkralBQCozU/bvSVzgqx18YxfUKsL8ZSKh29RgeQJ4Nsqyiqf96SY9BQXEOgj2LZY8/QMp2eZhQqJTlXi414FlQ6R+IuyUsHq+CssLnWyl/8+AoNVZsbbGokwGMnpUM+t0y+XcoPyn0xcPZM0eV7R/Mnlvoh1XB05MqAWCpztgP/yn29Ucu4I61rIsLDns+CIZZlhkO6ZxrI8iEsMFhlEJ6OY43adP3mdfv33SZ5Byz2vZs0HR07pNFIzlZ0ggtUvKXwqR9lo5/q8Ha8HitXZseF0V/4fOURtDXw5JymOsfPZQxwh2h0OLjGf30VyfJEbKvtwEF/Z0mfyH9XOoXi341kAn4vpC6u6zHO0fuMWbGUPdODnAt4l42DEEcwY/Q1ALU/osYS1a/IfsM9WWeNZ+qOAmYS68U/IsrypfCQ1kL0ppoMilfyLRwp2gd8xFMkW0BhVYYta2LNmKr1YwhEMwygDnpjTCv9zlW9Es3zAcHvg8g1H/TjLjvyW0dEzq5as14Cb7F/o16VZCzN+NHJz8XRKsz6TU3W7M6eVg2y1kAw09HU9FFU0q2Hcqqxm2XDJGlkCO60Z5KkvAVpJMm/xJxGqTpEbyIv9Kc/EhfgGvlr9abS9UX7a8AyKgtLNmCXz/crZmNn874rZSZyZoto1NbTUo1bC0GEq0IvSb7aj4+fZTW3+0KXDrr2BQJzuCLSAiHK5/BPy8EM7rASicvewWNwSROkb6iMZJPzgD+sKaLTz9SMIUXs14tNNnrD9hXe+gMw3wYVnEE0TfC9cY/3aF/BT2TrhdyIhMzgUiK9PTf9XfbKVi7r3ix2pM0T4ztb75T75QfR9XcjFV6bD16ohtJysZ8llE7p9AXorL4kwohwqe8knFPYy5dhPmbQoe2toLrf/oJcK1JZHAPRBqRkUgbyWu++1dvbs7P8RCfFaQDulTNOOXZs318tocfXrBcMeX8In42LRH4etcbXBtsPI41OLaUCv7BzBul+LEuR0GFltKHum1HDUzBSNzDTsBsMWj0SVrCkFDFIcJgsG9wg59TEiwSlYdCP9Oc4tlxaqqJtwJW9MBBHxNQy7C4JdZz48dDvAMHJwqIetrLt7zjxHST73MordTgabgA77+Xvf3o019D4wVGlD6Pnk1zT2RxRKaA4om6PwYuSHGzwKbvSrMN6STXxKnpbNBmWMcbxjXAqs/fp28vM5tpE6GmOrXaEv894h5U6YRiKJG16183aLX/wt8DJXXqDdXt4Y0OfgVXAiWJGrNEEuaSmpt6qAEB4k12hyNUe+MbRAk8dUenkge9uNYl4jZfznO5JzguPWnm/MG1GQJvwrJ/u8QJZFDg5mptlw/lU/MkWzpzFBmHpSmnqPRjQvmJmUIg6HBCdjWiA6DuyHkT6Bxky7GN1qlSN6q2jfwGpmWZEscEcItjL70udLX5wHev4thJKwluiRhVTaUG4YkYUC9JrUMM58BDUOODEf1yAB0gWNlf3Y3v1SGi3YpAMHsXlYUE1m58VNQsC1ayB0p9qyZLXbpsbLUGQIsBTzo3fJ9oznUrGVb3WC4OKFUU7Of5CAr8TBEBIzfxLiz4/5x+tsgff0zdYr2J48DDCP6avMtDTlcDhvb/VVO6MagccthtafeZ7BQW60GSRjiOGgDd+Vhc5iFLbgfp7BMDzTWtyLkeD3DTFV3HmbOHeh9jKTQLCWoXGgoNNSoj9OqaCjnOJUPZzSOXna8xfPAtJwXeMaX6+fr7a29DX7lLAX7qKhl/M0Wj9bRdGVp+wf7Sr2cB5FCfe66dOM+K0c48j+TXMcGkIp25dX4GiZpAHgKzLb4FHRWvPf+0TJkaYYqQ2P5a8vVdLaHhxV8w8IFq1MftcMhIYczfKJI2OugPI7YX7QWS17+c9ejlZvR2alRWigK/z7MnLA5nfWbMJ3q/tyeYJbSeMlOU72exqxRx8rkAomsqsKzYRkwsVZu/WDk6tSbtQS4+EzAi+xhnyCJa3WEGutU13njsvw79UFn/ZnKd2agsM5KPRr0Yo5dPp1cC9DALMq3rklPvvuzLRe9QWBLxzY74vyWlTtcQvgt3KHy9frqHM0su8Mat05SLKiiAUynK1uVCIek4ae5dBmOJt1Si050mzx+GRSxFvPypo02wDWDJg3EBzcd4/3dewRMl/Mvq7+ebe9J9bl8ZjLogQGq1XSjHTJ8EoNy5IXs7J9s3ZiZoRPKlFU6ZN0N/+6DXM84NTTY+xA+wP/FF70Hsl4Cknv/CI4sXPU5RRZOF0pTPIdZI+ecbTgn5h0gq/NdFhoAl1rkY7JaR/HVduAfJUFW9VEikjc9jSM70Ug6wZKXZ5ADuURKF6YU781JjhHCS59ALFXjd7EjzAe7WzO7nBU7yRmCy5nYSST4AIktsJrcghpLmmCL0jpA0Rl+EcFdWLll/jmuHEfGFpqWwxA79tYktJEIVzXko0nmeYm3l0NqCWs+T1+9JviDl93J8wCa2IUdTBNXx1+iBbiQw/OzCBAYW9EiNHTPkOLrtbyGvJNxPFCidEFO0DYRKr7LXoteuoR/lb5wIuEVsBxy+5f4mwpeQahEFPBmyJjIncYPiv7l/qFP96+Jh8yJTPJkA0zKIih+DtP3SpC9iSUpgzWyjPNNHUlOarrKaVj6o4/PwBpXtk1GwTmue0ML2FzpqOHiUBAYzL9B/pZos7i8OTXmY4Y4faFzr101HUeR0IAIKnlQKMfK3cnHGt5DRdYXJutffZC4ybJKtMW1QtkBVygfb9I4poI6Db0XB0C9/5GtPhQyOn3eUj/fv6CX7omC1erkoPP30C4zBB2+zjAmHIZkPYeWjA5MZcFUW6Jy7qgjh/nG8EqA/mpZp5QLVRTivYLQRtH/TnPb9IhPn+juQRP6nVYBpJWLSEbl1+PfULxb/gUtCRlGqc2V+/PdPVP+QLy5to1xpcvILkS9HgxLOCsHfHzFE17TCSqs89vQgFjZGqitDxHxk2NBymRQH2x+xxx781hKROPfB/b8hvd6vFQeVzUfWb7fFGUI15coX+h6sBSazzR+ukqW22533166Jcs8k511mdL5F5V+yT4YFvc2sIGsTZFm6ot/0rPd36XThJfR+Ip8Kh55E4IA1UdV2oz6a7ViD9VQCFYpSTddUJLjD7F/NEmWXqgsSi/AAy+GUADrM2IW//jYMeldn2Ux+RhW67bEXeiYeTzVG8VALk2EfTdapFWSE/LNNi8bz6kVFccojaZs1hJG/kAGaSe1CAwBlxPCDhQbLom2VaO1LRh7PXj4OrvQ05mQSzvNnecw/XSikT7hv53CwL2ysfzTDpN5d/Hy9SqVBOIk1F6cop76ymc9wZ9/103o04Qt5UTxgTIV4LKqYTWbo/UH3xyJ/ODDok0xgI6Dv8UREHUW6A2bN2+P1gdoEJ8BTWGRpHhQsi90crglqvJxkuutTBCYWf6T2+WrZJBh4zNxtqp+JDScLEGQbF3AWVWaPzuh+itw5H2l8zshkpaF0LOSnOfMvpN8PLAUxQF0cJqOy9WD4nuXWOFa0A+4vAlYt1xWgjmw7/TXgRXtLv5etnru0ZHjQpAE4iTxO0S7F0o1VpK46IfC6TAcmrBFFke8DauK8vCB/yJ4GM5hbTjIwtdbgXkv4/N2DGCIZ4lr4hy2Cv5TeVUt/t4U4rFw8v9T4A67JS2gTJd3l6ZT1ZMx/vaUQ+YjWccHGQvBv863AbxjHAlEgxH8fT0AeVsRCAYrltAZp3lk5sdHRJ0R9Oq09HWmoPME9s9JZdHW65I+RhbYvvj6kSvRrmtt5MB0xPhM5N5uH3p6bXV1GwckXPZfOL5AkjDUtO9fEoFg3iHEtXXZse+ckdloEAJi0IHtJVFzHEkNObIiWW97kEzHpoFhFlAUKK0zxI5oaxaAUV48Heog9Akf3NMadvnYERSvNV6s60fQNxyZKSYIW5sAwTD3S5VjlJyn76zUCznXBpg4l/wsgvSo/11oqE9xyccUe0jN8Hf7ns3/zBXwtkSpc43V/fU7Sq5W6fZ6TkF5gI72x9twaiin5up5shYLo+rIb1boQa6XD6Vn0CDAZ4xPUZ9LaVbOU32iRiJcKv2xt1onibrWYC3dXvpf+Pq/c/KADzOWLizPRz6I6q/h859dZPPqKQS/UMfZ8f/eUhW376W8b/6maH64pmEZdAqnDr19WKAfUu7AbTYbLrpUSQKhPHfr7JnFaFYZpPjYv1GQeuJHvKcFOiniNPEUikcVymd7jFKDP8UaB02btEL7ZyvzSbTax5OVYu58m3g2IskWefInwoWFL+Zggqbw/EIab0ZYY40/1ltThcZPcF3XNTLUylhIv+6P9PXxVsWJu5pYNtXjGfSJEahKLMQR2f0PzxsiF2POgCcmdnV66Loz7YOU5Jx7G9iJUdVGVCFWW9twty9WEjz8hL1+wx7c5wohyIoNCA3f8BaVc80Ee3Wcqnvz63eLeSIPbQMuqgumWaZVBP4nIXJ9PZfzpPvrimOAMJMp/8smrHa5XudkydVSowVIELL105cmqO1WpvvEiIN3liu1plIzqRfIT4WNmzHs8zt51ipbbrXs2K0Nsssxw0VS17DeGbQfWdCSgF1+Hgl5+r7jiSH0WHpGdCo8n3JIr51ppYJ+NAiAQc0ocEExHqxJYeDYBW1LHyuH7cxKtPSwI/nNCX5WjfJt0gbjFEgQ/33dT3u0+dvqOiT/qlAF7gBfOZUB8bSneZnDTFygdabluZ4/lzjenrr8vFonCcI0yErniJlJP5fdrj9YhZAyRrGVuRbXsu+xLxMGyUFxPCFXs5T017pRGVHB7xKMjWNYWEBP3Ge3UJCndskhW/jvCSz3qi04KqDGrkgvtFhF/CLQUJwAAyoQU+tBEMJpqY7KBUvVFjtzKSiX1+mUQod/Udjdw19+d6myHv9J5+K3XbghnkfMs1eL/kvJboNtEViyevhulpNsLiI5+6EfZk3znoulzoyenmKzZZ63eMBkBD0vuYAa0mJzS9UvFBRXRjehZI4NXEqRjVhMmuV1fUQ1uEASACeSxhlrT7Jma7MIS2UFy1uZ2fsllCR74BxYs9MELPGNE52x7stlwNaYP8V8RjczfPIuRFXjwFHl9jo6LTKFp9MsDB/XrCG0pNbUnVkVVk1rxuiwZSixLeWFKuTBl6cn7Rr0h8XC35gqRlm8rIB5fBEgc/Y0Ymsph7ON+k4fCPEbYURiWijd4vKpRsMzrEZ4gvl6exWsUAB26KTKM4SXD7DlJ3VAT80zCGImmHbbmLURjXFR2knVMHOmXzdeQa7YOFrbSTFn25ztQKgPyG3qyLKu4Q+uXprX1gAff0EM4jt/QeFCX5RppYvIdRGkViX4T5atBSLYSTTWRzeAHMjj272XreOyYS881+xhs3+7awiVw5vBruNjnWvT22/v0EMi6eHrmjWOFG2iw3WOOE/YrJ3AwRcw/gsXosWc3tVM7iMjttT2W7zm4Sn0JvzQSkA/1NbDF+nGRqUUnzwJ63mJ6/3QXnIULWMfGAhsQakA5rAhxn8KSTxwbIWkYm3HU+bM60/ns/AHnhjLXgqNQnbzq/ni6wkjeh+Q3LE/r8q+VR+XpCqJjvyCgixIqejmHxqFPY239rjFpNCGN+TFKZgIt7j/lyQg0II/q1LyCzyXgC8TTTlHdnF5Mk1YpPvDl01fBJijxDzn6irsjKhT6R39+kVobc6oZKF14ZSjO+x1nCccY0pl8KsT3nIgw553QOGl+IYsNfwfmCakPyy6dc+ZvQKmHLFUFAOZFMA5hlr3pmXFygPNHMsa41yaR7JBSMYkXAkIjYSjzcy3ePV3meEGBrldkNY90EmJwMLTMVL00whVJmz6LF70r29NxXII21QZzDNKb4WoJ6SlmUnUqfaspobEacWwylPjFIrwP5r851/7SC8nHVT8By40dn/Sd91O7vuNy36N9phT8P0FwdM7yB6sNOjE12TbGJo7IZODnWoinX1LZijvP7zBnz83aDU7TeNejF8hY/rJk1KLQnVomzVi13t9BS9jefOoWr5GqMtGjZYHgzIBTWEQG2wP5nuW7wxJmD6kplXVEgoOUBakDmFkjerNvAAj1wGLMkupd+FN7TyI5Udn+Slalj5aquDy/ajvpGT+2gViL8W1h8V+3wPyDrsePC/Kyve8M2aC6SxCgMlZtlgURlIo/DvaMUpp86eSrqfUjXRL6R5fxM694UFhmHiH8wosT1cpE6+YT5/2UPqQrRuP+miQtqKRWMISUox5HnAlegNBKdMkV9Al8qslZYkitZwI0zbKSXcM2H9VQLex8jSZrgFPUZyeCAzmOc29USid4ZmB2E0F8/xTvdjMdF4D70nOjGg9ko8ggev7x0YszX94g5lOWNRoeoYjRtjOrQ6Mci0PA2FSkulS1lkOwC7pXONBlZITYz3/ksnmBjHPfMjSyH1pS0wGVbgUqfZ25/tJ59w50dYOzSik8I8AL1SZtFnuXas/UIfBoft7OBuXvUWTmAO8sPn3HY8T6v/Osc8nIXgBAskmfhuVgzDOUip7UMoqr8uTSAy1H/QoLgA2/DySiz/V8mgJg2CkuQAR+dvG67KlALoE2aWOManjssfgnJoX9ElcScUYCsujpflBVPfGylYKLKjfGq/vyhrIOrf2BD3HghB7u6kauv6n6a1lmDt1BTqZUbSZOBY+b6H2dFD/BMy4cxYG6WlEQZPkkj7MzJZlkKMpUtJV8XfiDvQRYwSEUIcjPt+w87Iwsspw5fic8mnpJ2mZ7maVDUOcYsDlQERZn9fxsMN+cD6X7qNfttssuo4dkpBzSQ3WtAfBW8jwKd05AUSihE+TqeKHTyEjRJpYod+M8j6Uy/I3FJ7AFJ0lUjjOFXb18NnVGxCI8vKFM/rByEWo1NPjmjje9u/o1LlDyJ1OBic3VkATT8rngBDLZzDoeJrsa4QdyVJ0Zd5BlhpEaQz9R+6Uz73yAwfr2DNIVjtxMlKiRr2EXAfAkadzKuaxi80f0ofVc7L//jtg8ot30+gZTuMxc/oY7rMKLJI/Z6WIEvDYbgg5OzznwPjI9guxqW5ynq/0wco9LvsqqAENMj97VXo5Wq2lR1OB98endNdLlIEE8xmBPkj66Iev3aR42/BJlkGu7rVg3fc2z+5kQw3HgX/q98QypkvviWUekbZD2uFJfKF5/TAuDq+omnEUY7xXl9e0mqG5Z3ntR+2fqlTzd7r+mMmV6X5vj2R2mm9YblNDfSGszUlyUmWJtQMzAwdlzLxcU86ExFqOK1+daKEo87M7v1lj15Ydzr/MfaaxHitqOdEO5j48fRhvvp/7RmKjhqyFswZOl5yERXjHTVsEf0FeSPDfZ8so9AsbMuL8Z0HykEe974BLz4PxUpMCpFeK7U3yjRK83KOuk0qJnhVOSESjOU39Z1YJrE1NLqS/kfJBZRuDmQnI5s+7SF8Kav2FKLzQ/4sx1FKs6P2bBToNVAxfQo9AwdJworuf3hPRN402Lif12+ju4zlGNX2s+21XSlWT5TlmudgR8B5gFL06DTyJ/6uQ2a3FX6rJGeDyDehUSF6vTGO2JM456Z+oiul+1q2XTY5vjPymqcne4EAr4L+MIHEU2DiF91A6SjXsLctC7/EGwL/dTqcBGVcI8XgghSZU5hU2rJQyUFVUyVp9DtHRuJpqtszT4/nDqgYo/dOiwOWu8ktHKD62XEaezc0FIE8TGEY99al+1lP54wiZusCiAqz+ZQsXr6/LOrnLh26mVH6+g6L3PYpyYd5wizbaiP9hM9rYe0i01ImhbAm789s8UWvIUmOHrW3q2l8Nvl+6CtTD1XSDg4NcoQ/ZVuCjOfPc2mdx0ivQ1VMp/B8VQtsYn6VKd+MHT+Ck5f+mRuwoWK6SsSjRcipPEtTw/G/o3ELSluMj3jgpD4wfYnT8b6PLlVgqK0iiQCv6LII6lMHQU26thjJR4PlChSd49WAi3UYuKnkyLagWyk4hRIWWvvIjh3XOWpuNHCgVlNljsUXKDJESrcuykx1URqKbsz/vGRf/nrUysn2jrBVTjHZPZTH9Hj4AkCdAiKAFE+BMDtW8pnqxAZjT1QfyGdZZmqjIX1Qh9qZcfXyNIC9ZBZ3C5ZGeJHCFhvbXT6Kdc80klm10tg8GIWrcMbIAjqfqbttyGV0eNkbNY36jqWEvmzynT08turBhKZFzIiLZtOYmtCMMaYJBy8RMjQvyfav1V32WWZFW8DJ/w91DVrHt2JLXozaz6FBnlxelDfumz+Pj9cJPRpB+3VJTimUWRMzuGE0p1IE9T9mwnftuClUD5Tahj7WTJAwH9lJeil4H2d/LLyaMqEMIs/DTtY598KktDxf2sIBnxZSXMovJPBWMQcguqWNbMUv0NEq1OyEY51YUSAwl5LBP3rYcUpV24v5FouE/2n7Zqu68kwqU15xq8YU9gF7ATXDAbwNO46qLDw14Ke94cn6MQEfq2VlVcoJVaguyG/iVFF0KNg2GtQ2YwnjlVnjJM6YMI2f57xgLJGRBjW0BdwDfM6NRPkqOEI2VwHJmemsoUt+QZDYeWSLhoTNN1VxFbRv/qLGu0nx/OiEbfm/B4CrnIryfRZHrRnsU3sR1rdWl3I6PtHP907b6q5LOyH0gsSw0cgSUSf9P1fBd3hc3aAKpUz9IIXPyQib0KR4d6KmuvyegL+Inl5w/nQ5GR1/jT1gh+u+VonknMjOAJblo5JDTvSX5w9Iry2FgzqksRTZCPZXfENq2PKxhM/AGVnH8TutkJNbP4/JXpPYy59bSg0U+0+9p3eLvBXZBJ+4DykElV31vj/+rj9a8URUC+DHi8mlT/NGSFGrthhE5h1ZJtGItiC6yxAZwla7WU5we13qbZAXrl2Sub7ay/SSg/fC9cpoOzCq5/PzCKLqcYbryUUS+cMUIc1GaLI/Wn1lFVtREr/XNvcJHvSnJKjeE4qoRjziKZrvVDap+rILCWGo4PxSgB6n7sW/a8o2M9vIZO2wuG7i9BWOiyBaYQ1Az0o6hdeko9bKEzrQX4uf7S7kj9PRohj/8KLSQJTDpne0oddpj/KGbOccTaaLtbExP4iy4jL0A4nxKbaEywIOr4zFm44YHOUbf83ueZdfdL8g8L4tvlQqd2jtLUWUiv1S+BShXj58AOeuXyz47JeAOirACgi5E9u/uXrNHPPOB5zOjtVL+ZVVJZYC0Hazptr1OtM1Fm32LfyjS9xsZKqeImSuHrh8U7Eld1DqdkXA4geLz4CKWKoIuQ47qV67mmkflTLFoG/jZ0sPKMsf6i89AeywqyGepn+BHuqs7rz53IrdIChZ57ZJAPpNUroL4B8XeOcdHMT5ddRmhTxkthTsNVi1M65NX8NJ+C4ucV7iMdgVAV6OFKjyBvLNUHNWRgoo31UHmQ8XpADiY2SNb4SUlG6B0jsBGg1JGmJNFobmutYfE3KpVEHhZcAXB7FHBkxDeEz0JYknGESap0Eh3ggUYSC/kW9mbmRR1AR1PnF2ODEjSxVBD0+0Ipuj6Ow/xLAUv/Umia5oBsmiiCqIlgeCNOFRLVqWZd8Wcqms08G4/G7s2IkjqGDjPWJWhBbY9ZP3ZImqSLZhO2GKxRJVaHxG1f31KFPXxwSRkduDTnf3tIX1K4oiRpPmULCoqfNMT0iAaJFui1JXPV6SwztWW27WctSC8o+N+51wZhNHJhpdviUnAXEV6JF9yhXN/28xEnJNl1jWxwM5+LjfRo5UKl38fXrgcHWrQaaCulwOfJ91ThHJR2O/4+g2q2j2jD0xMWEjXO865lpYU5f8c79LTBJfdy3T/cC5HQeg3tr7GZVWzLJBiQVhRxMKhGn+ijREUqztLCAx+DXIOCcT5Qwlr8b1hLDhttSoBzgkQ7P3XLg0938XWK4FtIJs0PH2DcvqnSRAqpOP6VrT1ZxL7Atg1JwcyxGuvSBnFvMxUsVNvmv5SdXukZxzgHKpy5a++58zKYbcw1Tggkjb1G0UVHbPmsaB9q3NixvsSk/qA5P/h6yDxqi9LzYMlNIAVH7Xd53rtbaS2jtriNBxxLPHc4nvZ+91lgPn6rArYQYGOJhGGcahRQnIO9+TsaBISTMC348PUfbojlpXz2woHRMXA80QlxRr/AGByx/Pxr3nfVVeHBLD0uqDSKktdc7Jo2UfqH4pU5V0ruFzOsP/3NEey9EcDG0RpWN4dWe41ded8I1xJ22xRIknK1LsyoZJKhFbt50DYK0BQv2BcvqaAQ2rL+O24ER/36UhR3Vp29QBltTqFi9E96iydUpl+MIgJkwTjTjdV+KnAj7xKlXw8c11Zf1GMEU2ZsqdhBZGCrb9sUt+DmaJj5oML6E1hxfjXm+jAlTsg4hZJF+ZIrILRe5OusQLAqxdIl8DmOEeSJeXRtUwyoZGweJ927bM+7u4mnlCFSgZz2E1mf3XCNpBh1tk4qn8uIT3PcdwdkZQ08VRsWN7Ff+UNIozj+3BMg/G01bAL4SezIrsq/Z3TFs6Na8R0BdmNW9qbr3qe7es1Wv9t1q4HzFcfb0Gw0F3DsKWK419vpI45/UyidPOaW1yykSJfVSEHP+/i83haoDedsTXRK77eQYEmIFc7llfVgfvIcfJb+/2d0hxMp/r2l9Z5XgcTicAqPx73hPTQSRYOE7b0clR3314lAGFCjI30vEPftBbKy1xBu6Km2T1Nl313lC4LdMmO7zxUrazDpQ+b5y5mYy/WTB9Mk6XlYD9Qqew228VlXdOQkget2FIGxv9oWrKN3LCn64AY1dFY8upnuyOgoxofhRhP8ueebBOJaEOwS3ssfR7fjao808apF/a/E8AXy9dfKE86FHebLiBnF8dij9XkVCjXi3z4xm6klEtzTsJcJQsjn2dSv5aX1UHC9KzY95jXUWcI2xpAj5Je8Vf+d0/3bMZD0gH5xgfme4mWERlHgYO/+zK0pbU6Udhkft1FwFIjYEwlJ9SQGc/HvhPw5kq/IcAdEBuxThEVr+sm74tuR21E5g/71ZIez8Vp2jET+Olu2QxTjOh+2R4Zc698p5kbrTWlWQxnKHG6kiRAg0cBhf/RGzBCQ9hKwTLu+yPgtfzJhneuL86wqLbXqLD+Us/BfqGV/8cUxAIrhEskvKAsWAX45gOP39c/hEWXv0wMJBnhXuJlJyNfsT5d8jsT6EmYuSfpR9VSYGwAVOZDU9VigO0Wd6uqfT7+PszcpDAxuZCFgJrfs0pLKYIvZl7WWqzOAKiUbXixxOFg3E2B5IVjL/pLlckU7QTqtB/UBqE+pJxQv4f7kyq8Id+v44mB2saaPkuiUFhBVIZ5i1kvp86kINR1ucYHOIkC9keq/7mvkwhE9f3vsSvIMRQ80LWn7hXdqTBmYHZuB2BITLC2X8Xc6nm7Bxa9uXXV8faWtEwVAYQLvcqiW2lFOeaqX7KC6DSaPINst40b5NTr5wa8x60XsI/NuTjHVpWzlLbOsCZTLTtiwivLviGfePV9InWKBD7Fqac7hqRBoF2iHaAxSiun7OVhrdTAwff8gkHsK8PAIfLi8rZ54sRdYqZD7U3ZBaCuMsr1GJeX4+0U8FjUyBTwiaRZ7Slhcua4TDxaEmHfUfVH7BdXMKB/L8iSxt3osPZnNTvBQH7m/aM1Dn4snpuuF7DR7wCA91PXylVufcZfoN4JPazavX+98QE0h7jtDcQiu+TlzBRTtJvO0BW5RwJVYLQKQp7c74ILI4Qf4UFMWZpQ+oF/KmbWTML7krN6oA33doajNh39/U7V/RAn3gQ7DVpfz6wgjwNyY0skTHOMjvtFis+ETU4D57MWfmvGZUdN9JOdlu4Aw1Do95txO7YXpnOABzg74V1kJqfAYLsUyU/TnnyY2G8+kK1AxlY0g3pS6HHBWrbQff0DPgBoSXoo1GryrujTLqkfLxmYqf+WHKBaPVTD+1JTSoZN9rkDeP3b+w0Zz2thlYEUA1cdJU3HXDsrrhIQwjmATe1ZoEWpT0AM3mCyh9+WryWhYoS+fLKh7BuiEONmV5F/s2dmkaOp+8BfXWuvw0wuGH2uF4SLtG3i3+l896PiirmHNJ316/hiygTOHuTSeSR3WNglqdQK7T3UQdvKe9gSXN0FRlL5Ths9W64SWq+qA96R9dBgZjta2oyUErKYDzVRIZ+O0gz/es+ImjDzhU7LBwXs1+Iq0UhytwAg+nHYBePLnZ9FcIMHwesdqFzLDs219UqL1XNq1gTD+TjAMUzFCL9iB0z/Ox4fxl9I5SmiRxQYXUrGspKEgGTLQ2Vjjif29OtFyuk+rs5TcZI8Y0Ya/vsyGvuarY7MhJ5iHNnjO9/VrC3KBPy26vl9KGpkiM7PRdVMVvwADqC8d9eBlw33khMuO4Ewt1MRSJIG/usquoMDeTL82wyEt8Dppet9QCqwOJQzgm3+uuEQFh6qCcCIIkj2lGDjDwRuUFGKnqXxpzfRD5uXbqwxXznev4pDX6NMFLg0ydOyWSqpZdlm5Iz4muq3taWnu248yCNdeehs475xdP8nX6PHECKEhDpBYCYzR0+e/EsnsQgr7uR9Rg9+fBw3vLx/aCmkrVUEsveobPDhJCbzuhOjLr6GrAn0kIqUpNyo1QyF0bDpAmcLZmyzql2QXEV2sn8FDUU9/d6awYTduJpQOn/x6LL9o9Dg+w6lWnfp6AZI5mBAmYr5MVt31peIO5i3lsiSuhguvFeql6HWrFP+G2P7sP99V3vQku5dmfTTJXRsVACTlSb5lH279GHoGyJCwQeqRV/qsZbFRNV7AsBfFICT0xRWmmeWQZ7xOFaj1gIP6AjWSbzAEyeJF80SbVm0hjrg3lH5VwbQyAA/m7++0xOAiHz/dsW4hG+xSc6wbopgE3mMKkMT1UY3Ie6ZHx2yWE6JuxsFLaCTm/siXiPDW0xEy/KPNlNf6cytiH8kVaOw/s8nx76XKNhMFVYXPvJ/y40G5f11gBUxQHBVpuVMRh31vpZg/+QpaEhGeZSqc8/4IyYyUcyfgD9999Y8E05yIaMeo2uzfIRMp4Z6Cz6SIMz+0sKLw2DWexqYb6AihwRbkNFz5yxkdzJ2qumgZ4mck6bz/3H+Hsfn9915zxZPkCyndoJy/Bwl4pVZeIW1CxOg/hl0F6DchYZra5VB6ItSYxxbvz6h9MQAdS+2vowQ/n7Uf/X3SoeSVH6o28/jtXXy2oFFZAuw1jnr+1gR2/DDbzbOdkf80LMFziH80Vqqd7NEo49jmlWt+pDn2oL+uMC/SkoCeNEYuUBqi2o/C8+S28Qmy1xAQsu3WI1z0smezkRSA94K/7rKbfyddoYfnK4elzu8Wyah5NVN4WM1KG703sIUsKgy04BHpNaWsadIEy/wNu85XyzqDwzoMRuO73xcNUxnZEdO4xuZQVnwc99cFT2u7EoNduIvdFvHBOdQSCh92w7VglDGT6aoH0s8iv7TyS35J95PxVPPipw9rxRFwoezG+Sk54s6BLwouZGlAsbog1/n8fZotpa6Z3qsulKUDyzX8N85lCF+Am/HSz59MGgV7V6YrDKyUybUJscG9k6Pw77qDVToJHjKetcG+ZcStULoPmodhlzVBCcUkGR27Ye7mwV+nhYP8qLtiX4ZFRc/fAHptV2c1IO/ZVIsPOimW0OEVdXABAYIQwKd4QOvoFhWlYO1YhBBsjiz5+KeuGLNoRhKWkkcyvIa9Iaq9pS8EfJ1JPG/4zwfuMrQUDyHHVKIh8IMRhsoWvy3m88VrWbQzBERrh4rGciLcXjMVl3pJM9t61KGRNBqlEZAYmE4AsSWY2NCWK30I4m+o5VMf4qoHuqiw1xpDqbKfT8NSD/hG3eGk3rehfxocS/LjXw/N54vHP4N+pss3CwgBiZWyiSD+T98F4hFIVS9BLIw3kJKp2sdPavq5AZpZvyTDbY0tK6tmBHoWGPDtGhfp2trks8lPwYxB6nGciTciJF+QxbHBIrPxF0myVTUXYnf2M1oWi5Vr7Bv/0h/+iwfit//dwCxm44pA3oLmffZj0v5ELaDnm8qwpl7TWKb/YjeRLvmN/WBHcWl7Bqt/x2ySAQfNGW/KKLLwMtVI1gmf0q4b11YNDDag35QYia9jgY3TpYf3188kLbnRrKmjPXQVfhjRhq8SlasC3fPMiuQaUpTtHD2ZeCNkavrTZ5PMPnwZcJ24+yj2gTxn6abENiMWHj6ZP/kcP9+lmky2byc8gwvej3mTIJscOSj42D88Js7wEJFxcSNhv0Dl+AvlhA0R3gXa3R3uATzJzcGMh2sgsosLEh4NnPntNOtlnnpNuqf3oHbsNa35lX8oEfmxvcBPgF2H1D6rvWdtTkw7mIO9f+gcFez2KkESNKcrBA/4mvvgrbbDno3sE+d+WIM9BJSM6p70v604j/tsYvDl/B2U/NPKivwfU1e1LCmWRb9m3nF5TBJLnMR5w92drx9O3oqJiY7urroK52xZa+vUmFF61q8c8TQObQt6KxT2gVxzDtYAMvNkGjoNqGuvIe6YAlIrdK3hb+ld5YzkPxCH0CBsgRPY4vyP20EPgI+Q8OrTGcAw/rUpwQf6fI2g8ii9jG5zNCZJHWH5IPMulFAtmfbhN3vg04YHdHN5Sbs7MJeHyks8vpf6oGVxTHTcTlLwR6xQ1G2INJq9JKL5RdtmVsjdRZ9fNxaQzxfMrCONo27ACdpzQ/jCQexc6sOvwpuOpg2KfvprsviZNt7z8SEZRYijFRyjepyjdOYCBj2ILQTEg+V3PTT6ndiSmVLPVc19g5gD0thnofbw/npzt/gSc5mCfWK9UQucmjgq6SSH2R0JAiWO+7kbG5Dk+CYTSnnFILyU08z8JovlN6fpzbrw2HoUJNHNgzdQNEoKjGEkCxLvhpRc5TeivZPQClpH7TmE4Toev8GbrklF0dTgd+rB+GbHjN+jKYSxOPv9nLWhKpnFf41OD7MJ2eVWxOz+wAWJEXfRtrjl0gUOcc8vle3ICyFQ+WVKJitc7u1rUOXHNkZvWI3Y+4YDCabmDRZ/uda9rmaHZdAvzL9KXFTMsVR/2+dCek/0Vk9u2p+63ah4afX3NQSAKGCNDuF4YFvfpObj5SF9KUBrvywfMtf5aYMjCzpn+QQAgF29imTysumrJ0WiuKqyrSuc1TIx8Zn0LLbykCwIdNGBuxtVLwnPmpe+YT9S7gOp6oWaVkcrTwxHtJJtr30AY1n5VPwCcdDg73dpom1KVqc9SQa00TPh1E/oYod1r7cHBa1iiZ/TFcLTA3n8h6nG3G0N0EC9putXVQiPNghJvOTW1ls1OoOSTmbFnA2pCZHILb0wq2JuUMjbhN0WALJHhn0S0eKWCjCEVgTzbmdAsh06tGny9o2QurortDWS5V8I1pPamtigHAClg90waLUxaBZf2m8P3gU885oPJwjXzPh15inUVVr6tc3qSBgs+1BLeS7UrOEmH3G7VnDoLhwV8hsiYZIHMAO2tVGyQfHGlk4upX70j0pPfQWRt3TeM7LtVQkrYTfoZqRuS8mQTi8lhJ5lnAHKC97FSoa5aXUPoThoaVQzCu16IAr5Y5HDoNQp56CapeTfPZrZA6zn1PKAlCMyiLCp5FsYdPsD+Vz88eLj2N9A8QlFjOhylgpEPdz53OzPJycSIXgdRujrOqRkL+BS1msS1RjLX362zhH/Giq1VCIQ1Txr5ERbvWZ+LassmsaZh01VTaVybPQbPC95LXoT2en1LkL7+a4xIiMMo8rwDSQidjmoNu5moPsVClcgOdDMVNzt+xHeTbjZZA6BqCucSDa4VNl2p6ULk47tmZJKDFYv1axMnqe6m4Iy6JlrV/fIQPDgXTg1ssJ5FN4LRfQhfnkGsAzPm4Cys+4ztSs4gcw/ijD8jVXE3egGS5kAwoSCPqbJYRc1ioW5MB/PK5tTZ2F3JJy8zIh6OAf9/18F3LBNDAl6scheIaQd+L10VSz4LCyD1qqpk3MZ1J09zmPyAc0YSfFaL8LRGPKxpVqhd7FyFs49pa1Y3BfYsfKhc3gc1zobIu9RaxwZ+MCVewvviX7W+5o048+nVLV0oQcvA91STBEuUKbb9lSFsWYuazdHQeoKEU13YS4/fNBWbvNIBPzapSS2dxtDxjy/fymLBLgeHmp2t6XHLbqhO9sjXmO/kG/sZA6C/5OKx65VzSiY7sZ7L4LwWI58XL2WsHaEketJY792kM1SDpACRuiTHh8haK/sq4pam7nkF6/bd4vf7+HA35dDWxUISPgREREIWC/LjCaKGNl5sjqTCR8neO12hSIabSA4J7J7CKRsr76ZW2a7j9fYQbtXxg9gbicfVTniZFysLrgcaZ6GAcsRd5fs3hRyHcZpbFPw0ZgmkRnjpgTBqP1PJm4b7rAjdvwKIS6Q2a3XkFPDU4KCQ7yc6Np7FJL2oqUhBkXIeA+l85jQRJyH4VggVw6oCQUNF7yQRMtvIIumExLVCV20T7srAXY2W+dO5z3kAiMKBG/IkemknTBAhgwxDTP9GKPz24kLzlr8lYlXQGLDV+o2A0696wJ3Oz9wbZP3cBcEEXibd+mxSUUDTt15tga/q908+v0OJzR+k6QdYDyAHyzhmP2cLj5iBu2cqGqT5qCs32EYVuBqiETba59tkZncvAC2168HIg1bv1UgnAvuXFlSJOTrWUEBmRaHqrx8n6D2HkIhF6Zo2BNwaPt7gzxC918c2JFYSc5She0aWGHzMSpNQgvPPDTAkH9ClEhOCnMiqolySWGBdvAomS7Cn5ZW4/MEEnf3txIISMdvWSE96dR4DCbO+7/qwCiHQTafl+421PdVL2fa0dtlrGcot+Bw8fgdnAOG0g44d+gkFyCdcCgSi5vruLJPUtsjm9Wlj2GCPWA9gtlOVsVOBqWPcwN+i+rVTsrlLT81gUUjXOmJNLrNxHtwZd2e37Md5etDcETO5+0HP+VEbARzHovYHFpAzPeY2nySHlYHNdCrH2uE3CKU4UVyTzYIQWgU3VB2PVea3n8eg2YRkBfDbqTn+nltJWC5eFs8CTfbF/s9kyaU4gQZ8ncXCC7Z3Smvr4ySQCtRGpPwPb7LHBO7rTYozdX64193m4LrpDDMPZC/9fMPzZSH3H909iEaeUYoVHaqDIWBSBWjw/jHzV7H9Dqwt7n7YsjKEfS1M/q87/he7Lo2NnHXH/2pLAFej7R5YbypxmLV8SzKV/ajx+5pzatOx1HxynE2Z6CJfG26vLmEiOZTDeLPqB+8KpH5DIrshp3veBORT9ZhtJ63XuXN5NGtYNaaajVtN3YeTTA5KdiPY4XU4k/NlL851WKqgtjXJIYjfP83bqdNSM9H9jRtp9iiShoSew+E7xbsFHHDpCiQCOYIm2q+v2/gsxIEQLKw8Y/MdsFl05EModcj3PkuwMQm/Vsh4qFdcwL59u+zR/2HRExo+/u733sbegLnVoYzcgjVIXxLdpwVrI8mmW0mZLHkfVWTOf+oBkmJ6OslIn72kIJMTMXryFlO6jJ0gKbcAl7EWUB6v0qD+w6wzizuZb6+tj7hS/8AkRSfm4mGdw4MiBc2t6G7nABOm8rsnRZvxOqB8M3lOe/Czd+SWcW/5z//3vjTcvrehQO8IK+JTT3pAiaMn9Cm9X0rnzIo65zPvvzC915+gr4r3jEeDfMyMOaDmb4hPicGjhLDSM9fEE2bHNnOXYoGYBSGfzc1e7Sh3kjWd9OeT1q+71O4t4BMlxZJ5DYKDC+xdH/GiqnllhpdQuuXW6NB5SFT/j1uzoPEaHy+iWLeV9YQe6Te74GAEWBlBwGw6c7H/bCa5eT0+S5uLUwmb/n41bMYyMOuI0sN5vSx5uRjuID/3kjS9t9cTetwYydGB2GY2ZZRfws8hXMjSftEl4ISbR9Cb1A6AQi6GQhHndBqZomuni+7kjqQQtvog2QFhASmyhSxsjb0hM3feiw6MDp2pe8Wj0WIbO2la6wGfvm7bCSGj+nfeCmOENxdsj+JUr3y/GI/zHwtIy3DvdUp857aKtP16m+0prF4Gtj8zlCSg9vKOy/iEDwcb/3i6bum4yZbP9drsZxjppS0rONnbHwLOVCf+3oUaF9ndjBQm+l+6+D+zgIjGzG4xHTIW+pdvDJ+MYyUu6MtRzm89dLqzU1A0D2fXx7/C6LMLQVAckPm/tckvN8npZ/kAsQtw8b0y9w9HzCIMncQmenZLvxW57cUvatnseUk/ehGYXCsuPO6bKyRW9a7dk2GdVd/V5dKQvxvpbhLgtgDNFsYZBhXdiNrPqWumnqUoYk3EVGwcpFw/VfYy3+nXGtioPEwj9PjaNzK7biZSsLR3jqp3435Kk+Rs8BxBGo34aAfY4F2q421yR3ubGBHaLOLV/x+GLM/wGeTEhQlVGa+RTwOZGF6Lh3B826cBY2sJJeqnYNpBDSXeUn3yqz3Wk9p3XEMdrfJ4nYKyd+ivMdwRDSkichoLseHGngVer8TlvzcfIQ684t2ENF2/G0tg5nswElOGjWJ5jfdgSjm916KCpbtuEKm2U4rucuiE1B8XpmsBbndHsanNmUHqEOgNbd/o3/330wlqxu67PbxvXocEnDyORC+FEQLocS/Fjd2g84IydbbacPPtm8MTzEGZOSbP+hXvXhlXACgtaBsgkXc21sCHnjauwbt3cya55Z5F9ZnXFJzVFpZzp174RvxvBkHc+9xCIYzMXn4onTyHdpneVNxrY6LWqjAVozzVJEW6aT4zdxyO7QeMjYeQObaMhTK/hkv+jT39066g2clzwVsrKPncq4roio0wAJJxI2wx6d9e0q+hgW1EcIKXCpGrdyUg9mTKPZQWjoWNY1RHa8JKXYu1nFI8W1Mr+2NjI8qSLfGpEJbWXZDbvIoxo1GXkoyDqe0rvErNi+8iRDMnG7nQETEvLJSNYuJG943BUkPb9GNHgitMYbo1vjlb9kNiCqOvyrDrdfHioISCnxNExv4TKG/0W3JcBWujNMLJH8DYu0XEnVAEslGdXlHDQz8nHEEUhAFewl0r1rpLU+VH1Zi5gkMFuEhXWyAkXdokMUE11+nNv3t4seDQiTkQgAVmrlqpVBWK780CNSIsLfvsEChM3fCul8OM4ibwE4akw5Gg2H4j8mofaJe99V9vEJS9a9qpiMPX+IYlJIYGjZt67ui24iBDf0zZlMxQtDj82hVRYNjY2XE3HtH3OHxeRC3yGzu2m4U4Gd6jXHwGGJOLxd4On9IhnK5SLR5kyc+8g7mdnAI7Ju/n5YBX9v8yn1acbbnJ2jXmhNI9gPY38SiTKxTaEcbs7GaXIeEEel6mFNberG7meTDwSdI0703yI70PXAvtASq58aAIIlL7LoQyGLs6VOZR6uruYzfy8PmsiAiwfR/QL70wwGgZ/oEXqt1H7c3jchEWCmh7ltKe8TD/VCaeDiazerriKGe7Ylx6jEwSVUKiGz375PwOEPgzG1V7/4TTBMwKw4eewLZrvC/nTXTLMEDCP0wIBLi11qoG5itRbXK7ZJuSn7+Uj6keZTGvFV7Kz4wpLSg3ICoIIOVyOSQbY9Jv9ryAinvEFHOh0R4D2JLiFOp2JKq0YL6I79vKEOcV300Uj109K6dvlizh4xjKTCHMI3ABaiGkkh/Dy12dukDjl1GwGxzIt7kCxW9AyptEIxm0va7g431PPKyXQrE+ZCRxPuN8PExlJazMt8Wdps0kdUbLI0PRJVRKDOkKPS9YgSvDsHZL0/+I1YK6l16Lf3DAn2lXfEQkPp+Sfm8Nye8pPLfaYGZuPw6jzdanoM/kx5QfqBacGaM9BU67LaAnzrkVH/OGbDHwP6PcfTwtQeZ2QAjzW7TpXHv/Ha9Pf9qIg0htNMFL6yfofPrsCV8eFzb5ST+IOz90cL/gCZlQ9LQEW+ytnKzjkyO72ey7lpWBWNT42Z39vY43srgJjitRG0ScLGsplHJGpnNv6yazZ0w8iZDsxZv/Ld2GcjJAtJAaEX9iB+oph/IPCbRCEVAVgbgJw+8oTo2oVlRPBHJIkwk9t+r/So+u5vdgLvfxGtEJziXY7FBHh9kwEAJaG+0oVvftZz5chLRJ3S30zqKg6O0d/b2BqpD9V+FqQP7VEhopT+S8cp/hymXYWVe2Nbt6txV9TWPZQ6CZKJqBaZUlV4mDbon6seNcNviyVDCYPwrZg36t33uHnCUNsYtt7qLt7sCr3UhuzFVAJJDOa+beETiBzSOHm8zDkJm/pwv6zfTfI1JEHZQfGQcwZWSjde6zhKHn89nd/LxOQTw4U1Y7Nf8plDd75MRFVFW8PUajjVyAG+EetJQUhk8T7jjjoR/fNK7urGsMr1QwMXIV7cpDQQHmcSPp2ZUsxG3TXqpgA3YVK0vfmYmJITTArl5Ur6tIslQFwv7u0rmFtjFvDGrjT7L+vvuicen4pOUXlh/PY/HKnKh6acSSt/Pw7/gX1EkUHJ6/OqfyFF+i+Bi+iOJetyZ4b5ZlI63TLTCgjdqyT4iBFpoIMjpOj7INiNg6/LD7JIOEI5tg6aDgiNQbQ75JOyt6GvD/qSquXYjsewB+Bf+njWjzwAiOOcHyJHObWMtgFKefdt5jyzSrXqL6EZpr6YugFXcwrEq5sfvofmamE9EbZa/k+0mrA4ou9YIVudsKv9YuWv/AqsxI635QAy4EwOIEhvTUAkYckg3Cu4Quo9MvdHsg1/V+05SC5D+aaK9cqPk/GdiEZLo1/cg0Klz6vAtZ+UyB330vREY/e3xIId3jbqMo4jOrT/8B4QNUASnr4e7P6puljQqJkqex8NBCKM09HcP/7axZDubu3INClh411bShe7I/ooNQsM3L7zG0506Ys2SxsAHkgh2MECVj2YCxwdvpKf952BP8pVqxAsOuLa81cb7TnTaXtgx1ZKYT9Sw04JNZPRj3K08KRJykdttXgrtBEmRVlduVPzSak6LJTE5Dg1TPDVOV0Ds/jl925ddpqrkY1GMVr7arEWHKGGe0tSm8yXIspIAaB9wwY/XRWxIkkTMG6C6Kay2oX/cn7TsXfuPYz1EmfVbEgMCM9/SKmC3liOHZ/bap27NxkMs+pLvEV4t+s8xOAKIR8zamo9T/U6Aq36FMqIK8Bse0hoL2SCKTr8CKNS7yfe1lKxmW2eZBI0SPQC5fT5thXfkKoYpEY5fkO96x+857/GyaQ+/4B5UBnT4cwC845f+2ucD6iM0QP3Ja4Uq53gwScW/dE4QyMWKVS4mYkcYVgSNwlZdYyrCJEqVup9FxI86ZF0Ouol2CGtQrQDDJn2H30ZjF1+etmxEemzEJycE1OlVIqumprZoU3S/g1sYLH5es3PCk351pDRI5oeCEHiVvD8rrCnna/nFHjO/ginlkhFkCgUadKHERhjfznrTnrSlyYAsnNAWqmILYnfBjPmyEHQKeHtrsdH5hifil4LuFWcUe0N2IvvYBjjy2UW3l3UZ8o8sT7JLJwj9aGMNEYvN3LcCmEey4ww+WjNquaVa+eBj6ZamJ0V3FJHKReEIId0AOuOj8d62M7cBXFlDXMt/Y9y958+xFCio8yKDs8IYUqym7746QrdnHYTr0kWtLZ7E5I7GTKvIEXc8TgM4ZuDn8Ml7rrNzWG08og+OoYUwknDbZ3NlAsrS/aDqQM1QZscEKoKFzha8xZfVYGz1bsMv6cZW5FrLSrSXQk/d89TC1ZC0ew4g0oC123vACU46j4GcCeOyWITc11QQ45okyfy3jbMIyOxtJTB2hOmETLTLM7p7xl0HO9NuP/CU3E7FjtYINGht8OyxnSI810MxgQ+nvzkaG3xL4XRGljMhaxU3Q7YO7lt3Cc+rk9tNDi/m04of3+iF5oqtlm9y2uFf3kC3kbN3qxO4OA2+FbM6Xve3oGc+OMyoQGuuCw+VEnjNvFYl+rD8mcuvskKQnK9oGJrMmgdJvzoHmhmRh4d7YCO9cIet/M2mrklRGXPXJLg+Vc4cHmWTTbzcymh0wLPEt9VaqM5dvf5hkoR94fUQ5i3KDMWE+C/TElnoPTxcmr7yOMb85efuVAuC2u4GrSTqC9Ib+gePbtQ37RtrjgoPcfrVik3c5V0iDqTtCwTKCBkln7yJx9V7W1P5NaNZV/jbdDw8lZ+qr/6bNgH0TE2AhxmtzDCpj4kSjnAJWI0c18u/04k4S1miRzXdAZJhWrkmkodQ/MXW6JVwk9bH0dQgD30PPPfyIjfMiFVsyrh7LQ8LwohIZO2YJXOd3kknw1sc78tahW/BmY6U6GLj8kSgiHBLIFArPkxl+876tR/zmXplIdfy2iLAs0LTmNpaAt8WYE0ov5vgVlMTQZcQtpNyg9OW3o+4sVbmBwNRVMb5Pds5WEIOvEFy0mmp+UKS6bpUep5p+9fh9NsNtwBHPncC9l1hk6Dl1hw9+T37s1SPv+0Q5m+SLqpvXRjm342/ggDCuzuIBBZ7tAELfA+JOgKdUz2z00Us12+VbvIAcXt77ehcWXzi0pSgs5/d2nwCK2YTpGvwZFqvz1tAMCRUi+TiMZH+vDbit6xwCup7GW9SsKL8kZ/GTL8qay3Gukyez3wmPsliIZ/l8Y5/6VpN7sNwEv2GckHJHRP5XvvtoyEbZ/sW9F5jyOs32Jlm+yRS4l9FGnNYIC7EeBjtuNHaAgFjsmv68yXgZtbthZTupW1o+SqVzxXxc9uF0RpCliV+8Q8cnN1d5LOda1Xsf4pchbJjUn/5iDFBEnaLFcWK/GqYaxK8dE5cdRQlPXQaWmI6XYUiMUFvwVJB7DU8b5ybH351YoHIMHmrUEFsK0N/7WxPjIOn8xR08xJjc7D/8PJUK/rEx7c2Ren21pJpBJqzy+k5zJ8zNjctgh6Ucfl6e+TVqYq7SmbtkqFE3tWswukB0q9t16slrqLTtLXtjqrI1hhI0GYr3ntgseCL3qpFIxPFmxNVRQ6o+8msKBU1sZJ1k8VQVs33xkl7Tx8702fCA0d5XgEwpT0VejeFQ0k5yo6nAASkmbfdn5gaQ/H2ieVfkjWR16sQ3gTQzbuqmosbujfC1XRiX8V3awTVcCyqMDZTR9yFrylWXQCPqos5lYt0essYM4thN8X2Ojrk7TfL6SibubSaIo5DQP9acKR+IpQbCf1p1kNqEiZngLvS7a+MIVAoEtS1fiPt9JlXUN3NuCVON2G4OVPv8Wh7loHgvacyPfWdh6bMpU+PZsjOjfRajrWMkJoC1wiaAzayxQH9GeOUzUZFzzdTOrkzwnC1HOeuDSdikMPUvW0rNbT3ryYK6fBVIiugvj71AVK5SQyLgRDoyPkuMcVurV4MntASVot93mueKtUAGa0tsGPOnGetsHiQ9mUFjruY0L6UCAAgBY94T29ZANoxBFdnaPWhtmCF2Qhk378oGcwfjW0Lp7vRdmsMBPMpkiJhcitacVCmrFXSIz4/H/2lZKs1/2WAbty17/lr5civvWyQa/U9ig2cPeAJQM09rro8mpz7by01aib5qc9DKAkvbdXrGOx04NNdR79T2cRsWN19O3zFHpK6T7p7BzyldQe1OeDYaIOk9ZDQODtkYCIYHP4OKAn0N6FA65nNYlY8gFNUSdcUGZMNSARoe2AW7u6SP1FRXmOT0B/ieeG3kV6D6JRrn9Qp/JbNw7a7hvcJMvmSFZoqUgIhsi1sXRfzh2QJnVnxxWb/QPgat9vqKUedoR3+tf3sO+6zFkph4y2PdfWbE3IfOaJnMQoneEwjgaIavgJXUe9f+wsdMv0uUPdWDzT9aug1PWB1tHiSNFEQZ/t0J30sM7Ah3P56bPB1tYD7wIj7nXr4ZCpOkCqPriJanB0/GKcGhEWAySo/qU+B9/6K1fJ6vV8vy/ky7otTa+NXXqQSZ/6BlniyovdXFLzfuAT8syX6hrgRiUr0as9VNFKAlO+u/AAhbDBwEj8Lbi9UYV6MTCgfkwZOQtZWco4V7mBK5Qb75hkBULEp6v25NEPawOaWTvga2kE3EUMqVqPowOzyh6byyHi/ovbXwrBl+2fsV5mKZi+4WWslbBjU09bfuZY+Z+Za/sR+0E96aCJl3PFDKP7HJRCSQvMc0DBZQxmlTWn9ATiAZ6GqQeh03mcsPjoOjuxdap9IcdEQSppIAawxJxtn+wUHVnSamjAnhZC64u+2dqhfTz/zN7au5l2vDT6OXPLxt9vLEMvIq6JoWlLd2+xC8U4GdSNG4jZi30Uo+7guHm4KyKi93MyqLvTEHBxMgqS/9JFrtxyuL5D7scrDf9Gm9ftsieavEZetVYhdZ2nXEijsuymT9WimaorV9wnrMBkBG69VneJ3TJm67qSl5e1wxRhFttfCGaEJ790ZP9A4eUr4fNAmfcy2/WGvUmTYRWJbbzf3Rql0tuLLM2ZakKjcFrGbjRGy9yaczfGBQTQInwfLB5qL5l6jhSZNWrXfAFj7sdEmk1X7crV1GhS27Eu4czuJkETNQIpGc7bu9sfyFlae9vkFn3+DRg9kUd8rkkD7gNxx6J6+yHQaf2n71SqQhgpnZYuKiFHjee7J5w3aXVII31PFyoaIsrFZPyvWWdHR6bMSXqOkm0j706LDDwOgmjapWa7VPKwq71KEgQpNTkc7U1TvqN/X7TDa95nGufZVocj4yR7eig/Lj2mcaDlOCew0QTIycR13t7gUaXSmUMoHjc6OnNHB1NHZxHusdFvoGmyfQ+cIVfQD8SOrROdQArwj9xcZzr4NyGM0GyaRrT84QSZxmqdUlz2XcyZG08EevdcYAdlA14CJmkds8uWg4+7qg3UKcfWt2sft0tm2veHVhrNoI0nG+zvBw/sRbG0hztsjqJB4XQXfwsanVmwyXof+7amxgiXhEfOMeIQnlm5SzgFcRBYrCdiEewi3zJUdcDQ14r4JO/oVUp1C4cAy8BuMV+6w2t7Q7YbXmHqOLUaw73seju/uuwZxey0NS40Wjh2iNj9yX1Z/O3c/SzQZc5MGcqu2l294uQao/ttTAeJY2jROFxrwQeMK+YQMDZQBBWTO9TlSN+57utF717H0HiIdmjrfn6TucAibyWBqX9B7fJc1s3qFZzl0P6v9BY820KoWeo48RscaLPjz0DKGfwKssTNbiuJjw75jo6LuA8so5S9kqRzO2kOWBAzjCBDCDj7hNVkH179VrN9Jayf7OAltSCKmjQup2HvFIxtiXRMgct7XHVMjfs2wVkxy7/fjrJ2rm/qq0/HCu0jwx8VDGfxBG/rnAL7Q9lx6NJ1DbPxaJmtn4s4LoxRljUo/rFED8FF+lUkzBW79W7KKuTBySeujMQJ0ABdCVvn4GMEBeG1rj9kLrh7sFRkP1BfU/nPK4ZiKd4Un99kfJZ0VxfDuQmfL94z19sSaI/X4XpHdbRg9JjiOzYtQfnIJ6Ms+f2/hN7rUxmv9RMVMme9AbnbutdYy8tKm0A7Yd0utU7Q2KF3UvxmZlTdBxgPhBbl4fNP+JTWGQpSbtpzWBam7vGvmAsntyq7CxIeRj4UYqcKiXwD5UHHapWj/LYq+cyLsp2roXr5d4F4TEyBRDYe5bY/anci59egnsnuPXVVW7JB2zxdrUSOvW2duHfZIgHRIbaPyj8nym/Iya+cmxCrv7vco19T9mnxHK3b4dr/dN1RGWEUFOLUWHh7zZXps9u43njqSbebL9MiErox6D+o26m6k8/vhmR9lTFJiHt5n8BIKVQNtpR0NyUHbXweiGS2ejJ2N2BiO3Sm+9nnMaVvCBQousHxjJE4gLsAmuCvGQZ1/o+Lr3S7jQi2tirGfGuHQpL7Sz57vDVeFDoULb0iH+jRjrTQcmkk1u3hYHnBH8602wq4d9RTqtB8adhTUMRCZpxLHnsMJl3bNv6q0tv5CqZ667nSotfcbptkpxtNIL82bP0yF9Oc8FiJj2R/ehFEujsFEmxladGX1aLFqsqkFEsKTIlMQ/0aiNhCjNhWFdcS9rUnvVjD6U7k0cKSlYsW6q9dXsAsVLKNc53srcMKGqM84dyiPx7s+d/vNhXeqUveXeY3ze/ekdtQXdyBiNzr8rwEHuDvGh8W+PL2ggFfhAD1zxQSqY+esd0+TgcB8ajE2OgeoI987yGrLvSIHF2FKy0dQHnN422UpoxZPa/oX9eqDmL+UMfb8nv+UnmYmjIQ/cCXKoR5vc10iIHvTvsgPOLY9oQmKoa4axsPhRKLn60qMefzCrGsuikXCUuY33ZUr/bz0Ucqdsek2Paod1zvg57ySYFGCxP+lo7rd2ywVpS7S4Y5wggahr5WYKmTN46caBIqwTaC37/vh/fasThCt079ESl/AX81lvreS1sTGPyRnfQjrYOgEfLY0XIpehOIkd6botoZ0oGrGb1JqrFJC7KUtyLfuNABJBm1cpNQRuHv5B6xqSCp358NE6PZdFcrNZ1ruhpwMDR7qOZSDyEOq3t6Y81eaTx7lwU19B50nHu/TVyEkckojfs+1eZqOWANHZoVaOCPbg3yPLRVFun3VVbwLnFyzxdCbK3qm/dwjJX05REoZcYIsIUTCe9vcqou40+3s89hgrd61x36vRdctYlTa07rqYaOOkblaNzPC3B0Al+nwR2o8kJUyv/naZSjyjugvJlhj5PIXKfw632CV8XQ3APmGhkKIC2UTIqgx8u0pRm6YOpuKrfaOvUlaf1Fn60C5m4PYfhze7wkxhbTobPi7J3wxeerZWg6bxBhqPNjudhPAXRQtJ3GvX+H5N4KfaZHtTaHyL754jwE5acSDUyYaALpG4vMopOFF9yUSH+70SpSazZWFcVq1purvJjx8Puqiy8vICKBlwhpdJdlOqW1Msfl8bZicQtXPkd+iPBnWd/LFEMmuvOD99R3RPugNYaG1vlvObAIky9P/hk8w0B67D42HHko0ry2rz+zwEfgafuho6Se0FpUx+I1JGHiAdSHw+zB+A8+NNkxn5HIxp/SBps0ac4ZmJjGyl+x66LtVz4p4XTna3u9aTcqGt2qnjdxpBKQOXNV37UpRfTNckCgg5LReFPiwD6fzxNRQ1sJb1v72xWLLuUStG08jie0i/By6wDWyo+h1hIefl3k4VFicmVYI4kDkLZVnX9HLfAKbaj/wvW5ZYDjLL3e2o8jYO2PtlJAeYcV4SeJbk5xmXOPpQ31MNVIxjMwNMipKL1sQvLz6xojCoYLZ9HWPtTYE27oF8k0dLWSc18d4J3Uxw1zRZImxAz74SSb2nWTxK5WUkQh1ly0BeIrknrFDeSc182Yn8nyR7zOaBeJ5zeTz8IwOm0oDzv3Z9n7TumYmXNBwMqsE3sM1xGMZFodsT+auDIjLqvzRlRHQGrPK3gr+329p1N8vnJhjVIrhb8OTA4a6qStmvYJf10cn9dT4bT4cwRXQk+gSyWI14dYu8z5XSxT5Iz5v/TWh/heml/TWrooPnQhnY47Fqc0K7Z7EZDKfRoR23NrkiPxcxsyobWPnT3HwQoLSU7GhYM/aIX2XbCn5lXHM0OmlnZ+R/ZgNbUKuqcNas/GF/4AX2WoN9MVYDfaFtpZy9zunezm3qWZrPtJHj60GcLg2Sf4NgnGNAizL0AHJa8sVdUo6DBaBi8NAaTSbWIXDEX3M2ZFFsxMRQvHZZzx65U9tdXF/nt4X3EbGb6eP+rhnmw7PryPjjsvamzMhmh4L/LvQZwBEvURsyyxi5331SCR+cyVfEXdFshPnw/QKR2TU+hEV1irZCfOrr38G+iFi0fEK/R0yHT8l0s32xV8vBhrSg2FU/mcLFSyilo/R3ahF3DsArbzU6TsAfE00hrOBr1Mxe4Z8UeOvjEIi0CXPzgHtH/TxDdtxT0d/Q68G7+UN97q6QbvOs4OTk2x2Aj19fFh/Dfae0tzInXOYCTqROiuEKfqhGWfkSPFhDBaJUpjD2nvkddRjpXexXHan1qmIFTND6CDFGm2hIpOeYUMR3CfysocUdNUnlYJ4OPaIXv/ggxaf1P6XPtlOGF19guQFQDIyodAyLT6gb7jvXw2730fXju1C0BRJPs8Ar+V2za5/np9bIuJt4gU/c3OELE9Hrq2u524A78YMzjYY9PmBQDXcj5qNYQhuIxTsPEoQm/CLEoV7GIXp9GwlKna015cHXHdnVZxyL2lyHX8U+dqSEBMUUBqCXNpsCDic9ttabQCR2xz2HYZM9d8EvAbQaiiHTduBRIdK1ia97tuhTXrKS5j3EkEfo5vKhCIgYq0J0T3ZYFMGv9wNruT5TrMhEvcni/iM0eye8hDKHPwOHNUWSanSA1L1w7IphCnANItcYwmjN0Ulo28AvUmwRYKH0QP8hcLrPDP8w1AC0/W0iSFrb7oLXKMsvY0CxH5wK9QWHRvHONEVyJvALrn8Ff6q3XBzCugWNVhcVJqP9RqHvMMlDfGSbotEz/iqUobvktm5dUxYxEQBs//Nbh+A2eNYlF9eO42PlJfzKBmXD7MeoyqQFaaGn8NN04xRS5a/ZSZTEO2uRH3H0tfLPCde4l+z7ztjetDfkC3K8izFh3WXdSd3y936Xt4ebTy5SG1KwTTVxp3AnPDYkVZSbwfCgxs+g8WF75EhZuh9tTDvG7p5N0c57NhggdAPH9Aj9S1x7/G/64j9UrHmwQg1WtcfAdY16wx8F0zenmL+41gn3rJqanRh0OTo9V3uwLvJIwCRU4bL3ZQOtCICe5n4tarsFafewOJsn/GXqPCS/HZgUci3UjaNVBBGDO/S3QQEM78U4Rd+UuDCH44Lz6b7qyDUrUVz6ga5JzIQNZImzbr26sEMHZCKPNihd5aNvxunutmSpj7ukNesN9wN53VMHfw2I0DuptsNUOt07YpYjJU/dCLA/VrRP5nfXu0lUJ+pDObgkPX1RiAiRvLM4e/fNKwvhBvRHfnZI8jHShCW7zR3Lt/y/Mib6q354+849RFg1d4VAo49VGByT96Wifl6x3tjzon1rtpU+lBROuitqZSZf389Wf6iSXvU57PFM/ZmJcQ1iKQZzr9dWfTbFuJD7x6AMnW6H6CDnnK/3Wiu5s9Kygs0oo8n9wFh3IreDOb6HOCJX14Os+egtfUo9ZuQyheA+yoHkw8qsATEj0lO5HHWm6yL2sdYdQvS3ayARssPwPEjA0xR9viMISRPe64VkaBje909YaDRafkGnPlNHmYZG4B6M8gNF7/pXlJzGTQtL/vq1iodreBjcNSPSIIkR49F7SdGV89azt2btgXCJFBvxHRCW1GLYkeBDYK2b9HE2GMxKsaUVydEiBrbQags91nj5cTAdiq+5gkK/kpuYPHTMijEEwVlFQzyvsaLcfiXGX+WPIYzJMZFjVsmlve4HS4w8QU99mNKevzrEEpVgsqVQ8vjduJf6fGhP9h+iYpSdzyqp3KLu6UJFy4toKQzrfBA7W/U0rQMAfU1O/7lqBo2H1rALO43dCPCSQazUkuRPz3iuyWwHZc7ghDiJRzhGGjxR6CWe7uoyz47ZRBeu8RicHIvW8P95hiF+IxGl+OHr+zxxFfq0ebaPbdaWr3Rd207wsSakeFua7YDqh8ZwnfPvGtnq72KhiU0KIXRlNsVqF8YL+Qfv24YYeIQnNe7Wj3GPTHm207ZN6mwH/xQkiw465BeXNdb5c1oZJcO0fk7z2GgDj3QHGAkAuDO+7tIJGLEYz5V/Vr/2Fe71SSybrPllVWH+63UAbllSv4TspQCS9y6/7Z0PSAbxQo6qYW2txfOe73PtrDAC2dsrSHXNv+mLJUrl4z3nSWKZkKzUyM5xndruz7O1Fxe6jCZQb284e16wdjkPIpPjg8q5+Oa/M5Limhy7n1b8jlfJP/oBuNPdi7LS4+DeFln8qJdRbEtVfO9DoK9o2/z/X6QTbnVgV8itGai10kzb1esIynJtvhxbmOmrEYhZZqjWkn2Ht9Wn1Z0O3/VQM8WUcxLkoXzswwp9vvB8kATwqYulwqCJytCiPGy8bgwNxHx13E7kyNrxgcz2qqBtUtkyKow3QKUmmtqS0iB1p/myKjnL7rl6jlKVQqtofRK+KnfWY1yxmuosHGrC4DC72WzfvF7Fr71q7DfDYYTfKvuXCbmHzETahFqMbR2IFcyScDFZG5p3rtTYBDcr2EPRdHnAitLmOTK1UwSnIrIHx9KiYpF/3JOJG/hSNK33V5Y0DF8OKV7rL8DUOdSsumw+Iq2qqPPF3QEF17/RsedVJOgFTETDxj3mu9i484gqHwLn5AS+taD92ZffrDakBgUNexMoPLy6PiouqZYJAbl9KcXqFnRLNxheddmx1uqUJcd8+c7Tb4nXONzebSR3C9Uyh3l483aaxd9JPnl36G41mMGPZveDPk6HT+5i7w1CnRWMXkckmFBJaYwY2baNgSn3VzyKs2I+76wMEHH5bWukJTygdcCma9DkMybXWh1oJX0eyj4wteQa3HH5oKiD9cX9t8vQ0jrskBTy/MZxIyJIP71Kq0RPZnHUO71wP+G88DsZ5FztdaY2P7UD/sPppOmiPkDx3hZt0TaB0fqKQN6isQWpRzECDY20XB8OJwObN6Bg2Bz+Cu7Noz7vdzT+KIuXaVNrf5mESx07bvw98GIM+iht8+3CDR8ftuy/pQxJKDwnRKyqZGwVquyOqfy2ggMDuUTunnrQ/W/d9fHclvDw1bwD6t6ftgn+/Vpzm9VTdeJYKNNrPx10LXtdSfJZH6iF2UcGOkdbuC4ZZzYyjlkxhKQIVoIj6Odx69fGTA085ERXyt68KgbGrmgifKVzSYRTbUeOErshKwsOm4eAolgHKHNr4SmGc7IzI+UBzA1K/w3KUg8vmJj/xVwv7wZIr81cfB4HCcHMd10U/NVbu99UewH9qn8gc5L16DTA92ItsBXObjwU8xmnMCcdFs4ADjF+Brr4nk09FCzdIqO3Z+P6wy6ShMvYLvkX1UT4B+fBD9+/vGq5okthJoeFPFDlnMXN3umUAm/jdlm7QF+rOh7P6sQoKCP/D2VYjdeoBZD2bFAnG/Egj5Dyr2b7EfSK4b2mDQUR/Y3vQcSRlNNcWEAXadvJSb3vXzltGFoNH3jenCCS2GF7UUkv+EjXOgUEJ2m/iqaOh044S8+wcTUJ8W37mug0ozx4obXPsejJZcTP1ezgwh4owu/lPV5+HkzMXKaARhHSXHvijS2D/DO2blV71sgUoxoPAbp0pegr39bOQwO1OIWfnawuvCzSXVGmeEBZcT5dihs8UkBWIsHFebYwO7DyyYPhiJntAJSnKIq2vkYQgIXnBcr+dKoAC4HGFsxfz3nHvSNIASVfAfUMFWbDphfd9v+69wfPoAeGSu4wyEQdwCLVu0SgEXJYwDekyQtRSFDLDM9hlNoQwqEbhbMH76n+Jt6rtzngTF9jYxlNlDBaddZVsSN/ksgUdyHAvPCzlM0kpl+WcXjMixpLXoAsdjNwhYM0NWv/833bX6/sHTBRDQqrH3CPDypH4nSBR2MSuRRj6p68x3uR5Z87DNnciqNGYZBEwfK4wdZlytiBCP0eBMK98GFMPHuXUDM32VdUd/7zBRsY0/hYZVcQgR3PtOgEsBOtnzePxT2VlY1gb58z4JjQdDzBE5PuBEDUz2yeuQJzlKC3zKMhoqXuCfwMGEcGhgX2VILhtL5dykXT1fj0nhl2SCIaEYx/C6CPBNpE12Hcty4nrc0262Seivlcm/V3iS09I4AnjYQhk/TSPmd3kQcNfFJ0uE3IC7UycTiMdCbfNLYb/6HQGR3BxMU+pPlW38EYyBtcFTVC8+xMjJB0rpDGU4vuZ0sOR0VIOirXC/wPOuqMgIAvRdO7WCKb3lSdI1oO5DKHFjb9ZFy8gDp3bFqsbxEaQy1XgJoGzxJOyY+FK4lunGgWU4e5WenalZIvgal67i26GyJXISO5vWZB8cdqI8rzjUtCRobPT574KcpeSqo0t6naM+BvhkhdCUI2r9Pmmt2rVeX3tbZYGdo4lvk3tospjjEOVXPw1WJqHnSMph1BvgQjQXArLMYsNcc/0svwCzGUtw3ShKg3Q9X+mU9+f1VG4KOgZnGd/VoRKqiv4lcGY2gxWcnU5/f3ufOPmhuL05A0d94hdVAQVJ6vzYqybD0gbUolZ4pTqNA00EYiKTiPI9/+7N6t9xQ9szbPUFI7Nf0klHDaRUFKM80bPVd6pSNjQE6dtFuyzmTFb9MF72C2U/SgKCYjx34l4n0UiZnj80kjwS3ggISeH54QzRqrrCplh1MFRdx5N5ubnUQYZHaWNsrHdpfSex9q2TKBHPtNeAP2ITNqYAEelGJbBBap521ijALwWuOtAe3gq+ZaIje+7s+KlPPdePd34fYPMiZmaIxEdAulKZ4xWu2wSFEfhlVvG/orySIRRmY07kHk94ij35rC4Fci0swSk28JMtb1x1rP25LSP49y2/+9gNiAW/o2f6ujncCZP7F4ZQUgP1hvCfEv3pIjz2EgdFXbXJK27sOIp2QQHw3rkg0Bot8koYtVLS6VirxTglav5sQfr/EicjWJl+Iny9kGsxCj3jXtpCa3YfQKdl2N+f0Z8sJ535+c64rL+nAqfBFcKZzXIJq3EhqqhEfihoC/8qazkOGnTa7epxcg+FdxtFQVQHteJhi4iDxQ3bdmjvWc8S5+jCvoTwok8SsFnW45YHO95u5QyTt6f7EMuFV0+YtKEygeAepOz1T2D7Q7ZsHfW7HjkgvnMKoT8Pm10uHGK3A7ao/LJGM2URit22K2sVxT3/5rGxMdIln7OM5VIWCEoV5nBNvAmPyPn0QMYAfyHoVfAV5McUWlK7kej8SKZGK3wY5au6YcrE+6XF1p5mA57PPq3xuqB/htRj7vDHwx+DlDOSqtgStf0OxZKW5stUUEQeGpRbeI/SDBxjRKpHg8EDwj2G9XC8Wdqg3CMmrE1jVRXBemKvM2FsDhv+dLVkigUcVw+DLaFaYfXJ//nhgZgZjErq7Ap+o85lmozV+Yoz6K8fOm4OvPhjkMmZeIdqCGVkhLLFZg99hDxvkUh/unpwT9U+jiYPn9cVKj0V74I6XKoB0FHNr3Z1JYRuR7CJrjGRg5+JWwL+95/rb46qtEO8s+X/5lIrEfAegtuhBtuWIIFH/U/6yD3liL1AIgH7OTo+cuinjUz6HXlxZT24MKEcSk4qtS8UQWXNmcgFK4KTX6zi6J1CPBNL+FSg5ZMIa/Pdjk9wBzj3JXjZzEvILUZm6ynj1RL2JitRQOebti6q43H/1s36whnuB1dx8F0JxLA3nMuMPRK/rzaQFEqhpyrScWny//NEEolkph/1Q2ZtnxWpMU2OF/svUdSzJigTJr9k7heaI1rLQN7QWhYavX7LfrNnOaexZdxWdREa4h/D4/28clI4MWtSgN4IjWPg3kWNRPr6laf5y9bjgUnBUFh0tSBiLKcQe7KR7W+ZrY4Uss5iC8dcs3PevfADPVxc11+tiyu6UnK0mqVI3ODxw79CVHrnjnjOTA+GGl7EAScfB+7RxuuqcmIqCUGUOQEpM6P2NNmAEHBRa5FfY9F2z3wS7onOU0nPsnCqXiOzKUKyzXzIsqEh81oip1bguLVN5fTJ6SyWFD9eywSllYg1SIkg2ZtqIxqCxzYHVPufo93l3ZEwvdxcPet3RnfjqI1paUEmSIYL8DYBl0TMjKPrURfpX24MJcqDw44usfwzmc7dl5bwO56mND1SCq50Qp+4axke8b7wI4/Zv43UF4nlaGemL/BCyQK9dJB6MB19h6hi634OYky2xE0ilHXvZUzh9JPump6/FAq/JwE/1p5JMiHRGVXmxSbierChBQuzPJPMWFpd7uPb+U4gSGWDYE6pnKTo/svh7JqQKBzt2OMFiI7Ewz0JOTlW2ZYAT1p0wCcIUrOvJHMhrJgT9CuTLB6vqOcqNYKqc5kPch5kW6bhtUC4QSU7OOljzjZJ/T8g4NQVUzBgt0ZLzkYB/rwq05AsKqh/qOQ7QINfIBppoYIhUaC5R50PjVNoi/1vODH9l+TneQ2R4pC0MCvsU3LNpYP6d41ZNIr9/mk86RpSgVCE57iPt5Ket9ZwS0Oj3Au7wIY4rPX9WYVwISjrEzIzHh/SA9mFOIcjz2MT7J6IOEK1idAOm29L6Q4D8TSLBQY5FSfOlgGLojILQVMgS8iKBWydR2pAO6YUjDB8Q2I7+kkkklgqEa0jfSaOqrb3LRGmzFFJkckiXtJuING2c1OL58iW4tLWaEBFD8WZMyxenyY8C65fmL2mWAw8olnxLVMyNn8POWBcNTtUvMCXYZrPOswKucY2PuBz9RkYJMfFMOuhfgsPa8UTsg8htatLm25Iwns1RQbtU5iTYYekvDtMR5nJea6iwDLoWp3Ht73bRYkAhjWlSJnfa//Wgv6dfMECIRcKkxeVzipBIJbbPZU17+N+PsHo5s21lIViMQRq53Yj7C+9fezIbxto7MA5GGLj7BUUuZmoUjulkVx8dYCU0hhGoFQbYC0BGraWzUJSWo3aU8bRKXQoLNitec8GMCkVqc7AA+vJXbFUyunhqCe55uBbLjMVO8otMyAgN7W5SwY+CTzI9Oy+t5B8sPxcEO1yYnxKvygXAyLObqoH9JSI05Tn/qdDXp305i71AR2cx79n1coO84UoRqGEy52TydZwRCMqEoGnvfVKBpEjsKkv0c9htzvXmaQmIOmjMvEWAsw4M2Ogo2FRCIF/GRNfmIb+CZcoi+f4pNcLn4IMOm2XTXWHpRf5bkCaaWXxdf5T3mwPhF5R7GUG1cXNvGdmRv56yVA0Ss7HxL/VPbrIYiLSeIWd8FEUTsQ1UoTr3t7OxhA1M8/U2XD5UGtt02NrP4PHD3NTuTh7a9+x7zbbFRxy3Y03rO28eNyZ5g5uTk0dJ7b0NDdP7Hq8RAlzdeHUcIFOJJYH0/czX5zrU27hOD0qgP/MkqyrrI/QkFRmmLBWQFPOrYbjZyp+Vp58bsqHDZqqLpG0MR6u5oEkSIT9bQpP9LLm2AwopQvfDp+VJojcIryugs6zEhVO/N08ORdJ68DphUWwj8dVzV0yUaVLTPfDnpVM+F7tMRBHbV7946anl13fcl2uexrJv0uc7HGlKS2WrCEjzMsoKZek/dMEq4C0zOYnO658WsaQ9rtYOpNTt38T9JR9RKvVoVKniyLUaTUT/k4XC7KBU9JOGb529qDN6sJTcRjI1qT0iYmdfwoL3DV4GADhV8d2/Y1tqcUoZghs6ONt5UJpEbD4M2L0LU7l4gHkLrWUh2x6f+BNPNRhlFyqBK+gXwrS0/qcIB6p0f2Z556YnGsSw0vlq2r4pYaSMXZAND85IIvrA3s/aiCXQOWdKgDkE+gRxXXtPVuOQm/9Pyw2zb2N2fKLmis5xx6dKQA3CSzItDk6Yi58kT8e2wz7M00YJC9s0LdOM4vCC91Hr8jFuxsBdbWql35U3Jw1I9ot6fRKypIFydlf1xx2DGjfe7bLYpRnDgNM/1s4t6FFDfSnFyxZtc8EIW6KjR+Ct1pxzFXAiWwmIAWMtEhmJNL7ADa6KcOjmNmipEZ2PQIxCVFxw3qab/UyUSVEremR1bkAgqXNzapSd5PCHlH6aE1TMe7g/6dNRUyJFOdlRZpN+nyIwK9rARk+o8GJXG+hTs99JfmmmgG79J43k6FvLCFGhdSd6J9N7/k9gGpRnlFAGX+RgFjstuuw8mVecYYMelydtmKxr8O9P8FGuymZiTmhRWM2eXJnhJdPULhb3pdJQu2mSpWHsrKGSA1HDuQI626jgqmfB/CJOFvWlgVzqPlzh2SDzz7VsW6No7D36Z5rFP2x1c/1VsNFhiNEh4i8FpGH1ke0djKU6gwjvEtPFWKdmtfFdTpo2TFLipZESipiPWsw7ioZ+z02PEbTzIrR8/dPjNMjSNVwdxyPC2s7KXq4tfQADr2TRQFtp7y2lam3E3JLfQrVBVZoPHIlfH0k1pFX+lsWxIVR90EVOaV6tbnpbUCEaMC788Mud53J0oAr8fptb+mcR3exBYl95x+24RG3w4nD2T3048P0g7W3k7EatkHnt9+Pmu3N37uIUK8jWnRlZRVkZBiVVGamKxBU2nHNvktDEZ0Ft2wJ5AS/5yPRDOmPuBz66Hqnr1wrUcy4UwPmaxzYOUtkyDfawgvthzvj0UqW/VqKqQ/zg0vmXryNFFv25vYhCIp2XLLJL49gPwxkPTrD1nMlyHHdpeUxjkUNDQ1s/jC8s8XeYe23sgwOHL/2uPJJitixZyr+xuq7p811SE5hYAYtr+HvtUeQHJK6EdcYyHSQNQHjeYhFnO5Sd0iOgb1KmWMD19Ra6s0HxYxQOIsFTTEWS4d11Vu9LSh8pFOovGVVcWNsiydiwqfJ1u8scN18ezeJ8Jjje++aF66f1Ynh5MmNAv4SlG2iKe3e8G1zhOkYzkf1z2c4xixOidLucJ+hJ4F8J+ql2bcmdxhVfhtK6psVd6W/dGgOiYthfQaqKVzRmwXBewrr52IaiND+iiWMUO11bY8kWEfYaXl58iN6Wo9dhAhp51twX6gYKvRHL5qTH5jKissqu17JfFxI9y4CxMJsfz8o6nNt04BcaZaD9iE9xL086E8I1gmTScfsu6XOkxxlnp1s2PIBN0A4UTAWqPY7qbwsHXyqUS/041bMqFbRlX4yHVIwTCfB5U6ItpwLsJvQgcsXHRBLHSs1RgfEjZEkwZ8uu3gcFWdVvWEtl16XWIXHnnhTzDcW4EV5u/0IM0OygU2QcLOcGlgC8l1hLQfcWtJsEFCN1VSZeSaEiZB6jEZu/v8U9Vi7Tn1/+0j+zAdc6IW3TtPgg1xG0L45RfOAxsw69KPhGy5pCN3SJe72I9/pR5q+R6X0NRbo20W7heEWfPvu35bGacjSo04w415dW9SXdNd+ia/OjrUVzmsqEiiz8GTfpZtednOiaYyAjDYgOGQHds830Xg/y3Hc8/WPbIIYYAE6Dy/RwKYK1rty+0DND0cpzb+cKD2N/YtuuUVnWl6jvja/7eog5YGbD5WOW9abC+hzzN10h+wF72hlzss8HfhT6a86c6hj0X8ozPaXZpThBinV5YGvibJ9MhvLs3zgIo+N5phIos1No2x4JCPnnBd80f1ERfnqFPyThEt0lbbZIpfQkJO1/yw5kkLXyw9rt0lY2SLnHNYvukpAxkbbZf3gGNAkSeUV2i8AkcVcfCbmBsZy8juClSrwXXpYR7n7Jghg5omXQwwtdNDI8islWR/1qudYwDaDsw8GFTMEy+BujOfvK5J96wmKVclaYcm4JToy30OsVfVw6gH9ixvuD+CON0yQK4mX9t9bpuro7bcu0QnfO3J1u094zJpU/eFPuT9NaxV+s8pEAgap0tSVrr9RQEi3TeFrxRb5j9bd842hpJ31yjKRjtPgbCnhwC7q/ecJZHfKHA7v3UFvCE+OxOZ/0cHHJqzDF104YzirpAcV+1PpIegU8Vsc87vfLVMDS7BLkHbY84QvLXbxNSjQ+EOY+I8h0RGVmfi3THvjR7l2Ea4cEt4YdpitJu4wP1YPVz1aEhvdJqSy3sxh/pZYv3nj62Psi68ZR3DKsiv1oR/AlzyyX+fQUy/s5zyz9/ddi+6WCa9ofFfl2IG1RgwyPMT7EX8v1w2gMeCfz/QI+LT3QTeIZ1MlF2LTS+sUKlzH9SJYcQCNkKtxYhlvu6LgIcec+OGsIdFaJzWOMd3jVAKsVogARfqRnAoYcwevzmJa7SsPIYXZtGeO86C0zqM/RkH8WyxAIaM9jSSFEKfV+EtEoAQj6QtnXZsr3s6IwpZGzgMUQLaVUnTs0xz1hDPF5X/HRNAFjZah99jWXp3R4wze9tVxxfSkGCpcNxBHNXkEDyWjINjYEQqYH6TzIgHA5FX70LwUCH4IcdFelrSgSeuFAw6PnZGhi2RUPOsbYkWFg30MoGVBWaLcz/nIxkYaG1bE/u8omHcpRf/d3B82lYLoQxAjtXq5YkQ4PuoWQvw2sZx1swCoYX60m89f47NAQNzJe1k2FyVaBMm6o4quPqjTjZEK10oO2/tQYuQ2Kq3YfWnPCJFNrZHGO8qkJ9oPAX4yhE6z3MmTGt8pQVXKo6aNafeZx5PSSBoSOtUoF291wVtxAGogpEiNYy7wUyo11L5QyolShNKRPtHZMoyHaOemmLG1dFDeLXLn6w+Etu//UlAgXgz2cq1cs1yM+KJnJv6CvBpT4XYtfISwKhN+Fv60AyFkeZaFlxoM01ZdMEO2grdDNapIId4oOE9t6LpJ9ibJEuSiy5+TYmiIBFhMJKvHnK364ydmxfilZvX6FT/Y3nSCuK3sgW1dOhONlWDNcZCJGZeEV4lxsxF/XgMhdlGcGtHXRjJASu7H8bhqdGo/aoWC0ZMabuCcbURtRMJ3OUVzYPknJyVejfMFsdcuE3CSjFIQd9Bbba4S8bvSxbYY039dPU6w48cb08DX84tB1RO43mk/va77076H+2gbQUglzJnU4GXn3Lnf9KZW4oR0naZR8nSlHdqcE6jZbsjh9mYUkGmC+y/9ThtvAa4rwh+9BlcV9wRiT5BY3aWpF85jpVrB4pl6E8DbTlfH2IYvJUB1EIh6gBpMS6VFK9VJqB0EcB1njZc3N4z8xodMjcGFq/3R7vWdpSTlXM/R5DoDb7W+5kPP8QqkaygfBeRGOcNmCLnMSMe7KQ3LD+9m5Ryo7Hjhj1Cguc55eQDgk+ofU3dp51ETqTqxjO9koxD8pHKpj6LRm3g9ORvAG0V/wQy+r1VJIQT9OI02S+QXu5JvkJl79aVq+nDbS+hMCJzHqPX0Qk2IM7xuDSOHubnCh6uf0jcz/m2DlQYRCYOPM6Wckc/W9eMoFeujoyORyFGroC7WvyenR2WBRkfHJK36th5x0opH3RTXVhhP+dC/Ysxw+nUYpSjbZvhWd9MuX1HbQ4xAT+YzaR4w/gW8NuRrIxb/sd8VB1peHewqWkDSAs1O6SWmt6DZbfb6jL04EBWjJ/fiC3zKpTkYWC0rM9yb189isSxnf99VU2Qje0Rm5bsFZcHVPPMsaucjyY7GGhDWUASdEKP0GX4fBr6coiEQI26rk6GGT1aXGqxSxLLK14SAIqBZIWrAtX3l5F/onSSJXAQXat9bPvyxfpRRca03ow20bpYDIwPhQiH5a71u8Lsr2j4rUDisy6ZhxAeuyW57ndvz/KiggvCo08Y2R7Ei6eHBN1c/7/QE/mpkk9/yIXeA4qZvWqt+PNPWgwG+2LNiOmcTar2VQiJa2cKno7a0aCRl3f32i/nzmLlezJofg10Gwc8ZWvN5N6DlBczz4vgkbr0nKxxCOYaCLu5QhSLqjITPSWdugnsk/Ub4gGEEKWtBUtMgXyGNYM+LD/vXe3xTha5f/2Bv+MUBxwsMimQcLaAT+b+GYiBQasYmIcyJONB47UoDADuohiM47SYpqiFqg5YNmolDWCewOI+SLE47Y8zASt+y9V9oMYE/FdS2eAKtz0aKkuC0Wrh12htn7TKdHf7rCuJlP360wvvac/AmS21Q2B0x50RHyMBypiagjIXKBWlN9g4SNwyqQGp6iYFb9xfE8nH8/EBB8AlGMhyP/pQ3JtAbX0aYy89eCIOQ47wuV3K2HrOSeJ8jNOX3vRtJCfYR28fjCfNG5xFUlHLdHDw8cMEMaBhL+0kSf19FFpBL7q767mGc1hFqenvzUtIeO43/rhKHuY4+L2GNY2CwNb3KHFdbO6qbc6+JZLLLqnHqRqzigMM4rY7Hcp1nGjBzLAg5yYX+Swlpjghy7kE+L0eJfJ22kVvn3+Vwx3nixe9tvLdF6IaFv3Abp7ypL+XXYgHip0i7hZ3YLp12f//NPeZyylmlQmM8YMwLCT4b09Ba36tDTXn99JUgSMO819dA1Z0VXlGuHJqurqkkDeMPgDe2lgBQea31tawSkuBYG/KckVU5aWA1rPXA9MsikCRNRe/yXYI6kSLgkjcI3RNu8rUwhIbIzFKHKzqA4Z+OYt6iqePCslz5lDh5TEinhBgTHXc4175hpWdADmmvcI+vm8q/+x/0BsDZpo2nBW5DG3X1gqL2mKwZZ1xOGwNBLoE6Riq/iB9h17cmvDYA0b5bc6fixsootmhhsRGDwiDwDaimuvTNI1XzPGqDejWPtQ48jae2uo+7uqAbFewfZBhgz8bWT5sNi4kZN+ZYFOghUjnQd9PHzxoBlvGBvjrcAFD5b5KEiM3pmGdKvDM1Ysc5kEB2ixXkGXYskSBqb5OUQG21vuip7ckO0IfK1zLkVdblH5ln7W3rigCYXpm0sUIdmSLoMUNdOt9dj0fJ4hk4w/43mgrMpTGsM0xo97iFHSlY+EEBs/vZ6bRMNbTsiHSSClgM4Eg5DSYgbZXryIni9tCG1oTN9rgKUu43VEyRkqO91djEXeMX0N/TPskLzLwHxbO6IVlso5A+5gvXqurazW2+WGPqAThBgFACEtN70t9w1Vhb/6Kc8pL9htdQdoigD3r52Jh7baiwF9dtwskjheJTUPNSqYbAzpZowOX2SHNcHFyTK076QjDtpdee+VSQpleHglGWFLXBb09Gw64WzquoiUKmrMI8bEpYOzC8ji0WHBE+MRHPvTCbRm9VOi2U4V6mEf3y6QbIPLhAx8tdGqIyRNxg5JG/3i7A02TT/tB+utDWy9wHOr/oRLZCg6rbWo7bO6fquiP9d0eJeP+wlaFDI2d+/RvTm+3kDik5X6q2/lsbv9XooSikcd0m2jtYfB4vwZSlR9+evWvh6BptZ2KZhvd8yttlvzk9hXUL1dag+jC0Qhw/ysXjYwvnwcDCX5yvI4H5S9f5g3IBvOTZM+xfxNzRfv7C+jAUmB9RX//V9AY1ufIrv9TsGCz2lLoW5sDwX9gm9x5V7Aec2gZg02IKfOygi0EYmA924vUA/10sMYH3Qs+LYnlNm3aQYjnCBru1pxjPh7f0F2Ad8KWfrUDAVumBBrZC1Ryj9M8+FuRs+QhlNLYuP0/77R9NZv4AGfyAbKh6R9HXhoA/IqYQP8HosJbd1f9uw/Tcvfmr7NyIse9OQyc+TbP34FLAyOI+/s+D2OxyM/edRDOPG9SshjAQleDZB+CuEFnSISpAiAl6m8lFh58+XmdQ4eyoshx5tDSflfCEvXjluCLuheCrAk33VcpGHDcHGSl3rq85pKl11WuSSsNaXulqDXmrUVU1iobp5rnMIk1FcVLqJbcse2+9HfJiK6uP+4rv/E2SvfmfiJ3Pw9H8qxr8POT4niqb7Pge9EoJQEHrLuRONO4ZXCu0Em6Jp2Mqie7qsEPHWSk41ITQ2O57ERpFsO4sJyRy6j1H0FP2lMwQU9IrdBIJjTWFtGw+Yr6HnOahkQzwREeLwUS8Eg34G4ojR5riQQ8xHRAB2fLN/JW7UyJpyLO5KFDPPG27GFdwugF2iDOiImvnv4DmGispJ9AbdxiiETTNfMix/rXU/NoMMUPW4RkkYNCKW4czpPzZk15ag5hJ3Hr/A8bCfckG/Iw3iI5gfKthJZ2x9qNqMh3flSEoj8a+zasAk2aNtVvxwlzO/lFMGqRcFx724VJPZTAvzrxEXZU9tIwcVjVtOo5hi3biLy2GHHUSdQS7ciby/QRrFlGR/jPlvrgdjgjSPePvCFmrGX5btb3/6ol8v/Gdg7X09Wip3tCKa1DPEobXTgkhvW5978PDxhg37PV9b6syP4vEg83kGBXUGo0be2MzG3xcT49VEh2aw+q5/+H5A7X2wO0s3C3o0VPLeyN91rgOWLqGb8buZlyojo8NJK6YNFP+s7/7agTuiAUTRLWj26GlGlKomgK7dLiWUElRvAznRETTwoli2dBFLECGen4M4KP6YkJyleAaV3skLo7Fs5OSgItMIuiigfC+EUrQ/IMD2iCxfHsPGtDPwayybj+os8e8QX8RED2jkfbRWjhjG4PMGQZIFxAaMyPTyFKHvD/Ezt7lJq6zJB4abh4wVPnbxCR7Wv5UEzLJ/m4321WhyWNQEvzyFsovMlZvEieTfMUYmd1Y6Wq6uyjr2tx8y/MO1GvvbQJe4UObfySwo48ezThCDBZ1MIZKk/D3IIfDaPoygPFuIC/RECgf1IGz+z9Pw4g02ajPhWM9YC+uTlqjhZ9xBjC1b98fur9tRhJ2s7PRban1v/9MUG9FNdU4bBNG5TW8mJNRIrlgkoz6Ubu5+PxPojCghJ1lRpEN+idKGiscrE0nY0PPijDpX6IVyWIe8vdbtknsGQnISipGTxIM+X8GRP40el1+1z64+YQ9raLbWV6QB9mqO0VpWZxmzlZxqOjGYeklgc0aHN3gVux4BPMBR2Qdc5aJHgQXShHYIvzIGFgvCmAi8w2vlcMswnQwz3IyOyAeKb/3SbM8/yoqCFF2eZxvJHmJB31nb0Z0VrzJtJC8QcamlO0vVSehLHeKac1FDMaur488MAaleZsMgifpGuZyGTCS7Sp7/spXoxsU05vegctpWo1gQZZh/bQi3tz8ogYulKMeNVH/B1aZCcXwCWmJhepmPQV26/GBNmTm84PZgSYnfR25bck6IO/2FBBfN41FPaHqiPxJJ3LHVvXRjdFr9nK0UAEhrJcZaveejdBjl0A0sr0seLMi+vbEySKiUSLaWXp6ZRzWOc8SU9sJoT2yzkR7dE7vGPuqyi3qnfykCsAEIO+aBwec4ioPtA/Bd+ngzswShJKQNOqAaeyvEF4ZQ5W/BJweq+bDf1iu8tH+TEvzT/8mku9zQrVvjGQL57WpBQ5Alc1Vf2cTT/X74HKAcLIyobPobW0cw25qECR/JwO9TxN0hJWu4pfdQ0GlxsCEHRH7/elRZFyN7rVl9NBZSahD9b2PSQw+ohPDkv55FfsP519bEjf6BRWR9wCIvthRrbTP7zbXCVu9HxQyqWmXdpDB2a7WMxEop41r2cmcNnjoSvxLWrJRSXCW4pvB6L7eovKcp/xI09KOqJoTX43vMOx2N+V8SM/TzIZ6daw713SN1XNWzH5sLe06o9dSaQ5jIn3393QAknIngKqyCok1fFYj1p824YT6NqG1px+Cqi6oK4pew76PCowKQYxT+qEesbPs9SqF5I1SLgiir2jn0YnhLESnYf54jBuWSacvHJYKhXeII0S/y5eyQP31InbMDWPANG2TZIt3JpIjxC8CASKU9nxJORMXROcjFW5ZwCEZwycahcOA83N2vhG9cHw1aH1NRPuxZxvX2UkNPAdbYtY3aer4pQfQ3I1I7LxN86bFpuDa61mhqJyHME8cfjrLJafS9+/Adpt03AAe/+wr0W7O9pxzLqkX5mC9uyvxQ6pUz+NNSpAIfmVFFvlTzN5GZg2s48T7vSb2ZP3EsSbKxHSryGtRbJDHegro5Zz5i3S/v0Htt6fL3qnf8F83Kj7ibteF05C8ld+yDZyIJzMX9jgr8vtSniLDaedELK2J/vtyrGMB8cyMQ4I+pQSfqIWeqOEiHAPK5iz9Uy4jI5T98ELY2PpbWe2XcDMOSP2gIOEI8N52cXilj3sqX/nhjChvB4HzNrwhE6ZhjTX69XCNnVDdKA5Kw5VXRN+fXuxRJZmHqPsHlnIIV+GOeJX4K4vP0OJcMQTDDMgY5cMeThK6KuhLUS80/vJNbp+FZ53UuNnR74Cl+owlrriH4Xpi7U+JB2BNrU0eJXgLGDsudmhfyyoLgO0Mc0xKPbuLsD0nj7xukDg8kgpAeR7xmzUu1HyG6WK8IpYoh/6b9Fku201KZArLCZEv9sszoNmZOENJNz58p3Eus4O6Cna/lIUs1ZJgav+4DtFyRnekQPz2T5Q2vWNH2cfj+esXjgaB2QjKez/nH537EEpsscAX7XiSOBctkHpTb6STvgTTUJwaVufFj1O7H7JAPgdwMgE8NyLPKt1FPf4lP3Y2cOMH4ZTDHYxeRZMpkUdM5NscbbAZJS3BJa8n6FR02oZAup7814Fk8eqFZ7FnG7wGyL4L+HWX3oT3BS7NzwheuJj9SLOS8a71sj1vOCBUk/No/zt5UPmaF2z74M+afgx56e9N9Inbg06f8TozIQOdej1wEhwuD648Yelp+o1/mZSP9/bu928AcOsd/m1CnhwpEF4KFwsZS6Os/cQCsunfe/U2yiAFJVEYIpvAK1Ri1fieUAIyboPH0embEsAveufTC+9qXx45zARufwlPY92ruRLXed8dhx2F6cvLp1DbdByFBqhdYVXUoNv4cqLpsT9oo55s71FvisS5gTtfcJ9SNfObx530UM/yZZNnYuEHK85lrQt2nrzeBqgka0R4/nelFf3X48+JbVU5/H+pAuWAs+GJjn+VzfxOXeCMVuyAS3Q+KY5SIXkw3hRoXnB3bASKyEasUzUp+E6S+v2ARXDNCyGVowmtMyZ4MCVJo5q8GUyHPyaC1nCqn/cf5JX6IJMVwXZLdvf6PVd/IvafxZ0JSusJ8l/I+r2eLe06m1ZJmYiuM/pYveZlaRKJcwZbpm6J7aD2bh40+9fLoR/6i/pRP+vSsGR54ka8/jM/oKEwM/HhEfCA39UodP0jKLQ7VeRi/eMkihJjOoANKE/Gma37Fy5fcIyh2BA4UtFnDTqmv6XbA9WU19Q/arVYVy2o2nuq8EU0lnjvbq+jjBdBDQ3/1J7CfZipqJaChU2kyLBr9ZN/YnvLsqIeVkR3+BLT/tIU4ZCmoEF+yio2N76JVQmGFdsB80W7ndmnlp7Z3uJywsQZphW8OwTEha+ktCbtFQAuulcLWfyUorRVry60yiZtioCREEJVSZ7apMy0L0zm1VgexomwY/1VIT576N1g4W7gwGkCz5ja/tuGj4In6yJVSr4+CvrJjtpyULlYma5K1H0ou95dbVSG9LIKoPsvsPeO9+SyFDEO5D9xw+u+9EEVUUdXkm/kVlSz2umtQldzFYzqJqsZA98IPsAaLpm0tcq4jqkZFyjZhz7WR6G/8MaibT1wiqEbRRsTwbxS94n2sSRkPgoRGQRWR29hVaNvIPBszo1zjorLE+8ImS4Myst1rb0zOB/prCwSxiZy9QOhtFOWujyqDKRHgNiZbhlHK3finK+33/F78iVeLfzXDs4IcGO0PiQzfA8GITlEO6VygtlH2evSLcKytR4+buwnB/XuJYj1Nvu9lkmMpoH5c8zmKqwP5K08frHAfgg+NN/gTTnvvG95QGRjQvWHaUJMJJxM+073LiG8JzK4yjUKDkLwl/AWyPa5BSoTC2p/kh95nwHcTZP9UH3y4qgn4HtaO0BXpR12uvz0otgGBVIWsdd25Lcs6SNmRxORiAS0QzW4xSXAueEPVk+SZw/F3iGgvNi/r38xGiCQp6pDM4VX+OgmGOuDLSJguFAmB15tRCe/PxU8dnlRhHsbm1xndwe2tOidBlQUtf9tdqW3yNPC0aQ9EgNYTCg1QydFZS27YTGteN4IHE3ujUZTdZ8RkU8D9dTSS2coyxV7vK1z9PvCcTQVpVxoda+xWe22zCv3hG2ztHayGQEWA8OmZykIbf8koqM4bV7onE4Qp7v9mIQhivmZokIKfy4m0zP58BIXaxo8XsLghkGzdoBFdMXn+4L+UczU9YTuviy6b2y7nYvXrlbGYimKTTdaHUQi1Vhl40KNmyRicnoP/Qnf4xvsRwPEh8rP3u5QWe97DURU8zOQJgp7q+o4CFrtlVf327abYaON/v89DFqVsxd+HvsM+5mOOlOJsPNoRInyqmbmttM2k6hUlbWsjU771/dChswV69uSBMRjSD7p+MK3F1xkNAKYPlUjYJ9zDWSfjfm1JXu6gL3qWBonI56ECcizMhhoUA/dUxFaIQFTkoRimovnCI67h16tZ0GA2M6RAJICRBCbihLUurR+r56E5GVSt6D4GnXx6e+VRHS2s2PfXRtTFBnkdD/5J9tVTzkUk7gJKUGMCyWsvwIuLLeYcSrQu1rXIqF78YpztXWXJXxXOaym3nFJUh+bp8WLte1IQQH51FoEOtfw7R+incbJgHDzcVw+uZXAXg6XgduwsK3rByiD8KDoAk321/zTGDvZQMMcB7BcaoIcIk4JbtsI9anNc4udTISjSc1OBS2DKiLk8UR+vcXnNFv5l4Rk23P0RfhCKCxIZe9+VUB/r22znT8pIi8dMdEDm9pHqdj6eo+dG8fXfNCYm8zYZocVvmNGJuJUH4hkzfad/eV8cJe9RIOvTaiIV/6LclKf7JZMI+9OyLFB+o/5ZKeKzFdiNzyyf6dzrt+Yp0gHvWs3CWTLJbswgKEaXyj5G9nWGmKtnr0/h4gODbXBniEPKUmu6wqV5oim7kkg3JbyGEQ/yqGSDkcO0Qx+xxkUSeDdl1n2lxnI6wKG6lZZeMJIIwUBxzNrWNrkW07zOYRsPfWexMleQE/+iT0we6r8ONj1mk3jOgrpUeYmWy/uENJHklTC3Pj2QW2NRWobZKGbX506RcTVOiIp7ZY30XCwkNUv5w8yiIloXhRnewIEqta5T6OviHCXFtybuJZGRR/2vOyndjN/4odjLut63SRHEGR4OKqCp3hq/n5I7JHZ98C/c80Ugo1LaxvN2jGu9fMxscsmFhoGPej3f4eOQ57WkmOhWEH2MUMwMMQUQw5R2BuR/+iIIIFhPrrp2d9236snuicqEUzEqKbti7ydCIoBcYJEr8rs+QzhPVeIZl8M5X4K+WSjq6G3qf4SlOovxR/yScsmebyZnCX3Jrjf+mtb35eFaS6/83SOnPj4Vf1/oZrcnOuJuv/DzmVFgrg2OpDHIqRwtXEMajQ17mUkpusZ6CssNNanaamXx+zFlxdrWom7fPKWwwSpDAZlRk6oLGCYtkJmNAqzEGiGWvH3JfTrzmT/9tWCnabqi+Z63fbfNOAu7Q2lm9EV8PgmCZ093eNcbopqXrUC7CjvXI6p4R9SEo9W+6TYkh7VZLa+64opj1X74tccfn1kG1LuFNIP2IBCiT213kDObaW8ODSru670qC90/HMgo9mtb6O63P4Kp8jXZp6VMVjn4VxmnrT64I4LBrS+Bwclq6dw0NbRiEQ64u9Y527ZjwsGK4y+Y7+K5n+sgiOEZ4emWmiHzPof++vmaA1ufT/fSzJnSnSlMrP+WfEEkVcwInQzUJek/FsJctMnoAbm4wsLvm58FAFqmVBfsOHlx8tXwW+R/+yEcTvtRPZugqbhDmbPT2iiOZzKetDo65EK/fed+4e+/r/EUNMKh1Q/a16TtAZeNffjjplXmiSrELIjT3EUfZf52g31Bwp/2kA7DX4xPvy8/t8xliVNJBuuehUnqDlxwxQOfZvLFu2aSSvHmP3rC/cEXfK0W+0jIts3YJvqt9+/8rfOetSa+sjS3c1PGZXphvJhYA8G3TLe/LbPMlbXpt5yX+TNteernShZ5y3Eow+gb+5hHvz1A9czK7p7BojVlqnMxvj2FN+mskN1PrIXf+XI93Pn0wHsrQrF9E+lR2F+Y46QRv5BJoqUDXXnOJXtWuvKeo6zuWlm2f2NwOtEM97EfqLg20CTikEbj7YQc/1fJUaS48j44dKBRfjRrEOfs7ysO95gk4qO3PeeIix70dbybDL+mcnS7fNBGYs++hLla6TlxwJ/ZtHNIU7Nt4diAB+U+j6osQ8w82fsQ8u3a4P3xxCEe6k/rYylI0m7Fr4kCe+5/JbxtsTYbJOFswt7D/BqPSOJAH0LlRJdY9qHMTphMGdilm59xIAjs6vSdQfJSxLTvpnKrbbC0b6PoCLh+6jegIMPX3pllHiPhr36jcZqVBC9cCnQWMdhTcUbIQQbs+NoK+uFUAdVrbQM0CxPO8Bs/3LK8Tt9XQcfM2DTih+uCzKsZZotZLvbZpVHppu6ZPOEZeVOqjzvF5yRp3cddhnZR/NgIjmQT60aycDZ7/5OQotN9fBEqT2gx2FXTH0RKnK/LEAGphvClAyy94/lxi82LnQ7CEygVTBzh+A7s5zvhAA+gTyPWjFhYD/C+5M04RWhajcjJZYMuxI/+y+0zNcQdUdDy1aEG5OBNLDLcyAj9+b/ORXxyUC0TJOL8IcXqYkWA13CbQY+slWpdF3vZzMm8fEQsas1si0bhJUnuy9s8FPuWQSUV2puEF8pLQFo5+6a44z/2mdASfiZs2+m9RQ6hQR6PFvq/l5LlRLr2oGpxADDR1Rp55HDHIYMAhSomzEALC8ke9/qTaksy7xthReu1mKOpiCtvU2ORf7V1ElNboIjOIDUxk/51720Ka/jIOsm6rF9qzBpjE5ONSITmhN74P3yisof7R0c3P8xtLmOZSKRLpJZ+L5IckW3+4WO0ulhkFIykiQ1Fwo//UgCHrf0CHf7yLM8lNO79AMYKnAl55cHzCzge9AAXhbdpTQdyF0gFrpU+/KjeD8AvFrNwnINXzp/fAErFt/hB/M9B0uhXpLvJAZLWDFZYXOCk2paJ/Fp+PUNTum34ICVIRYJMKaDBmdT1VqUdmxmayvH+OLH8Roo4ckrI3Ftm1rqBWBk+SZCD2hwUZeqI8771C7Jkr17dtlJkmU8cct9+LYaEtsCxqKuZwCTAozJ/s5vipm8voIaiQrj8FLsnX8a+cYjN2Bo1fSkyhcqpSK7y59VFcQlH22lnFy6vuYhGWy1VUImbDWN08F9W/1NPssUP5oYbuclL2e/noPcBuhVQ888Q2HmzQ1YLCJZbzq/za4fdQw7nkDHuTwg0vnrIe4o8RXBLMLXOFrp8u0wERz8pJe5BGhEN2eHkZPXlOMjOMfR6JbuYxEfqoHm3ZjeK/pDGI3o86/NHFoFkgdzztBw4Z8JdVooks/l647+x9ttACr0cpjlqXW3xEE3Pu/NiuGkTT/jFqUn6qY039v1qzkHZrTEL5Phb3Xhs3J+CQtFclOXGCp/cnyEVkm43pkVGkrQoZuOzdkuCeI/30zb82JQbaD8KYEx4+BVbO4bKx/C5hk44d6L8Ihtg+W5+X/O7dsB52yr9lPESy09p43k+q0cHNugKTfxZ8SPr4VAhHU003vP2fG2RfDtW+QJgkpfVECxPIfEIJ1mHRsYVDVmBZ/Kjy48LqwVOTPq/uMpYUUOaiP+NUVIYvwVDeYNBTOt+ZMw1GF4t+LKjk7b1unzDk+a7iyMj+BNpn18C0HrmOmDpYoRcBNu997egUYYjR9H3yeLR2ActpoWRRjMW68/3c0nVVyjP5SRdftq5ebRPhCNYFk1bnbnevx00cIVNmxvnN4qfRPBoVbPJ/PF76bEnuWhh1xl1rRWMJbv6lvRHRq28wepc7EbgOMjymfrolzByTRigCFQmjoxT0TdeHuf8oPX2bYxTfKklEIVhtkzAvgrO4a8nAt+MsXHqTa3dwO2d9fcRCN3BNEu8fqXls+ijhdIBufBENxXuX/csOO3nmxqiBRpQ3mjoF62yiub81fFsQY5YanU2xNG9mat84sjtAN38fTnjh7xfnNj8U/8ThuYojxnjo/Y+ROwwqhx7CCUxN7mHh7XuDAM0Omx6jQq1qiTx3ggCYjq+1pmeGMdeQnUnkgl6AHzuTxk83thC4rHu+9IGykX7Fy6D5Da0hJJ2kx/CjSGZKMAezg44NaUQfokTq9b4UU1maSNc7xGL4zANvnqikb1IxhurWDrmiVfRAL9Si4UNqA8D/oB1QQV6fMHgX+l7TTkw/MB9ZknXvo4nZ0XWTV06fZpWGFlZc21y9G+hquxqcJ1rYiepOkPQjLMWP062Yz9Ho0htDy6b39d/k3cA/ZovN98gio29rmKtnnkBY79weT7vmKM9mB2/qdBnRB8UOKQdxJAu302+41WG+hkTB3WLS+Q3QtjDGxeW+MsMW8fgMVVK00jhlStzNRLlYa93UZIoCYhVjzJrGiPA9pJDqeEkTC7onEJMc305VHdC6ZvyNwoTcloceiv5ouNpEDiVPGQYIWq794YqHPrb/4VYX9R3sKYJVea1OB3k3Ef1TnoX+zh/UQF8DUL+VvPmNxDuK6l29Z1Rtfn+NKZOHD0QbBDkeUcoVy9EiJ1pMiODNJ7WhL2TXPxTr0gbh/2key4ORDPBHVSVJjlctgqCWQJRTMZ0pvz7cKS8DX067q5ezu+9yhKH+y0cJy+Xe0BBvUE5fnh6nvyUiyHMKjT/JlaDMSmb0htRB0U4PbqwpxKWbUcCvTonQfOmzuXdhNyN56CcDoGQpgw/CysUTpmVdcL7dGoHuJZ+kyWsO1FuunPbb4DlSZUomjjG2c9+kosWiJZfu/1n74PFf94woeXwboyplnadih/xDiwMoAdtM45Ofpjb/A4B5ICOIEH+lV1SyyCBls52pljxL/sigoV+mn09jdn8FBoXzCD9j4Mm4x+b5aaHuWxp1szUPF7X54Hhyg2J70bEVWsm6cinZLlPe323FIH1oqDI4SnmPfy8UYjl98UNmwSAdgn9aUV5frCCvtHsp/CG2dqo0+q/RZhJz0DmP9cruJLKpR8D/zU6y1n+HuevFQaZ3tWXVduG4XrkIOzNhrNj2W4KtZQErAENC4FDAwLhUXG5ATj5LXkLgwr2ntNjmxmusFIPf9iDaRrSAFUT3dUcO8FGNJvgvNo6vLGVSdgP9oEculV1pf3528LfKPILla6X/qgC/NV+ecLV08CqsDzN0mUHKMaNpLgk7q5pa676th2d9V/bkuX6cPJhM4OnKAOiSP3mEF4/ATyFul9QrbUCe8eENseJb3Xde5U/lAouhrcT4G8EbX8W0Keg82krROts8/1OL7zg0qr4QhJaTAqkb4mDkDf8WlYP7CX62yvND1/+ot4rlbFJZXipftiuM6FHflO8FgfdHl/bZXE+NiNn4eoOo7q3ByusajsJB6jCx58XGAA7ZgwKNSBmIMoldHNK4WOWgyjfZdXncIslIsA9/Tly0eiX+9fx9HmRZReoPMWG/ed1Zf4HfBAV4bk7f9sNs+GcUdVsZijaje4CpbqX/NvFSZHhXwu5KPUvTHbmjb+vAXmJOwyfeuRI6A1z5m3K2DOZGD7waO+hPJnU51y4dX1Fe3e9CDVxT41XzftAMToDiywZpq9CAEzrRjw413ypABN5Z8y4Qk1OQc3GtpVOAPnE8PAznLF3oKBZ9ennIayMoG6rgdLpcp6lLF1VC39KZYcCim/u6GUz2TLptdny1OutS7mPq+yPmvMzhfSZ4GkM7/N7Q4MIZ71xhowKWXGOcCDQ5geerrcEMZG8boD7fMIYzC5TXGhPiNfHPkpCOc8dVfy6nMR9wAfbj+yzyDib0Uphx8Kv42B2bPSBnsRchPjQccY/ejBRsbM66f4IryuC9UeR56c+fTGUm6AU97Uf5SOiYI7E7xv/+CxZ3Z+JIZJwMkZk1LPvgfnlj/lJnbyYwkEqrsZHQHBJIJlFUJCEyy/7Wctbsy784Ai1flD7NwfqjYoVi/W85tGi7ok/+xD4fYaHkw0Om25EhcvCkfiRq8XSd4AGTuFgJ9MWrWgpzrcbASsH2W9WB2WaGPzvtqjlqgwpQQWaIp1mPkqZbzN9wTgfKJgj+jGzh3ByzoenGWSu8/FlEwwbZL5XkcfhCIBg5ADkM58PIbHF043ENX2ihadcrtTjv0H126vELGbQJmYdpUO/25/irYXNXDOjl8wmV+OLrLCI6phDoy5HSnzrjmXtQzdz9iQwk6tlYmL46zJJzJp/6zQB+H8jtS89lO+HvvHX+86SjcOc5YjPDx7/OtkT42qYTvwNh5vqkcrc8Td/eMlb2MMSlVjpjm4TREHqkGATnWRpmm6E7vFgYqV/jkDP9fefbpmiCVHwwdI3hilVpqVCd2cV0OlgVpR/NgIXcIAz3jnHuTp2tC0LlYWGKWEF8ydw0jEJycaRFuYo1+FLZUqU/yiGE7085uOalUz4PCUKukRYLF/gVWIJWnrFwdc1xGJsEYXc+isU5GBhIewNdt/Tr/8268YYGCImNoU0t1DU2C7+X/Lea+d1bccSfpq67APlcKmcg62sm4asnGVl6el/Ta+9C+d01Q800IW6qYWNtdenz5ZlcpIcg5OTvANbvEokG9xX6aOafXm8Djmr+BqSN0lKVuGwjPVNUt0J8OqmKYyibafzZuqqOBCaWkvfB+kF32CMZ/fRprpstFB61UFamTQ20cLebOu0Gc403HrqrIbxQiBNLkzTzg/IGHAP7d6u+qwRz+Y+k4ev8YdTSeXgGhl/xW2FRxGqjz08i1DMLOtVM3Bq0VDSFwi016VjPLHgU03Qi8TVx1VFEAAq35N3VPYxleNWCXlz2IDUzZaktBHDW/w9wIlaplNH3ptNcBdiEHC/X/fvqK8B3xNw3Z/sIFUqv3H7QxAb1EYf2E8ATBExrBhr32FL46pUOcU2/WYWCN42GCpBNmlSfDN9MOMhO5nbkzBnEOeuoCdIayw0ctdRq1ZvLpft48j9EtXy+8zPyLEL7OvQQryaxZkKTM8NA/zyuqjTRtQ++vV9FB1wVAfWduvHxl3GH7djpcIXd4XfdEyld+4L45xhBNQ8ej0o/fpVkr3GhT9CkLSPXcv3Gb1/4db7WJtNDhJJ8B4PzPede0YHlFI53Cmv5pbrGhoCIhDPXGJHkA8X+ZEyODtH6Ji6jrVnNnEfTHYKGPZXQLbx5rOeExkrZMNNf08qSPsxhSPU52MEolmd33n0LdjXofBN3kEqnqOLm3oGJN6Vn+7qZmyIqTxSF0jKB5CQ/83GRoAL+iSVKa8UnTqJCdj6qd0bcrm/7kiZyvl1JXMNPp03J59MeokMX2Nlmu53tqN1aV996G+NgUE2EATEaXl9hbrU2oHP3VgFU4mGv96E8tvxM7zycSL69eJ1Sx5zJM1549XlFCeYuIyYLo29B2qM37U+GEhbuqvixQGRwclyuZ0sIJ62cDyQAFV+xdgKe6MFP23qqZBf4XozRVTlaxrWaaFSnRRs5E7iwSNbb8Moe+DthyJKomBz5Uo0z8OCNC6+RZ309n8Nw+PPUru7pus3wV745cUDyOfInf15vAuxZEZPWSMQ0sun+Fup0VmR8OGuKrzjWk/VNfiOmZWOuGfxHs69AaSmuuHMKO+TIg45bb9+XQ+jONiwotM0b6U145IP5lHDQgOZSaXmv9XSQ/Q6IqAgenzICaugwHJ4kTnQmvBd1CYfl9TBRVjEciGkOPrt32Z8YxTzbt4HSDggfDnKU4CGiujZX+0lSB+2LYVWAjMdxOThYyvm7F0VSqzgaA5xbi+1W73+YDj/uAw7zmkL7I77QcujX2gOxh7Ko152vkwQN5GWcGYyF6xHlbJtOWH9OwKzVk4/vAsewNJVzXNZTR5IR1ruMqHwKT4GqLdvqcn8Ghy8cAtCASX1iohgmp1SJxMby1K21UbFBVFGKKHcSK+XCzgpyAyTK63Wu/0mDs2Mfc+QmvUim19mzfGrdozV/az1zLAJuDXb7NuzDE4Lc+Dlr9zHvMHqXoYeKhFVQiLobMt+Db7PDvNzIuAgmvmaIrloruqhKo2g3Tt1QEsa87v9gJ88z7G0mRSZVD6/NoS/AspJw6UPRYFsgONZ1gfEHl4B8g0frpPhrQil7zdB3kojXxWFg54WrOMHg7rHeUDPhI9GwsVeQ/trquB5YVPht1qatw/NxvFFARU/51q/sw1T9uII37dlwn2Pxual1QFL1s5jGuncLZDBJx9CaDkGBI8U9m5K2yxc8YyEUywJt7eyGd8LHwCUtjzsjE70loieW/OrgAosKG/N7+YiUb9mM1osi+f7XYao3QHNnx6TvTpVRhVUVnFxMhpHoxtZmDmtXN+KzSLYBAPIzAmKsLkCZUVyqtwX8TVDU3HYGyTPsN1CbQmfAzvEh8d4X1SHGZWEEZglbwaVKPrKCm25hIslpFCd2K+2nV4Q0jj6ogPGxsGyzTTFhDkoqt5S2dvlpMxdw9cNbVQiNi6PET6wIRWbLBHf8MgIx0GJNNxh5MIFNwGd2yxHBbPt9rFhv5TCj1bpGWtvq2ln4g4tYNvKc9IGYx4kBSA12N95G003BdvFkMyvM0Td4eSx2gIoG7nd4rV+qUvHjsIm0gQMDfgd1X3MU1e3ESQBRO093r9pyJrmY5heqBOlaNUkIpH6hK/gDzPko33SjSUhtG5MH45Nz7yJIaBKXuS6TFfqzL+P17v8sZdHdQ9Z6yVvVcuw7hi4u+dLy8oEikKB2uXO6MgMx+ldGotkP84zx/boSt+DZjO8/nuoB2+iBlizHUqY2zEp3K/BU3dKtjz2d5kFRqNj7o40bWlpAYJ4acQVKmcn77gNdxcQwCWpoiU1ukPbX/I4LEqCAu+IJfDZLZL+sFfzwesSRe0HXGzUamR+Q8+DoK4wBfIKhLhHDLwjQ+IWE0GUbG9lWLfbSgHSS/bLeT/6Xo8DkVOwg4fLkHHvHAhgj0kAc3vCFz6Rm9m61rcogbuVEnJtPmnsgxWpIlxIm5jUUJ6FChwAozr5OxkH8n4ciVNobtZgK+nMAc1zYMTG1Bd6yIR9BvZvH9Kv6W8omzRiXjransXWhdc4H0Z5orKHJ1Rop127qDFJJedO2Hvasf5vcs6Wp+anqK7dwt4Pfe5N6vV5f7kDQzfAeh/XDzLyoJxDWNL9U90GqrKgiB3MRxeLst2W+D5HhMlA4YBIX2qhkGQOXoEuowFTBA8WmknD9imP1n4gM6q8e/PI0bDmzCyxtuWOez4KMaEkOvJzu6g0WIrEPM7tamLOcD/n8kJ3XmJkyW0+HgaWvyzxMVm5KOC0SerW4te1l+ClDlx8dJS4hYfJfAge6F/MP2bnkA2VHdVEahekeHdH3zo0HxZ1W0lvxcfefDJ0JTo81DYnJJ+YrVRcwRAb90uPKWLVRpIJBbtCVunJ9wKYYS3GS/0rnAKwDH7hvzOgrIE5lrCX9GWwNJ2ewrab1gBavFh+jF9QsqOydIU29gR3Vjio5foufepwDIirGBLyyHCQWUKbm7Qb4W305yMW/rCz2SboryzpxuNjhLThc4l5fdiXy4KEZ0ySnpMRMdSl6od55FAEpYIwxkE8bHT+KcoqMgIEovtuT24LgO4LvM4P+7fCTQ/wrOvqe419oXyrd9AHgCs7XobX/TsJWg9C1Mm0Uc885ea7u4WP4D1S5L1gMYNYZJbdyA0mq+yaeqvXeVcKBtges5QJHTNzYGknOD9NRWDTbnchkGzajYI693PetxwPjRfe4cJFhCKcJbve0Ru2LS9RlG7ywr8diqLE7HrUH08EApp7rpOG2jb675qXN7dkUF4nBqWNhyZ3UHyPplMxZUj8EvtMvnRQXKDW3wwxQMqpXULn2B+JGMv1a0v793/ir5NvYn82DgzQFev1bcPBouDQ3ekYd7HL8c6dAxyRMF0U1ZaEfdsWuev3F3hD/CQNXXy/jj3/QOcLmkOfuqPl/JUP7vm0T5/yRl1LaKrf3VBMAR6jIgS12ktLioIPfxNkyOWpUdNlhT0YEcLi3ndq39aquVRS/Ox6nS5Ot45Kl3mY7Th4XHziZT+ws0rVJyZeBPznJDdbKxFeQj9bRv/JTrxS9trdTrXgvQS4ZrRSAupkMIKLfALzt/yUZoYlfPakQzbwCLezUl980AYguOKjbuV18ydGFWZWMKUPwEMyijkzxuWKb92NA21NoIcfeIiuG1a5+eRUeCNhHxxi+zzGQJF1wKA1RbBtPtDwizJJLDucAZsRJb0ZRpMvi41iVrzaFLQhpJiNZ4KjKosART5/lMXjf+sE7H2dKiOS6vn54NFkd9R3htQ04TaQfqqt8cYhY7akRkkau2nYrjBQhJMBHiwzSB3TzPi6AlpWlv+Qv13lCmk9TWfZRa9eOStg3QmqbGxnBZ6xSU2phjWPNnpqESxECVocSNW8Pot1FrdbMYKlRKU9n6AHsJjIZG6efhMhObWUH0O4H+XP3srwuc/BWGiNQFBlAGt1mRzNG0VL7bFbfLK4A9oa/X3bd1zSv3j9YFxwzjDA7+h7mhdCljPYNk3h9IPVbxLVFY5nNy7j0qSoyHIt58jOAv2RPeVhvdjg6qITWuRDGgMQBkYnwc3Xv8lzBsT7fxSWwLfsp5ZHThkFfuXqm0hzCxXTjYU3Ucbi2nxZBNygRvjWJZ3UJ/z9IYonpqpbOKHlIfMHGxCfwSxKgKNjBYC7u7PQPZoxD7gAClEeM01V8JHG597ox700v37ORMjIajdMvluFIVf5LmL3xy8u8rA6K5vplHTJM6oEVsWwMTrPzptPrgtToSXmfK18ZuOYF2KhU3LIHxDcDy//HjAfQ3guy6Vrp/xXRW8FDddg2Sese6xgm4pmTUAFO1uuyYI+BybDh1T1aJUmwkyFUYmutHjqNTJTPUTG8uwAh0uk+aAKypkexNsOIAv7jehqM47j/Pb0kGMoYlcrYNMrW4GgKC9Zs9PKWtq3bBoTsNQbEn8Nsd2c88wC6FnCzpoGGjq1cNl34/tgS+CyOxQxMZeSYnRvaaWUsr6d8IZFncL01iz99UhXUEc6SYhZ4l7LqtdtWWSy11bA6HZxCwlkpap0cj17kpx+jujDaH5+XmIswfWHdCg2AzGihZaTx2j6u4/XXB3D19Q4qV1MgNTjZNj88FmbP7F0I4oxi762bdZx76HQcvMcX4IezO7gUVlHE/MuzTQMD5L/SzKjcoAlPnp7KTmLQLXWF5KG1EB7yfieqvVyCJAYDOkaHD6LkDbpwFGgpCjtKUDaGTyvCzAa5gBjoL5hTvG5eaBNAFaQN0fGuyl/j7fCJuk/EU+iio2hqJTnfA7JnLUu8KUBZQ0MmQTThmamPzp3/uCRMrzC+TeQxrRqIlsGQtw4Sq+b/mFs2Ahz4xC+0TTpvXF9GPGFC74Pi0HAQ5ptS05zbz3Lfz570LP+LViCkp1uyHggrkzVuI8uq2efsDCUGSAaKKoC17+tk8U0nEv18yD0GGCqqxllw1cU720jXCBCe/ZRog9AZDeGb0IeQhhd/ZIEJ5OZaFYkVbbeqvVEBNr/6FU2bTmruTm+4MH82hQuTD22xGZm7oTeYyI3RbEGGHe3/UF6v7Y0a0qGcop5NnpgTepO+UMCKqW3C9kIMPeCAWyQp3vtqIeldVHRlLpBYMeXNtT7Lk9ivLDfYWjXpFaBGa9iYYiiZ0wcrY5fw7EPICYVc3f3FJhKV/Qs5IMtYrafQqz33Ob9p3UtSHisWDuHtJNsJOpQbrWa44CZuRhTp4TEXilNrOHyIH3ctcYV1ytzM1g+6E4s2PgkQbnhZcWAG+IJmmHGs9Y6+J2+hOzHMeRjXa+XW3AP8TbthJ2Czg2LbYwAjQIeXWgxGOBAzSbdWv1tdqvVn7Dz52+CpG2ZP9E3WhDZHOYismf9OOs0nRPQnA9/v5CN7IvBSfxw7YlFI6InxgWIAu/IlzssWwG915uH3MwCr+e6gZkh4FdWOxbeuQLZPe/zYzpYp3J/5QTZSE7MIuAbDoYmaHkPvnjcFbBucyPri73RYqTjtaEjCPAMasDNTa8fk1sq6Xyf6ZWRGKlNgG90ooVK44D6pQ4WwR5VZ6pxNdXheRhNN/eozcyMY4kQBF3JYkL+dPQWfU+uemLfEB41w49b7uFw+3UapmPY70XMkaYO0x/vy8aB54BiGzGqUoS/wQmK8tII+lzBaT9RN2nPqF7pOTJywLgIuSJApo0KexzdQQAcA8BHTdb++RQzgKOfHcSTdUW/rYsCxJVpv/bur9FWyyfg6LARsdteyewSw31V+tCOuhV4z/QBaqd1LRwtlKtwfze/WlMe9W+Mm+jWx29U4KvaUO0SDlRCjNcS2OYDRJDTA5bHlvgdXnfzmNF5iDTZu5IbN+45B/khozf9hUdnF88p/26+jzksKrH3r50yCH56m2YN+WdpiyihqjlVDfjrpNBz43u6jdHIoAfocK3s37Go7+z9gaUPa2jxozTkjobOSFxGJdfErgfcPBSJtjmB06v5wnHZGxt9VpURT8rt+uip8e6xyPj648P+Pwjp7+JBqwtu0Hzu6PzobXH5oO8hdGYwWlhs5h4GS7NoppEaW2NUZUwFmuoYGattJWXLKKGY10KBBNwGY/PA/xqTAU86b0BBxV+bySR+39+GN0xi8c8XjAcIHYydVJB/7ELUCujPK1ma+3ftAE3o2HiZx1wMHd4W5PkruauKYjfB3d9/3rw7QyaD9OeEIV9Ug03LDqTcFMZg7Z0mnYf+JxIXGWw8xiV5995hjywOX0yvKaIo+TcCqB2ZzWc2ahCv5BP091ydUhFK2+jo0mZO3myo08M7v670wKQEHl/SdGvGuwP8vwQnR6L7dtdjrDf7c6ICxtW2VI32mNPe527Nta+M+BXnH5ziWRFWv2+X0ozrCUKpcjDN9iW22RTpwx46z7QvnMGTwDCpNmqIDwFl3cSw7phUwH409UqbtyyDSoKqbqdqSrjakFq8fKVUmus2jxM9dK7CVI5Kw3oSBRKt24e2HpMC7pi+xCyYMYbhGMbx3qxv/aUqtluGhrTtsrWknZMiz2Z89lfbKVxgycv9Nn9Jvy4B8n8svJgjloo+J660ZFvOWll+pTH3eQ/T5QfuRVD0Lg3K0tuzxrMQgLsBLmD6PvPreVaA2KSviK2DlliqLXMliS51VlEzfbtFwf3cPqHiFTTEaH8lc1ecb2zOUZNQ1E9YMVldpXL1Em2zw5R34TDVTbUkORN3rmWkpW7o1aEctnUAx5VYgLtgTRXOdb/l3wnvP2kxsPI+RaFOr4LwMhzygTZ/BXjARdD3xfWGIeNRQ5vEb2zHZ1JxVKGwtCjapij+LNUMG80dKgUK9ARFvVLlKc03Hluyb5EkyhMxu7v01jb5zLQ9uCrVR6n8xHJMspnxASUmtoxTJvzsrZH/3HNMS8M2pU9Z09i8O2+MmUhMszbv1whDM8HTUG4G1j4Nk7ipdhbUvdZ7Lm2pqb2LfpBAPP0yfS14zMUofPfDPPTm2uFvZwIPvlF3A72tgTzOP67GhzvauYe5LQ8rJphq+p0m+eDvnSRJ/L0NOAxkQwKy1MX8dL3fE0JMjfSGIABfNXBXTZ5KIdvx22N07wB4lzje58unlAXWJbB8DgU+136m2aN066BatCpsxb0pRKvS7GMcX1RhE9NBpehxcG/z8dzf8GG8fDVqF5J4YlVqnP4VhCNZyYCYu9WRrrnJYiYU+7w0OoLB1k7BMFu836+8qHvgSWfjWnGhlend7fGaNEX8hxADux/oqOMqt8/Pg/0SY1vVqGFhnxV8+exDeU3nezE8xM439QWHYgKrc7oqW0y7BXkun9NemU2peCYOeFWBvXNa1BnzRRy//iAU5eW045pPcLvxV2pfb45wsnNZ2xTevogAUbaAuvCHwX/dRu5yP+p3FiUqQCsYxoZHedgu15GoEYn0UkAL7jidW1Ffanssxn9F+6+ywhIe4MEwbsieylFg5atwXlljquJsViu8VTj2sviEOfjZnNQFOwxx9LL4hTQ3RqBagAqKB5TbfygAOyn8NyWqpDH7N2Z43uaevvMuf8Jjc31/E6WHphSzIUXXWytZVXphcg5cOAYNSv0RMNqFiehx2McJpVanf3uZwdDVnaFXYv8aBYH7+nuoty++77uwujM6/ag0yISIWoaCMqpQjuK+leD2ZaKS897DNN27E4n4EDh2C2LVXx/eeoLesndXiivG9FXsXLKjtjagJlMG3D1czQIzFh5eKzWWSJ0RkvfiSdjpD9l031xyXTZOryW//0pgAeZCgShomf6V8D/P8T0mVgo4JqKx9vE+FESBU3WPsJahF7hfcRWSHZBuRwXeH/r3Q5NSmzyIF1eQeqhaaT+ce3cXGW3I4hYlGM8N2sFFFPcZbC5SXe4rvktZrU2N8QGN07B5sAnTA9xb9+f6gN2F/dNEettTs9z/esSWbBpBLmQGb7MPwErbseNlRtIUM20+ImFKCel+gAAd87naonu/UAf+OHeRskBJuB5Y3CVaKeVewRu9OFmrLOPUc/1YkSG+s/2Y9M6Ll88vtCsjHsAppUKAigXAgRviDXuU+o6bU8Y6MhBHM+rC5QsE08IzIUTKRHEi2h0sj5nlu0b97lDUJH1be4nrYdT4RJFR8CvL/NA4YSbJrZHFYwA8qkWctMwcbZr45TnQRd9EEIfo9Rw8HQX7HvxshKQC/NZ4vzBdw4nD7B6KYVRN82IJXHhptCMtUYwyuw5oPWfJbxWntdW8pZrhLmxcoEM9IrI7loQZ32yNRV/e23mQyrXe9lWgshFd7E1FI8vfI62/lk2pFvcBxB/jk3OpYJPEu7s2Rzs2qNTCjqlAIVhudDCKLpzvHlNYqA5Y7AKdy7fzm2Fku3G4/EaL0nkuO+3YhZeHYnw5NR5KN5fAJ/Wv1Ms2sncZrc6RdaQspcwN9gRhHlNABGu6Te5+ebjGVuU9AulM8wGTv1ZWuXS4rwe0bSHFamhl/cGRFF5vaB6Q59dDPZfqbk3cc3lTHOC3l6lJHk/g1vqOpttZHti4ue3egvvh1QBndNPGmIqTdcuKUvv+dZRXNUhIU8ONH/xRzJQEHFHSFJX1cCFfSiXLGBbuoc2GpQ9dl/NAhb2yae5bO/sInV/0bx4x/8YSPnFdwD4uMGlc/A1WfJNasncleAltgVpV9n0uskAs6kOtn58aSbju5c6+enkKyrlTFBxpF/QAp67RxWPingCJ1tUYSBnVMeD9CP3HnqfB+pT2KsptdwIgqvJQjsgDDP/JjFqrXjKf5sz9DtUKQw30kV+b0VoQfnT335yJv0Lm1g8lhiwhvt60WZlRJleSD4XSgkpf2uFj4EUp6GQd3aiVanZAnl3CqDmcs5qXDNhCZtM9mrU1Cd++oUzFcYrFAqn1bZVlIC9NCELBLhXiwjo6r3j4DZYUpPk1leBEmBjamzT7BtuurzTETKAtA3P17frkhsNhgqjEYZ69XSTJ2mtC2r72DE4WE6y3t8LV+L/mNxE8TAxF7j3flehyqinBx9SUIFPLnfySf+DGDiUFpQ4wI1E4B6rj4qf2VkoftuESYREGaV0NQM5P00AMwF5EuXgRD9LkpyF8q4WpgghW2KCgXr8ZSq9Xef/qQwjAUMPMiLniZrxv8MBbtfZcQeg+MPvWUTexvSCS2jZ2EIcs0IYbj6CyMWeilAqRRwzX3irHQBIqnKtBf4Hgo1l/m0Q7fYevMeeXC8mS5FK3YQoGp/crf36/R1csvmlclhzgYpR/FgVrDYHSZOwaLCI4+9ovv466kBtl9A1/Su+Nf1WqIX46qhlw96i/Dm7gNca6xBybyZyeEyESgfiRrJlMCqdBpC+OyJR2gy8omzUNWcAKJuCY1aLE0TZ/Bz7hUiEZHDRqgT0tAX0iKH53f06QSe8vVtD7nlDXa0CQS0cdJfb79xZoCgoJAbZ6bLfSVmR9l3xOzCiNihzzc8vb72Rs/+q9u3F078bE0QoI2oD9RTO7WppPEhNHao3cvHVeTaSHm1c33yNzdElM81A5Xu91Uu1jMS35q1av0NAzbozkFmvpzWMzdR+hXwZW21hA3dRbdzU1NZaYHymEbz+1G30OhdJZ+3zR9XxDDXRbZcfpoY1Mpuzw52x+W0QNR1tSZ5TOx5R3LbwytsYhEW3MyRyPg+lrvk4a0L5v03xpCN5NCA4tCEG1Bz1xyv0JnCqP5V9dLDsXlNFYjzOzT6HA8/KX1kqCzAWHUEyycB+M4NkCOFHY4e8DQvfAbmOxeVusXOzKJOG/ZmMn5dLqQygNBg8+4hde4EqBPrInlqE8MMd8M9WfI2Cmj8cJQCRJzms0s5DYtQeW+9HPBvMWjIAOAzi1TwppbF85LEPysvIdkYUA0AHStfzMVtszJyiIb644VLV3Ybx5lssw/g7SXUapvSBoCWomHa8XvBibyTqQjlLRFaNxnSC0/RavgQoaUPmi9mCLWy44ThmNFZWj7nGOMWpcrQHThYKp/bAcriXUZTI699x8YFUD/Xn+jIyRsWC1zJZBsTQuKe7XpUVUhgBQj0xZPwOmupCXnx9+efzKwyGm0O95LHufKPMg7MYK1y+aheZtUdcZq3WFBQI9WOn1hODHbBaS/FwVfgXXyRqgZ4rYfPOws+5DqECnMzErKrOP2y+WCJBv93MmWrhrg0bT3K+U8e2x45V4lb1+wQATBfsY8ECGWIrcLfpSUS1i4GI7Cg3syYpFebgE1fltBvwW2jn5EenDkBmOLZcMsLaMORvuc8TfFzdCXET7zHh0XMSLm23nzCfsxut7KKvhPLFkx3WZKk+0pItT6wqyf1jB1YmuZ8An7tg4lfC69pZZDm/ep2k51ERswjH0lmTJZXdCqsH4c1OhhVEGDPwgL4V2LF21X5lLcI+TAmWgMc85tV1/TtVi12qNwL4tDbxqA/56A8+G3UGKftojY6G4m/eq2sR1M+pMSd4If8lkeAfFGi5g3X9lnVKTGH1R1YlCxk3/+mel1W8vUm5Hqygb2KZ/DF394nidWJE3t2vcgbSaDMl8imd7AZa5HKZ6Ne9UNm768ZmGXxKX5sgKlNUByxP5Y6UqvTd0kOoqH4u6hCj/JXholSlSY62SVB8fIvpBo4SvA2iDDjGQYALk3CS8cZx+rtSyUZM7/FyAS53skjaVWt8ji/XFDdagv38R74KCE38ziVGN5C0Dqw+G6EUdpfXuBsUUH6eRM4FAxB4/5JFvjKAo2RUV3uaPAn+9UyE3pVou4c9ZQK+bH4RdsFoYrWTpyBWqrUAAfB8xquKF8jwFdkTOpqPyZ9g/+6uAas2SZhqxR25WqPdombfrUS07Ih6McT5w7iCtn3sPwH3WJqF1G6dvkTpgcTZZt/jEa+PRC62hdJo009F962vHqSZb6udWlBCG1ee1FPXvhPzubbJ5pcRNZomMFpbbiFRud/ub52u9Ntb2oR0P79mEvmFysnmAV2Pa90cOX15sB8ku7xiAbTX5yKLpmXcpJbS1NT6pv/k9GJGcZ8Z0UL+Gu+H3XesPXbPegh4d/G8GvQFM75ML+sXtiTVA6eNpL5R/H1f4RdAXEbJTYnPQJzZ6Dzs7Un0NwkaT3zBEoPTDHg+on9mwKdwDkYazidwwoOEt2YWX3DI9P4a+Q4P159mPMbfWITfkmgedLX1jnL5PFfMZFV7CBUQZPX0T2hgeFJMXW0dbni/wl8G4Z6t0HGMGLzygNaP6Vp1OmF0my0EmXkuUwQBshHXs5U1Q2IMBDumLvREnRax61kF4lCdvkVgqWXGfBpS7Rpc/KNrSt7Yk8xfrbL4ykqP64gbNbl26Vd+vysJG1uZDNRFR8EXPhZUk3WiOtpS75XPM8PoHXAW1KW9/CK+4idr2JixdH/3KrU4iOarvnrHpINuDLdnl50rE2ivbjL1HsRhf77zf6CKKtfz2tW0k7fnjA8wWJFkPfz8m6d5mN56BKQ1wFIsI4C7Dq5SXeuw4LfKlEe3gmssP5AbYcPXmLX4s91mEPchXsdsnyCdkeR/eY/Koi//anQonJS+adghKGHNhtgogeaiwMuZZPFn9yD81yW+PS38zmHsfVmiOXmVE2oMe9OJKrIfwKQdvA0jwMOO3Jipip+z3mpnTqvynHs1Ps3EPLQujKjF0TZ9cQ3I1V5R8vE7wl49R3buYPpskh1ZIgSyomD1oi9+xyCUpcYfxLUQb65WHeyWDTVk2ws4qs7XG2EiKqMDGBdDCa8OSHY2Kg5JTXENEDXDWi0bueNrjbx83q0pGSUPBbeDUW3xxGg6FysblgMnZ9DuGXHXQvhbeEz5y4sSgtjCyGtg9T7lI4gaBLJ7jT5/keCAsWl1h5CJfPuieoPXNGD5Bjd+EuAtNMV63IvsqG920qz37NGV9nfJAfNwKvpZBOgSXq5ABGsetmXFBgFqQCtBeXlGuMBCJ4p74EJ37a++zDdmMOxN9Edy9l3JvYcSQSakOsji5yyCfuJEWE1GHpDFO0kFysEbHpajwUSpDQdmJeABLVp5XyirAETJQEgOavb1BJJn5h/8XCEEcmYnFXjh8C3fTimro5EKsYVkXkgGzWKuo50u5CWYYmW/3R2/TsI9han+esHsHHup8eDQMPOXzlm+bmBCvr1A50d8TBJ1OTrkvYRVd/JTR2RocZfCnvZ+dgof19kqkgv9kqglr7buAyZMvQH6gbpSzR7C1unnGclHYyhZ2JWe1RB/fnV88+RBGxsp1nr1TqkI/8/7BhPh3ZHMHfRfm4lK5PuYWjmDZl4kPOXD/xwGShEpu2+9P4d1R9I0ebDl1aG3e3zbhz2e1gkWIw+jVrPVlEfpYbVhbObnNx9F4Y8MFh08c5Jw5xMB2QXLymtGFQTAfu/DQMx0i0foJRujEyw5a7hRg1epKqKnWrl8atnHfVuzPr9nxr2eu0ZXtLhkNaA4W7u1GmuBwCUFLBupGG+L8zNH9bL2bbZvzK51UB4m/6sF+57NDI32IflNk97o12KIGmDLbO8U8fCbwjQ0d29cQ0+CXEIRplTJyBi4rIk/4yWltlUs8YBlFWdxc/zA20rGU4wQ1XWZatiDPwqoglQ2v2rVrI70Y59IYREiP5u4W2kwUkrj5AgjYL2jEHGqZBhsqcMpZLHBkit0910dwpEnx12YRBK3APa/PUHTbvh62xkZbOUhnxMCxfhJX7+E3pj1fklZaNHDMXSDcUxwcXYdi+7Lxni259zw7GGeDvOYbzXG9pHEF7FQ1GCI5xZGQUG4y2Hk+ZhRqvMKSr9b3HzsMxlbo7VbdzhecmNk45EjoGLfKbMYGB/3H2vCjCB/fsAxeAykliXXk2jd+iYjwW9/yhL1hhAFQ3BeAZtKL98ck1kFmeVvvZUjQJad/rd3u2P75N4OGo8w3oYW8OdLpNllDe6ocUS1WsS5ejhNrZIlBkxiknjMBISKM177oI7Ry48ckqNaWlAUNLmdmW7VjCExc0smWBR/JjPX5BS2IxXq2JgziYRTauvZrNC9xb5Rg7U97PlnaEgSQWYC+jq0Cu8cJ2Z/SJDpgiktfOI7mLNdRHx0uvrfHenW8PvZtxUx72UeojOUYsMObqHjmk1ldVtnZzQg4dgIUCPZX2DBVQX9Ltgpq64a0avNrSyLPeDKRB9AnM9sURSrfWg/CRPuqxYeqlDoFzxRYWMDgRplxq6AksF0M530FohvzGrkPis6tOCnF34HtbYqp206Fww74EgobxI7kjpd6aTLiLZVb6y6giF3zMRxeAkNXv5xyMKbOrySqzy3jxURsTXdrQZ/kaV6f6C6FvPrWkUmy3FnyypfFaM+KaFmbr/Os61fNadZLC1rOqKcOGIid5Aqj5+qjObGD26Lpuk583Z5dkGsLur8+XyYP0ZWxAQFDHqfW4MRVnlFRw0UfBl+8tlH4YmnxykMGecMKhim3zvMkpYSyc5qAWIqGeYoSEHCoMm73sY907+vWl8xfKwUXpHtdkHpyGy+3S5PXSPJZeQy5zybONeKsALAqzmn4nRFuP424QxJ9iKeUSgP6a68QTBpTrkfcXZLDlDDxrt8fm3QhKVd+THKoBKalEhaB5vvIpJeX0w+BSb6Jo0M+a3dVnM65qGUH53+F3+iVfwP1H8CvEZSsIuBbzNc3LQVH/K7flxfq9mNdtRw6YKXvauMV9zxed2qun+vBkZ943BDynWXJEL/fdoHl2npYi6t/8Jp4oKnPpKxq7y7bfz62nVmGPEjdgBNS4sAqqpfHYxdo2xD89zGD5cODAxb3xnwIp6GvT7/cCWwh2ETe2gzbsarB6SSoPc6bq8llfudIru+TY/bb/4tOTjc1nm0fFo/bREGVYDeMyIXD0/HsfCXzMBBs/MMYS5V5v2a+CUxIWAKSkvLDvzO0ggOAUQHCIESU/9F+Prdr+wo/BgmJIXFLNU5yoWOxT8h6IO9dHkqK2g26uI/dqs6XtN7m4YnNg65tyN6DHbtaCMcGQtLcpUcKQIGwN7eWXXO6IVQ1hiCLzCC9PlCmnM6R30eI2+fkaTARdcOi27FhMJGlTw/bz/B+Cvxf8c6yWnaOLa0VQkdeaKod4x6pxb9taTh6zeeCLuQqfeVX8kXvMFXc1CDwFDdxmKcA/mJCFHiYhLavj3P4p8AqlmZzxTSxhONcr3RLDbc0bP/TfR2WzzMthZLTROg1DsVdlHZg3+FhYPBK34fvhD27Vaguzf79pYa2hgcVkjZsxd43ZeJ3xuBFOj4kCiAe6/T/MzknO8aj3LYVK9dfKfAES9h6oCw77rV0HUaeVJp+aqJL5en8WqbLX/AYWyBwPFwUump6e/76nglTf3hW/CE6JGK/hH62XUFFxQtLt2k2sb62U2VhXyrdKHtNAEoTVWWUgL56LEJVowQCE8jlV7mWGJyN8G37hfb7i8DJbg7ai3djdSoWHww1AWDd7SYCbLslmd3L3dsh8lHZ21ZJQz7OMl7Bks0Lc58cZF/4UzbBnmDCkZjPpJVaeRKLAAQkKkMrG6gG8n45EXz/yDKm/CEwXJOaoLyUFopq37TXdTdfIeOLoteCgswWF+w+iAfV3nHnscMaJ0irGCxGoCB39ECtr/CrfCYtzXPwWYprMTRX6mAU5vAXZnvDe+1IuFmX1Nboxnh0jW9V3Oi5ATK8ByMiJlOo0d2Zlq7u8PmTcFLgyyOn6UXsjlE7C5twWZX5eARqhb736RCrTVFN4qJ1C761txgaJmO9f+RcJCNgb9H6NTKrH6/a4Ru0B4VCBgFVLtCGFINodmBl5AAAJrcXPpE6m3qG6gRZeH/PeXy/IvfB3EmI4JAPAhV5YZn/mXbvk9jVwQdw6G4mWD/mFwMEGkWkdSvODj1I2R+iSAfV2CEd5wruoVBZ+nKDScLDW+nNmybHSHRPoCIHHpQ4gTp/k2vvWppC306kw2q7yIqje6+Db5DRerPZ+out0kTtT/QtH+aAIdrUNa1YPeJ/yNL1XcyCg23muzcIagocxAs9d/fvihyFM45j04BD5hXRhscsSMc0oAcBWx9o+K3F+okVWLS/1R3rtGhZ+Ds8WDWE0om/0vFdCypKcgMuLjBfSrZiZbCUv0C8YT7aTjjIO9kPS/Iym6OsPYjbpa9r/E29vmmwUZ6r+wsojwoehFEHoe5xGIZGMm3LxghvBDsM2fujAlNRfcp84M+u8rXxOrCvx6SzEOuki7Jl+nVl9zjjjg97faCqpU0UFBmNY7Ya4/gYdi0JLX4We3RSbx1j5+wUgJ11wx8f8J6sM16+3Vewe6b0YulXO3QPhvOOM8KGXES2/YVzz1GWIn+RlFrkdh17YW0EwTkO7aHCZOmvrOkasaLIYNE/pxnSZ2esqIO7LwLyFgFfQEwWRzLsP/iUk6cg5iKPTSL3/RBhfQgk5vlvscD8JB11MYyqafXrVuUVM7Hlt2ussBGiYvEJ/UOyhR1FMEjWPxVrVFQtlsu5XKD2WLvXd9t3AQOJdh57pejPRCfHlif3gIfQcutFXJMXKGeUIaUq1uCPrEn08bke7qwyqLfp8jIdt4e2+IizUPLZVC4gu8oYBTsSV/khucP3g9PepzCFhmmh8IW4d/vzXY3ieVnr2Tvea2Gp+LtUaRTmytd2OiV1oVSpSYND9/XAc7IZk2iEhLXDCMJxGO4aLor0y1xiwY5a4gfr6osD+22KUa3Uln2/vxLALSa+D+J1wiW6XTsCSQTnYM7OJj4HmaYvoUy4xwWs5pk0+Rm/b2t1XkmoWskUovO7jQOUtqA4Kn5DZTVtF031N89BqkT3Pbhj6Et7QCawgHwyG3gM+wvcnL5qiUeOV8hnFTMIIYjm8HbcuKX2D2qaY0evEK2DQXce8XwYfy8pOv22Pi3MdYZFTt25yGU2YZm8RZsWjVg41DCa3GFOtIxx3hyFJB8ynXooZBH8JG3OgLcAgkNOysWMQhX5MxUd1dGT6SwIZ5lfaIqz26TNXsewuapjKtimQ1qp03pj6o2p1di9QLPz34xrj4gdX3vPtWQz+i1VcXzy6BVSEU11+yZLOYfyDr+sVPZ8BurOdYK7uJ7MgbAZTBi+DZpkV2yKdekbhTkF6RAXfu5p8u6t4rBm2R6yhQojRFxJd/peBPolGgDoaid6dKWlTsjzCkRLoMRXSJQIfp0q1Q07SP7FbhJCMeMXHllOiK30HX351y0iTVD/auZXbUU3yUq0qnQ58UTZDSdbfYxHPgxWV07X3yZFxQXmxvE2JbFndVK6RxsPABjzKo5EVe6J7jMnZJB/E0tjNx7sCyw0OTq9JnsXUGc75w2Ob5ik7/xpsKoeUI/KKFGgJeV0KXjrnyVhLVBC1okWVY7orCNRqO5tpA9+Csrqjfe9sFuxA4PEJp40r0ID8Xo0OdSJoD7fmlJ76Y6gfKEo3GlbC3E/XpHtijNX3aBBzqYMEy/n4UOZ1KMf026/LaQ3C1rmLWcROjpCi3+NEMAxLb2nweioYcFLr1+k1bF4umIPSWZxAQapXc4JuY2IhP6QuatTwVht+DlNdHfgAehLBZ8wULCyMwqSzrLgew5J8T2dd/5x4inP+l43ao2WVDjuCDJxgvFxTOMTpsM90DUc1VwzTNZciO3AWrRoGN+S3pSzur3u1ydkEmWrXqYAOWEBuwUHZiZK43wrGsGVwsODRN+VWYzb42EcHVMUFec7cJG53WrVLh8h8dm2DYIQPprUDrwh9hJSX0oUOwVMeb+Mj/7pZzMlt4Cns0oFDha6SFORa9Lhrc2drt7U12/m1h//a04GknuKH0Xtlb/ED/X1ydYQ6sWsrmAGVa7aheurus1lOXelWF0AN4fDe1rWq0OdUL5QZ/qEio2hhDOv9AYhESHdEbHCMGFB629r93Zs91ij9s+Ig8gxZzSZhqXLOB1n+/RkMS8tleULff0p6d5B12Ur0p4NNTwOPOhuC4I8C4f67+TCzEhcTvduv7YSRrhrc5v2cPNODl4CvDSNztJDaxvwqj4voVYA33bNMN4a8QRshXbKATqaOowdU048XLyovfDTYuIcAv36iNO0fW2Ij9L73t3md4K/9+Rj06lskLuPFwyp/kGNBDDT/k99ooh4BMF0mv5VnELdS9vUn6BHnaB/NOue8COSJDMXSP/VlpYuFrHHXIx959d+trYE/qrMo35DC3l9qQix0rZjvGWXOkRbb2YpnWwG/uo32VT6TWFVje12upO3cvSOJ3PLkUnqkk/S1ScDsrqp/xLxiNjst6/3M65ac9ZtONQ2zgiFn/mdhcSrhrS99SiDN5aHYL5PC6fHR8IpAB8uL/8KF74B+7q4ch/egBJzh61cVTSdJ8q/EzlNtcU67lnSuhSkjPkOrf1xkYOvOHRaAmKQmBhyiZLue102VWyXRT2/+Zt5zVwb0QqT+5idD84ny1vT1WuOkeOGaBS4Dr/IbOf2EyKsoMRw83rZrNcTLyelLricbJp7vV7+K1Ki1GsOp+9HwKDY8GFI7yl2gvYizpfqumZthOlVsJXKZDvUp1+tp5J4F/hR9S1ceo+iCMa9sg9tIuP31NlJC8Tbv4QUPfGDsz+feBX2mfReV1nH6qjl/fgi+6//6suS5G3dUS1TcpclOnnCsb4z/ypEZZmJJHydnSOkiHwi6C2ogheLCeXTNiBrDwuOZ2XBxNRkHiYtQWMeof2+tGjMDe338XtmPwhI0LxEqJqbO2M9iPD0almhQ/Y3THZS/Xx3eut+QwPt7ObNDEjWucLU3C2lasZJg7mz3ZWHfCGH2NnoaajJKQ5o1y7I7g4IVtIbE/meAPtx4u2xNq64HEVw7ZtYtdHu/yroBad6M2Kl6Oy84+eh0o360oAJOBvMsH5hNRj/0PI3ThHbDU3tko5D6FeyhJHuKf2apfoD3OHp97Vd5UFolnDwnetNjIX1TJ67tGv5YFaEcC3DVA/is9rm4jtdrek/jvf9spzpkN+eKHovf/M0hg9hbfkKn15pQApM+6pBYspE1DwLWufrsERxZUOYi+qLcVHmZGwcAjitri8ZhvFi9S2I3rggscI+lKM8drYOZIN9VtN4ZPUY8yd+Sp2lihA0Vi37aVoHadm9y0wYIX4HNxTvqyve5xBXm6z1ZRVIB2foQzL1SOmqSC2d5KHanYxnru44+LsyS/JdMU1ck5rQYVSOeSD+Odq7dU+2aywr86IxYk9NTWsLXmUG1eRjOtsSUCZwjL/q+WNqyUsNqFOk12So+DpPLy7dhentW45jKunrq0G4SmZM6TIQ27AqObY5ktHf4dA4I9ycO8U/tfLS4OMqYT6435fP5MnKRUZ0vhGt1zq3VuyHaZ/K91aIKzwQt8Sgs609FGa+hqu2SDCT0Pl5eUGA1URaBhkFOc34zhssPM3qhppAiDlWpcYnHvP7ZVhBOpH3E20b0fhDn3X8zUA3hLQFy2F9Af0yZn+f/CUiARWAM/mEwNHi+/jX2dC/zk+HbQr221gKZ/WynkehMhjwR+hEt3W2V89x/wbGbj1OENrzec3Pf0OfNyDwn0tTMufD+k+XUOHfUK4/pXzs83V+ViH01xv+F4z99Z7rzwUEhv78fNTZWv11C/qv11R5XVZ/3xdG/lxMlj8Xyn+/+W/D7feRwMmcXN51fz/B798IVGd/3kMgf33annRb/ufanwsg7P51YamSCfyz7pPy+T9brf1zv4fAoSz47nWadExXl8NzbR2nf7qqJ5+8s8elXusR/PYzruvYPy/owC/YJG3LedyGjBu7cf59Flr8/jwv+X0Ys0x5Cr4v9FxJ/v6hqM88+/slz8/Vuk6PDP6UXIlpNiD/qB/nUNRDls//SEfgebJkBZEGXAd52ewRQz09DwBoBPI7MJ2PU5f/YxrK/wqtIiT0L1ol/jOtgs/9D1r9++L/i1ZxEv6/0mo2Hn/JNkuWCsj098M/6bf7PzSYPgLI5/8bFf/nK+PvpdSf5ZxM1T/2PE/6f6DZP/b+f3f1sJ3/RVYFSk7/Sfwo9R/FjxH/UfoE9F8hfOR/tvBh8l9kj0H/nbJH/2fLnkD/VfbIf6fssf/Zsoehf3U6GPbfKXz8f7jwcfxfhU/8dwqf/A/CT7Z1/F/LI41HxgiUT1Xe53MC3jWMGRhT+3/o5vnm678qYs6X+k4+vxcAHU1jPay/p8TZf8N5AIiez3hek//1huQvuXd5sf7/q+MBPfVQuuAH/v8j782WHUWyrOGnabPvv8g05uGSGcQMQgw3ZQgQ8yBmePofPxGRlZERlZVVFdld1X3MIs4RQuD4ntbavl37Jwzcp5/jz6JEwGVefTe7n6+K/TnhGPtOOIa/IKZfSwf5IdKhv2MaRAPmKAUNan8lBuK99OA4kMZPn+fzgpXQZyP45f3rr/zz74/rXLPafTnW9DEQ+TNu4i75+FDz6VTx12f96vDHIL4c/bdUC/RPUgua+EotCIT4Ri3oP0krCIj4ZrKzNM/czy/7cS76vO/iRvjrUTZZxvXDaX5IAlCX77nQbC/n4Fd/h+CUn3HwqruGGXz9Mvx8gY8XVjaW17MAh/u1l4Y/v7Di+Xq3+ziCQODoNMfjzIzjh2dPmniayuTLYbFsfhlUl345qeu77NORz++DO1XZPB+fBQw06Dr01znQ+g/F+HS78aL7/mcJIb9oApi839eDa677ZUw+n4VTnw9e48yz+ctB8vsaM2bNpY3r13f4nvw/Pno9KOi6+MsJn23kr1e2wIG/KiLym+ABf47cf9WlT1f8q2b9MrQ/5oKob/nY0S/fKOB3CPYfZcr/Beg5KIpoSlDZllzs9i+XAvxCbD+KrMY6G/+ix91fLpa5X/8+2O7Xpk38INNGsa+R6Pc8Pop+a9vwD3H5NP2nG/dnC/5s3l/e+fe331+5IALFvnJCP6Mw+rcc0T9r5OR3jPwTSfufNnL0M18R/8b5NPJ7p//LPoH4Qov/DB39VZhBqN/I+IJD/zHB5odqHfZvoXUU9Lta94tT/P75P0Dt4D9P7f4h1/hrRwR/jYZ+Rgj8/6iSIv+ikv5x/PttfuB/Xg/+gYD0v1wP/ga8+hP0AP031AOM+I0/oLD/o3qA/3fpAUx9Q1F+VzE+T9HfFP5/Ny39nGZ8Ndn++YLfoaofd/9yAEV+Jn/9Q3054Rcu9DNFob/6AUq5/fXDQKlf10i/cLLP4/90118RNejj54+p6h/Vnb9JvKCfIfSzIv1jwOYbJEL8Zl2awL++wic9/fyh30E0CPTbC5FfX+iTFfzOhb6c2L9eUzZ/o9X/KBf/Nln7jaL/reT4b5PZ8TYhP0/Z5Q7L+fhL3KV/KdNLUNeLn9NyzJK5H4+/TNm4lsm3qvFZX/7rX2fbv9QM/FJD8Hkp5u8k0r7k3/4lrk39Acfxd9cO/m5Jwde2DP/XbxYwviMYNP35dRmA8GFLXxnqr23ym6KCX+U9f0J/UDIERr8mAQSBfCMfAv0Z+VZC6I+QEP37TPPvefK/hnEMJ34VyK/X5JfA/tuo/E9kIyDoF6z36eo09AsK+FHZCPp7IfaHpBy/cXs/IV/bJPbblaa/4T//GZdG/z6n+wcETFNfCxj/W2jtnxAwBn+F6uCfYeQ/WL7o1+LF4T9RvP8aEvsVDP8043+O/SII/Bv7Rf+T5fuluu63S5Z/hnx/n4L98+Z7IcEfJl6aQn9jvejfTCT+J4gX+439on+ifLEfJd9PNPjPcc8E/Rvz/ZspuP8A8dK/ke5vV5V+oHS/PNYP4xNJ3w7LnH3QiS6bt36syy7/+dKP6yCO/ok84ifia5yK498uyOOfH/fXKPVLxeO/loj6Azzij87jlj0/Kn1/ntrpW/BPETxGACxynZyW19z86j0MYbFfUiH/YmH31xEERr+dTPQ7pAzFf8Rk/gGl/I8r64b/bln31Cdl3PzUZmkZ//SpQl78+PZZZpqy+S8o/tOXVe8fIWAI+/sCxv8kAX+Bm/+rBIz9XQHHaTpm0/TTs+/rn4axX8vr1OmnsvspAWMBp+AfUs/buGx+pLSJ31oz9a2wv1PP8OXYvybs75Xz/9gKtueXA3ETj5fTBAHzlwq1X958XeK+nuVjdN+pafx+SduPGeglKfD57CPKP49fDfCX0V3B8pO6QG08zV+V3j3/Y+ru/ow6Oxj/Gg7R3zqqX1KIv1Ze7EcU2n0hUr8ujv19BfqO9vwiv2GZCiDgaxhlcn2CA7fqPgDj5fjnC6d+X+rcH9DOv13TeQHorwzie5Wc3zv2z6rmf1Sl6J+gsQj0m2ru7+whgb+X0cZ/iMZ+bxPJP+bFPqbw7zvbLwfAFH73uuCNnz6JCFwWxob928v+jnJ9uvA3ivR33eGPeFr45+ut9LoV9OuwMTXxmv3YkPH92yMft78Iw7OPx/R/ahTozx/3/BxT/0eGgH1MxNHFLfg2D+gDNU0XsCsBMIL613/nWPCfP4J48/opabL4yxCeU99kc/ZHB/K/2fOhv9lE9L2lvF82rXxVOAv9ENf3f5M3cuMxzXHDXTo5ftoRvH/aFRwPw0fXnj6/KIYed9cdxh+2Rxj7eqMk8Z0tS3/eHmEC+dtR7l8LR78Dfj7M+9d2/b1A9L2Y9R1H9IMH2Xd/iNn8jw34J+DE+48RzR+R/nJp8QfyjT/i3Bw/4yn7O6P6w+D3h44VFEBkvw7G07/pMLv0V8H632GEv8ctPl85+cVZ/vXDKA3TH98Z8ddD/8II4hY48e45DZ+u9P8+tq5ACRgSlHUfcfaL6czFx9/Pfs3+v78/hd+lTOMftLD/RiUZl+7DLc+AelbLBC6H62AuPvCcw+g/aqzfffrvnPd/CRLBxNfbBPHvbBP8bvoC/iH5CwT/Znr/ydX3//qHimD/iQ2C/+NbAf+1osav1wsJ5DPy/XfcIIj//i6Ob87/0bs4vmyo/peV8jt7VP8jtrF9q3u/mM5vylDwH6uBBPqvlub/jXoxmvj58nS//OC/WW/AvnqX/LK4+OMXtH956h+2oH3Rpua4osf0M4CpfxnKIWvK79RK/8CCWORr+/vpyyP8uuDyOxHjhyxkfwlP3yFWv7CH50V2P8FNkLL+6ULIJaAZ38Px3zCOXwV+AE4+Jrqcsz+MNcCH+uGayQkk5/6BDw0jmI0iW/5IiuivH6umD26V9snSflq++Qfu+4fQ7sfPt9Dt/8WfAX3z8cl2uOzzE1i9FG36A/j0/wzE+m29zE8o/Ach1g/JOiHfluT/ssADxWNSlOtHpvAb7fhD65G/Ov/Hrxv+H9QV4mtdgeFv4Tj8Pef6Q9Zm0P+G7WrfQqLfQeX/CdDon4Q/X5zA1wD8v21n4pfb/yO56B+Rav6+bX0/3fxVRvpLAvrDmaDMp5eI+JEu5soHazobpEp5D75I1HC9QvDAF8UG9vUfX3BMCH6HK4QF1x85IzSC/XAwJjtoLqQaN1BaegpoctxO8C2zaz+OBDkgmYTeuiLhSherbyGXgn5EqseG3I1hQtdTBK5wmbHjfYfkJRvDX851wiN9ZBmJ4rtM3Tp5xTNcXwL/0USPR/MInOahHRa30WiCGmd6/bt+7xhNwyi38Qq170NbqoZC1uepKZOpYjKCinlbhvqGMFtZq+6hrULi7Dg8Uw1UrpuDZzwekpXPs6ANTDJu3MDjRSyDXidtkEZN3ZJphjyfIDuvK/aik0S9yWbJGDM20CYrh3Ghm5WTMcrKP9nhRhcbh7OdjIUSXyaI04Tp7IU8yXKUwek1+GbPhOIxsrobsocSIbvJdv5WYprX6Rpd911XltIVGdCk/p3sqY03cZOT4dYoh6zkL3FTnfta0loZNh8N5N1c9m/pNGgn3HdnMEfPXePG7S1yLJ/CULC95ftNCEG/eFFctES1kIl7c5uNT6wOGmlIvYthk+KKsHyTIxW/DQOFN3pQiRCDwa1A+jG7mV7FDOHc19Q940mBcCLtfdqG3s4iq89ls0l8H3v6SFGufd47M65abr8dcMtVXO4GlIa7UzypD8oD3+P9urdAWbjYKyNVfwy3iSBfb4JxGOHI3mzLNDW7s3W0P+R2XDrO4xUHORX89KRsuMJPw3L1nQXf4rz38tq0nqZ59V0fsOkkRG1wOornMcGa9UcWRomQUSFagBWUg1zKXHpOoOGUjZlbEOJltU0qOqTdRBl2wEx58oxX3kuy552QK+o5r5fehMf51o67XLL3NcMWajDpgE8tCNeos8h6wzIxYuVldOrQo646+yX1lcO9sRsFK2LjQ5yjeI1yg9BRTbO7bgr4TbK9u8UWVhK+NNtaZ0yoWSiMIItjUOa5kJOv9KDx8NBhfT/jo0QvWDo+7lGBF5OA2aQR2We1YAk5+3tFNApjZJonxaNHlNe9BSFQeiYUly1nD8h08KR0WbZTIF73shDXuYbNM7+JJD7txEBy78zMvpR+smFcDffdpso9OPm+0inEEm6TAHlOEeIBdIvk1jwR/h6bTLSnfWZ7xL0Xb+GbebZKcZ5N1AqjLxFBnyELhDRN5mOp8+aUlKa1SZaUrToeaSAv5nkJHpH9aVThIro+fHAp80p5eX85tVc+JthapVNmqFGl5h70O1yUj2ZsJOoQpX5TDmIs3LcOFsKa3cZu2wPyz0gXziCo0ae6vhWBt3vvdukFV4ibJlo76zUdI4S4wIMmhRoNge5PDyisPloAQUhbeC/THioRdIN0JdeUxM4+BLfM5VZ71t6S7MfDSZvuFES2u3zmzW3b5A76TNyZVQrd3i0JfDSXUOH6gcWIxGT5VxtxA1SCboiK5PWqZL8DqzXCYLDft0gE3ZFTkUmyvUhfdeurRLHYO/A3goZKDS1x/v2svaYV5Xy0y9Z844OJFGgz88us547u9LruvK3iRT8wZNmMoUmbycFI+G2SwSMPGZZkHLbdxF5ejJ4zyheDXrrQtsGW6kOV7sbzQZAlu3/qIcUfs0GZTL69hjeHmfynr62uFoti+lKos/T2DBIriI2o2iXFvFWUM/Q0MfVOlxX0mtlVddP5nnKusOFHRHmwGmaHeX68OJ4HHTD4KB1D5L4KGb9zweJubyZ8J61T5IZ7RZkalhhPfts83PavrActCovjQsuC/zBUMRau15WYPKhjD3Nx62zt2dnnOn40ATsZhUap+yx37OqwmqXlSAX7ZHEGr2xL13XtZ6nHQPuWHF4xqp8t3alWWW/kHc2oW3pgaWGtKFzxZJimBrvn9MGKT+Lu2Xwvw6Gnz0aGUIr+evUVio4ld8ScDL6wG22Af2H7G25HuYKT2RP0K9wMw81N9J7e4ekpEqyf2Uqed5x5eQWpHdIzZDaYqwzIJ+DIDtOCF/X3xvSTVX8ShsjNd7te/AEeJLGIrmcD3yhf3Xxzg7yhb1Zw794PT8ouBqLTX1rC5F6FnLE9ZHYa3eL3fLZI4cVz0Y3GbuQvjGTQfLH8yIsmf3hCujfS4u3JqR9dlVYyyJzb5hEK1ZamAb5hvvWd4VQ22O9hmN+C+mA5odGZU7H3Amq5bIb587Ka5PY08pDjG2+78WwLPfWEa4PWZy6Y6x63sLIvZybU3EwTNhO2p8Dg3EOZt1Zk+AYLHrPj1Zjt8pgN+oEKOgLxUiDqEU3EWxPMwCLzYw0fkhwaGw6RixyQ2vokc8Ta22Rrc2jRZKGWpQsM2LaS3HRullfuVCn2zVLVwjxB7K2RPjAGtxSMh0qTjKxC1CZz8XY6ZQXZhVPXvasWUlw5g9/sA5aAJhZW+8kIqApDRwOXWiEYX+wIvAZdrb3sERu7W8E404IvTaV8BchzQFZKRyol0C6HNkoXwkNnhPHVRBEoRn/50Tsnu7KHnenQp/Sm8XwBIrQcPQ5B2rDG0+oUa4ZM8Ab/mDhHZoZWItQk8uREZW8Sq/IBU8aBznK9u9RYDxH6tGUSD7BdRSUKn6CUgSEc8I8EKmY7EZZ7fc8doEAIeJrSCd/15R4j0OlQLunOK1tkmJ+q5I+6saPSPo2xmU6ouDZ1frYvN1dAG/bPui3XvWIhwgTJz3zR8Z4rUb+ly/nR5KHm2rhzgYrNPITw5siooEom5j6aLPDuetsyJyJ46duZRuoNiuGNU0WdOG+md6uflxPokhJZima858jaSAxdGuzkr2KYhplQ0rmOTZL4FOuNZH2FP/3YjGaDCdN86/gQGYmT1XhVLw4Tq1wvr1AOyzbGvMBKMLcBowOsuRzW61G5MJb22EZJYmhUMTq2CkTP4sadNiXQ8F5J9GpR2jvJX88HHV9A2U7uPJMUUOXyDBrkj/Rlvy3T9ybVOi+ngkChH0oxhjAY8TbhLPeexwYDhb7puR3PrbJhLmmei3L3jNUCTUFZtIDwfdGLUj+Gd2e7wRuMbzhviYm47iCyKeggSbt2iPKHTLATFOPlGNzeQgpjKt221vlKGCtPPlWWSPdKZ4LknplziikG31vLrYxt7F1QJNfPRMhkGU5pqvlU7mPTb3PyHjzildpPw2FP1awYPEGwx5isQ92neFI7LRM6736Gp8OrFiSPtXYLxNHmcaZZHKXeXeQZNtnx1PXCFMLQG7A0LVmeWsYtlrwqP1hCJYbhoHPkwH34fBW+7/oKass3R7IuTBpKcDPURau4A4KHVwRjbDtCXp0DQHC3lW8lBKARY1yHLW2lyQ2WHfY7M+FW44gh/CYM98nuhaWXLs6kq+Lc6Vc+WGwpMw+aASY8KSlL75z87LGaq93jUKYIAl0oVDgLnjc7uFiQtGBPxsDrhiMuitO1qh1t+cygQlzWZJAr9GYxos7uYduXyjyKrs5rLjFEb5K+SWV9xYx31fYGMirYh5VJuogEt7w84kiZdsfpFC729bF7Goi3rDqUD3J3SPrT9G8CZyfGZt6m3mYoGPI71Ikat749Ylwo7o4u2O75Kpm1mlJqDzwNfg6HUg76mSc2hDkvMeWZcp2d8qbZ3KmVfg9aTIk2f959KWT6flQ1jmFHdUw0EXVrXVZTaWC2poaQQDIhUJW0Y8ZFpuSJ35Xmcohrll+aS9+eVd9c9suFd9qKZE6/2RSfZ/J+bpomeohDN6UOJT6dMaMD57Q92r6tmwrF7nxQZvm54W5Am1xx4dmalSRotFZABjm9bEGvPao4bilEzmUrZDsnlqau059iX7a/SJZJE+Lii6Az6oKjte+Bnix3KJMdnLv7qUtb0z0xJWQGHQat5EIUbbnSi1QDQCm3Vr6HxjOPKvI9hthGR67+qk6h5UyPMMIZNmfDELf8HmtDqecqdNL+3KrbdDwV7u1mqEDrJHM++gtGG5WoioIZII8kCuLEuOWCWZYEF+V6cqqa57DsOXaht7a4d0XMHLfSYqtvic/zd+Zm2Jp3N3RRHMwMepI8yr3uBq+LJxfxdwFLWflWmaLzeCRFwOMvoWUnWGTmBOL86HaTEGPkCT3kcd2rWq867dnJEk2pE3+XBDe88FU9TKPoDELnCoNkJMgOs9KdsQmCRdl5AvDoonCXlxnZSYTqWIFgzpEEDjr2GopsdzFnzDV1wXee/Kw2zxQRwvLOjwZvFXB1E5KQRd5YSxAIA5HK/C7SiPQiJ6dpaeFul16GVF5Wck9jDCXaNa2i12fs513RzOs5aNWeHKeYJYWBWv1yxA5+BJXhwTpy60SIk3i9oXIZfTSEUnOXtnn9UsBCSMux9oiTC3WAVCZ2ud1CEphgu+0GaGKdth2ms8zFeh515FClvA00l4QVPG9PZ0F8n6HCoCtDdFchusReK0zU7oVaer14rdFegl7RxYldGMtnK+lVwesG+oLDNMWhNIxCfr6AFmCPpI6jSHlumGTcxwukOzIuK08vjZbMaSLfjTS1eu92m+qR+LjY/6S2vQCDbzmFgnvyXtuVbpx3PFuI3A7DNtxQt0e34qU8bxfWo042Olqg8YVwx3dOURjg8EU7QhfP1xTMzvtAyR/9OzojSnxDqvDGVstNF67C/boWpSZ5aJXcLJSKe1XMJoVrFs3FitWBZm/CQdzUoUFccuUhkQ2c66ZVirfPmc4OJo36N28hU/+6SEglde+GUf3Xe1zqJX6X/s3Vb+/+cbvI44crftsA9HTQvh8kDrqMiqPFvgrQqR41I6ol8p41VYCzQK8zQne6l0ceoUUVeETIcp8M7vui/OiJwyg/3vGRMrxN/vDu4g2BLH7UPHoppDNdUK4MLxpSLlYojEHfK4c+B0p4BwQAcTjKLC+/aYB5uwzvNKCq5lTTnaErhHvT4Ryi19GBBgd1DFzxAwfde0Ek0Gni4TVFTayS+uY+kR42cexNyo+uj4s+PdQdJoe33lbyaFrvhaLlNQH0rakPo9j6BH7wHvbI9GXrrZcRHG1nSqDmjY3ORT5A8NZ5XFX5J/Jq3DfsasiHwwvvprUHstkcc0HFKQ5bbW4Zs1eiDOHi7UjzNDdsPuXwBgTFwj1TDcfGj9Bkq8u7wFy0eBjKde/SxG8K5Zdx64auc4zFRxYntu8QjaRa0yba6PU5MQvQOfY6RbaO3KZN64y+pewiSfsYnKViEvhh1aX+S3YJMOapYSNCYMZ3anltPFF+Oro6XZ0HNMsUEnBYC3fN9p5VAIa7Ld7HMDuiklEpZMEgXDYwYILxHSKpt65Ee3H4nUGe2GuO9TdIXcv6AxDlW7JH60t70xrX7C5m+M2mr2GBU919uV/aJRpdckva8Zi5NxwX042YiuEEVa93wrFAVOtuK4mrC4/j17TdA1HL61xduS1QBqrTyHCT4M7yRYLShDhSqbgH7bXW2c94NOplooUNuefsar0REL+aQw1Jnvdw6mCnJu4FAO7oz1mkLeYVgfE7bgFDvkFWd6LPtxndbP9Bg+FgMz0r9zJ9K6woO1L07heL1HfTGdFHgN6nnTn1XlYEziDOLfLb7XkBLZBmJA+jivAWm578Ku2lgKpGEhr15qnWqxMzGKQ0WMaA551puQT0GuO19v56DOXL2HSKoSpNvZgyS3fCkdDk7I8zIw2rcmDQqZ3dcm42TQzvun7MzDLUpQ/BTqsGFueiklWLpnHD3bslDhGnwL1aTBWl43KnIKz2KBrUyrd0v5t06xMTZ427j631+RLnXiCqy8GW6lp1ies0oJMbbMlmQifbu7o7iUCqDxSIp3sFrPxEGfKiHMSFLapcoriMUYN74/UneZuIkIXOQ3tfyO2DYXKbb1V1q1TMRV9Rbg02s2BI+NERYr+ZD9V8F10VgmZsVdQ0J6tHlfoaLxtnThgzETJ1vAGtJ+sBQEAyQNGGtGJbc0RXgg5icimhJ6BB9jM1HdnHB3mazNmtS2+Lc1wmjUB9vQZkAlGGJzQPg2XB2KP0TWixjb4fzwI9MC2aEUGyjYm3RsLFvDTgqHuE7TkhuTlrCsPlHYCmiJb70skJwvYg7V6V3wbwk9bvGEggo6slhWEY5WrRHoRqGjqFmBfwNwbxzGiJLeRbgRlacBA2eBKVTbGeG48AJ/KTiHQo09DwTn7C+Qar5veN3A9IjglNDSokeT7hOwiLRjKIj4NVno6fMMvbxikBWB7+Npgd4hDSMlDWGpyoPavIGqpi/uQEfRTkRWHpJTTnjkbMnbiXEfZQEuAktSjpJOtO3hfnQb8rxtRQvFpYTFnYNR2s9J44b/+4Y95cPUQeB41HXRHQTPJC9ZiYzR49bb7ernEjvIf7eLmiBX+n9uwvj+NRcefZyiUya0/fknzKryg5VCC7FPTyvg0XocXHullTNy4t9imHwR396GlXbKMxoMC98pcPChClVAWpdg48apLX8NG2Gomqw7X2bK7nl5JdtFLsI3OHzoUZQZJtMRfTkkji3RKmuUmuLFjke3sAR+Tqg13JGWsIrDNo6lAmx0PrDpzYcIQPnw3j1KneCbkXQSr7RPslHG4ialcdIw4XnYclJeRfJRUaIJfHIpuV3Fx+2ohyZRBCXo6WSTmVWvtcUjmtAcA2gfyRTbQbaHdJptqrmupBdaBwukDi9oqU0vnohGmanQeiWkWvJDmJ/TwwaXpTaGRJqLhkdBgyaqSscjF4JCHWqrG51XdJxUYgD7FhuDwF/CRIVvPAJiN7Hlxyx41923p4iS6qziDLwCR2UQ8QLblkv7y4SaQn/eG93WG8Z8oAQePrTl/BP4v4c1CIWDxn5Y12HRq490p59nKBF5uBtHFZTlZWwKDAgV0XuWWFG0o4GrTTme9pmaMU3BT2d8aaGx/ddeoivQDbdegLD9dbjEgF2fPSuWIiF+/qLMgwhMKvN/zwV68Di7wiaNn8KL2o8W4xdNaCqEHpBTznwKd0+V2gBaDZNiS4LkhmIlKggljtheLmISg/JBf9r1yHRgucLpYnoQ4z5DjjWGuJ3DyWtwflr9y4PR2dV8JS4BBJl4EBvsg1AR5jM57jhZpfo/TgPJXXKdje8wewKY8pO8NjbtnJs56/Dk0iScg4y6TQM21lvV3ydjQrvpUcLAlB5lbOycTIycePPTjPpE2esnTj5VHg5YVBswgJnKrg11shQnHFkOZ+8qiM1chKyIiqDCtD3SJHlL2QtgkdqXoVVjiArWpl2rRDVorOPR/UkLhEWXCEVS9Et1X5y+RLj4WxyR3rbdSLwszJxKAJgUwfxUyQTJ/plYLxReYPTD/6obtnnR72mHPGtxrAMSLhQ5RQsbsTK1JymJoQIGhF7+9+Je/yJheMWS8sVev00qtU5cr+PbPJi6udgsTDuFVmOHZo5YmVG+4trUjc0Ht6MXxfwGO6uDgacwayTVqPvJnPwhVXDYFLr7iHKDBwwF0XgZ3fBJ0HMV26aqToTbmokHG7GTx8m+fAQIh8wbbCl56JsoGccqKnJEsje+SzZOmty3LvTuAkhebVCdnwLjdiqZqVaLedRMdWok459fs3rrwCKllLhebULC+FtbPZML7nyfzGEL0rWZBTaHOpL08p7qBUe5pm4u1SSHHnNeg5wDyNo5f5+aoGwYLzgrERaQ0PpAyjrK8E/SY+NfukTZTrqYIbG83SCWCs8voiljBrSR4kRdaGORtvE4VXwuU1aSeT2W+oEsacoTi8MI6vIpMQTI5WLjwF6g6dED7McVj7iSGEz/iBIgMR8Jp8kfInffe8VH7EPleBy0wCS0WN6D6ISy0uxt+Xnm0tBOmJUY/XVK6Nu6UaZrBwuz7zt3uRP/WHBfFuj8UEO5q0NuoOYDCWqrdJz9rvJ69kfMAI+sspWr5NaT4MZoWhuNZyTJOtQQqQ62BkIyf4HhDZxUJvGh/AgygHhlYn7zC+xqNdeNU/QrFTXUu7KLdwQTXxbGKuraMl2mB5F5pg9lPYWYtEAHr5wAK2eOcEvBHA8c1vo/UK/VbqTgpzfVylscS4fCUP6fYAfmRxzoA1bvuq35lOHFq4pjRdY4m1V+vStR3XfV5igAYJ8dPQk3QQLcnbi8Eth2jgYGtLpAgqz+iw2UDvj7sxGr58cV3VQZyU0HI9RE96nK33hf2lPVjK9oLiRNJZnUCAtK3l46+o9YW9I0InfaVPWhCs1Jn3tzLlfLXrSX3uUi1sG2nQ3CGN+UeRGMeHTLKjNlTr0XNmq/O5L2hhnLnukNxs9OetIbkrxLS96m1YZFYFszmDfoMQi0y50zb9e52etV1FWJwwMseguclkh1KIU43TClgqYyLmxDJK9ThqYm/jUhqD4ighLRzLq7gF93iXa9ANWkn6kdkjs7YdmeEh/Na4VE+wtMAfarZ5jrc9ONo71ZM/jH6AesMmoQVbhyXCPUHInDD/lPvZtmEN3JhfTlhzKkNaGCvUcrMSe0DhEleGX04Om6OCFXfxzVB8fi+xo0zYu5EKaEHlVnFqIRtQt149p17zZMLMMaLbbd4JriE0qG0UAJEBlloYYHVRfSESiKkOWGFptuXdA/lGJSwMeLfzmMyHOnLnJTi9UKOa9VQG1hBWBXtLPGvVJKlXFBbyj/ertUOT7zJ2KwBB9jzR2zGxUrbS6w9UlWNy2MQ5zisqCqvtVvMHVUBWpfhngK/NIDGUhBiAsvAXME+AXrD26QRGIRmfcJpqlxSxuLdU7IT7HfSZTlHY89+tTqPtYGVtGAXNA6fEE+799NVMx/mOj9shvtEB6LlWenTEPdVeepc9odRE55PnCZyMdjosm+oq0VLvlxGZz9fwwPWsPO8ecksF0UswR35TUUc3yYDJPW/lrehguoyBSdvN57R41YO8v/VXjTnLJHws2xBWXE/xZQazRmKZvWQrziNKzI8beLgr6pqCaL3cCjkO7aH7j5AaAudGk6W4aTpQCMTZU81q/J5l611ANPUmXrSMva+dyU5Z1paStR8VxULDqyuHdOhsoX7dYbuGI2MZE4dM7UqAne5iZNqKu/Q5w/A9XG4Pn0CxE/GYu7dRyQlVe5Qk2KtFoPHYmRfJWM1x1/YNa+Png7V2sFp8PN83s4s6wprwcwexZ1XRDZ+OrigZZ2UsOeUyjUypBS5sddduyhVzNz+oAvoEHAA73O5mqp1sHMhCHoWkdEh2N/yj9gA5nKoCQP8LoIj+SIhY3t4oi8dNCSCNA2NeRmPcC2FwEMLtvHzp/FDrjTnikhqXukPVmSPOxzRGO+4G8jBxYs2jbi7pdVHHlq4wIJrxa9grjeiglgc2y0kObKn1yFG53QjnGV04sIzEltP4xGGzoNBZ8603RoRv3YI6L3SB62Sbx2eLx0aW1e27bEFOwEFfUcQW6Iurb8rk28R27I/DmiXq4ac+GnXzBwZ8xmWzU9ppeHgWlaNt3dPCp583Mt57y2i8l5gPeOFicXZzpCPk7HeYB4ARixRJNw/p5CxLP451NHkZ9Oiu1sQK1MuggpauoiX85ECAO59fl3oHzTPblxCyQLJvK9a1gmYa+E1Tv7d451M0DTa8suZxviiLxVzJv8AKtoy+mG3U62jEKxSdFrBHu2QnCMB07wAA8n54ebneZf7swyGWvaU4jbD9uDfL4z5HP90HnPdjx905dSwgw3XFh3esi9FkBFZ4ReMioR9DJarcH7Jv31hXbYKHsgS5Xd5o8wHM/YAid3sOu7ZdAd/Zoa5fS+uWbHWmem5/8TV2iJPA9fDbh/KIUKOWVfvUn/dwksPuJkID78SRFRmq1y6TFj+4Fju2gh3L2FT9SgAuCmQzun0dtBnaulsw2/vbuswsvX0sJtrOXFsiXsfb4d6IKzA0dvMUrdK611s0OL6P8XPqj28VTh+Y8jRhJGojJ4gaHcrdXu4bFb7Zq5AUWC8FSQEaWzfKsjuUmBrBHBcwSOi5wpaLQO1ZdtD1+4bQVH7zrTIUKqzpUQKpAs9ASO5ZHkVtEaVhm8C1ZI93HpHyFrncUMJ0cLYrnCUqgb9tunwIjwtM4rLDLdY0Y4uAQpCoezBv8apzBT118CEsDuRK84lLMVyPl+3sHV/Pb6sP6nZDTZ8yvYsUgqoTwyDAVMmO6K4FUc305q5szqiFNO5hQGpqg6RKvolSeuKsXENCc1h4w9GIqcZrA0oI2UgboLt26dvxzF6InsbQlIElQLFVojh47KxVzFW4fix2ATr+SY0VAs/8xJxHkgSReAnBfJmu9eqlWd1XjBymFfIvRTZjA5AODnogTGlTulRMOruuZ2sU7/TxALVP8H6b9CWfTgFaFbWtvCBDJ2t6AoLPhjBxTzCss3e5NIWCDyAsyolMlxS/jPcax2LjMaHiA3zVnphP1kVKtMmJhuodtfo40KLDYyB0PvQiMlUih5pGq0dqmwzPOelsXfRiK+SwVUMjbqTEDyUTQgLVO+4urL0rpOgw5wlQkM2j6O1yXQ6qRnrCfrhNnTsgSZOmedxaZG3sg46Eimvc4iP37O36Tj1uddzuT6/YcIY/vdr0zgWpKelFx2jkl4KrKw9h8YsC5x8F1bo77SwKOy652k88dwTA/c6R4Vte04Bd+MYevFID6jXZv/Sz4PLHhbQqWllqVT6XVFtc8WVyqjsQfNRvsjYm/T05zf0R1mVkKnk4Gwn6DoO2d+IbZlJQA7PP1cZXOu69HPECvwLVpnrzKao/Dtpg7Obhe2DNwaVfuX94NxZqm2K5pe8A/yhfMLFOaB2xvsnU2Lmw7KlUVvLnAylXIa8u+t3d0Z2ip65brKeEINcMmtWCkRBwlRxQK9qSZF14kom+XVFiJG30finOhzE5COwX+tOgcS4jWoNG8MxJoLcHcNEUVjRMZdQn95pzz7sNPCqtAgXOF8DBrIFlsSIFDmVKsQSZIjRFSVeDm1ElT1XNOcC/QT6zCpJPD60J2A5CE55CWUKwr0xYR3IheVcAxRAYFn5c3PYyuhuOXvDOiuZfS6hnIrT0MAqJGiL2I4jJsEGOnfSSLUEPMJJ5V7ytHy5dyQrB3sv5fugv6pl3vDlCiGauW8eGGkbG0bTxWlAZOvmIyrm5y3lyKSnw4gyxZl2O9Rd3xvjxlle8m5ysplt3cR0zrbltbzCnPISAcgipvE30UmgLxMSr34rDrX6abuanDqNMF3zP7myGTbwXwNiF5SKDcyTbj15z84psBs9j2epfsB5Mne2hF2KG1a4J0rdSM0KWFXyC1NGHAE+LEmWDTDf8UmoABT/5CPBWE4OM2FLemub1bq/ZCIMCY4CwaBR8NtfdLcmQuT2rBE0+QqcOajEPvaZI8kSZxwibC5AOfSC+ccb71NUPfqeoWjWzbeYCD3IpJ19GCX5tlPda+wWPlo8LMdE7jZ5OLHYgOfkE/4kAsACtWqHbiG3PbEVr0d+XUb9thAccveA9ToUKLqXTX0CJlvcVyT+5vnXYxo8akz7Nu7rO1UCUy0Xk2HtfOu/MRj2YJnOje4CKoZsFMZQpMFlCoaBs6oHcrM2x9MLaW7W/u4vhMcFsZNwchEYQu8ujQFAmdlGGBC5WzYrqot/ScNcAzBAvKPkSR3V29o2NxCpEjEoCcAwdwKAt441AOBqs58eaQojQhQQy4U+OUzJlgm2kx6vik5H0DMMxjOs57MM6+2KnSjpYMKDuk0/UHyVremNZdUghySslSZxfn5I+0zgu0ygd3Eu2uL9er8L8NCmZQsprz5u5Vb3TBQFARysukDwtWDhKyBoiz5b/yAvyrzWxq52cMeuZshS3bSqyPgn91a7VNVgxeAnu9ggmhrJuSzWnzjW77pEDCiC+aM0RFg+EPDeUV3N7CMdgGEX2Ubib1+qpObE7HB/LgZE0iONRYYW7qKInP7YELOm/NR2qCAptAvBFoqLWUkdXy551rnYfASTX7jNgLR6eWnD4yhgXtdg5vUkCljSPQYZ5+JT8Oj4Z4NsROnNxMGotRmJZe4fbMBcUuo4E8CFnhicA+uQVq0/P1ynBxcKEJknLF6hakowoiO3DIyFbyXN4D6FghsSAuryi9mKoNQoe9+DOyyC4E+059wlEK7Les5BuZXlWgmKELbFCNtyXRRfIV+iaOSSDegORlNbXgk7mDBLQ14wzL2z4ZI0E0H521hyz7fYcnvnt7ixxBWo9xRvav3q+TBWuJlB8cLwTj/WGZhb1xdFDyMYbnu/zkqYer1RhxJZLLB41fVjuLbCYcHLXlVGfvnc0G/zwjIeWVmbAgCWZdrFC4vmgQVh5Z8los4+62imSB+65AoZKgv/Ym/Fs9aXqNAcu47edVPMFgwLOS18EfQeLXaWaGmIURAoB27GhNrSID3WrlcBl5xmptEvXhFMgH01kr5dqe3r6sQjMwsxKz936KiEIer7fGQkAZDOIVJlbMFha87itn0q0/SDZu4M1brMl8U455cUzSCvgUNwlTr5TXykONRf1cl1S9cxX1GBeMmgIbUE6Tzr3EcZrUruRVS81ZgxWPc4mWInkjWrSuQUe3MV63GsUqtDPSefXsaE6/JaDOi3eE4OOMChRD6inx+uS1YddXEvmfPaJcqPURfdPelRf+55phwI9yGnPUmKrg7zPUE/EL+4X4ubHGkwqII+sqep5ZYcAZNdTfzswKaHaBjYtlcLNnpFd4lIpSpvIam2oXLqeLxu9Adw3ureZgeoEcOPHuY9TTy3XldqePMdNPPFbZ/lL0jqv6ArB4kSC6AvKvJ7xJ5cwWjph7FcUhIidU8CI3upw3xtTjbpxnApWa7zUb/U+iWI24GeldrTFwpL5cnY3kN6YbXSLrriVo3tdd88Usvyoxl6+YXNtQQiDUb5R0U+4aL0Dh/duePwaIx4M6tMs15cg6mhIw+LTWVCAIedLmpUqjvvb1/ZXpkUFFnQRtRBQg4ZxVDLIUpDxkRPpvfBv0USANKGbv4q5fJbk/Vmt7oPJZAjPemuCrklmyyM9N0h7xpS+P19uZQ0K1fq4osw62b086mNx9twHDlGaVfFPfppXle7q3YZUSkMw9M7OR/tk9BUqBMCssbExsf1lQ6IcWKJQPJu5F8pHTONHnl2XyYVIheHIZ7DywPzn3rF3sovSuxikFpnfdv+N7j6lLSwGyaVgKXBwCegCB5r1KObH+6hDYOTdeLstltvWKn6cwVMOpGdLm5EfcwjSXBAy9cLUIN4rdKJ1o+ZXdMV1aEGvSBAR4i7rgVOQklc8ruhvBBV+K9fwYwFTZWbdHfsQdVHTk9c3eQW1rZoiHPIp6WlcmBwmcQ49Lr/LFrgf7yRn6FyQAW/FrftOFX02UHN6MAUdltahX2zGP71CHykd7pzZ5ICYaaozJuN8AiBKgwMu6lbafDv2nbyvLEscSXnfUC4IVXBh1ny+C4ydFRM4y/J1sujxURP9BmMutG4P99LML4whhSP92vUuMJ/SibDIWAqvV2iAjPZu7ZWPA0dl38RZMUqKg2xLa5+Y4glWC/JAYprKaY6CmxQqCN0aXhJq1uAeeYMfPvRaSTlR6ZdzhuEGHB3lbe7rdRALj7o05KQERgHrcRaT5ylndbtqFMtPpiTaqNutihQbzju2UOdEZD/uiwXFNWhAPhaWM8RlQKivbMUv1AtMZp0/jT5y45/jaL7Yd1fxxJYJJq8bUl0EPZ2TRSYg0xiTSm6j6bbp00iQfFrsYZFL8g2zmAJgBSMSDKct7LCCwu35tBK93p0HL6z+GG3lgLdcpPT2oAmuCcgCzfnEbNwnnw+o0DLkxRjC3WWxUqgpZ6hE5d3c72ooRik8bIo9eJ3rRkhJ3H0HrzhXC9nejLvQsLOR1wtkysx5u9sL/1ZSR6/dGCd5Q5rDp0QUT37dsVI3N45Kj+QJw7JPo8+FX8nLpZ+sFUucrAnQAQBzjS1dy4gWWxktyQFJPmsMv6vJ9cBPC0piWuRr9n0YFsY7iBfur/xOEgOgnufUYIliAmabvJRiTYu0JUpdgusCTfNxPIyXSTGFV+3xAlJu8Qskb4fSezzs9aHZ4bHhKslxQhcJt/YZJMRbQ0l56D+5Sbt11wANAY2ZwdZccYugXudvl0tWzVvIX7M8kx870Cb/VcrmO+VdF0dtzLbI2w1R+SC4VOsJQiOt03ahiCVVeosIXzYeTlgfHcEWUy3r9noQwRl25pkxPwPsNbHIAElmPc0Vl+wjf0gPYq6E9yVpJTqQOuumQ1tuR3KXcbh18XM1tZgt2oU7J/xNXrRyQbmkBHPZO5PBo5l+s2zyPTtv1VJuBRXmA0vvIgEeFKxfZ2HFJAFZXjK8v8ESyPxALH7ix/AZw9WJFLnI70INtrdtouUdrqc+48jQArOg84Uk9CS98y9AaLQOSINm7Y/giuYYEsqXmkszXGkgD3qi4aNA13TGhU5NFagUF/5JcsBMBfY18nuCbEjTcKgVureKXuiTvpg9Ir9lnxIf9LBimUVI09OxLsL3ygHR48NAEs+H0dHqrd9PmQxcfbWoB7dSjiZfIUw9+f5ySNE+S6NtCBXkvA0YoDtGNXcusUrXc5+bxTi8nvHTy/apyWb7GuxyEy9PUcikgAbaa6f8zRge2vu5Bb5/Y9clgJpgWDK0jsgeeuqV/sFqe/ccg/ENkCG61tVMZBLbCWwN++P2HLfLIdRgCarIXkraRfnrJYEozS0oxIKMGo6B6JZF1uvo5VAFdRvsqWqKDwU4vwFDfn7satJLqquCBdReML5H8Bx0841bGXSWMoGkPCNM3WgMEV9NVcOid8OpJ3cKnsgr8ZxAVryd74I8giBwBb/kdoLN1x1lwv7ZxULcpl3+mGHIpCGPT8fEPCzugH2outdBYYPciliLM6xFlSj12JI+S6o90K1/Zs28yOGTtgS7dGfdg7D3e55mX4nSdwVNmuGjVJhelm17gNez0EqBSofMAsAiHD/46pPsX3bWpYWHxkeIIO9a50GuGIVH5lmN7CNGOHjOR7CqkwPLxMDmApHT9FA5X33xVCVj/3jXWlIUq60Cj9GKpV/Aqv0FHp4bnogr9fADa+pxCK3ZIDKJbMc6gyQ00orZTowF2rkrds8Qry5NybXDfMTlEep9qxG/Orikd1qnZ/sBY3Vz2h4AyQAI3eXeCcR0+sXEpI0wN8Nr4IabGQxuvQ4UmczkkTL4fLdJ+VFpB3RhY5en6GK9TgcMEIeRkA4GQKrFjQVkKKg3pZ/A1sy1R8Hkd4idP6z1XkerycfJ6SEgz3MnDsjLBWZ4ov3UTxOER0+RDpHi8loRAqLQwwZaHeBl3r6wPOgGmRL9DqcLI59ZIlCzFHi+kGBriRiVN5oEN6nfVBtOuMd+xxdrzfto1yTGjuocUCiR41wMx5IdCmOwIGtRoXDv5eVQQ3zZz1N3krNTmutFXRaMpKZ9paR5W+WqoCZiPgqag58ExE7xnUbU3ahNY3/dlAtY5RWjBNvBm32AzbxfpHbzuMKhDCxXFFEh8wBrKisSOFhZBhTSwFzA7pZZCI6bXEJZvpRv6IVN4KsS2D335ObU9kdUMfhz2EaQIAVuHaaL94qt8F49qUFJb5bAVWvojy4QaeGfzj6RCDA6zLASJ7+ifbZgOmregxOQky02Y1+qphCUsUXjIr7QdfsUQuQzBwfFCiQBevGAze1F4i9R5TR5DsecSHR9OXWyDpH5zP1gLO9zYtMOS3fDy/y8qEkeJkmhED+W7yKojD6utADNX/m7uiAaj39sJLubKuaZsKu//Rcr8OLoMyBEeqDwMQmj4aVEXQ3WUZJbMOR6j8lmVd+74j0Zj1HJn+ka9b5UfAI1Hhtz/TmjmI/Pqhsu3Up4NxLRQnN4P71jTuL6wpvdk0vNLVDew2ni3f1FQVRIluax8hDFUDH9rvCH5wfeMRKy6KtmZg40BJVqKzwbWe4fXmgWS4k0NkRYJnbbMc+ufN0sBFL2r8h8jTX26g0bp3PjgczZ92WEvA2qLWptGIrE0W0TAvKW8pEfSnqmL42vGjvBakGmUnV6xHqQDJ57dAIUoIcSRUXv8/HFoXfSMqhTXiyJqtPedCCoU2JPO6aDFKgM45gYe1uwDFJlXdPD60eCq3C7i9URANlyIKfOWSte2HKipLofYQef7ClaMNtRMduGLaf8npTtI7IxTLq90FCsUMyJi01eZGLb8bwTqO0RnT5GwCrWr8FRFLw6sSAoQ1J1e6CeedL83GUrxQO4WbX6HNJOJcwvPCctmYSsjQB+L9lN0YIE54U9ypRd/Q9f4Ckpzyp4Pj4JVcm0/cnRT18+uFS+zHo52vOlY83jQXRqLL3qm5D5XKkVnHxsyutBJEUJ9KcPiYLR527CyVtNq0InLn3gmmwmqYn0xLZ2gh0Pk/aljPdUk9LJEb0dIneiXNDUdrj0iUQHgzq6POGlXyf6SQjiRrytdQq4+tx7Cb3dzKKRQaXFQJmZQolJhimnOGmP3HElvjmw7cxEkP9JseMo8CaIn7dq9d853j5REwIld7NAze8L6fFGTCTcBemuWPgApdcL4YtkoTwRr7/56ejrgS5JvMajRljeWUGQvN7A+41YH5GUDefDsvCH7XfLUCjh1EoCTZnPooTL7iTspyucIuG5bwHamff94Es/Fp6nf9mxCxdCTW/zUzJNDOQutjuTlbPDWfvD0aeLNtyJi1G9YPxjVrNXdrkXgJO4mLgAG9PRJPMkVWVfgPAfeBUjUpNs916Solh5ocmDXRRjEVV+GBdW2q/HM40LOWBmyBy2zqvK8lrRHizLyjuSv7DQelQo2yV7l91lp0miE5DY0eUt6jb7/Flok1QW9mjw6f6Qnna3kZtWWQlL8h9rrSfCXdxZsym0FJQcdwZ+hw/lwt+FKrUsoFJMt+LWU0TUl2IXY+rJddYiM302NIO/D3bYmTt0qV+ml+fFIc7XBT9R4F5GUia0E3gZKoNnxY3lOOTDdBthhKdTkmRKGqdZXrqjBIeDD9CygZEk9KaODKwggY0EILAHj0I7TjYFHtL7SE+x/nR0wxLlBJ1ZNK/Ob8Gtgrsml/eRT01QvUUGN5wk7WEtM+RcKDot9OxeyHKblCS6gEyUe9jN3t6TFf/IONps0hCLRhd8dN+73De20cToU4b0zRGxpyIoay63co/rKXBE2onD8/9P03UsSIosya/ZOyT6iNZac0Nrrfn6hep5l+manppMiAh3M3MVWx1XjSBQngoyABP1cLnm8xd2ZQ1AgM6+WLdkMRHf24rOZ3zH6ICVh5Hgk3RdWLMRtgv//LAYf2/6Gi2ovErbM9tmRS3AEG8UZbMG0q/08sLGuhwI14ZKIhqQQO06siy2HA7miy42LWzk4q+CUnTAKZ3fT8fKPvEdEIxyjSU6oFS3HbwFbMfYwxBMlRI828aQs1+ERFigl7hDcV/DN1DBGNf6tReoWG8GwwXhX/wJu2Cb4EDwfBL+/IEDhbkTrBa4wEosCMMdaREec5Z6o/8eOqUOqfxSNH1TAKLlkGQedFRSZZ/GqnvlfAlglVgm7o/bbmPtaU/aZyf3X3tED7WfN91ur88og3AoERQa93uIv0uRwhmy2QqsfxKSLvxYGZLPSAA8GSB11v/g+ERB5vVAKezP49VUHYjXqIXW2aFu+4vpNeHJuOoN7EpgMADAQ5nJsMoHAV7SctLTfoxXxKmHmJO8FBXxuUbEgx2gJw4SHoWpKaXyMeDLpualdIfHoDDgmCHMrId746M4ZGoOkFtY/iUGIqyjgkmquJVncBbOTXpSBcuizq4Z57ZmfvYGni8hLYvAKzBRxdJGnnTKYVK5IgUQdYb5sZZPOjhYvJhx7ETYOqzirC90+hKL7QJ2e+i+KkWb+URqY3zRZcjYNRl+xfE2VscKPyRsSs2lMu0toNICa8L4LegDZiCE/+ahwo4P6oj5jyjtxXd24HIUfNl1NFo5cHOEVHdobABIPolNhBQuiDn7ZVT+zQDgpONeYqb7+BmtbMbpdO9CQJeVC8N/v4RSKAqdvwthElYfQ+eAt5IU10Vs0+sQg+8uNQ6Xon2fVb3EddKhTSjow81ijgNPTp2r7mYdx5GLb1s8AYDT/5ZlJMUafbnTZ5jhozPvufqrGYS46HsnBPNd2cEPVltz6/C6SA5RAPIuP93MuVIam4oY5n9B+dv2Fdc1xW0ouMdVfUC+C5is363/fayqIT6TJaI/9zSlM+c6mMGNzSvcjq8AHmqge/3WzuKGTxgaH7WYfvL9V62B6Eiqbc2dPbLhS7ThrJuhz59NKPD3gY6oyQXp98WCjscLDxMADv6MKvenuFMLifBoWpA2TBtG+vnUjzVhZTuOK1nIC6GUab8xa2oNJoKJPmdH/oJCp/mWaEOYWvmhHp6dP9VteVUG3pXCqLPhW1B9DFiRvozLRVdrb/X8SsFYbXy0tGVBuR1y+3ydS2BbPpI76z5GHzBElVYNCP7imnIrwVIeX/Rf79cJMUPKgVjZanwx5rQvmGABvdyWWp1DOF6XLu45gPKtTJmcsSGZi7jBvWCbRkqWm2QayKO8IjQvfKX/Dq2wiQTOsw3S5cSIxPdmk4kcji76a859w/kH93Oy+GKaE/kLgviM1QRVRQHvKgBw40Al/wrbe+hRyh+8JV2qYQIQCDE3iazGFF+V3/DrpLaH8yv7nvcBQhOB1/FEUKSZbIF8vzQhRI0EXaX1/VfPZ54l3wKr96kyj6Q3XyfR19A2hG0lltG4V/xeCG6ORAVf5Gj7DeymjpaWGkv+1dDTSbJb42Kw2fWMjiPy1X2K4+TzyljNE9vWCY2dQMJ/EVJv7Fd6A6Jo5WnJfLL6bsS9EyMRqJr2sjj/71BSnE8K7GgSaBhdP1LkO1cj8fqT3G4GwE201xPdyeg8bjOkGCn34JOhNmTamsBjGZEl+NQr5bobHxWlvARYKQf6TlaIFo0nF59nYOF6ga0Nt4MOGI2La/ESFFq1LMVMYX9eQIF9uWM1jkS/SLboQrUL0s2YgWrjRWdGzj/5o5Y9idDFu3d5mFbD4A7MecDSe1fHalha+MD1lCgfvuvwoYrtAXxKvYipOdjW5cbxBCC5c1HShldr5KIFyv11gSiaZ0hHafskbjYohXE5g+F3/CeAvX3rEYr3sCGdGcnreheDz3iwPo/UCcj8BbEo7iKKOYy6lBJZAog9pfOGZjnQA0SQD024uWj2Rse8hAgGutWGVZGhZXOnJWNoywLzF71oe4OA0P0y2khmL8CNJmwDHC/RZst8VtWSdusr5bmLuc0qknjINfKYbYN4A1zWeqwxirb6sziA8WpDHme61MwEsiy9nrPP3Dpo8sLpC635kusFgkEtCyq9Fi+1hgjQOh0eNJLtQB4BKQLY7bDtgos0xyvrVBqXDPkwHkvazz3WvB9KKcTzW3Y662R6X8vZmdlo1DryqSSpHE65Jt2vWCf+Are0tjKl2an41yN5y9xkF8Cemr97AYqmB2XjeXk4uylu6P/iQ5dzR/bbjdp2zFblyI7rg55jSiTKoG1b/S+9qhP+ZgOnZ3bKSyJXtIpffyK7keNIOVSda3ur3ecWn3ZBUYaSQYunc0K1nTBRY7e7k9xcnBfD65gRc/DBuoaMKzXggtxeeZl49vhz017JuHdU9DoUR+L8yQTZkaecM0vNFqAhUW0/KAIB9W6uCO0qBXkA8J9yCYqcOgAnsjrwPTu1yHJDZA5MUeWE+UXc9Bt2XyRHFhv1rTtbddNunetWlNMciwbIQ0q7qt/KaP0PL22lmmaXXrCVvZX8OSDXt8kY+un9CPJY1LxHlzsposGIl+rRCWV/rp4f2ZcHvz8VB2kGYYKVsHz9CPgIrsguYz7JYRJk1JYopY/ve4WyorFWy0PTjfYpJx3APJDfka+ZSHnDztDLOxlqbsvuusL3+6/7VaKirgWODLhtPuQnEf0FE9W/ugFGNR0NHr7opdzCqojfXim0nAATUESIFOKKJXZu9BRuwprhi/kScz1yKL/mRGYc2lGNtOEVPhThbfRovRqKAzznp9w0+7XasBW6myjvB2oJhFwPELpuXAQ5zZTVV0X7RFMroYAiS19ExQs53vbDQN0Uzm5bObBtLe1H0RFF1dU5bxbSQP26+PgJ738zVrfPop0zw/0kHLFz9HGFk2hIdA1nsIvj7CPaFNGJCfEN2+WkrPx1S3798oeMsaWsGE9JNzvwEAYpTJtqLnMfaIXMsOIIKTGtd3DcCY3Wx9vSrzDGrIQGTBMEAcHBO2rJJPp1RdF0t18lNV83pVaNJ7l/xuT5c0KvaNAgqZvLoQtIIF/K8x95otynMu7fOWqhre0axxIVN+4JUY2BmeRSiVrjix+FNZbO+/yZN+1qeXlIoDzwckd7LGGyrasQmyDqiVfXmTjfi7rdzJFRSgcvMsgFIMvpkGjlzzpWv25u2FY49cIQSWrTnnPDhTHDE/Z8lEuiz88M9w2gTRI71r6HaKdVjfSbqRZ9nW6P5HTJOwpz8xUXT8VV2lMjfA73r+nBjcV20Ex1IKUfL6+fyfvz5WCedhcrfycUkC/E8yhTcb/i10zeNcorF/wEtboXDBvMTlKtv3ABnBBAxF14VuIVrZenURWGiE91XatMgVEcUbA1ubdBj4Nwtpgc+BNT6WKcCoElG14a7tUYAbVFERgtqDrTixYhQSxt9XtpMBuzELgTdV+lvS+iqnbSfsSVBrmU1yXcEkumllsqf2458Llko3HrqjQoM1J76jfs5nSgvnPKKFRaZG0z3bYWNfs2DSF8jZDAJg7l3meHxFGbzFhCrgnl/kmdEhf+1ceTroe//pKXaYZg05oVTksT64HPUpBFW/sq25tG3zAhEcg1Uk2ug0C/ROzfJSwCjfXA3P71Dt7ewVrDUVA6GlkBy2fwrmeNqivxN0oHpHMrVIeyMlozaWF+jurfIs9Sncj2I/SqRHr8OXuN0UjsGWrV1C6f7yTr+Io5D2Ia8ZJqcqbInTGvdK+iCzQZMjdEB3Bhqa/diRJSXWRHbzxKZvIPGu7xeLlvRSqnC17SFvFe1uByg/2Js11Jqymbf22GRGRUrtEJvL9U+gH/xx5p09Tg4pJ/U2GjLp1N9vTw8TRQ5mzwNl2VGaX9osTZwOAV7eLL8IsuTIE7QWaLfYUqZGcZF8Z7TYkDG0Q/Yv7r1xhVWkflAz76srbO7ILPk6hYvfqVemAIsHY9yBSzGB2Dv7oSyefiO8vV7UhoYJxi1xt5+Xzr9kkpA8N23dJArfQDTBLh/mbzpCO9RskIcUv1OO1zTptT7MxfZMCfotgvxVtupd+CK740NwspCdC8YiPCGG/cW3vmOKlMq+1ERKVKZM4CqTyxJ9xu2SYQRISoy7Eqc8Vc8qZRTJcQm24LhyC2au8Z5iaIOqL7Ufa7RnDKhwWY2Z+jSuj3Bu/sEMkFWcUa0YtaRRAlp5F2LvpEnus2kld/xVGtA2AlorrAIEDsoDd3G9R6gc4PWdvxCyL/91dsTJX18IBeezuwWEGbD5KS5AP10VqMR9tR2FBmat6XkwKPSUn+wnvhLLMHkzZxJUPlAY+xAr++0vZ6u4zUO9bY3wJ+FX2Gx1nRsP6Rm8y4DXPyusDf57h+KNF2XxwGCreq45im9/NekWzp1KSpYSy071W5j8/nSD23n9ynPWOYE8rxIcxIp8ZpVYMJlkPzFB8UBueDtrRRv/h55vCgdb5ck1MH2OuRdWblfiyC3J/jthxEQ/i0XDmA3xrfgU2tpLlrjYrZKlQLYvqo+aGMlW3OL8ztv1533i1ZOV5wXShNOs78EWO1Qv2eLX9xgrFo9VoosdTZcFvYmswWV9QUq0XCb7AXtSs2fxtpd8CLy0LHT8seflV8bdpZNSDEMmNQIeDoIXuZUah7tQvpKwv0DW/0QftHbbwqL0gT4DW5HHb7BTu/inq7ft1onKSXU+blo91MkPLJhNJoB4Tx1Ulg6Omr87ma4wljJqPKj09AvqaaBycGPBzQpCzOuiJRcyweu4R4iNHn/WT5rkKhmNItWzPX1q0TobNJrVrBDaP2RM+N8deWNtzUylqJt+rLkyaMIAlOBouEMIT+qEu3P7OyW7iWBGHa+MXbKcmB+fwlcworpW7PSWTmPFfxg32bBpLVM4RZcfUDQ9XzO8Oy/nsxDiR/xJeep+50PzKEipX9XNk0xr/Qltg7uhXyOVoKI6ggPVCl1TFm8d+/s/L8qfoeP39bd0ufGpAwle/ffezFhMzcCbNp0k5ALqOrPtL5cVFDEEzPOMboBfJPAOtl9MyKv5QQog9RAK2UHV9gciQ7/CXmXas6BTf8CiaVEi7Ea1jPZ6YcA+5fW+lbATQhCzOiSwSS5Ee9XGSTnE+RjuJpUaJKtLM4Vyhg4wOO4Jl6RsJaNDGEsNSx8E/08iwNf4F7vb0IzV4Por4gWc1qKnTqMqQPig5joT02lBbGtq0JnABftsuIwgHV0/UO83I9fwYPqEVbLM/aAP2JC/q7f8cR3bnYrnOE7tfE7dLJFzUt07QNmMdXTAx7rX85J2QnPGEi+Aa/Z6Ks5YAKgxDf+dZ24URGqf0BJzOSE+3dFar2FikGgrDz7T5E2RbtjJmN28q1HvIll3Q0VLbGh9BSLDQ7gnVS/1jUG5uNvtssRFdFdPkgqJwK7Pla/SmquQsJ4K2GzK+q4WarJ/VWK9wkwIhYzl0DafBoG7viCcNM+IXsvA7o6UymsPH3cjpXWtWcGbPQ71DeQLoSnneCkix3IDLuZdA1gnsRqfzAaeDpil+lOHzluszCaNvwCO4Lt2IRBaxQI00sFXW/0OejIGVcH+N73XfxIh0DvauL66b+bsf1BYeQ8J6I4JI/V5Pd8FECvt7daKDo0+jee4DHAE1c/gppOf+6bwDQOzlkK5+X9FYDzUoHNdXhYZKXgRARAT+2Thd+ED6UVWBnx0Q/DdqTH9KQNHFTQQrPH8DucjqZeXyR2kzOvsbYvwwb67FL78nsyLPTyfm9/og0msaTW1fXjsl69BLr4wvyNYXntOP+a71WcjvfiLHxmCqec9FKBQo+mb9e65dz+AE5x3CpVshnWR3OGRmtb7fGQMQRsdH1WFv4PuizlidoYC5ibsSlUkV7tch8XMbWJOevhDlJG4aB4s2B70/jQrz8MwlqvyPjUvubiAfoVeC2FZqgpXrpxI/+ZW3D18ZARQDnAnB2DbBcDbe/dI+q0y5TE/IhTCZJiuS7vyz310/ndQgZqw3nN5PINP6mB+t5Dee4EDt3Ry2kyFeNfbHEcm6z9+XmL0HpOFZgVGrPfT5H5jfHany7g2ee3UbiCH5qZrM9s3GCT7byj8aLB8M0Y/1LTUtF9HmZAfUjw2H1hejaD1tZJL/xRhD77nuq3gWDossatP/+nz0SWiPeFwdq984bHWxSCTdtLpgIpEpFMOGEH1WceEf9nNDlPUmBGl9A9ogzZBoZvuzh4oYn/qv93sSHVr7Cgq+a4gKD8dhB5ypsON7plNnD0/UhmVcGPnaApfUzNOMq4ZnOn3UFrEn4ssCdaNHWjcrkP1X5lmP14U3hN+KLd36EZ6oNC6GkyBXqkJO+/g3OAxj6TJDl5Orr5/X8LXlWchYXpsVfUGEY8S9/jWKN9x0a9csJbxJ+z46QrJYwul48BQyw25C8AJkNkRGu/KpSRoav/N4kZi8alOKl0rk70VPFoskviHVI16wcTdtc+4QJkMHQylMqQ5WTK6hyooTaxtzgVnSeQiCff6ZcDMnjD7ETnjK/cLLJYo1POk4HS8mR+m5gGKR1buZkYlLh3YEIYzbKCIMnu5+IsxbP3IkfvyaIXh3YLRvu0S810HjuL6HyDD+D4fopsj119atyV6Q7T6bKU8E95MytohqxiSImNC/ccHPZNiXpMlVvjxXbSnogPyc10U4C1pdlBPdfVYZZbwde0L+Ju/HZBRw/HJAn2T4i1NVxFFRwvjnxCr0kYv8Xpi8ml4i+PMHvsQ/FBbcJ5l8BAeY9Kt9/VRW6EXyJliRsTr7ygGEaFv0LmGm2wcQcFwSaua0aGN0UAyRTLyh/FhJU5Xz4Lheh3j0hhK0O0ZqINwLOf3PIrZVGowZ6rmfqAw+/CZ0YgkRzMS2P52zLD5cJJ0RPgS/keRL4kZr+bFW+fzHasE239Xmrzv8CUmcOHu7mabs+7d+gNy4L7T1VITNzv8PWpmAKIItqlXD0VY5s3c9F8/vogYw1qL6m941k+/AnxoEZd6yXgZNPT2hvR5XIe8SWfSGYTKfXEUMCX/5W+WLzuMWgB7MmcNkh1KakTuK6gmCysIzuaSL64BihJw85IyI/ZsJ/qXlbtRQVsrgRyaHEPnD7ywc1hK7Fe2VVkcUtxV8/lDKFXy8cXMzmfoPteOPXMZeSJ7ynNmGPL0MJXOK7S7tXcx1lTEsYTFIgIA52LfQNDYEuhWimue9jM0pdKMgqyfJUYG62MfuiljzDyIa/vF6cOQiqNdrcnvTsjJvasVnsVrNgDW80WSrs6zoBGxe6TEtBy6Tas+js8cZ88dDEwwC2K04WHFVztlwcK12H60Z7nJT+XVEq5A8WVL7j1KAXI+ncD9U1ReNUMBV6mnxCOe0mfEU8Hi8kPlr95T4rppIu110EB5eecF4JMtCJNcs+TruMx315FQaLEF4+WVEqgmd5HncMMcYfyb3YzvBwi3xWzJrZ75cMzJ7UpPpre7AFV9RsVIFlfWbB4YM3I+NEviICT2G3Wv+21e+Y0S9xNUIflfrIohIF5nUPphSLpMr7p6KGMt2ETXkI6UR2Y36zU6ZeRkzjdBM8+VZX/PVyQcvDCYM3Il9Q8WsKIeJVarENE9lRiObEq/rHNT7g/+xSrvHOH3cdd5oe3ZrhX68bRwnqj01Tp2e8rudqLq2xmDE1kBo3TId+Kgk/OuMZzeJ/df6cP/jajn5zwUMrlF43FqhRG6oU+OU6KIbBSha9f1v9i3TuLwUjVRoKl7GvV1CimBUZwDuKgN5A4etoB8pBwikl/IWahcfk+vmEnFviefa0rLpmpMhKJyfVa1G1ToDNMQAWKBJNsIpoij0svmOcY9DsjftBX0jXv9LiAv6lt4lP5DHHL9txhV1xhQyZ6lWs1qh1632LSUP7C9g1I2FrJ9QLUrl326vVmZIVVozA+C/BbUWzttErCArPq+Fpsbikko+HJpix2scKi1AfNjxrgCneDXC75v0OnoWzYTfIz5FD9f37F2i7kgpIIKa6mGqojgT6nTQ2yInVYdo0etFxTtH2OwO+PFldOg1XX7fQ7+evy4qaZe48icmBB+PzEY5hspxFij9FqHYWWZf7qrRA7g0ZzPcxIQwOIsgVERTa6zggfJG34xYNZMtT1JIAVfyY14j4OhTB/ABZ/gEpVufwgemCSjXVkoPe++swB7Tp1zXA7Ur+/Ky5CZZeA6cw0JxPrPlB+EEWJH4od1OsHlaNonSR/2UchWiPHhvxyiueLjQjpnBJvFI/f2x782gF8ykoBE1jhxkZ088xgtcCayewFrn50ZIZHUpa7S5esTvSjnpBJyjvxH9QgstPEp4DGUR/Bfd8qOdjxhwiB/dskc26djCkZT28rbNOtcivSZdCslHc54B/OlajuxkuBO+Syd81FTxB4PiKi+RMg2uJCY5C39vYe8xOG1cttol8/VymfD+A/Rv6q8IhQkbgvbl/9S7hK+VZP6ydZcoudIDtpTyHY7BfAvlijrI99pPAHGTLnR6MTRuFAYjS0WkQ0Mx+KZt2XGwA/3R4NeE6Cmie+Jmrpv9e1KbQdp+dnSCIGujdc7E0SlIvagFCaxeYNVDDaVTh1WJ4OTrzB4011jWr/Sv27IFf9o2w43CGzKWhhncYbwWSokjcYC1pYVEd20dhPS1hI2gMzGuGbv3V4xAjvdBO4FycmnK0CXy8Dq3mzKiBno6BTXMR+AVKrstU1RQQvsoTqP+QCHhSVkwdho8Ze//mwg+fG6WJOq1u5S6mFjFekGZereY/4YFiaTdWNP6vZuJLGOzTPXbt+16lVg3kRuJIqZAnQd/xN3OUQ2ZxBBk8mca9xObyEujU+mdV2G1E+Wk+TMRg4dOJ04XwP+YIy1/wHhU1bS28ru30zHOny0URHtJ6shNmqXXRLQ7ctNPkaQHiaw5U3PrHKHuu7NX61fvwdscz9x16Owj0HD654lJfHNuXgcnFsKJ+QgtuulQDz487yy4AYrMyWA4ZYahzyuM1C/THMmfLNTefoiHrHjDlGb+C7jA+5bTgHu3LdSC8nBH993kYKgD/saWXo5qfAxoCy1qAhxCbVc9SJFWkT91nBqRX+IqFKa4R4zF7uvpfRSjQHkyHiQ18+6g1mDcStlE/ezbUNWgghuKX7/ePYUWAhsQvcErxlerh3HdBf/+GUbxSYejQpsHMDgkJqZmzmTjd5iFDcTyjqUQrlrm60DM0lKtYobZLb1fGK0qMeb/r/C4c+SkaPOw1e++ABtQ2NxqG84qJGGgeCDJhDPlyD42sHtUhCPsc6b0QqJo5atM1BRPYsvVD6XW3acTtGPycmO1fdckQ6+Uxb9znAme8Trac5T8MS487FbRJtX75vAEzeGt3DAGgx0CtDkBy2wxN+YKk/GEwNkx/MbM84NogPeqZsltWzQqDrGM0d0ym68iB4AMgTjpA3A/J4oDc6NDQKXz1+g1A8rsG32tB3m8Uerc4tyXEspMldVj1V7S1BS3qHTp4RSRBACwbwCE5wIS5R4k7atRM6JYztHr9LcFzDred6Tk3F3r4NbJ9oLXsxveIhPpTtu0Xav3HcdeB7b+TMnPy60bC3s7molvPRoinSrfB6js0gxNLSdcbJL8cqilbWTGMw9i2oJ/1dh9eP7oc2OXyQ2/aatJqxsuLN85FwCB/d4yyzhCyTDwyRWcQfjkLOq+bMLSqoFMiN4Ro7S/wqt1PbS8l6UtzX3uUTdfM2vzdSnIVitXPjRen7YkaK2V2eJY4elOhI6T24x4e8rBgSvyq4ZRLO9m+vK9Eg1uW1AertHdkgbJ77ucj7EbXx0RcZbLbyONkZZnKYmhe/EX6lrKUonYcqKuSXgq3iQLlp5F4M0Rl3E8QU0Bq0OwmkipldLsAIjHe9buvUDeKk7gZ5Ayve9FyGAfXsPm+Hl7RJgT83fAMqPDxQYqczoYEFCdUeccD5MDBhn+D/wYIXSfn2PwmKOwVwD5b+eK4oD82daxO480yYizFwdfvIHyFZA0EMCUeaH1Cw6yLokxCZieYICg0TV8CBTys5dgM81u/bnidVlstur3KEYxDwx1lXKfLeIYL7BTL6Lag9AUipIXOFcPDCHtO/QpBLXPgJG1kQ2w2ayHExtLy8upeIhv0n48sXqUzVEk6ClZX5FivfYCOPQMuPIHwoMpf3XH9z+lQbcgreLwC/vQ11yg8GycnqHy9Bh6Oa9+fn/fI4ifWYuhZ8FycFRrjHVPw0Xp+6KVO2eR5FfbmNJLEMqEwpGy5kXcCxi09o3tHqyPqy+hRPAaXVerxq9vCk2B/DvfqBR4tOJxzPvhvCR0E8ESXvoPpOJxO9GdZCFoPAP9mY710peOSjVT7T7PzpQFJAjxOkPFVdNan+FrA11J319S30DjEL5n0Ny+3ujd+lmeUHZznPQJsjq9frdZACvi+S8nsoDITb7VAJHP/SHIcNe3h+JsMmMrhuftKH+8GKN1dbP3zBY7Vr3DQuEF8mnP5ClQiEI5GrhZN37F87/IfmEnsxjvzc4vH2ZMR8cEyU1BJp5cDb+csir3o/JHEC4vbuKZXQjf/huu+ElqARZFtfbOBAYqj1r85ts4qmQEyWNDtS3BrSn2qXqxw+o4FDKNj0jnP3iHG249aVRMEAQ09rreVwmt/4ricOs/HMIyRGIhiQ/CfiZ77AOW93KBYvQ+MpFcr8hNzoEFUqU5lM1PU2UjCr/junHW9gVj/itaD+leLVRXOe5w/KnPYSqigo6qEXDfqDP/rwiVOZ2dZVIO56WPJJ2IQCQ/HGimBoqGC8ZxmiPoISBR9gEVPnnFCp9+raPvDPbexeAgYD7wQDXSPwIYvEnCVETVhO7SPK7nnSDI6fe6lyswu1Lrwj1AZ5D7Zq9oaBoj9xngN/Zl/VoxGf0OJlojk0yeUZu/yyanlaaqtnB/G8gOc73wmfWYA/r7OY+EvHaPkHRNo1g8GAgAYmjn5uok5YElIjRkzPuedqSEU3sbrpoYFnFC6sDjMjetZ8vSrEtYIgYLzm897F0kr2Jti44R4cSkPvb2hKdZgjxkUwMaPk9hVopyT9gfmQRmtztNfNXlP76f85kQFROnHf1Lnfav5U1UJ0rCfjRaXplQzr71SpIENyOi/V+igwoEVKW8mJbBB+YFsdvlOzpPmSaWsElf92hAsVvyQjHz+9e/ZLLgCHJgZq4LhE09sB95HpFMxvWWXXayAl97ZB1AaOOY6sRjFtLMmaz+I3i/P2l2Jmegwvsz3cYwXrBDnNFe7fDT4BC/z5eWEQfef4X53bMCcqxMvam48/tJ1BankHI+RWhUbciHAb4RQ7FTHuoYSzJrwZ8bc1D2WRp9EAbKsZui6hk82GjnD4E5eIwI4or0AtjjKlSS66sgOGlhx5Fsh6X0lGnGj0Uvg1TBC8Xw2sb6HDu5TOPddNAPt6wDQ5HkyAI48dvMyTTveqTcxrePn7Wpc0cuXGV/PQM9y4bW0rrmALYjmWdii5oK9rc8mufNb+zcdacDjVIazwHMIAyuKgVVOnBMLlungfuud/btoMuVwNnBBV+aPmcKVH2+ipQV2WDxXW+nV+P41G71urOmzzE4mi/1hoJ+nTbbzvg2kCJdGkd56Nb8vhhXm+fjQU7Erksuokid4rdo9GsBYbWqzw6valQvQ9vx+QXbRNA66XEubq+js1U5YJoGi0oFqd8T8u2wjgCiY508gt6WT6eXqURxOqvslo/eR+fbCYasiqqkL7rxfMsUqBbCBRvJg8jKIr5ZTi4JXgEAT0Pdeu2LlFzmjyDkcMcdyWKWQ75rgRDz+TnMkzY3WLQA1PW3vWFl+qsU9N3h1s9SPvTvBNxiuKCdlTLf6VyVFkZ+fF8ezf1xJLrAg+Tz+dztTDkXvyzmPxpp2tfDQf/LiJvJIbe0gLIhxxfAZxeYvIJljSzdEv5B6JeHLzWmSpP2Qlj4n014DeBSmFtGxE9PJKMA8HZOWBGlpTgoRhDXosu+HOC/no+7fSGwuQgUPiLoo8AICcgymrTjfi9hc+ZuECcHE35AL/Mgztvehv7Kh80KK2njtL4FsLbQ3CgyjxEN/LspuxgI9YvicG+YdyABUCUkMo6Z9y09/NB+Qxql8kKkNv9i3fSsfyCndlEZqjnearnOpUf8sPspW/cHv7Ku4lkR4fjgHPZNQAbWQPCBQvnlHsLKFZHk5r2+QeSoQlKsooJlXl16fuv9r7LbZmA3jIy4MSqA9otTV6vP4vg3Nj8nUqmdwin8GV3+L4SCOF8WAnmXt7E1SUevHoKwN58+a04YEQhsJ0vV8FSl1UuoFkwITlcpY9V62UQGZyFQYE/0JyXd6vbIFtUjEbSNzOhPSM5NMRRgrrC3N++qmreUUrpFlg+7iTdlR1jHs4R8L9f0wE6JN3UsIzNCD5d0BOldI4RUQG0X/PrQ0vrR7LzSn0hOsGvsBxk/HnNm0oDfO509GH2+AH8G0gHgts+a5ftqvP49Dnm6DCc3dhx3b778xUD88vx3/2RJx9PKjOH3xl6zXr/Pb34EE7WQG+KYnYD3K1w5uXvwD/CX0jSOmp0EupG/O/CvNDv1v7sV3oxasUGTaFkTMJIPlRcLyxVP4LCT0VSo1NnSbnmpTt09tu0T6KPWQrDxjkpPNDu5QTboj07j7glPEIYqvOCMNRnAs1FGPlhgcFj67Omf71oZSfjwTMxPNyn7q6jPTk0tYF69hh326kHfzbTzoBNfHJQrhnq5INmwrQfFdxWw97sOJdtINzbtZGYJ9yZQl76LTlllCrkRiZDrtFxxbxLVlzY0ohiKo/UuEcsjRWcpKuO5iJUG2M4iWf6caSjXYYLCO/uTegoLHfQoIgx3PTNgHjEoEQf0XS8uAXPz303+XS11SkOxXeYLDXyYIP4q7j/WfUpzYOH1vpiXuaD4xWW6qyShrzgSGYyVMdiHIX4vll0f4JiDVtKWnwYtglLrBWBArxf03Tsw4RKT89kr5LBn9Mtlit5OQUfB/j1LGZOKlf/MmzTVycKnBv/BSba8RY8nRuDLDssgZt0kyYbajN/x6Z0KR8hB6fQ9RxswcPp9SDaqNRY+P8/qlI0F+IhEtody8e8iiXEv5oirKpVzokP/s+hfFlLXC/sKLSAP8dW0L9Qn2iRbMlUdzcfSHuKgaZXjwV6YOFR6hnj9xCTTnK+7nBIzGCGfJ9PuS3SnL5Cn5m1u0JvGvWTugPLiWnnYUsW0yyoCHIQAd4x58TjTVJSI9jq0siXAbDT3K8Vs4fDpe+VJ87sjsJJX/zINl9m0iMcZrIkbeQdkSm6v7qzSo967zVZ/z44Hz/ua8TuSLv98Ge/R8dKqmRJ7y1N/GTEu38/FzGaGN9SO+8ebs9trVGttnl2VcptEUE0NPor0o3HLUSBziOlqbz4eW4DwICWaiROz//W8uWTuRR8NZo+slfz0kX/mpTFJL3Q5Vk18ABC2l/lWNog34l5pAiPnHClYsKvou5fByF4FHElzTCLnsjU96UhuU/LT3B+MoiixL9HsdQfQ4Cy9Tk7ChFrs/oOSh66SZvSb+gb2uGB3a9/DhL+JDSZC4IkrUZjU1M5uigvXsZr1fZd1K7Yu4jygncYGCSNNxBunWyIksmaSV8oCSEMhfAxhxlrOWi6xTiqv976pGar1EiZU1ftSxDfkKbsq/6apmyV2gPakASo91mjQLwUMuv5zu3K2WRmhxKSGxgmdMo8i7w4lsxo+zrPLQY5yLv1FD8w9evexVDC3NZiwpH4W31atDBkIHp2tsEAg45MuoDg14Q8auz9D+F+UfplRfbgv8ukuKSVfnSZlXIB5iOMYwxXDYPUPTrhW/Np39S0xzPH061K0C/tkT/ss1P9OqR6+XpF+w3gchk6m60t/n5an9amQWlCn3vE//Y/ESK7hFN/SRL7L1QLdmz/Dh794ZSyDPxh7p1yX7KlFJvVnb/Sd0KE4Pklp3LGlXtTlf3eZsUX6vl0rFURy+XSlKwTVA0rlhrZ6XzReTSI+F2RuFZOF0QwCW5+Y33Z+OY+vsxSZMwaMAaXqQY6+/arHJrcbAvUD4vpi+t0TfJX+P1F5/7ov9W6d833BpaFpTYP9moH05xSZRkqCKq2KHXM6P7Arqm3J4iRFVQi9LiIuaW5l7had+6UAEDUlo+J3/Ml45PcX9ezY/YvQ5qnoi31MHkL3NZydPbAm8dyKzWh3xZf//Li47cYr221yZo9LAJJQF7hlYmOwJ5134uqu4oNrvEG9OJ7+Wfwei8Q/4gQjohSqAG2VTcZo69JD128aRENts78MIXuDdYfRfXz3ZsVECR6UxhTM6zd1paHvpjuKVtKAQfM5BYHAZDgx0Dbvc372fStNqzWXBmQrqnNd5iyiPokOa7RdHSU54q4PvBfQjcby2KgwElke0ujjeobomz2LVAZsd8joGUooncrC9flwS51MUa9Yci6J5BO+LTcP4g/fFXS7xZ4gLOda2sFhz1hkCNuzwzdVdJVU/4nMSfOMLgoOxxdjkM9NYik0S5HfY8dIuaqchMtw2a1F35e6MFSyapEOZLbHGqS/rfBx/1fdx50G+uxnS7F90XESOEZGga2FhMbtYWaC3eqbCF3/jDUE3JRED5NNTQihAdEK3emXTmXEXXvbW9fYkRDURT+jJGInw9MUCfNw8MNfT/I6CbXtW18TqVKhceuj/LodakOB3QPcU9IQK5eEqoz91jxmprJxLFcWId8tBziWq0kodzJPv1nrqThZMBfbXehczSm9cWKHSgZgG+QgaAzBb5MZny4uGWp9Qh1HWfxdbfcoKs+gCY44/eIW38/y4dzIuQnCeH3biRjdn0oGd/0H8x3u/JO5EnyA+ONXy01NRL19l4DSvjGyXIY5nFeNNhIR/3jdfDtY+GWV0BgP4adpDzHUdQX80N26WBcRB1BKvWiXwuvbDgTUozEsVJE7VpHJnW29a2bMTJR92ARmiiB1+9TX4UEg/agNxFrB6ZKp9P6Qy5HtLHHluwqjPCKzhHnA0ywEdaxj2g6rl/U6UGiftd+IalwjOE/+vL1FoIRs5nRcEQmdDYQCPNcNZTVAqu2H9JZ+LTdZlFtp2b7r1h9ASnPIO7T0JS4rbN7+DMr/4F72KSFovwtUWdkXHP7pDYiZzRQS1dROOhaFurNt8ZSEgRlow/YTmW2CM44oHBi4NTwd8DBiwYp1ROr5KmKgnTdeRGESiblDv/yJk7W5UYvyyXCePa/HjaLtantYW8EtFbGFbFJBM45HJDh4JQOWCfbv2EiTF1JcWU1Sp83iWOapbel2dgzvSyZUrArRdJOw7vdfxMERj5WSeHTrL+molqbz9DuLrvt60E++M87h1MzqjuJNa4FfuRDsLaxRNvKQK7QsuOPXQyw7m2QMEPnGv3wxo/8Ga1u/D959VcfxduFUJqlXYLd34VrFvEgajH8MbqX+Mkts/yWakA+MW4eIyDnn9ZvkzZcNDkX3d+P0IUh/Ckc/foRxaIZplFxJON2Tfh6LZ2oyAvE/HGflVHdRa/7bXHrAmwLH930nWWuTnPAw+X/BXVVIyveZIwN1L6fbs19JI14KqbnSWqPozeoSMxtkJU2a0Hico1+7Hiu2HdASUmtgGzuEzVLgLoxkTex2+qoaG0Qg67uN5aDccmJAHQikk9817/qyK7Hwfg83fyxNq6Vk9UCif/I9DCR+XPmjlHO+Kmn9Ik+KuEx6F/0SR+h3XP8VdiR8d4zKU8dJfQXMAon4COF90ZnC8F2bFRDBzaCEsMiAJg5w61qeS+siQCy8SjVsQWJfsbrgoE8IldIfMhS71ZL6wF+04/sQydnodNHlmBpSrmAM4UpUY/U5LKeSULTH+4spLmDbW72+sEYWF6cq6Rx7nCgm1ni9jr6Wm6KvLwDTRmVJfhfV8hbjapZp840GyETO8dYFwFqwq4ZqITXp9cotg+bhrYyO0YMV55Wql6/2aPTeeJar2e5LrF6qUIO1ORwfgh6BVWY50ks/el7frXbTZERhMEZhqEalUKkRmd0qKz1frlX/jp7+tHmDOy20uBO7HXHg/fERy9R467yKs0HmAX23feXnX+5teNMo4uea/OFGBJ3o2fcQDbSB1zmK+qu/Y41bLsULZ5wyVng2jlHfMQ6BW5fOhk/ti5zwHWn8j7mTvJxIbwHrZjVxH8rXlNtkXDsQ3zIA0ZZSMq2p2IqdjZpRGRi3Koa2pclfi5CrQCJ3sLwgQyIQFRRtSAdRdvihQ/tEyNpn8Si9kywgBi6/4Diq3CKWfI3g5v87+OWyWpriXOm2iwdZSQAz+d3orfIIrlD49/Vw4BnLwz/yQ3nlWvY5Vu8nqXjStm5/NGqqpD/XG92R/oNKqKs1Ml1FpbOd6yKynGt7anLkdipCZAp6Gl3TGZlvlQ35ssOUI3yWb6Xwkms3xxCdbh3L4FuD9G0oBKemLrFLQAlkXmwgsKqm7/TeOrW8hllewZ//9au5vxl5NQwZVLs8adqd/o7vSZRe4Q/7e/ITYipiRGGg9RKxNdVUnJUjuyWyWtdh9Jy2NvUt/T7LsxoGWdKOiEb4vmUNK76PGk/7KNE3wL7NN4V7mG9pNgCuNJZB9Ao11ZclPh2J9csgJWpaM5VipLoQfVtqZ4KI3aCQXtsMqpoHTCPoXwI+wmRkyE2gdThihLFQ4K27pAHjEpnuK3hPrt6D6jMXou+uv/kNePrh/F3QWV+6a+UcZOkoP+VRk6ExBHWq4ViUo7oETIhCtm/I6Zexe5D31ABPQpnvGtnuekEadFQne3ckMktuk3IIZL2IlUT1qbBN0Bc2DoNJn1n+McfobTNzE+Xyv+zbMC7iYryhqcOz5/fuNL34l1Av2LsTwVdr+ilUUTufjZ1kborZp4VYBwYP4mC9RqBzu4JDYKv7CCN7kHrJPmX1bF6jX62ikSuOcPiffUOtzWmLxaYTUFI80JLdvvhZ7VpTR1nxqXUdaw3QlWAarcph+C4WBasGis4HlY3zfDd1rfa6pG+b6FIYfXlAX5cKImxfd74rwORcVM7JebOIKafucxyrsCDkowXIO/dY+XGZj/wHKuWOgSRv/SD712wIzGpBPpj2XiHDb330SvbzdfB0XAul8HkKnRERr3b/wxC3u08/NvePzNAlQnXVJ7UEu596XI2CSC5pubdKV7mwJ8wTpMNCeImHM9M/vFqiu4V6UOXVcG8pnH3Ub9IY0tj8d53V9/rq8JejAXl5hZWAJ61Mf5Mx/8jJLzgk6MlM3Q07inVsiwxVmqgtSOIbT/vr5ao8gsgvztmEARLswDIPA2CVX+WvTWFyYYnYofAob5uxHgLgmJPF7gtzhQouTCWDTqu50GrbcqIbs/brvMHipVhp4zkh/o+2KRN1ZC0VziNm6/8WGQ1I3CLSAq5v4Zv/oDsXy90c7I8b6ancCDkPmcmUIM1t3JQyeIShfvbeaE51guhkXTVHwAwxeQISBDqLF+3RVBvHLUpIkS5LtWNMzOa5PJN+qFdSuDgRwZBkANDspvNrhsxcN1EM8pr9484BSuev6x32uuuQUpa56IuxpWkpMA1sTH8m1Qr+/Q4Tx+TvTLdbxKV9WrsOAjO+/RnEEp2IRI+9hBfdh4hVgFTfCPOhHYo2ImXh+gmxWsDsq9Ttwmh1lTBdyNeQriRd05Q5o4wEFc5iEnfBSpv60lKrvZmHSf4OoViJdgqCzfHGveb05EctQofLohj+qWrPPegnquHyHFE4dSwhJSfm7bjOgvHWoywvp1IAQFHeU9zDf9BNfussVUiF04B14JYrwhSRqRqkMUYuq4+eQwiq4IJ0CFd7xpB+lynBA/FNh7z4vTPhXv+s8wiy25++vMvja1N+18T/ml5bbCUcZjPU3qzt9AuMHF2rNl8PIH4clCCThAAz4A1MQT4OGDhFMRa1I7EZwRcilIsWhPBuIWGOxra7jG1u/lGALMwRCqCwbTmAz57cBTAta+Azjha+SbpRc1v9T4gYBmFu72UbAzEhhjePrneJdmax/rRZHtouxSVpRXhsiwnfKJckzYsKt9CUsPuoOy8VBZ4xzwfwuHQXBcZANtu7LNg0690+74VNJlIPONhDS+aHEn7dbRgJTwdMgq9f1BN6jRbGTmvDnIWZHRO9fQLcHCmFQKI6vXhmtZLpqHkDyhdXleCltYLUkabq4SAiYY6czio+eGNx+RNyhFwA9gF+zLQgbLTLYQ4BQLZXxEYA3AsFNkl7qnbPMVcRSGz9PqcY3pQRnf7eZurf/GSOmBbeLmrhS9nmiTrY6/PWxKnCZausKGNRfZRhqXmTSW0+4UqC9fErSJdE2fuRwlPJolghC2/8G6rrdAuOIjSMbSdPSZXwFP981t5T1ITjEv5zqkCR7D0/1u7aCQtGBH4n9b2RA7Jq4W1uc/pk9YfO9obabuvDyNp6blkFfQhO67eaE6cb4f5auYslSLAr+Eg5vibs7O9zd+fqB6ll0TERPdQFX8mQe3ZpGUiV+6zFHKVEwcTf2+rfT2JCfvfXXXGpODZW6VYsRlixKjt60fqqv2hkl1WyF2O6COlR7ZSlsT+gUf45UUU2T73alIWO/vx/ndQrnfB7CzMFmbL33XThPKb2bMiQ875bv0QzffSZ5ZCmppLqEdXQIcn6Us2dOuUas3FcA+hHpMGmaENdPzxM7LjOe5TFTh5chuupKTIV9EKOd/06FHTjfmHJKUSduUw1CNznz8cheqf6I6/vHQVANJWs6CtjfSb4oy5vjiV5q2xG2fE1R09lOZlrgZL0cN/F5EBXnosBg0dFV9vwYHjkYD2Jq7lOsiK/85bwx61XAwpJ87nhBsj+7ynh429xIP1NhBdfXsnSTmnuUvifjPJYeLXr6mLc3Xy1PlEv10V/BUs0upV/n4F+MVRQ/3950W/zV+Ya4a96pmfA3b3QiniurP1QX7cvs6fkTrA+oz9O0s88W3MD00dXKNTD8b9jIoCfwkEmquijRDQoAs72Sh/LTy4j2xk0Pc959UYWQGXg1xfvN38EiLSfDGxqV0H4tKlLXHUCIC9KfDrDbtWn4xefJVz578aoxT6eaww9cDkkWqEBc93HxIufzpfN/2JG/1wIWW99fq1+SrsoPjI9gVaBfedOh3R1wvk8km31jT6jXNhYZdqTcXzv238s4h2R36OcbCc1lo3j2M1+KONvlxMD21IlzZhH/rGiHl1rXfv9UbX1/muUIs/8nWXBOFtmpMOXHy2ke3i0LxbIGp0x49TrdsZmKpXFkz8wCf7wUZAJ5NRMJKxdU7wsk6Emu/3CYEPhfa+3HIfAiiPBKEDfPXWDY+kr8xeSenSuq7BfI83yHGE5sHmk2RkfM85cwea+eQaD5ST+vRktdWmCH1VmjqpVXWcBLqp4lLeyDie7JEUTdupzc70K5cN1howeANKbMf17MdTZXbOpI/bNTbC/IXWpKetN2crep5+oY2lwgB+as5mXW7TWCMAXOCBdNUsw9nOn0o+64XKji/Nli20NIUWYo05ZqDtuo8V+Dc6K/iLLdq1qHXkXi5oA9SYGy+9HTrEja+AFoMqwbdjr4qDOVHh32RMlfkPLLMhe7moI8o7T25hEvRA2hVzWOXrq1buRtSFO3Cw3N6GsZFB3r5x12DtHItI/pqkQdlvF7/X4o4X2wF+mYYi5qWVIOiBoNTbX5M30mOakg40d4SgHpSLs0y/3S0WnAB6tptVSkICXU3lXOUVCjz/nozwZkbVSbZFyXwrsmwdutOI9DWlCVbsw+913eVnpzfgHZHE83q/BECy66iervM/nrX3WKhZcBKXS8yro7/CWYgb6DN/cdqh+jD1S5c1dp5XoSG3yReCnEX6f7z/zdHqfOafoRAhQfUvA2V3fSN1/pv0lm3F/lH1WZqikP+15X7+fMgVgsbqRowWsof2WrcXUzptjW/x71E5QiDsOAUf4Q8kvMy600c9vPRJAPFjYhXJlTOhWsb3XUgEfolIMgxHd4upznSjnaygNxVEHaWGJJUhdyWrhYDdv6qOjUPBp9okdsEWDTrk9Z9Sm1/m8Y8hDmsfEK6XdLNpxXa1zqHKz/XZxWrlUkGhcsvbZuXlqbti9FONzv9v+1150nQubiCtuwD6R3k3QQjE5r0j93IYfQvdSRhnQ8gJJOzXNdESLXw0i5eSZaXB98VNnA6OeIqpphCPiyJSg0HsAWa8Lr1/avz7NnlVMn21s3Zv0Zhs06RHpSzZDYiIIhnLj1WWvlpACP/eVU7wRGHB5NLWV3ZprYr1UcD//5Xch4BOaoG3wBCXatSdh/+8+XqE4ns/4p2JVOLGYUUOjOaKSbYzUnLLs6W+nPuY3IY6OImklWRmN3HhjDnWA8X6hwjifpM9kv1W9VpqMstO/oUZlU7SYOCLAK3Kv/qlkfzeJ8j8DbHfFGi0LWoZWheY/geXNmeJ+bdeKDtAfbM+oHTH2y0D1BNtPsjAs7ySJVeVKIAlfU56/nGTug3NMICt943BJ1BLo6D0d184RZIjsybaA0L0X4h5ufM5TdxcxC2TlE3HHlQeT3VQIkD8ylDZsxsa3PT4A6HXLBvFajxwhrS+AD5R2vfyREtoUY5n5MCfFy8ewkIjU4cYbZWOA27/yjGJCLWF+zLxc9NO0SW+wH0VZXn2SO+ce+/u5wtsBk1beTQBFCaWICIvF5QWpYHADFAagPCRHw8yuXaHUMTbEqVnP+zk7IOtSVwr99wswfvXBprZ+rZAGIpwQO+owGZ5fgqS3qguir/5di6Bth1XmG4UdIstzoQuktMTNXq7GCtIRd1U27ch77XfsiWyQCkSBXAVDHNic0I3hE1Ks8yqSv/Rhr3at7A9vpSM0x1ebkc5mXvzaBg/nnRnvWRKzXQXr1QbtGWtOrYnZBjo3GvWeQYgvYQnslFSYoj9NcBrXzkxenNaGng4tAwbEY6sJ9uxrDpQp8HHmIki5FMX7H1WWeB8tPRzWexvBbnLCd4/tivbzgik4w80nUJwDF/46xvrsFuIiPkG1h7bAiU56Dp/86qO42Ry6+nVpHXPQkE/QDbYqpqDGPdJ3CahOqvaSqGwyzRqMlr26CsDkzwezCxcZjwVGU9RHMdiVemIvXRhXXCVIR1rOkaI0nJALVlVTMwYmzMoaV26ODLIJcollXzQEnpFQyn5vs4Ev2mY2kCgL9jrw768ZeqyaN/TpYgv/OK9D5yoOJenykvsB9sZVB5+EvkHDCWSVQcWgwKK/aG4mAWX59jS0pdyLdpdl5zIrPuqImgwjOCAbZP36tztdvRYIPpKpPIknfOuDVF77/Ig+FKI8GI2yg/6WvVGCz7dBNg/2ovHBMMA3677We4+s7m7EV9QEgNs5yLdXiVAomkEeZ/fjCVQegWPT3savMX5/ZNYwc+FUilXduw5877tkYlg0q3TYx6jWS+CnBGFHR7V8NxSScPxfVWRXopzRmkF4MsHjaYyGElEIlkqIOLIWQ25sEYHpEYIdeibrI2O9RRIbkt+3UGRoo5C/vb1tjOZT190YgfF/2uIDsA4tpxT0exdAb2uPrKv3nfPZ1GDFncvwrJ+Y8AWroU8w1LNEBzOZLJJ5uVGAu/ltM613nteQHxV2PuT0yZc66hcR6u3bFZReV6RVJA5tDLn54rPUI44+dlmaKuOLv8Bm9dVW5TqbrfvKgJSVQwNyuChbdy2NagYfATnVOHWOxuvtg1WwH5ReEiPNqXi0iA/CkIVZ9KSftY+srZ7CI/QBKY7ymkHpk1nr7o2UPGyVyTM4VZAu8htQqABK2+nREepKOH8dRmBDB2IAAy9oZwv8M82zD4b2X1mho9oyFqMK2hzg53Sp4+Hr8zEcpLDvhcFwc+Z5vr0/CSWnXjbJE+TUo+l3dEou1ewW5WdvZUnOF3fsyTrJapGBG7dkXNGy86iGPXwdj8cqX5l/pWsm4ZyT+xLtOVJ8d6phK/0ZBSbLrf2Sp9PuON34tkwHF81A/4xu/TWUC84AQ2hAIpsDFZkzU5XKvxHn/lx3uzfaiQOCvi2CfcLdw3qBmLLZ+we5UBViwgXwZqnda6nY0WHVvEzdU/mP1Lgy6v0lxN36nK26c7yc+9h+2yH+tHRu1pAY/fnxAr4/S/e5Df5130+HZOVWcLXgbDNVT3Xymh3upyXejiZWI4cbLL1f/fEABx7ii/WLBi2md/j3zmK+44m4HHzNxg4WvVpnjMJIYuHgNmMlZWKkZR9jr51Jd27+iyN0lL0QTdwFP9qQhqk+DfSJtcS7pTFE1PVS0QLHj0Lun4AgD3HFUOYTOw3S6y24/v12PQLZsVpv3TtUPftH9JfPt6RU30rqlJs5uZjbtLokP091z5rFfO0kK6c79hAy/btuWHTuVJhA9j86Fu8VpL1qbB8DbAgzBstEyh3VGK4LPwfuEASsoE+KeB6r+5cIFgq5Zsujyw1zfCr7sKCt4Ok2epbLeCklgV5e6HYCvu+KzyulDv8EnQ52RJZWEm+UJHYnuNuWcV41SUwYEkKmboq9jDsUPQEf86oIf4zv78jAOuYFsVW2ZAYVOM7kysOTvTVRcLTEy49LHL/q/Rt32lYxRCfObP6XLafptBYlOFD1Gh8kuELfwkHTmGbDMfFUDH/UiLPoH5MJMu/mh2XQcqeLLDjDZe8JUEi2B0YTGn0m4pPnWV/6qa+smNKGpS6kz4J2M0vuAjx7z7I4DVoN/SFsK2IU8yrZpgAUZZ7xj7I0cuP3ZjvuLRHElR2JqMOIUjBKlYKe1OCgZ6c0b+VQ/DvDmc4iEmWkfiDkHDdbZcdINdQVU7W/+SkUT3x0DByn3G8/JJK43r9wBu7AZVHYw/Rb665b9uaxxfl0RMFLJZ92QcwT6exjZJePM2epS4uN29aszbYn4Om5z3cql4Movo9paqWdNT+TM2oMcyOzIGpVlihoPviCnckecMF13PqIk34FfELx74eIvkeD34XBB83xTi11Mr3eiMsGfN4j9BZi/9F0ExyP84pL4FG2Itn0YcY2WES2KYhBjWqixvYgVzUTEpe7ZmppDyzkT657YXAS08Xb48DhgHd+DbRnkGcBI7YV5uUA4sI13Hp55S2HF2PifTu7cWLaAPxbJQj0GEKlghL8xoJbFojO+83joV+VNIuQOQykOxb9bkQPaTbZbzonLcPoyotdL5IbSrQk0ow4MJY3sUfVKFGCYn+rgixi0DUU6U0Ypfzu3Nrtpps+APZ700kSBT+MspsLZav9MSYx60fWzd7MyMd8dqmzx7vq1wt7MYhJoin1Zw9XwCz89nhefklKmpzI70B0hYvnxtlBVyDqo2D7L1aV2s+lvohLh9hGznYcg/bVbFpHXQOa/CX5tslfjQ7tnQwwRwd+PPl+UgiM/fL5y4/cpRQW/lizVNYRthpz1Zoi0rh9vhqc/vCKARu62AcdTMF/BjYyD+Yzbd4GemlL5gY3PnpCO/0NJ36n7P1XqL4mksQD3x7pYHP/wr3XQxyN4DOSAkO1c/9d/t1ZWIgz/vbJPGC3hwFdjWbIidlBGir3zveWrsmCcgCGNfUlfN3BKiJnMSJlrPcNW07m2ggYIUl1vmMJdlNGsZawQNg8dU9lpO04fR2chwCHWr/jiM1va0s0uiZs/EgRsssKGGNcZBG3jqlbdsXrBV8EmaIfZBR/GV4reRze6u4hCQ2s/6NiLj/6d6AWXXD6tgTDclzPGl060T0UE3eiit+NO+YA5kY9i61bsmb9Yu9qjmfWfcnLnbKuG0xY+fuzbWUTFafeFh1hF5geI7hhC5EKTOHzleUoz/xALw12MjT+IubcvQLQFpzUwK8UGa9in3bVwXGNnCqrVbufpHsCWmp/BLmzau0tQT/rYD6cfG/dersyq2Jdze8a3Eu5fKtwHbay7S5IDDI+ohxXPuGp8H5bUvMbGPrsHTo8HkbG5hxZKm5t2rgFbdkRZvDoElT//KqwEy/GQDhRmP+7xDB1CLrIOhRumXH3AVpU9XEQqgNP6S/WsAeA7eDyn8s60mIGwpfHkk5fZWAkrLfUJ6WWrU88NlLEItYMH9szSWGN3q2yIbCKTBW1rWey8ptCGV7NOvSe+7H7+OiiL9VUr5Y4Uta+EesXr5/GGGRALVgJIe88rPLdXGM7/PxV1CKBF7xBshgAgHoIqOr5TiZuaKszNjyN0GSkmJ9dDcml+5Hi9luEEEbkAPLLweNI32NS/ZausQXOxiH4NiUCX4znkvdjUwddeBvdlLoSv/IvYbQqCGYUCDy722AOuffFmLSvVpagOvMBrRSVLq8k7BBC1QAe4nuFJ3EUrvh6WH6tEVyW5MeaT+t+cIDMRn5J73HC95tsQrYAnKLrqoqUR0R8lGOuYtzCR4VmGM+BTBcT/k0gJCW9g0NSor9TPfjmqdO3gR1tvNHoZFxKVK2bsmyDuea+iY6vyIn6Lan3eFwMQD9MDNI5PvHAuw580UGYL/T2fx007OAf0w0YOCgVArWJm4UP65rg7GWe8NuV763Nidk9KDJJl3zfd34+1cSln+K3YCviyTRX9Tjkxgzft+IXmetD1V2JLZg74jfyj2vrWNPicg7+JTH6d5yUt4R6wjemK+fIzlDzPZASY8utyrbDGW0jOWzXX9A2bi4j2PL4ZfSSQwoMBWC6tYas+tJYEse001/iivHpBU1Gh19S4ZrSAf/dfGUpvpRiBlT4v7if5Oyt1SFtS4pkPaNBMb1lWQlsSgYiaIQh8aSplXQ/ZJOPEt2lqFaaol9Nik2uCvwarpy7csLYICfkcArXQZqR9UPayBQgMi+Vcvwuya/UFte7cxlPb1IAD4BHyRHtJkCJVar9legFErjactSLafP9KZLFlkbzmsPiyOzVMopL51YPI18++EWjy10PomvQSmLgwFP6b7Bx5iCH7xD5M12JIgtJBi8J97VsPbBkAGO2ANiFfVvhBhY7CBmHF6ek7FGSox1SWyBwWGN9d9eaDy0PrV01dE3GnYhuAH8uYvRYFOvRgXgXH6evXiAKTMYUPNJOJdLW4ExZxfqbC2tTOoMJerg06NhwGYQqo5bJ5hN51r8mMlkei80yBxDH8hRhWh8TG+MuOEaMd+qWv3VfUIaxVO6gksF4xF/1yKBJ1DJpLriPSEa388k+ctbeggzAO6appzU/icvjahJv5dDhXHfxcUaz9/0zJ8v9mJoSjpkLgGA4XB3KacWmKQy0j+vrZHoWfdrO8xl/uPKc4qJsA998Y7ulXYAebHpQipONKQ1v9orJX/Y5r1diHRwXjy5CcH9fjtbbLGGLYxhlxTGtBAAlNTNa9/0ZJ+FzeaT8u14fzCiy7UbegpKrLZU9Xwlmzcj0EDArr99fBSBV48hp7TmME61duajTHIpvXVUulKAIdS2vRbYkjy8DsqIeMi8zmw3A5kSD7SaCOReXpfzVdB1dNvtLe4J4MItkm+u+wYDGd0JpbpTAGfJn4814MTig0z3I31nl9TGub3QuUTYuVLTvSBsQie58YxH6FKbrA4p3nZUOvQLvroNXWoBr5UpMjppHed2pM211/qtxln95SvC4SxgmVGVELschSBx6DeU8Y1UyMN1A9q0uKxoNRfrOEVgOcTfYcUeVUQYqdEFv1Hs0Rzc/UIj7eUShu9mOMpo3qLy3DligU+r7AG/z1/v28o91D1lLcfsz4FRE8rzoSH3yJM75SIXiWjP3et+vq1TBYmJxBw58zWzg1xbSDe4xY6nTT12Ll+6YgCBiV9wbzhI/9Iwc0FqXHu0T4zIR0LiIFdA/td3wo4utPswu58fnzR07N53PWgxoXlDTe6S+QHXYDMlgqJd12bugmbjQY8jPRmRBfFc7sxxkrkGL2kFl8J4UTEdzqJzWyfyLxQSMcemYeKPwoEO7tTALNtSoEhiXRI6+EwQz0JcbnmVMjleuOtE8+E20Jj9fYNuoGuOHUsOifjyYXzWgZpLkfbCvXks9q6J9dBWW66IQ2uWcC13I7iN1EUT+x5Gw5fDO8X5m4AOR/oaNaIeMFJ7JOyCW9BOxZyjdejXzGVUBxdIPoC6NT4QX8tXr5AX+dmZ44sXLaTmDMsAjJLB9md+fyiwgCv6bD9MpUqKzBZv6vDbXwPLIK2yYldWrOVxnOcrDwPfverVSHChyeQ6e/2ExIusirlutl7f7UqPRQvcA8On/pFJejhinjpBYL4zLAgUrqbBa53Jfufq6uhFfP1eWsv7g6gnT98yLbySWL5ln7KdpFYrD8IPTimTmkwhTcAh+RozEQeBAktK4Au0JasfEV8V0zCaJP4OBISYMCJCWBlKGhls+ZCEQafdWgvCRxspXCTIfOyVGEEd3TX02+3O3lHKS4Ecn33RbDnTHQNuHJ0MyBsoDA4l5kwzCq6RnbqeSNBWLZ5sZxDmTP9141izeRUxgFLXv4uyptV6ohXaZAvGfkw7sgzrNZGUY7XClBsqRFbjcd2lnxWhP/qhKvp1CTO2C4U8bFEKvPG2m0VEup8gVCm7DqQAMy94zCHCRVOFGbz4krmM6qUlpLYKAT1qi1+jPMlGQ8DC9P51nxhh5Kkiafjwv/7cVxfL4bfFcraVdJ1c6Phjp8ja/cEQ0d/osEdRr2QuB9MokdsQhxn4jS5wKbWAljtZ+bJ9x+T9xfoLEa2dyMZ776TbQmpxIIKn20N7Hg9h1Srx2WaqUCiXEGec/1O0wVOaGTb2OYtdxw6V+v6i2ilN2FZ6PP9wiDJ6X0u3JSx4N2IfvBIIG17rUWltdl7pIiCuJgF+Dlq+e0OF+5Dqxm5jFOF0907e1+2EteFjyfokk4M9/sBoHolFSXGgH6G3m8uBAj2BpHljbimlk2fTrLg9Ohcmd7CkLur619iA1+Gd1lZ22TdPskUs6DiA50nqKNZ+L25zcYZHBuSMbzMGEOBaEOIV2cyx5WHnfOFdVT7ujX5EKsSw9YbBwYS18IEFMtaoBlE2Bl192vWgz/dA8JcjXCD0ZHwD5ohtJoB3PJR06a5e4M606XSEi6Xa7+pxJrW4tlj68t+mtVRUX0gl58Aet3i0v/bGyoVln3c6uvPZek3IOEUhqExEXYzA8grhng1VUE5L6hJ/KIYmUQF0kArH+T2Kb+YzA4uaQAud4OA4CIc0xA48hN9j2O4aO6uot+fLlHLJWAGk91t4QS4moRMCPPGsHksZm7vOwZibxM5oEQNTn7Ak/w4DccgZrxr+LBZC0QK2D6wbTXpwzzx4R2DEpO2SFbpMB57Tm+fwU9GvIrW0g7wvMk2x7VFG4f0kp6/JMrlYkfpQ83Sor5laUGUquAMV8zQIpUDTyaqau2yS810SsvM3yXSVXvJzjRLdraoIOnO0XwIzWliVv7QW7aoH4aXKSSaNT4GyVgUBPkvwxleOkg7t56+seebAXDkJ05lM6SUYVTaTkDHkrUshmLdVkvi2VW0tl9eXr4+aVwwSrnj/VsleZQsk9LKOiv0cGRh/H2jEqvlkXymzVPST50BKumrCMXLx/TExrraeas4ZVOJ0Y4Qh+q36Ll0E/67DFqtUcwz1Bg3AtIDoCvxkkKOfhXWR7tns0wi7Wi6erdeL1ZdjfmmDKvVjTGF0p72OPDbJulqZ/jVdhnWixLXMKUmZyOShOB3Pk+APkrMujcT3k7xTwX9ueHgC0kZl8jujwB/D7LrCU9PyhVsvjar8WOtARamW1dp0sc9dhqtQTWpjErrzRM6Z2xkjvHlffunn4cawCWelHPVr5yj93LfKhLxdFWx4hS+f1R1sRuvKk68TgyFokPseLbqQy/IaNZ2lRts/ZlErQEedRxtcy9C/PapGnPKL8Gy4hQ6ebv0U7kiaWVR/ugWJWZVxTY4peQLOy5LsQN6OgB3NkDquGU3RgccqsFx2iWMDzk1yaACpeyQ+pKRHMKT8n0rJMKHdaaxWkfYMVCs+NBbkViLJf7djt9IxZITAi2EY8EzHgTrDIt/J2st+32SciP9HmQ9QMJ9eznqKLkD2HiZBpnTHcVNcvo0F8WH08gdTc/FYttFuWrqb/SGrc+Da29+vUuGgannPT60mgqX+iCfF319QXk9b6/wxSklwpN9bzKsK/MSPSxiNLLfjxUKglIC7wvUiAWq9/n9avr5YrTaiy0glt0hRNRPmsb5gaZfsEapo6DDAR51pPa5FKdRaD8haf5FqkmTYiVSVD18wKGW95KAughTd0L0X8wLKpZVk2mr7kHB2udzu0fxA4qKPcu5/BbovozyGI3whIXQnZPe9alrVHj4IvAA2kauLziAKRDcBJ6dinczZFU8juBCxyRHqzN2XCgQIPxcwn0DNtt4MOvk6mkc798JtQCPB/UzSrVQrSP75fS+5eUftyOEqus2e/6DOYXGKy4D4TaU8nqc91elkpCqHXShxFwFgZGheLkmnck6uXT7HKLTmCM1i9pxSr0daYFDMGFRjCS66r8yz01waFP8Wo+pEZB84lFsMjBhuz3+YcE7OmXeiM2X08EM2BSeKCrJuCeOP7VRIx9IK61p+XmA9CZRLvvFpbb5JnmEswuCKFdrFf32wHeRgWwKVUk15PHuxijT2wetzhckwozNxjSRQtovhlabWSNhynL/kKqi5Ui5oRmM1+z84imEqWZ3wgXKo5aWHwPPMi6k0fDgyHB8TyLYaSIxORFxqBbSw3dhf818JKVAQNDUMy0fkoJVKqwdE5f6Sk/3k30+2bRYSbVue7pbmsRmBa+x5yHJiABKGT5pOb8N2ygZPqld+WMWHNgR9YL8HHmJ9Ojk1H5Wt3BqwU/COr7FqEzfGaE9/QnVCVhDPRax7BMRujm9NYyqZBMr5jZdCXkzffs2mFkd30de75QV2yhCl4d15ZfdfcN0G4fk4gilgpkPb0vwVykzcjesNa0L4kie5kZhmGZ1kkGV+Y2wTThoqVDss2vJwMjsX9cH/GiWFiwXA+ErkZn/TBxA3hrVlSKaGUcXzaWJLQ51YBhFLulDJAkTZK2a1GeSvDrwccRyqZgD0BiVa6klP2yEQsn3L8KLFn9068PiRr0I+km9byBzCxrQW+5CuD6qawq9D1eAtv1UR1e23mUqf1nbPLpdrBIlI1GCzeIrHsZFr1qWhji1UyphQoukIZk0UvVYzaV5l0qUJUGdQYtwrA/psatrkrtjMRXb1k3YoKrlK7y39CMliVplqeTaz9BxjzhK0FNcnL0ouwcbRdb4kPKlWQ1qo1ZbUDI8tWejCRaMqDDnZhGhKG6Gi6GOxorN8N0JYdPkHozafvBgUWnpYUZopWbtUEKXYHIQrmiGotMaizCIisCzKfGVDsglFqy1nVgb1mQNs6uMkZnwjQSz0FX8Usa+TpBp6kVy0aMimEcR7mdlL/7Lo+z9B5cqDmX91/LXFvwtc7N+D0r7KcMeUja3F0KrMm4W5fOwQmSk7Ltbs5HJRmbAVAr7QsNmXUqfoW7hiuC1A31MtHGI6AvaaGaheYuIOAsPHYRS0y1NWGxqa9PDGgps6+y9s8VhCReDCcDrcxNz9uOAux7O1QExfrPhxumPiuJVa4GFveled7D7FoSzhvMrF2TxvbK0uCM+IhFyH9s/eLMVCM2rFnqWGKlOQQL5uMOzmsc0CveGWU6oReHbfjwLCl87p3uS/UqpKuFPVk2eTD3bjl4mqiltaA93y/wwRfK1fwwbPxaiHh7+cCEDXyRo89p6r/pvaVf2E84R13j62X2xMOqczam9mmtaBMsY1qH1dOKSofzLE5lDpvhZFLsYYnpE2lopyK0VVbkO0g+IDX+wthnxldjtzKWde6a3BiuVN94mXBN33uCppWs8PXOpFojtNJBVdp5a9RQs74I6uPaSxe/ayqwBMK0LGXNC3WcVJSZffAR4tMgVX178cnjHcyacHoiCjOqHzzxBTKKbgpU0VYdids+y4sudLaFVpn5msVw0pOejzm1cchRrS2JAscvv3BUm4qC2DPcTBlQxWyFZIcG3E3ww2EQNjYx0vFy2Mv4aiWuMiqMX3hJ1MrguneGKvMX/sxtBOODV18Qrru98sH9rb8HgoDqbHp6WYhBDUCY4C+VRkAssO8JMwKtCUkPIBhX0lNOe29V41wceL9E178x+vHJT+SrkTC1/tCKWa/ePPLQSXvqWYuOpixA/fB4sqR0FGCP90vzaBFZ2SFPAM2wT47mv+QaEd0TRXVn8AmAZn5tkCED8cB7af9ZN09mX8xxK6hNIbZr1Xr6Kn0o2kQJp12BKyrjONS89e7t2n7l2XlNv1M3WzO5t3dNtkArLv3nSHrYd6hM2lYEP5waW7d6vPRc/SFdZrBOxNaek95QZDtfJwROMWm44F3t/CoWqMwQ/eQLkdUJVYe3Zs8i9vXcpn/3958WrkY/BnqDvBKJXlQbSQ+48bMJbrgGqz/ghxVvfEHabNvR0fa2fGhwoJJ1eTzLHxYsp/OgH1/Uol8CtqFrjvEpumbk2U0Vm961f14jqD34HXYNw1yUpHGxl9/RF9moiJpS4fgKLCXf4DEUC0HzPTAu3NpdpIPsP9DjeOL9aPPTFgixEeTq5vKYW5AF0VvD4TEMH4yrK/e+g0Nb62e/1694SuIeUqr+/Mov9VXDC4vQtDVzyb2BS5QUzIUKyjCt2qQZ8ra+nc4yFO7WA+Evo+efPozUqJOhxBah3A1nB3Hqmn7aIQg+6jGiksmpXIWtxTAdpGG9yFxfY5I8vOq39QqAayAIFrzc9FEcbteIFp7Z1u58PYqLYm3YUwgf9iWSVI6BJHT+0dNSW7/fztEaqLrX046Bf8WUHzNkGQdsk3ABcRWLVdXDnsnbJQMojbhJd0kAi9FoTCNN76m+htFp9oXtmA8YV9ErNLW2+mYrS0cIytyNsa03ZNFJ0kODUHem4ISW4VwRI5M9PuISZmBjSF5DR60+D/rNzZ+wEdzKtDNr/EvzdeN+YVTr/mnr7C53Nh0Nvay7HdeptkbDVTCA4+GqiP2un1beRBLbqVyxiTDHfJWSZerZIpGGlAXKRGtniAgW0y2xRV/hhCFqScQ3g1xM/StpEi4E2or2vWE9WiIIsRNA/NEnsJgKI3g8GUFq9aGrc2SUOpEKwofSVu6vFYoGQ6xk8xt6D7nNGu7s/WTXVI2hiSkJCZmWwEV6912FSbU2e7Hxq/64bKG+6T2gBPk1NjTQGq8AWz6HlzvCirtnj/KqbNWGnAvkreR2NGIQrxPG8GbMAaWZT8kpFza1PYUKCv8DgwAetDtk0d1lwby5NRIUVIteyROxbGQZw64KHfVdN43PyVEorLpc8b1bobxL7uoVqR3y1KrEGB482+qPhpKay8jvjT6D2vGtOIDXN46a+tGfUKG3X5xHkTrB9mqDCRM8r6FDcZhMLae7t2VWVNPnkVW/Qq0Tg9RL2C7dqrqJxoUXpWZ3yD9fONWGAMy3xhXYodx0xPJt/doi+xKqFATWcTjY0Roj5u7u9ZmuuTh04KO07X5qe1H4VtoCjCIBhLfdQzw4ErxS3p7vx6gHWsZevfcTZsNKZM4noIAA4lpsNK/eo+xT24lP76qQ8UiC1Nd3AFkbUpQLj74YKrWFPtwp3aRR12/bIAYNYZvO8RpSTUs7j9MhgSwjAQjLGWQ/WbXyNdz59mL/jHKH/qS2PTyAG5D77kc3MxF92QRVy4XgaATzFhTr+ukpVXUYAtFHVVhmMyUiIaztLoxq/OdcRsxjoCl/hfjIiU3tbzg6NIZUDqmqjDYldvx5RTiMRlaHjjadZK85FEzBatm1b76qRTqIMgkG/gIPqv85J9ZT82cadHdm5ixDi581nBxsTd61ie80HPinvv2SkSDE+aUPg+LAK3Ffhi3h5mdIY4UNNKgUVDYI0tQrrw4FLePzaGZSfIP7vjm3oKX23K1f1yUXwZ2caXkfCVXsbtW/NioAwQetryjKRIV6GPNNnPcyJKrsPOehucKOIqig47CgbZNfNZEXprAMPORn4bpeoU/0BcK8rApfQc8N3KezI1yvs/9FMLklNh19km5QQ9WXGvRiya4nP3qniXqpYU5rZHE7SvG6YqkNm7Nhqqiq0kE2VzG19QyEVnmW4ua87zrR4UFlb/tI/4KCGKWSmEf8yJ7uFI7u7YPSI/RfDosskt7LrZPGYd69NdfrqdAlf3jFHa9h2kOyZIpU9XdmT1NNFJUN5v2xX4sWVdkecb56YfUr0KBkYL8G1wtX6yS24YwObosazV3P1AYAtbV5sv+Fifjss2TmZ/8FNDuJLTVdrflCtNKNkqDUWCaKusJ+MzSaxuE7P7BtVazZDWkUYgUAtd1iP9bX3u3ipAyfzFXG6Ownh0TcnjD5vNduAj3Pniqc9JJeDdFdtUfdMPsw51WpIpinnqyUMSIfK29sRr5jsJHNgUXGnoVKr/1F08/dG3JJSqJa9cUE8/LzY7xXi8Kf/m8+sJyzzUf7Rxa7FBfRDh7oIQ7s/ty7ejI2343aNB72cJ4Iei1x1iC+I/O2+co6FmpO4NdKZOSDLzofJnPaO3gSrF+YUxm37oGGFFz332l+DJUGC555tDVmBJIwcqmRGA1ghDFiOLfrWEwKLQW3s5H/7LrsKRV9BiAhg/2YWZzOTFEJZVYLjiCzwX+zhDcynyQGhUCBh5XzlfBttqQVE5j4q7zWV4L90smBv/ghJ989q1SGEmcduZ7QGtzDKfJNnX4fKuEu4tzZuOHi74tv6RJVkakgVSds5b+x2rhS2lF/5rHpU5j1/QREZeaZ7RBbQMPwSDpFFgulFYElHJ3llBPnaJxFbpNiOhHklz+1yuUJr1AscbVE7FccLedCPm095wC7aD8xIPE8vHR2Z9u7D54V5FuIkWo/lX59siHGl6pwhogp7l+q4yUcnMDO1K05F/xdO1LCe210sZlyr7zsOKPu975m67hRzDO4c3rh1ravehW3kWlOl9AYbedcAPrcmN5gpowI1FTV+9mRzkibwtuSVo58rWopWSd8tDpVxt3a0De3a/aZFZFmbwaV11BryxjQ8141Ng2krXol+AqX+SoGrKfFwicysdpXqomUWzuFXTuhbM8jv4s9MRtjm82TtpjzLn2ulra+Ht3huTyjqM6w7FZe5PAaGJtL0D5E7Rjrw4551Wa3cjdEg+efb3gN9jSgQppkZXX1fsBaoD9fn5A+rNqrfk2bQlEw0EboE/5aa/D1mRcUR9N9kd3ap/G0W6dxp0PS/v1BYDDzl8S65h7LFXJn76uY0BC3UilPjV53ASRd4s7ynqROwRG+vKKvxY9rJ/o+MZIDxhjYt7+GVBnk7ofimu/ZEDu5CPbYO51b7ThH3YrNRwvGS5TRIQu2Evo7ieXoUtPK09CX8q4h/1rfZIO1nV+D1BX6E/26OZ2UniNxBgEGMHPSzMPUVwDBHayPGiEadBmnLlir2FzpTQpN9ms/pkc1FCehm6Z1FrBqrvXmivtXW7GpPerlTtfqEJYIHjIJbGk7vGZctJoJWubMTmLH2oznu6jHe7i8R5lGeGvOTNjq+bRRE8effM8dNYJaK8Bn5XMU5wkA4MHYB/aUbpTxHZnZTxn7mhbq9sN97He1luqZEXVJcOjzM/4NEL023oGzDyWuJykb/IvWPoKvjwzxfkkLXiZWTLU1vNxLCUHS6NExp4sZrW9C5lALENB13zYxhID6jKoOkZDBmqLH2QRaECjr5V6qCGcO6WHiQA63eQFiK1zuLu1O9Y9SSWqAQ6aNz6HbXERKCew9zlMznAvoNBjvRVklq8BVIfAcI1+jL0XMHvKCVtL6HJp1a7lurTLmEU58xIQ5OVQ2wNuWtbk6TtBwdRJACVnR+4LfnkmcHIf8nYs6JYQCd3I338KtrjrrHSrpE46Xa8PA1e8RxfN/FfkF5wSRbHyZKWqqY6qpfmrm4QIJCez0Sy0W0vO8DsnhrsWoxxRW16xhNCbu1Z+Tk9HJ51OVuW1rdscXDcpP1s+RIYVag/2Jpy4wN+pg8HnyTs9UmYUeJ/s9TZ9gUZQLnIRfRfjrlXXQcpixW0M6DpBBLe5ZIQxcW4FZzq+CKH8tIBly/UohTyfr/5KYqTb4moFxnoA2BeWJmW95T1Q8ynFY7Dns1nTVGgk/EOhwEHMr5bsbxhO5hvqpeaq0v8JuKp83jn9ZNmmaTgeJiRzslUceXFsKc4+UAebFEaeFaeKDnk+G1lE7X3Sz/LYYyCtBeQGmY6nD/OwhFWySrKnI2VgaK/5Zy10rBJ/DZ8TYli9RvYQcFGo+/GZCC2eW66WlcT5aFxegQ7gfsNL4h2dNRUM5juAxoIvdD38W6Uvfj8JsvPRavfTkSeDESPQy/vLU8B/JP6fSY20T/AKlVa4fhvhV2pWCRyE5V4XZaZnY2KmiLOZPCuchH3NUaE8Gs26c4ehPz73KgRzek/ouSnEBPXiIaZLbyACuiFyf7LhvESJgVSEwJjYZHyfG6DOVrJvE31uA09bZcmVLNcPNLl/mOzAqlAVNbnXv5SSuHm6ltZYYJ5EWFIqO3Vqnzm5PfD3YfcgW6mJdIfzqui+9j7FggiqhLapZV0QUGkz2EcCCs3V3bLIONOZGEL5m0PV1JRuBjF7YoXjN8I8E1VDcjo8Vd9vj7sLdfmWXQOgu09IJ3L02lpM0ciqQogWGMscI1sA7cnqnE1MqpgyVQJQuT6fg9JxNHU+VHsOpsfE7BZGG2l+JwCzcZxhiB/iVKSGxkMbkRvKMcWExwz1bC8oPBQ0trTrgqkezxBofFN/XKYLACD2r/PoPpkdOR/CJsaDlU4oM1l7hVnH2Izba+O7gXg8H+J7gR5hxVoGf4GOTXlTh8L4TkYACel+Z2d6IaeOof6EkPShAhbFnX1CGnBbA+69hrWwbGZbqC0c8KWtbuOds3V3qWz0r3vbgsp8l2JJb6p3hTq1MLndwZAb96i9D8moxdZd6bQbo4RI2dZ+vnPewX4dGjGddT0OoreOIISNQELB+5bRAmcJfbgxJWchpoRt5KPis/9yM9ukyFMYMKURyU/DpTsLtE87reSBMysClfY6hwaslYZqJtcU9HgWlOAQvbhDa8a7LI3DBTSnvBQ6xWxWLEWndNQvZPevQuPdRRzG4SwGisJMUtYRdJk9PsJsajvafDcxNpJyVAIkaXAbniGtqUv6VfT5yqKxLK/8wVGVW5WkTeBeLZ49MfBoqhVUisRAPBC2F6d+sCWlbXsRqZ9hC6uEZHbFjEKUuC+Vlo3YN/eWWpGaV+yzH5hdLRjK4swKTPF7vmZPtD+Coa2WW+K1TyQMcbp+xonp21iqJqyTxslOauzv1Y2a0M7Em7Ic5GqJqvPCT1jFwZBchK7hTg4SEofvpnofRwjiMAotBhbhcvICm1hK9hTzUlOUiNkLiVlc10tDl2Jtt9XRnA1AXM47qat9yp/6kM5E+n4AwVaCLBsW7SjNzPh4ZgoQTiQ/d5zqzlsGZ7FMmne0SfNmD4orMyuRFegSCG9apkv7XGzlYfoOIBg7iE7mQU7wv/M0F4QqBCAILXVM/9ZBvyhxX3h+AxBADUMUZr8KSnDxKEtZptPbPfDcP4WQBycSJ55MNeNWdkIrc8JoaIN0GYCtPZ+mDEusAx8pgsrbvLb04Ci0cZTx/y/JNa+ZuNKudxpnMKGEzyTI5xqAiTWG/3oUcocHMrW/PalLXtfhXNA5h9jOBsPwpFE+nSfN8IMI41muSt0VaIr9Mzbs1Um2jtW5Fv4R0jo9LeI7mJFSyw8J558KqDJC6fPsWSWIbAdbLAcAUEOOwVlKPJmgbc36MrLc5/zfk9Ui2Uux9vwrm/jBrzPKxoeaXrrtCPaXoF9E+R4vSLvPQJDfgyypUpbNiWGeMCF5+JNM2VHYEKH4Be9fZS1l2YcqibRGyHDqkOz8UaVCo6CXTGivLtFUx24tTTIXjfHr02/WloeVZZdEyToieQUvMIliykNbSDpTtx1JKyHZjoffcXfKUGpPCTPWPaTvI74uVbq+77hwR7Bg3/jJZygKE8PoXAtNNdi42rQ5P5iFeRp2zbp82onwBG5CqEmqKhxdrUctKhjBh8Ma/cUfKr8erMAKXVY1TDYYsLXifGyR5POsHftmf96D/Mkhpi+hYS1Enor5eaKhpB/s2th5miPoZ6Zd/3Q2YYjEbF3tplsWDjViMYWPUliTSlmRk+ePtJcdXbGhRYX32LQUBbryQlyTnOk+ka8HKinS+hDrow7leJTD3PMD8gmZUOkkicglWjeh58fsJt9ndh2bxqAdSC/OjVPXHNIYDse+FT0GTW+TnwUGWJFScBk1EykPquiv/VwNYgSkSzb0iGrrjPqFJghEYDPsCBpvQoGQf98E1r/MFGcpAMyPe3tj6dKahWoM6xXOObMyAGJbp8lqaeui88SN1ai+Kfdd6ON29kDhU0gVL4J7bv7qY6sTe2a+CrwH7NodKpHh95Ez3GgFW/2RBuvaqTb0XBI3TMAPYMzXlTEydLejxBEbCBanp1ZsHU0KtbJ78/RhEe8zOTS8Vm5ysSmKDTvs0e3xR8eDQeao2y0c5uX0iN6R3YxbruF7+Ug7kfRch/Ca8VqsZNRxOfY+PLF1J2xwVWfOVH9v9Vjf6fRdE25/OpYlk75+gOYZpGLpIl4k5WLpYz0BWsvBHZQA/AL09uFKdiL++TsKuHH8dFL579hEmNTskpUYJK6JzZKR/IHW4/fXuZdyXyRQgaklvTU79VXuShUuA+aByGH9Sj42b2sgm28/hsaEOXkXM1YstXXxbrfDHbRUnG/RAyotiP/9j6SoWHTeC4C+J4WixxUw3ocXMXx/N21yTXa89M11d1ajKzt9Utrk5KC4JfiDtXv0VjMDkLQRHc3zsuz4sIQsfzzK5tDW/zQIiEc7FYQ9ScEt4sAlebDX2aZ3rV6JSFdQf1oI91emdTx4y4f893WZbWnq4eAgCIT36yX3aCovkK+WB2twFWNkwGPR25zaIbdlRkrrDRw9YhwuXKNbkkmXtKzT5r8acP0z5UBCLaFez8fJOCvOvP5l9Y9T9A5aIvUDruU8jrBRXleZBu3taaXQwwqEKI659Vk0UcZUpCebmlMFNGtEerMBkvzvbgnedK0uzZ/6rjmpQu3wTnIYOf51wDUnZZumEZxyAwFJ/3tdO0Cr6GkJPV4BAwxssQ7RgdI3IRy2xkpnIOFc9+7zQYe+PhdncV15UljntY+jdKMJbLYChpU5dV5BtkJ8QMMxXEi8oobHh8l3Av+RuKZzMJKZt6+EmSsLH3jBZ0yS6K+5XGnqcO+D9gveBOT3/HF5XUqbNTOKpEfJSrLqreI1W1XVn44XzEOvkJXC0/I3JZSgbQ8E+cyHMI+KXUITK1M7mt7sm8QpBkrYGKfAQTUutDa91uovwYtnwjbz5Z6itWxvU9TVEx9H8JxmAGUH7p72tZBqTVxAc4OQg/4xT9cuFda91MRGZTaQHSDvVSNoDmf8l7qb3cmK4Z+pTc9W/mkbh9bSvpqhwuSN4OrlUapf5K9ZLUSjRTcy6lyMdlUbdS0IfN3upRvF5xZqqX3i/6vKS2UbWWgIMz2N3Z17hvcBbPC/1MnPm1fSfarSO5JJtdFw932fGp3SmuX8WmiVYSmcXX1h6x9hHsv9YQSEoxsyB1jnsmB1t+Uz7X4c6TlWaHEyRP2K1jgOyMrEKiNZH150NwjHT6GCmZdBW4etuyZHyAs95xDIyX4E1fyBnYwtizbI7HISfwJEJGdvHuCi7bv/58GfmoE3z2wFyHBFYkxbof9OQRrSpI/qHg6h3IcArQ1NjEdjx3plKrRVBA/xNLmxlE8JtUmfrfCs85MEh5TdhEwSGhX7IYXp5HibVsf4Chu4E+MsDAcX/nXYO499eWu8E5UZpoaNGrvdOnoan/nT2GN4oqKtj+n5a+65akJomFo2nr/Fze6oOq+Hoyuj91WD/F34Q3/Vs0hj0VzMttPChil52ZnGQ5fiLORPmO6WKJcQfd9t1EKGd4xNGA2uWv7R7BzG8BdmkVpOXl8/Stf4tGuKhQqd8XSIK1O771WuoFuWrndgGM7GbYPcfQaCfKsh/KF1xMpR2i5sKYAs9A3WX63xFy5h+qUXeMQ6efzMKBHS0a3VodBNJ+QdatTL5Ne5tQMmrl/reO7s1dCm7PFIG7Olpls6zd8dtsbGo1YuCBIhoM4Mo0xDgGKlvryxHP63IVVgOKqBctBJvBTb/GvvpEQF0lXkNY74lmNTzhMO261mSOFGAalpqkjE54ChrLM4MaPj1KGeSwHPtRA7yycqvHpDjGP/2rqMmpQnHv36bXslquiqHJZaG0KUf4fhYuYSpVpYz+HFW0V9zM1kG38a1d/yq+NDliGzmGTaBBbi4uprXcfPQKMf11gd+vadl3owczL9YNWg+PMQ6vkDFyacJOXwJBcqTdlO1RN3tXsGuzzIhtSfiQ5/BOl7U/aB2I5Ne1ok2zH1g3imKQ8Yk6lapPB1gmvJRKSEP+csqm4yVLrcYMPm6UcP+kaC8gXSa3yjVi77CrluP2sGBK5stltruBwchNcmnNRjHiBlFDyOiCOgJQZZIu1/jGyh0CIZigO3wFYYgQqOf0JM1wa6MvWmQz6zzzE/sTucFp0GNHTxnVrW+fDvbXmY9Nx/oMZEBQHFg5T2BrH89R5seYCiZDlFBRS2KhQQWESIDUXTgVM2UOiD8obU2E+qaxFIHlgGQJvmlPZmwyGcb3df1dXsSbYuGfES4MOuAUbNe7NyURSDObqyT/vUGDjatFWmdyLuQlP9tvuwdS2QNa3e2hE2/5ylFrdRbJ4vJt5GMxhF7vCTcg4YLxlgQBOC+C3PBnzxv0h7Pqd0ZaJDeEr2fdkNSPSYVSdHqfSbtjn3sRH7/CdTsWCgSk61nZpKdH/BquaOs6b6LTKJfor2suhlqUtUQLWH/q1TnjgdHrAPG1Vub7lpzPCltf5DUXJ+x+UU0xydcS23te44gB0rH/k7GqXjtY+6vznDeQnNeiWsVIDGRE+YWxvzfFuou9vwz807VtRIubAtaOkZA0A5WZDi6PqMwKxkqPLEcEyWdW4IEjAIczdIGGzJd5rcoxM5Wf7YTx5hQLFBRrSZTlf5nav3yQaZDKor3XkraG38/NUQF4W9q7Dcj1K/WiVj+o3IHDFBbllfuLtkCHIBQvAQwD54m5jYHd3+perb1wckAAKC4PMjvtQBbUyX/YR2mVKgR/3XY1hvJPiPNvSPYPh+lXiQfXHqFN/5toL+hQsv9wJOhh+QNiclEK6eoqQMxQAXIyZwugalzxbpjQbbd6+CM0HJduv1852lsdTFHxLgasqchXzV6cBM203CnewBqI71AXP0KHOsUG7q3lgdzdxnGqEg38jrGqq6Y1q5BHfUMQ+FzU8cnpUE8BLMkGQYYXba63l86hT4JnwcYkUOUDQU2Mn6yvvk4SMwbTavMsfnRhzQzXF7OJtr3O8wEo3q4GuzcZkxpG3Bs+d24kRTyD8niQ4+n2mvp/slELhucLawU1nWMw3/5WKVKoF8penHJS9AmOWDlmxJAvl+WPq27okdPmt7mbEKKTVqSQLjq+hIMtxWjEziIuUYSOZ3HpJdnImRMw4ESO1fE75Vq15xSyubdfxyc+QjWaQ6aDANe1m2K6YVtbh2Ydg6s8uQdH/3C+jsBP/IyV5oCLUGuYttfxvQIhDSz13d+Ufi6BhN84quV1ywdEVQY+qD9CDqrW0VrZ7lxXfpghvNFZf6V5eBae06hQN3TYpylkBZwQLWRwEfRC3lXpcAf/AyN1YnsL3LHJvn1stxW+A2kyfcEI3kvS3T4q9lSlYGn+QUTBjal4aQSJ3/fYY+sPoxAyp85EYnXwKUOkmkLSehh1Dn1n0SOFTGvnAWicMSpkgaeDf3fqezX95o0LLDnv92bhQqicCebLr9dGOXiZqaWd1xaEVc1j8J2O/BM8wLS480ZbbnfI2o+pu5bsq/HJfazGKpLFekpJbi/TSDDlTylVSEvYdHUQ24U4N32OdWM5YhGxeQzGGnjlV4DQj+E9VuCDguOsMT+JImVG4eJgK+ONwmBMSHY18GX9hxmQjVT98KvmdIvn2Eht3hQgS2x0M/ZUPmcOJT9v2IPOsXvrz1Z28H9chywpHu1DVYHv3Pg3SdCr/Li2APzNZvL/JIo5faOYuZ9JyTkCdE9MGd0dQFbGBXJ9cIvNNScDONOwgaMmhBJt40AXXXc38Ixa26shKien0jM9qDLHZSVITB26DzzwVSaLO8eUY8XXgQkvUXYR9hQbc4xuCNXVmnnaV+eXa07IeMJE4tYS7KpI0P6ID7Uc/4S85TO6f4biAP4vbJYrsL08sBgHWcSB9q5rNuCpIw5ML69R2a0R3hFwJmdu/hnUB27qLp7xSQ+CUwgjH5oO3hwS4JWO0b7RmF9xEX+twGkxMBFncO9WOfn8/0wss0L3q/xZkmacTm7Amw4VG0TnfM+x3b+/Ii/OWWvtteY718VzOAX/VQ7NwGk502tQAbjtfg321lNHksbSoKNmfezXlM4wmVKn1kjrzx/ZH1zXNE+msamDAWNYYiQqKihXCL/8Na+cLE3Iz4hzOChJyCtcqu8d4qOoSMmsb5Msh4hvuBKaC0cPX2O8rVykydZFj0qRpLIea0KvlkWRH/0flME+vwsN3aEbuKjnYm1v9yF6m2mJgEVjKfOrsLOZ+xHO+SvsaJvEV55gaU1C6VVDgcmZuwr3kU0PoQBFqmv7eybpBz5cSpmI1e+tRA32niFuIDapxb9jcr2IQ93+zB64eS34HDXcEp0LoHQrH7xH9fJEOYl9kPqu9UjBdSVLhbmXa7r5zQ88MG/jWmAHSKvHgNT0IWZbN43BudYCCxYXP1hxP6mCC+IE9Khpi3MYm4CEvGeqQRqGcXBWlwD+/ng8B1CrsbcoIOzxLHZeBAVJXQ8EYRtoE8U7KtkAH6RB80i7sAsLw8XSTcBAPxLejQwNH+LzqBGLNC4izerA32Ji2pynf7EQ8ZE2MOnrIIEGOdWRgBH/qJo3VbNUJnPVE7zjorq6hc6i/+35rmH995agLdmS97p1wWcJiYcdkQ98S+WYb43bsBXFQEwtP4VQwobKFVqaiXGigQOMTNNZh7Djr5i+wyBXqIHYiFxPbDmCDVcpwWGQdwTjT22f9MeZGViyQ+XLN03SfR9PvPEzDRiSZfbVMk5BnEfyDRhw9NtPbZh+wpWu0Pybgr4FSwaZvzpmPSJME1hGQUMoytq1/hZpmEHjlzAHOQYJ8SGQLO/qcPICjBX3O+I82zJc5Y2JaoJg63wiEkV34s9JfNAoNDSShikXSDMrgpUN5oC5cJLlUfrGowaRASE53a/xN+AxOzQA+8XxxFpBsiH0hFPe0SFUTvC6EBnwd/kvejfeel9bavNYICx4K+1b9S8HuGckhX+ixvQ5vBtc+e147VRkzuhHZEmIEC+PcLj7xHrPXI09oKlQl4/P1HDckg6kfOyvRwHfcjvsVJPZefOuMz3vOx9ybggc74vqs5X30KyMUcCm6QvYu+/BBw9e3f+/gaBgagFQCWgRCj6XNNcQsykuGgjOXOboItocVH24FezPig/rl6TBX+yTsOz9HUtouUQ1OZdjEsgqBZC5EXquqlxI2404edrPKEHXtTSySaecSlCq1l5SrlGqtXSKyStZHLArNsUqSTiETbAtgsBQWCHso/nYc8Sd0uzMk2oaNBMAmcCflnV/SAKxN6+YaY/Qw+wbkyPYWa2U+UEKOy5yVz2xY2/mxsCmIRxyb1qpcx96IHWurXY5O+DzIxQWpWbNa0jmcSkn6/mfreM9CLq8pAQNyZSKnA9C/wEXyG3b+pzVWmgKY3ppEvT79nTDL0bXKxKRMTmKpVlyjD1eAIqke5Cqj+BZClhPHVAnsfo3CeQTsvi3bjoHyiv+/QgHbRX3LWF6xlU0BSuMa2i6z3wlyK1rZiEQSXhHHtVuoSloW2m6+cBlbcCPYeX/kPusJqmborcwi3MF4y3F0Pc2EU83H6Jp/864QVT0ubzMjCpoe3EJhtExpvOhP5fh/jXwUUr/3we/yvNYbqSr4+GZEeTAAi+xUcdWcxIfldLnbv5Vyy2gQsTgie1iIPU20e9EOs8v/vfom4Jw0NTiy89BlEfATAqUDEqVKAXjaHS4m6B7oYlgshLIQyZKNltSJ0lrM9S9zhL8HIKHNtxAQyR9XKju0lZVgEAgFwTCZPlHMrqgGTvm9EPydHwkjzGXUwK1TV4gd9hr9uJU/Mo06VhL23WVNZPBGt+iKRWIgan1N3cWtYcXwJdvK8adZYLbVj5N2UzmitseCBSLpSZAOjHHvVX8dhuyIFUA+i/g6PreESKbZdZJfPT4H/bnfhv/MASKLQKYhgJVzMKMMqe+laTyvDK/Nmw56YR5YimcSFwq4/hxSCfqUVVY8JRF+0tPRp/Hx6WWbp1Euxh++/b2afnOxAWPNygXg7J/l6Hdp65kURGQ/PAIszyRP5uRW5ax/gCy8BpujE7qJQHIBwUL2iC0FZak+mwHYWreURuWs+zaDugkpH49+7fN1OyDduSTTvlRG6jRa/ZyhUf0wxWGGuSrSuuXA+1qdy9VO1KI3xJFVuqQsr1hxgKMeldvgDec1GWtSDvUqtdTfFFZ/1Vz40W4UiWgW9pXXUlc1xRK66evuXoV4YrYV9Oet99zpe2+69dQMSC10u3ZFK9U+Qg76GfFdvkeIY+n3j58qMWNRoIP0bRi7itJsyV/Lj4BJKQITiARN2+XExkakbOUotZrC8ncX//bS+Us/H0BvzEFyLrsfYcx9a891Y+PKVSWe1inYd1BWsH1aqMkUIug7j5I1UpGF7FpOSF13r1VBhd93179Xc5tsZzmV8PfbAH8AKphduyp7cUkaoTPJoPEgkdHZXTxI8drpittcBl93WzrtFwk+xstE+T8bQe9dy5UbaIohzJRoCpXz9v3PFth6l0/hnqX0Dkg/bJt10dAsQ7WRkZSbBoilEuCG1ChBv3+sML+jcWMHpxKv9GOuV1tguujKgz2JqInTW3nz4XU3o/XswjI7Oo3MnWqwl7P2f0PBmIvR0VsEenF5fXdUUdDrGR6Wpc4MbSAhq8XYQghKkfaoMlrMw2zd8+sZbwdb6x6Zc9tdgtIfnMGJDPXPZwpGF06fJNoRNIcM7cFrrV8AdpCciRMHFerX8HTIyVSFX2Awr4rZImwiozbl0As04FY4PZvzlo38xV82Euy78tilbjDPDn9vRaIQRu+gOjATumQUm2dDxUvW2m/60rLd07YU35356Hv6GMo/SeWmZSMaR/7arEnks/2Me0jJ0ozF+NwlRZsTVc4uhZP5JMZVhhRvhvHzCF7vns8vMcfHZjRh0Hqd7LycEbtBcUk0Fklogx56n935mF0UFlXwuQSlRVMev1sMjFubAW4mFKnDt56h84kadkKroo3FfKs61JcI0uVEctDPpMdyEChQu8/1Cy9dL34AR+XK2E0Kgs3Xrv89qdzs02FiGSRzNSprm4qe/n6Kx/Nv5ctpNBiSBLZvaKrtegPsSq6x98NxoHr6Atk/IHD/ZD4R91dh7FoxgwzILHDmGaju/zzfvybxeMl/l/sQTtqBPmRzR/2z7wnKkO4GRnyFjL9E/8IEKeG8DsxK/jd18AWIrMyKolLkp4JTR3rLPEk1xglLwP3MTyU7VMoXrj98ekGFzTI9uEmQj6eHiVjIXQizPz2W1/uP2H8Rt/qK2zLGwGhYQfO36tdGHbvpj8Gg/FQmAH37WJpT226X14Qkm70i1dZxZJypJ3octZ5n0vPHjwScHSIAeQMQ+kVtL7bmJDlQye+vdNmjwOmbM4Lnv4CfTQh26Ri/6ny/5GFwM/hxZmai+XJH0jdWK00jyuj6+gKAs4Kbl2sO9CO+Vk+nLD+g54WJmxFp0Js1vUxbFVO6/SWjXQgs/0dnMWz5KePyKRYlhUxsdyAY9w+HkQXRyb8IJImKoP5T1GqeuDK13WcSjkRx1Tt2IWxSAkrvzjo71SYj/HlMdf8fpDnzbxMFrz59SRHwDNr9feF3cT8nyt1g/8HSaWuzuUL2oyE7G+Dx9HXVs8insF+cyFdAMhFwba382AqgA4KQO1/6jjwFmjLJ9NlivyN2G0e9EpxOY3YTo/zjbi19ozUMr08Tx/s4hH3H+Y8mzqcgvF39txqE3FdN/kK09IJKr+m/eD5GiVP15HGxS5rmdXQkP6c16OB8fwQsk9YZE23h8lxfSv5MEOeHgliJRVdqaDz/xReuuS4JaItvxRUPTcCqSSUH+P5jAgVJQDMyqtx8h30FUjdJkFSMcuvF7d9uFdCQ8/75Jph9bngMIPYC6Rf4ssl6eK1El+PO05N+fqZHuR4L+AkuZD+hlbQVfQ4Ztxqsb+7kvydmQOMFu+8x60T2xJ9+unqqW/cgKmEQgv4oCzwZ6QK9Pi04JwGGeuMANSGOcsv+SUuqQc8Y106+toJfvXac/augZdqrXMmXHMJj7038RcNpUP4sA8u2cwcrh3PvC2Htb6jVruDZWLrXjl3AV/JPhvUsCTpPUu+jy3ZAwyjzhq/GrZSbXKnRvHF5F+5S91YkNJ74P8uwv9kCwO4qVYAyvaqrZzeMYq+VNKX7AemZKeTZPO4FUwTW/IdT0rs540KXKqw36wuf1oP4iDLtRRhOD1g/JNujqA7c7Q+iQ6VsNQtfAzzI/aGSIlqsicKxkkrNenbWGsmPPVO4mQWt3b8yCW/STCjiiYNhzBvFvC+zaTHPWdtAMdfQJmbBd0boiYssWPRMuuO0boY1Nz3LJsq0W9+zLEq3R2+S9Dw2a7BYDbihfYqZVNDf/Zd3ajrUTcRVSvt0cqP1S1LkVAgDCHNrzWmKmBXPzTU0X3yZg+WwiFN4C5BC1cv0RWXJViJiKw4pVJwjMAojJEAXeT/2iaXtY/1+de2eL+zbgl0thxfL/VO2l6BJvLlCCiQpfRPRahlIXRZnSX1W+g6jsz2xq6FmFSaxPbq9ZJ88t2pq9HwC2sBME9NANcf6rh1vL/mE2bGeiPBxntCqch8fitjskgJyWBDT9HTJxWPMO3oOIO5gOon35E7i2lLp1PIhNcF2zVtL/Yi+O/1ghJj+q9gFIL18hnSCCiwcwimAss6kyJl3NnusDBUSHAjm01/phsw1V+5/xvQP80fUd7Hk6hOf2UmL7BN5eRw8xbuRcspZUU8q+xHVbN9BBb4k5yV2G0iGC+kbRutB7TOrPqhhpt0xAj86t+hFqM3YUL0mxmpMmcGKH16uMVcEciGLm4I701aGKrx9k+6XGPZDvn7VRVZS0qKsYHmxoGVg9FnxrRydg4pVs0tcgy5/OCMkXTSR/vNYb9tNfsvK96Sh0xcX02WY4qzJzT7XP/I/b+vbOU+TLUlwZqLsfGzyPqv5HuPqAyqv1pN6xNj8GPp4jQO8lmaCvG355fSWGsZuX3M9gfZrfforApIjtkSitBfuXyXLPfOBzrwNseUfgmU/FxhX0/M+CH24i4KFzkru42wtLRXrkkGWfDym489kQqToqIhQEy6YmafG/yT5tVrqdX+JKG13CdlSG8tg/8L5HsyAKq7sH+EgarPxKjPT3r0fJgeNj35gDRMTTuxH0DNL95K0156Gdw09ZK2vnwu2Yqjr7HhEbC4FkM+4waf/ilKMgcy1PZ6qLl3nu/MD9Ezge+GsCM70VIq8rs1ZtQQApDh90+VWbKya91J/sTWmMMw7o07pOVa6+9eCJgLRUX82QpHTC9YQWxc9ZLDJ7hN3ORQ5A4vW4HOLxX/STY1SHID2mtyCbbkwmmUuvZxRG/JeU6F+Hdn0llZiF/qNdfUM/nUpHg93yOl9VAkI6u2DfXGah0WeHIq/6BSyS7LXq/onTuJxUtM5lrmfiv+i1cXhP6DELDl1cwyUUXBFZ7ror1CiQqUBR0Q2aHUTL+HHDdccZrPKvIcey2lb0pUSAvE3jWWxtsgmPAxsMz+ek0g3063nkdw4KP9rMeqfFUFKpzIZ/+dQDit54hWrGZP5Ev8wtfv5KVFOYCsYU68cY/SgBSZngfV6acf6Kn17gKGf1u3OD9PLTkrH4qvNjbSY1ur76qaNxVhJDGrwvuuX7B8cuAUMbfGo5vVOBNhEB6QkMwLYz78U3MCMlUdDzMSM6qL9DzLGF8cHamhjzXp2KqYjM6/0YQcptoQDCHD/Y5jfg15qVk6KNvfKWCPCK05G2RfZn4BksmdpwFgGYUjCl2E2mPW2Xs5dz8sUUxKo+GFHUgzd9fu5amFAMn/itJbP15BUXNz/1IT72px9WzEF5jK5lLmd01zWfD/G1zP7nEfo0F1DSJTwCjvvwdvwa5k6+ujjmVkg8yYDDUMe6wutMuudkOL+3rQVIYuymjFotXx6oF+E3YWXQLpp861TzOmBps9WF9yBoQutuQowGk64Yr+ztO2TguCzUNlhtu0wtJr3D5xeM2WzMWQF+HUyxsCPZy5j9O4lZGUdlKnlcGzTzHKHwEorRWs3okZxzdIVh/oxt4uKkfvPFsWyFtS6JEf/C9QVU3jOeQ66mBIpr+xLZRtKdkPwJMWBjwcdq4mTFgwm2zM/pheb6OvIwpLVskb8DLmgXwxYsnl4YqHNG8EyM0456wVp6szdA1IXpOolevUpjfqexiAB4ayoKh0kzQ+Q+dKFWAK7eRc5IDhwkEqYVjp7z9ZVpQZMCXuMrAykwPbqNSdu+fgfvsp9SJdzQo9hP78ed+sjsD3Mj9UFwlicnEYmsNgwdBfj/ryUdSzxn2B7JdK4o4e/9CPxtKl0q60+iyZKnP5O93AD8k/TrjNnxuMWNhODkWG7P5frzbLDaZ9YN3XdQ4dxzl18Csp8vsAXHKeF0r0XnEqyzxH+h+7IQn7K5K/2SojQ9aG3e6Hv+4S+a/kN59HcEi64d3zsZCvnH/oYdbgzwoe7jN6OpBJgHQaq2aCysCHxnCBxZySIo43sKE/e3woVzudcnwLTGQoTErgDFDUcvoSt6XDl1uo0WK/5wGa8dXJJ6XZYt11UScOv0FpMZvKSv1hInJmnjTJbG3xQiSosgiX0hlZuNVw8hRJM3y64P0qSTuLTrPg7ddzRC9lz8YXMXw49MmPIIW0bn6xhi8f9EDAzGF34dedwQNaZrcP/RTWJ1c1Dnrc/G9qNsm7FvBPa3RyMJXgy4QZ9PgDHSf9IriDLKXW1zHXPrnIeGCdtCasL8OOxsvkwXochEzrVBa7nqNAo1QCh5n87cWg5lLC4SbrpvDfOPS3NzJrRcBLH5DIOmPxuUjCpJtHGZYERiFADFy22v2vHPoBKOQ9Bz2w4gyVSVmdhfmyoPPTSCN7fO1GQ3JqHEjU1aj6J8oTZ+o/D0u/UpA6rN7SRT1KmelyZEX6SvNysMpJOm0aKr8uvZ2LXdBnoM8VJxte7/GX+FBvIatryiaqb5aBPsJaGGrBDzMPd0jxaqGp9BiGyTKxs9cfEeyptvOouoj1RSl7wtXgmoc8ebzM7FdmMZLdtnyn0wWcCnSa8P8xS4CAlAWVHzqxsRdQsrH3tlGDlSzeH0RCtv56uRVuJZaas6XSF7op+GCmMEgQe86kPR8bW4T1RzH+2iOxTgLmTq0l2xlJeQOzjQZtQALWVfK9rDtp7bsT1RSH8cX7kjq1kDVNt57H7+pMS/qyT+YeQUBUcKwijzTQJGmzZCZTOyCrgnptNQYqN1gPnkm7hJVPdYebexdHSmv9avL8dVxyV+8Uz3vb93dbZRVF9NuWbvB/UTfkxrG/p8vk1rsL3urR1FJT9nvztRUdKgwnPMAbD5nGqwO3VYL+79kYGzH3wGSN62or1dRPMdXZDpUjJ6HZ4EeKvAA6iCNZm/RSNnDNI/WanbjfbMMziTUUZN/K7wCj1BwZD6AK1wk06eW4Y/bzaIrShYDCVtpk2Zsy3Pbi1k3zGTpuWx3OvNgCouHs2XQOqtk9Lu41PZde4QIcLAPlGS4ReLwvp45RJWA6k8ZUtwFtfFaZMPq2hGV8qEaT46ngED7lEtMLuH2orWRT+E1s6WONosLl0hubTd//vIXS6SiRXI9iHI0QKb5wuf+Ix/dm69GkZQKVIjFc1SHcEByIDWRMjmTAqv4el31FwQJeZuf82RTGOgprUSOx1xK+TaELX1ifXV6imGvP0qE3DsyHSWsyjFveXDgBVY1+etFO2urKKSAiXcxugZ5vmRlsUP25XePF1+rWAUj5n1fsFfPl1h/dc5THWobhGvV2j/h1Cp+GfKJp/KNA7EfgoOn/q757loKZeMnBO9mOlMA8sHBcR/iFPxNL+lgYhNHLeZHZ9JtrRQtsuN7bVSyqLuJ9G9e70+hPag13M+gkm4VJZkYM8bJcV7hlxZna1ThNT+H1T0lqtNm7RUv6XBhThNMVT50MB9MmOeAc7AgrOhXZAq79bzbpsSk6Ks+uIcXrR8JnbYSFLyX+AODCrOIVDr43+D0KzuoshXmbPJe2/e5KmkRNprGuSCOTOtCQwrPSxUr3bXunt0bvgbmEx6+6TBhnMgTiFEj3DPS8KwfrR8A6yA5pinQnYxF87cNAa1A2+CMrnxLOQrYP0OoI2E2vUOAHE/B5XBQCi8lfnwa/eRe3AnsdKxdSc2msl1MRZxT20tLMPgVjCrfkxe9fl0VkaA/UMtEYcy6K5ghJbO2yRoKNFi68vMT9+FpuWkFK+IWPZJa424cAcfTkd4et/wEYq4n86SHn3OIBY6fbeh3R1Uqrw73/bFql27VZxEojNhNLiBQXs1/Um/jd8L5ybzO8g9PlbvyufUwR6eavdtXfB9nTIUIGzZAXA9KhnaZK0/zwZ5K8YgqXnoNURqei+Ff5T0fZ8x+sBP07gjA0+zxxwURy9/ZXjMLS5pFz9zr+s7OHL0g6BWaXQCbLoa/Pms3FGp5wIAmKp9eB7XHw1D9UgFrgwSEuDXR4lqJENQ+C+HtL/EWQ8IXVR8gw1sZGfQibgkBB2kbNHyPoUa+BUsujx1BhqPbItZ+2xR34S++bk2JBCXGq31x60x8vpShSkC09rUX9jRaPSn1YiIGCdqQEI3DPq+gQSzIrj3AhGIGaCafKRoj29SfBvdhCWJPIa4cyoijRRqfeOHE6uurttDZf7zUele4XNgn35GKGU7bBAUtAsRJFOmrf4Vq81J1SFl8/HN64Cj2I2ALempGN+WK33H2Ov0XbNqazQnnfd0DBBo5MPKf8a5axTuI+XVMFXrP+t6Pn/uzOBTihAkBNqtUUAJkPS8hrufIVvcfs0K6bwZtYq378EkyG4z9F967NRDzJVyZ+Uou+/nxIMUwPeILn03IPvC5ihLFdtRa1043jzpCmQg6QNDAKA9icy76zfxGlyCOAenbD6XLv/orVzZvgwuLuoef+nCazoHbPOrc7X6tiRnvxMWt8HCdrhRfSRrhEnU9KSseNKgo8AG/fT81BrkA2uIZnrtvYSjokevh5FwizMtnrmgpC4KQqez7vdn4fbrHcLW7Ek0/yBgQzF30jmlNXUPO4CSELcvwS1tL2tysjX5xlqcR9V6IXk93ppK2Qu+iID/nIzltUfFhwReTlnPmjNwrDV5g93x5rWByr74SMN/j/KNUoX2hcg787BmviL9gLPGcQZZHpwCIaBilz47fa2z8NiaWGsVBQ6tRrwEq5c3YLDBnTjhFeEuDSQxPjm/mu/75UgVlqNSg3fNR+7YjpGVaQreGFKWjHv3Tndlgt/HVr9gT0ZnI27oxl2oUOk2944Tpp6OAwO1j8jEajjoVdmeuThSb+I9Yb/s8vW9nFw4vcUOHBI9JtVymspfh+T1K5BolUykx4RAUCO2K7T/1C0UuaBwEeSSPpB1b49dXFGqM46o0xDz3Z0yXTgnr5w6W43OSEH/8TA2/EqO6cdGJhH3Bgu2l9B7eG1C+kwxxlLbmaZFqFyVno1gcPa9Od1xdM3KAq6XFYnSVb/GPblK7ZrUWs8Xb/lGCONYmdzC1OMuT4VeLXvjRQiCwPidddeXmgHAA5f+GJ5roGGK0Lerncf3QiBkRvzL2pWmJElQkmE9XBzJWtGUX/G1mxzx6XkHKv+GNOGHQ8pXJYEKMXYynZII4sUiq1bO8dpj78FktqWKR3zx76CUpzm0J7dxOew3RX40+jbViFN97n5wLjgY+X4hrd4bhqL498rQ5ZYqZz88PGWG3QAR7D90oGgzclOKkybwkkSGrjVqEPkTI9U6kMtQQGxItQO0K+9WJv7QJ/U+hZGTZFzIKUTcs278Tkn5wcPNKwTx+rEKDevz6wUrYrz+0AKaxstV/mQlWwQvaKtwQ6Men/VVf9dMzUOdwXrYzrlBQHIhtwOouur+Xp5464zwIkjxyCt7tMKBqfOGntGZ2MxLvReDjAgkNXjCLmC7fH7JYgsKxCpNgLLOK6qPA6DCa/5ZtgzdVhe3pI7m8z1i2o/5dspbU6zbawIgk2yurehGiL+VJvH6c4zPuGyQN5FleVf30CmumoVPSqjsFj18L2+FfH6kvLLmRO964fa2a7u8f1Z2STe0OITHFQxvC6ob0oUDXdB9c5GpEUeB/xAAWLV0CHPeRT4jjqwlp56mLikZoM7QIyeprhcJa397swvhL23cjpeefLoeWceuCGrobi1ar66I4fjzyL/AWN+8mxgd3/Z/4CeEP1Uy/29Xx+HWP01Mi6S8dbJKKakyd4GftRimiWydRJWV+ZfxlGbOce34pL+7XKfVMaMr4zg5cELvqe1NPkOxnNi/+/J3HqTvvTCZB1UWcePh0YLX1tftUunXPLh39/jH8X2c9P7i7Ku+7v9CnrE7qWgl5IxeaS7GhlwzJBnejRxe2BSlBDu8uPVIISjRILBNfCct0pa7ZzBA1pdcbD4YK+F+VEZad7m1p8BCbNQWYfMScBhKcWLHOVZbGwmAifzm95N5uhxPW/l5T4uUh1vFE6CyGhDdDYX82knsd6Yba8EWuNHz/2A8H1AUiaqKC9HpHycddowGuDqCOhPHQznvdb9aPKaQv64LPysW+T4c6B3P24Fr03YSMcGeOO+8kCBXkhyQ7+biSlLWf6wAB4cDFiIbO4QNXqhl6DGHO9hu3eLz15HZEhcyGvBWSjUTJj9gA39Hg7Ll82kkKXnE66gd3x07Nj57LQOlVrC6YX6MM2S0U6hc8lRYE7f0my9MvQwUv1A1jik3GRbUfa6ig2EYN+1WgZeF02GYLP8Fxlsqr99D+7MbpkZ+r6JM4vIwaI0xsdbHvz9koHf5UejUfj9N8cg6X+LG6f/yAQopHPWsiC3bExI/ldpL09UZXDJIkg8X7O3qKA2cF+1E4mLAqwKvtWhGiYTB0WdQmcniOsFv4DzTcvI7/7fAB4oDx1PPBYBKreqTA6kf57u4ORbuFAikgLV9dW86AdXF4FPy4NC/Q7YwyBYFwkeY0fVtNfT8urJ4NFpryzMCBalHma5j23zgRnlZdSed7q1uiwwjVF0eijq52PJ9i2J3i5aTES9mwGUMN10uapEsffge50cJL6x4i/g2jDM/8vVf5WttyCmk2fggK+SaxCWXEWVtuXBFe0ffZKgJOV8/0h2E+Ozbo22/3f0N3hbc40EDCxZEaK05Z32bAV77JH01B9zkZwxjk1FzGI7uXM87cjGHXh5XF175u7N+dSGOXML72L1BwGhEH+BYfNCwX+PQOh7i4LfMtzZpmX93OuY37+PoWr/v8LauCF1Yz5YuVJH+pBLKBroyYUPREeELGzQ5Rsn2Euii52tEu4sxSouG8A4ygQv75Xb4Y4v2Nis7vC5x2l8OwGViS+1dHXdw3LnfxGDxUgigydegDpkwiN11xUv4ix+DlCEXqX1DGod2JIyQxoANpGuUx+3w+vw/f8Zb/sv/tx6jfYm/rbfLqm4FZdnfrX/ik5VxqclLHW71yCqgo43i4nR3sEsI7c2w0K9rixnIFFfOtVU+unE/EtT0RlNIzsvvASZj+LJIO0931oTkOkklZejH+28ZKpg+R/2Zf2iogIBxTE4Yw/eorwG1f8NKYmesBawpRuyB9TSRZMQTH9z51U4/2JYIy0yASXSWVdo/gwh0EICamevg8pl9J+3pWN37wCMdlvte3xdm0FqBpy1O3+iC85QhY8nQ+nnExU0qoaSLQpnJUrG97O4ugVhbUXsBVQvxyzI3uQc1f75YScYUSmuf2sf6JdbqKblBW/C2hKZ6FX5WZfJDhisQ67m7ajja3mHMuf8sRsKmvZ6H1SwXSwkto8a3otdxMlaOAfUa4Ak2LwtdbXhTmhPei1GhTFUwSe5kegOy3cpI/Cn9Ej1SPzb9GfZJxI08qxMfMDLvF71EShyiL12oAInR/DhHjqFt+QSHGzilYYqvU7XrXBDZ3XoKlhc6FzjuT/ESVWFsm4cgHz25YdbILwCqEl4tJLezAutQiFSq5QUDCcbQ2psah12HM1CNSBzH/14KmPrIcDKKMzFedmI+RMYj0twuJC6JcNidv9pXcJb0UZqzRa1gNc8jNSePpwvNdKTwQBNYVwQXjEScWh0DEzipP2YNpCj6618hIMX6AlAF1DAwRlkpOBN4JDYirKxce9nYC/6Rnr0+zAfCzoPuqhb619yPDU533yI/4ZC+SPirU8gnl5lvAal8oyf1QgpsPtBwT7Ye/hIPhYtpz86TNSsdC8K+Jg5AZ26Tnd4rNQ0NQSRMFE1bq+ZXrVZdTqZuVwVNWJe4l16C2HQ1X2Xx1LjnK5ujS2aleKL0vq5jDCAUMRBqUlIk29ALGfEsufIT68Tcg8mY4yAfZiL/8uE3DYTJkL+VwMFS/9kELNGNHUXA+4kYTvUQGhX/6NpXneUd1HBEBifXXsgjUJ28zqxF2sX75K8yd5LGFucESHhUbk1D/+LTeVq6czK33RlZvj1CtUaALDhLcdmm71pBuBUxOYD+jsAHFSsT8xLN02VIvOR4YFHVvEsK4yDF/JIXCZBJ9xHJP9wNH4EdQpzN/BVu3pXeCgV+EzSVssvplYxYmHMrpGy+73Lrs526p1Dev7EDgJUdftpD4nouQwO2UYTFRSdqiV6S0X2EpV3hYfATUsPmJ/FXMuDXlhEagiZLzmGugxKnwuoVTPRPBbr0kJwSqN3v6F0IYE1Rzph9gq3e4c3IBVPyHkFRhiOAdxbV5yTqZGMriZd28n1ebAcKn4Z5vMNtNe/enmyAWyxzHD9kd7IJg8GXmP8/7OhKATCQ91ze0up7NpMjRf963+SPQo81EcxfjoVON7cJ7IE8K/RPO8tBRL66MxSZf6PYsgv55xDQOaR9C1t/Q4N5dyMMGGUIcDxJv/ux7AgXZDnbTGyalOAEfgiGWh6CYarcfjNoOyGBuZboSUK7L0qdfm1IJ5jUQKn3TlXNNA7Ki8eRv0oKtRWmjBMDoFa8M7FiL+wmCkRB5Zb6AQQBmSmcHKmV2Ruv3yDOC5yTuHauAHy8CGL/suy+O84v9vtquY3xmEIZjgn5Pq6lOkYVqgMLQdzhZ7abcg5oIi4OAEDhDSfph1L4+5el9Boa0RYm+xQmHqu5JHT0zaA58LITcvDB30nx0+Fho+8mvpL/Sw1QM/xUNuD0L9o7qulHc6au/fAfDnVvVY5/r1ojI9Xgavl+MzSyBERESAbHEyL2mgFaN81Wbw8NuwPIgSCSaWPvSI9KB6UfUTLzqRKaoDRLQ8jJTQzi+7fmlyiNaRcleBKWQp781zr7dxbxjvCexH8vt8UoULw2WH+UPAmFN5RtJ5Fy3fzMXWK6HxkvPSPWT38Y8TFFzx98T7xF9mMaFoeKoNH/YpLPUv8o74ao5yGbiF0BIZiEWuOx7lMkm65u+zKnQn4os/okwKS0kdpBRIqKHvIg4bq3/JBPz/6Ls94u70fvf62SELG5/VjMDbeGCqNHlwdhDKG2otH7uXdqdnewequRKYoiuATutihCxNWhQePdWBL/JYdU+c+A1z3lC4kxi1N6aDPLDT20PmedHmBP/mAF1NSQcncD3fjrYeK6C/gQ+zfFOVwVigx3Hr0iXJClMF/mLoRHSqMqS1IdSBHioVvyOb/VBt+1IQxus8lN1Z3mev6yhxVi9g/KCnOSw1rLeJakrT34i5YY0l/cW1SZAwb3dWDl2iM1ONWs1WOIXQ/nLeejidetgBoeQU/ao0FbKi+fiKSL3yaVXzxR4VQaZS72vjqPx/SwXtq3awXQqIh/bEQ86J7mVC4QlIg8k3PhvOO86mUISJTINTmHB3VxiP7oRqsPcP+36wafZkI2Pmh6qob42y8Sakhc8u1SOhUAms8nS3wK16UaNi+zXpzeakRJ0IkwWRcLxgZ+YsDIkBYrcU8Od19WUQTHMi/pjXVAsWN233H5jt5AJzippSzb8UZo/qyL56U8W61Ggj2IkUs4VY7cXSVOTj0aXqq8TUdVG9nXpBVBfi/aqSemHlv1V5n6rPP9N1Nfs6AwZPMom0FyH2zE7l7Ew5gYdDIFfhrC8nzWTExAVrRBmF4gSzlgj5rRpolSEPWR4fwzrqJbkaSYa5lvajOPvFx0SKUOLYDwbcK/FWca0zl3loHq5lN4f9tp2CP88EVRw/HkO/PmQNtZw/odUpRUVWaPSFOziLVVJ1Rd1G0X+8klxGUDsPPkSWfD1dGjI+knYMsepl38Ls6koobIjZH4BiWEJuriIXIbGPrB2G+b6BRlQuiY+XgJHiqnG5GG56wfFJ/NSe/a46dQATAx3PwNZWEA8fhS05XstjRV7Mpq6NnW50jgoRqW0AcHxZzEeSPXSwfrFP8xJZuPxd4OK92P6sFuo2iYXCqd/aE/O9MIxb+yNtOl2XZfKFvvEQ+qSevu5dXwD5I5LryBmHemKZR0tO7av6Bn+Iu1b2gYZwHnStmNsyH7YX0sjex7exAkbNXRgAoGNxk7slPIRzG7tuB80mPdO45rQiW9iWYHRInn5/VHT5s9nhjkvi/QUOvXG9xRYo4U9vxVaIRH/Botjp5T9bRClEA+P9KaSNUHnh92frZdzipz+6T/uKTgq+MMePF1rlKlmIcNrqJIK6szQhDqd7v2WdJ55txMcQfD0YPQVnZzm4zIglEjZv8H+64yyDdNL+67AblvuWD/DyteaIHvtDKpC6eCrKqTGR7Yse7frurtsCbvcRd/bG4A3p2+22wwAr8KerW3X3CwDj2V1Kyv1YZYyD1NNpbZj0czEa6m68g5+N5jgKJ1VJ7MONj9Nn3h85Q1QPgYvMGcIvXJo7jr9+AXOzuROy7wFCu19d9HW/Vz9nX0cMOkUwbHw0XAWxqfyIsKF1Nbko/7NRlPc2A/7M/yPputYkhRbll/z9mixTBKdaA07tNaar7+c6nlmYz1t1VUUCSc83EMa84DdSPPX925CFw2fzpH4iByZbsJnK8LyQRn8sON3ydwZjF4vTEVyHjUB9aDUaPjbUTiDKzrKfdM6t2XpxEUQhMKJTWcD9BgRhCgIpZCg0B27/spPauzFtOygVNOy68vi1f7lVrlOJS6UN2L0V+cM1zPLPWiGCDxxzJgMiaMjgv5OIJg+UZcUG3se/YMJDZINKIjIdM5WUZmyZ1R/5gqyG6yZnnvB77sLCKEHjOdYpYINcwhcBRY7SEBFHCqEQp35l0YvdMbONOQXQjc4yT1ARNvK8HkXBYkFUS6XzmL8bZyaMOgmVBa+gtrfqnmrOD7vDx8moPEOlFXbUoEhplrTD9baqUHRRBzpmzWfdaEmYqtWfA+lgumolRbwzm65CuvZE2jpZxkjPvMhy7OuNxJ249/6ZdiOhahDCGpfnLnMstHqRtK41g5lqx9FG6BHn9dWinieMBZI568GVaGI/QvSCaL5lztDPbJ1eOCo7f5wrE2ks9wvsb3GYIoWi+D00Nf+TqLUbWU09BZ9j2wnwleRaFsNqzuqGI+sTbnCaepf+hMwDmSlaAYPJr+4pu7SXHU4+MCOl5o7i7muftu1CzBx7nJpPSVaxWJDEfg0qvuQJui8bEZazeKyyQUDk4130q27f0keZFv5Ns6u5aR1dWaw2pHHfIWJvwiFw+R6EhnV7Sn04SJJ9vrywwCHmGcVojylllQoflJXeibjLXNBIZscMzGuha+TQbmJtHInxD6UwRLBxxPGy/icnork2O/4/n5gS3TajJtwhfP9w+ya4OZzkHF8RVD9uCXuAq2aob1R5Lqj8VIJHZFZ8+ai9XJ+ozUgMZCHgHFBvBYkBwVQe9uG8UEADY/O9GJkvlfrmi6G9heAlKG48vSTUNqqV1RqjvikJl2DKdbfBJ+ycDiw7T7wmEYCI7z5JpMbVBmBJYEnqgRxIc9LM2osiCA6gWjm+QH1FTGQpJSbo3w1UAkm1DF3jdAo74O2Qxhz0vilKKzuiBOWQFvF9wLh2B/fSt4roRS+gR4NztzzITlQjoOFcIqitYFcZqTpKuewXqXFdP39jV0eP1UZiD9dBPjPOUq7q9YeNOCGIATrxozS2/j7KgTjsFf1tjMFH+ubm4Np3JE4Fmtos6mTvX+cHc46eTee1l5tHErYD/lGTHOLMjZFvZAK5PcSXvoCJDpanUpOgUFT/Fm3Xsl03wSEbuTpxjVTRAPQw6MCNcioCSGMgL0up1LuzRgf5H2KOu0se1kbBoY8x0KB0jtmOljwwZUSjKUT/8QxqI7NyN5p6hgdrrx6j8mWMyd1nS++zZnLJI9vuXdqe803/EX9+NlPTcEJ9gGp1MwuFmp6VQWzWQtddH54NcIAk08yEcgAAeyl0D2wqCLLpr/OYZimjl1vSNDsffT3rmU0/Niw0ETxK2agHH/4Ti4zB2e04PcqPBScCjLZzr6F0mG8OkokScyBuDxcpvyDiXITEaz1rCSlFQGVsxagkZZT52dd3j1JfU4xt5hXXs2qVRJpY3U5oibbtgk31ZjrZ4lYzS2enEOEvd6yTLgM1WFD6tG4UjAoabMR5dXHU1d2kyMtVrIvE4/veGOAcRgOaWK3w/7tHs37GoUvduB4Y7Q9uySSbcxDIqw/Mc/aeR4Otokdg4xp5kvjpHjwjbERLSEB8odZ+786AZ0e8KCkd30WbjWB8GYyPhnKEItTrYjhyH8jHPG+X1qfFkpahuc4cXHqfWvoiCtjkpPqvmycruHE8dmZHjmu/dIcaEUhntywYGMu+DJhplfT2OE0cf3qonShJWVVl6hpL5cG+IR8IlU0puxUrFzoU/49oqBI9y/rCWIJ6mr9U0O5wCZ1Xt61pka0jgfsATVfKzq79cFka6plmQFzsZiwVFw0vKrXIbphzIRVxiBCKMmDHrJpnKpn+vtC4TiZoyoX8Msseuxu6/IxWC22ImX7i6e3uTRevz2xOUSXm1dytzk2fH/fIsdhIUn2OYSUwiFBZ82HJlMUZkrPHMdrNcIInfxjRg4qYsovgAvjmkD8J4V9CXipHz2mLMxzlciF4ADpHNB02KVNAdrbf/t/Pxhy/psYCUoySCYFzUC2bRlprMcoPCvxLJhluzqKZrAlpW+QA+3IBthcloJ8hMW1dRyWMplT23T2y8TCdD2fH6gxgxXOZ5uz3F+gusxK+Z55TDDgQE8liE7WM6HSkEb4dEevb6oP9u2OQTOeBqAN+GsqtTYDOgtqdeoA+QFX6FMQbBIP2eyz5KyWHeXTK9Cqjhiu6Rh8WPg0yeBQE98zceyhjrhRKFpUez5XAethCxVxgD4fbQ85uf7p7IT3BEbRY4GNvWzkYbG0HOcF4aeRvcDmxwjOQJh+Fvty/W3uWge/XkmeccI/3VEwJU04FbsFM91i0p1e7FefO8Nb0Tw9jurwvEtoZcuAH+eLSwxR/wxL3bKpYWxQgD2YSlzNM7IpHo//UnYsescx22ZrAp8d9YkBaFZbuJPTMJxX5zFWB7pgCy98E1+nEPVD284vToVFYSHDMcp9Hbd0q//m+hFxbCQbaV1wWi3EGh8CuQJo9Wj+43mDPY6e3GXJ7zH4eXS9eShfWiAghxs3UnGpdkL10Ggnn3O/nEnUyvQ2mZq3JqPKwcRQXnX8Kh1/zmDhvhAjnSqJVKtQ/aYI/DURF2arUBtQSs9K4lVHx/rji3QH68v4/MhLoVLa8W/B8YHi34/sYLq1mTOfUHsa/wX3oNQkKKfeo7TQMz4F0e6cV3HwTFzo6x2V0wAe5cAgsL19dCX+MUtOPhPFd3aAZdN3uapK8OE8urAverKxA0od0gknv9EOMgGdPk8R6cZTNJl1gAV0hHQux65ya2gF7AEDXZGlg+BpyXabUA7gY3yQf1LQv9ZiqpfJQwfUmii8nrpJ0oNov1D+GAXJHg4MuDG9/BGMVd3zzLtgA4gze78fDTsKXt+CI1IJJEp/1+zVlQZj89zBWFBuS2Lt/YsMaohYeDMimnhINY/60mrslAkeZMFjq0NsCt7kmHpzqzxQEt7b2Str0uLYtVqv8E/DqFv/XInA/k3VnKa+3aUGHZ1hgzx7Qj0FDD4RhHREIjShENjRnZaNLskt9NI2vbOHRP9MZ1qjLaaCR4hged2biG9utL3l7WODzctkho+uBgBCsW9jJkt+bi9LGXGZUm8oFec6GzdngD9/1cTKpPy9zoyJQXwxwDMEDtjvAho5Q2fPn9/4LFjfYTrwDQu2UW3BCP2zr736I37ATYvvG46LBZrIwGoqggN0svs6zF8BFMY0feSmKUlWgZk/YkeKgUM9BQPC6nQReRUMoi5Rs8S99l8MDOTB0j2cdJVaTyGkzp5Cubs9/h4aBU5aIlGZ19DLpm7ovl3LsOWOss3ouJ2aC0GHGpwzjcPDMe/YDV4y8e/SCtmAj1FNSB+eukXFki10Qbnuzr2YOGuhUhYqcBMusBY8n46ZVNvNlK91ZGBioQKOFyKJWfy395atWBWnm4T8fhDWOnPxJ0hhcxFgLuTfKJPiLwFPsXAK/mZJeMV/kh1uFr8HYfpYMf2uQh3f/G4pjAkh/h6UpMAE9BiHnK4gzBNdV3UUhQO3P2dtOEQNEnol3Yu1pjBVI3IgaciAGbmpGd3AKCiqG3LhQNkFAFOtflruy+t68HpAMQM72gEH5/3cBm+3PhAKQQZmlX6uLHvwot//5sOA/4CJvoyi4l50ArcLy2kAAl8XzciahBMdf2Mu7uhBVzJxFFXGtMvB2OkvwV1wy1Fx80+Nbh8S6IhagyG0DGSCFUpXtv+adF7Mgvf+8wQwJDTTK3CKfEmVSe6lSByMfkUR6ouRP6xSfWX7FrtaenQTtKYxwxEhDjbb6CflhIk2xs5HJodxE09MqXWH9eFLVKNl/es2gkcTvABckujwWNDxz490hBA+fAI9Q+6QvvZEJYimOPyQHoJAz72KXe9Baq+CUvzs9wy7WQUHsqeadfdS9goLbxfHTH3IwNv65cNbdLzNjISZsEQGgxdfSzuxDbCPY1Hh2ly+0+xLP3+WOjls62ZbaHCIMt4jcJXFdvH5ywaB70fRNloKa4tEQQE2yqotCIQMU1V/s14f5k0rCjpBJyGolotSUBo53TxsjZfcYVjD8CKIK1gvC/ipHyuwLWgxr89gq+t32A+G9nbgwPsaFtb36DdaOaflU36rP20K2dvZNrZgWi3+I4c7rZ/M2DYfIWPZNBuiurha/4GzARI4WGBrkmRHyydi0VbOQ+t5nhKbW+b808+0eGPb2I5O8zFUwnZ0+xGtdCs+6Bmk0VljaaTAPgI2T9jez2x6UKl7IhuyZdD8F6VRAzM7ebhrqY5LNJ5HI6WTdHn9Acq4a5c9usRrG4QcY47t6oe+0Vb4XqP2k1RBY61QGmtMZ32cDvwaHvc+SggXTifeDyGxfy2PL8r+K71TBM94VXkikedka0ZSxwFs8JE1kdz3PZG/z0SYwwPX6GD2t1KRD0BOEcUHMdMdHm2Qm6SCjpZbWtoD6vM4lwyjxTj12WUwucTKlHmkeVGg7x/ZcH9C2hI1q1duj7ADFl0Uognk0hDWUwUvMMu5buoFWQbNSeYDrOl1APQ39XhNc7do+paaBZt71w9MFrzIfuUhFHqHYBvasG6VJoeoJfc9VhJkJqJhnvgNmiglz3T9+ohr9cXqT2OpHMJhVvT1bEVKna4rdWYsbxey2Pp8TPznn0sTXUedVJ8Beb8kWmfcu6GFD1+9aEIwIJ9v7NfIN0k3mNN7OBWRMGWEKs4ci+leWhkEYTs1KpFa68aWnpVfFaun8JhdZ6XH0KlQZwmZI6N/kxLbl2B1VUf9LYj3bMPBepZSAoN10HmAgO3ioaGXaPEF/p+GTzv6CQspBABmCm6DlNsxKWwFmVs+wCqsBqqCY8LjyPxoE/8ebfJp3NCQFe+cFYRQV9nj6uqHXB78dNIXf93Hi7zpdNXStokzp+oTvKgb4MNoFBnjmVyWiNCvANSf8oiPJmrtSiOc6OfvQ+HknMOSYQB1aHN8pl3oix7Ie5MoaOKV8QBYPbkgilJDAYmimoSFKQY3WBCNa/5muLdKxLelzp+EjXyTlh6tsR/dZ/FYvEUI/Rdr+DHqIkhYVQNiNOh2hP9lMILcmJfh1rRw4iDn0gKWlMqY7TCa+5uSNhzgp25O/2sMBzegbf+kB/ifhSaIcQTATZTrcBmgcoNPsOYf/2c2CGcD2MYDECBTr2+BrzzjkDHo62HllJxTecdde05PquT+eV3xHNVzsJq/rZmMZkUz5tmOm/1wxWp/Du/y9fKVM/C6+G2btoAFDYpNH5/sLwe/fTQJwtxH8sQ41SNgYAmzFEq8cN+ggmESVUuoYBCuYlQob9Ytn5/vtj5F+6X8AFDYXO/A5VP84G8LYjoZZ6/21SqDyzlg8QbfwnTYdNAVwE5aXD72DXrPc6bhh35W+PJQ/FMPm8siODPTPI0idotDs8xg998UQmIPX2SQmSRNWXo1UMqgwWPdjjQDE4Y//7Wzoh6d9bGxy9Rsv/x7nT46job+qzlkONZK3dFyhyPtfRBHOTRFNsCMCAmTiJC4JIteZy0cgDbVN/PFO/CCWjHoXbMUeUH1ftUV8/ELoqDihSlYOy7q/tg77DetP6fw7u+sEXCSztyUvh9IZTf8Y7YS6LXnC7fPYEgfwuSoaSrMRqJa6e/QxpPln4ZJo9pFq+lCVmM+/TW1oY9D8zFjlKiZH/pRxPlL+I16xhjDg/+qCNTtKvwLq3fl6wmkFJ2EIGOtMkgF7U9dtILQUN61nT/jjULxtDGzy4EVWU9Waw8AY9H1md7HadL/8TeefX//3DtzccCE/2/TK0QHK10YQkTFTTy+WuNsrRRRq5/YVkLsqVe88xD805xvHxUTrs4IJdA0ivXcoKaOKEKEmYcsIDUulp49EaurzlnwmfVKYLOaDT1fVn0JqH2pv7vzaAeKbuGQVJBSBMZAHIMUkMurylbmrOvPSutmexdNxWkTISvTYa6+Fgpeqth0vBxaxnjB3el0Cq/Vc36hWcgHLWbHKpYjnQ3RbLWKP0UvEPyE+ed9+n9bbgEQMkk11xxplqwu4MpQn9bzTUYanSW1s/sUtcL2CCwLEttCniAEDwk2iWtF5V5VpYpXb8RhLcadRihuiN+ydMNB6UdwPWBI9Tc7PNw3WrCrbFwH9TCvQpeqFCOcEe7xqyQ4rxJexsN4I+w4hFbN7S+zU5LIH3RPIkoG0X2CZCM8wAu4O7cYg/fOKkjst7yCgj/EII+JuHj9uNMb0UfrptiZe+F+GYTvMh33sLjWO/XcnyeN9IEYpB3hFXQPRccxvx+9KP6b9PgV5RySqSjRQFQfLERmZFoFbmFBq8JRVoTklgv6I8X3Bzw6gisWUoUcccxvszPw3Cn4DaaKDMRYThfNIDHtoz/UpR5UHI6JUJyhxHTOxYVYgF/k2WjndtKWSAspunUor6Aw4MmCuV5PtWAkW3PVyTKmgH6gpLazQZLHC+x6etmlPFeiap5y3aeLyoJVJe/v+XHAqTvRp41LmKV1eHVwHx8Zyeu+k8xCEZxPXf6BiIWJC2sU0v2SVYvTjlE7ivPPSWSvSodVGWF1SEazJn4PftHH0v01OjNH1/z4hzleMLL6vp9UMW5abl6iHgbg6IrcnD1EcurbXoMlWpTBDmIoIsKzY1F/YloFRWRaCWnyVdrpdhwrdpxKNrE+DsuRhUzt9tVuT/hdq1AlX1HiGsm/2X2xJ0uDBQQk0cDZasqI5H+3RlI/BJbjrrJg+Ngq5Y4XOdFz9JAbP3Cv2C+8Z/73I4KkJAlHq9Iwn+AywcnC1T/3t21EPueVNAi6YrLt+pBc6/LVgjEUSQ0k5znIyGX+Hi4RVrjy+coaAYlzE7zPX3uw+AbahlcjsRmGr+XH/soj9VROTC9HmMatHyMsombnpASwW0d+DZpidvKfGJL+BmZTf/5THaz3NP3zmAXN4T1VUkpoIg3/2zB/AzqiOIl/KpBxlDhJ6W8+JA+HFgC0RQzW2TMzjFVw+FNX7+iRgzWMTBDQfr8xMuJHi5PAREMWOEyo/35fkLJyVDTttUcm7qquDQnGQ/KJJIkQTFb+vWsNb+r6fYpSuVFhYHDc3Ni+tvS6PwCf0KMYSG/lwGQy1Eci173zInTa172wCSiMoCHxYKK/dMsk9ubWvPwoSaOx0W6Vyo9Teh6SZvn4Kd0CHJqHIGIYxmzb8hXEMYsXoWKd/GiBmh76WWoTWQ9uaqzJTj91O5RNxSIPdw2jfxYfiiQeVB0o6npqo7XqKxfM/Whc4ilzgy2sMwVVjX/8yHLonY1PkUmk2bARljyL/DwWl29IvFubXr9K/vdCyZHXtS3KUXcC7TBiB4uD3tPnD5uo+gUSL1gPkzhhEZxUMwY1Xsz3oFwXkmF5M93OJAUs0jAXRgaEGPoUrsf+XKGs064ChlymVW+WAEt1eGL+QAJ5bLQLbyhlKVFzppzQ3XcLPZ7IbX33iae5DHNu1PgbflwTSV/OCeOiR6jfM4mju1S/d+rwxkuRhTp8OXWn/3WGmw+Ah7ruJeTrn9M1UFwKlW15OaiELTZOJCRiwGuoT4cq4RvPTTr2FMO3f+5Aj/QE2FMKCE+lk/kH/1tO/v9sTAYhsE8JJZ1PtO3OGu7HGljAqQAAXsZqDKMI+fc3AryI8mHuUQ0SwjlWFfrDes7ocEpqE4hgGx/LORXL6r6aGgFNec4YdQsKcTgf9mGUpJHcsUaU8JgnhwbkeT9FfvXP5r8ICatCwae4CimxJ43yOKgE7ZjaqJanWFLnoD7XOeRm3XV1PRkMx8VWSQd28h7LQ4uE1w1U9943cp5WhVT+OAzvJGhtkIgncoNJ2fE2xo7p2dBouPMaOGdZjNeR3sWNa63gtZ7gf/W4WtgMgpddmhmyHnlUS3f/ciZQ6sqYMrs8xR8f0fQbmlK6Q0SFJpe06NcCO65g9zKc4P+60Yrk/NrV/NNnrwu5SkpQff8cJzS8brHRw6cxJtgEw3U/tmsxHt9TyEukVjYA1nlACMXa+hKHQ9sI0c/xCL+mFWsjT7HgQovKUpK1IVpjp2RaBunAVYeIL/iIWomKILHW1WQJ0XEklApkDyUPhwF1Gtrr6YNDmCMQwvtrkQadAjyoHmGQQr82MtYpCvuNT3TArCiiiEBY149rVeRK/opMSyAUKnujbUgdwLtjWvofujENj0/Vlbrn2IDjk4PvPFUERcfgpAzAVg3gXviKNCaKVbqz/9lh2E6aG4EseAcwz+qiOtXkaueZspGVNr1unfN1mv3yYhyHDTbNLrTCxCUhikl2bvj1X/0TfumZNpIqYRERbbDA4l5n8n9/xWJfN/Ce81HMwXjYYTTQVaOyz3PcbhEWxxf5foJWIy0HRpdGnxEQjLOaR76oJj94d9QLVy20kqgfMHlKd5CUrZbo/gUNMmeLYTKupryoi2+fohGCG7hjSFLbUm6orfI/6Ykr9uTxVjBQZjU0sHeMfV0rv/tXickheMmo9Z2+/zIpMAVvhVLdqRJ5JDApLokVD5MxB0nagcaCBqJ0y20qMxupE/a5EZfIv/575JRY2FzazJZB55N7Rs7o5x26KVsDnJSuvtdeOTb1NWvVSk92UnaKvqNA4aY5aR8ilFwSQM1ajH+HD5xw7FsLexMbDRH8Fakgqw1/eZl/kUzZFWwm+fFFCHJZmUGi4Rz3GFH3GC4uKhiAStThtjX+kC5rHzb6/oK7QS7LWXGdIUobMv2InRQyzdBufl2XPZGD4vU5/PtZFyR2mec6nq11O/+FIX8IXaL+oPmNQMK6ZOeHGZbWlXOST2vKt9Su9kWFH+97gO/t9hjyOC8Ma6GD/+4wxG8rrmDk9tckIAZoNhi2ZiB4/VeHubfFiRxwarCX8nB4Xooi/dKW6Hvygx7G+d8WkkYjMgsq/1YiRcNA1LwWdxzlfniQ5AaPa1CO47y79DQg7wSTck65D6Qp8RDxC388F2qgl+g2308Z03+hxT2of2nKbw37AatSmLCElipiHHPLd+zQyQoNGyu2f4wi09I+lbnOlD7T13323cJ7QF4nJ28BOK0KNLJgQp1fmdLUflrMFvWjfGXKxqRpi0/9fcS2lNTG75eQYplIGo5Hz7IoOKYcSlQuT5/Scj9l8MNFqjbRCVLF/cJ6ar0ypRAtbvPtAtJTAgmgNum8dNtTsoM55LtgypauvwdKU1bwg2Wdyr33DUWTzNMZXS43E0Z6HC9Woiv6ERw1JMX8xJNLjWRFyJ55baNggG/PC2vV9dLsqJpu1haGo66ji374NzGAOFUrO2kHvZImOBItry2YthTmgvj0yhKH83Md1JHo8LxUQoVf+N9MweAJ6HV47+7lCgMGexhExak/73RKEIXfCHYssHyZB0Fqv4yvI7Z72E2qcOyf9ShhSzb131pl32Jbh8Ft2nxhISuzBD7d39d9GRchQBIk9k58yeBk6FqjaQZBpecBWcBfaM56sBpXz3nHYStyEg11/N6biVXyoekjbV95MKS5i+lOa+2ARnxnvRAjPE5g1D8FtwgGLGFean60R+jiYEgtveUm+M5DKZpMMZ3G2GKEJL70agIhuoVJNILxGcwogQpdrP79ivB8vCsZe8BC8Sm3BoGtw4gpM9msxV8up35qmEqoSWWvXONRL7D0m2AhXsX396x1r5KRAk9WnU8MoFIy4WNdDq/kroDE0l8nL7yHGc2/9C1OiyJsaDdMbEdg9FnEzQ+q8abaBdHKeYbTfQ6m7HKDq0uG51RJUqlTRJ/4FVPI5MB8q+ixfgg7GjmkR36T6LGRp0u83ZOoDR/mldA4eT2IFbGZtP9aKXRHKVbi4FZk0gs2z7CfK0G3+8SiSyfY6PE5MzWpcifuODBo/pdlc/AVAFQWyRp/oaFTtLiSJKIgFh7khOaS+R1u+2B/K4U98nVqXxprje573CAwDip3UVrkjIANv2S/zZnWLFtT2yWsK6Q4SvgTs/qLb07ZodfIrGgYb7oTRie6PFu9mwuTt9SXL36roIj+Gafrr04md2b2i8ArB1FVupNOjpSBrM1RxYC3o++wuZWLJuYcHgjs3O/0Flc5UFx3TB/0gh+nRixtVQfJl/qsa8rA8Ewywnv+vo9PcEMGFulVen6VAONtRwwXEA5D0ICz98+QQ/D21x0UqLmlFFZLjSTn4ZqrjhtyQ6qNY01X8IMnmT3gDPAjXjvuM7A9PHpsOTwiayjdUuvtfM6oggyKR+5tYNp+1jZ6zGuyXkBMMRqeki0KB6GfTwYiiRblptpZsaTdxDMyH7KDQ/S8zwty+cRK/K7Xo1BEAcFH1fcEsEl9wvEp9PX9fDixY0mPRyXC4lU2JksV8Nu/nNxJL/qHfDBCTsGshf/m3oIJC4zNpeHjm3b3Nc3ok3AvCqt90GK/SU1x9TtVkTTi8XNLIyzTM4gr2lfTfygv8H/QY/3sQ1xoT+1pjJtCamL2CYY3HifOYiRZWPD4+hye0xI5q176Sv5eGg2Ztkli88sJYQbo4R/kXIUQ4XUN16C5pIX+llD2PAyCqdmVdE+Dqc7XXb2qLxEIwY8QOZRKs06c+v50rgHSbZWg0U22z2WaF1ChLHRbqruNsJ5AGlJ/wGnmXwqjZJu2C6GSte1kuPy8pz+zy/utXSPlPhOyBSE4gtKZxhsjCYKWeOrBQ3suRiwjR6as8UPn+xrSvwMXuERjdpj3aeuVZxyhLDvyS7KsLKZMIqf1paD0mWUpDjeELEUvMPBcBK6W31F+TXU+UgymyZJm4cWuLWsr0QgmpPdP+j77qilHd9sk5OfZf8lH7kXLDTNXtcfWyGNQkwgpAlQ+vz6qvTa33TxXGUFMiA/MO6OAeTCvqGG71E2JPb4dFTpnVWt0pRhUoGSaTwCPEL/XJf2CU/84l5QX4r0AmeSuvor3iPLtr1+nPmRF9Oxmt164vZZoJsB9x0TMhqnOXJ/f2vdYvGYtJLxc8eUPf6V7op2zejGzgfF8WrUzokv4/n6uVeYngie9ksaSwEPL7fcS2up8q8oqZnzrDwXoxJYNYjhQ4ydl0MzPSLyQ8H9HdwWxiO8XsWWZIzOocRiTVWx2kRWYT1bPI6VBb6DfNxSDjLH3tDGNfkz7iIBa6cmMOLoiJG9UFWp2g+lUw/lbcbmCOIDf85I3VVPa6swiCiBsYbhstMqftFoH4UsJrqBB7WVArUnBHzGtJZwhdW7OVOdyR+NGGc3AQmfb4wPoVT756X4WGlXugmMtscBnZfjalXui21hwv3dw6tFfeSCwrp/QQrbk7E1S6XdBug7/wNp+INlKW0amCp3rWc5rLoPq07KnSx0uvrKhhFUgHAobQRvnQudYzOgX7sRcRq+Hz9kIgQwdoX4ghvGXEVEzTSiYXp4R/0RCxaNooK3FWggZdJnRKlYDBWH+yqFYDAVdB0w/ZuMdPwYjHHAkJMzEd106PurtM+i2fFEIsnKfq2uLuU48xLSD1jn1zO/2fIl8uUrWXd/8zzMueNSbv5tgTJjIm9WADG7Tx4OJ2DDQThYiMyVDWyXQoo+oXpeBoww1DEp7rjWOyXOzJj4z/nUZ/VVpPN888lDao7DJNLcwe1gZsm7zblTGbAqpCxz7CHem7/XB4nFrLu8LhzE6Bvq1wGZWzCJj3PDjM1GvEGvGpTcx2LT1dMt8izsDPUdZuUgKzTgzLphewvINh6VGD3Z6+ZWdeDY7/Eh22qlxjpOXxQNJv+RGdZiQWo18u5Ml/DKzOuW1o9AjqGvvhO7Km7eKuPf+dKlf2eUQpoL37O4u6WF5CZn07WB+yZo6zfr06jNS13AsdXwxbEsK1a12c3/wQ8EakJeqOl79CoodeIsRuj0Bke4yR/caAkajmu3V151gdlOWXfIG3IIxPIUvEP1OtE32Hey1dBKkqbCIq/BlGJelBeP2GRpSA+Cd9Ohv6CzwGmY187XDeKIsa0Pwxcd0C+tHvgm0Pr0s/CuJY0w3V57w7+xQLLsbaOvazyHy/y3skrBwH9YRyb0SgwL8tS07cVi+tz+LqlpTWQs892t4RoXDlrgUOmdWT7a9JYOhaWIgv6PvqPCKja507feaIZkKf+VPIKgzuV5nytDT0bgHea9c6XRbiu6hlCWpERyyWc0Ji+BWdukaPr4H9if23KFttgjtHWbO0gLqunbsh5+Vop05W/tBUDUjciZ5YlQnEE5o33IlVWGFqBXWfAUmUqncqDd8kRpGaTDz8+KN19fO+ZxxoOV+CZbQmzishqy5afrazsJYf/VUmcRfZEm/pLQADGnfYoBEvS0r2RdvvTXk9il3E+FC29mqxYwbNzzXs3H8kIlaVblTumnU/BP+2DK0JmG0vzCrJEyfh4mrVRyXqf6Ct5Vyi+wOnb7wlHOp/YSOEPXLAVVFYak22NPM2rx+Xwejj51v78IFgIoiwTNdqJwmE11Y/nmhP0PRv0hDwOnNnbCDIhQop8UuIdEfdye6KVxQ9fkB7VFH8U41A1O6SWPyDWyjcBA3o8yFBVHVZwn34t2ndz6N/u3ylofRpC8MIapftY1lyqakkJZb+Oh4U1NMP2NZ9fkklQGqW9ewMUFlPzLXX8emiZHP6Q2WGxuDb4CYuj+llxBY7qOq+TramnXb7fCw94P/W4bH+fA2aYN09WWjkr8rAzo41n8TjUJpVhdh/JLnkU0SpQ6tu6PQi6eLynpWF5ebfipnD8RyeNZQRg0M8XgBbG6c6UDwkL9zWDTwb/MIyd+45S7cQcAVd1ELIVcDg0E8oqb07lgDcZCKpxdGZeJ+Ogse5RdGhk+sRMJrHvJfL/HfyrEfVWVr/vIp4dXDbKEd1mGi8IETKLoWKFlg0WmorHy6O7eebXyNcX3YAObcJlVw7bl8h3fatImOqzPVQKuVI1Dp2ugAT5jnfMpOyPeXVEyy/LgV8plyMiFMEHcBZoy3ge8MfFyM94HMnflXzXuQ3gLLuQhRC/EBjWvcYv1Mlfu7ZHtMGk1oeKCzjxnGTm9NH7nv5VUqzacjaxLF8ErbxrYtoWjMOhdxqb/dpRihOAnIFjB6a9l4Io8xSxV2mlxscJr4M31G6GdWzt3OWFHuqMaFMqX6496qqpldCPSzI4OZDEGOuSXD/lToj1F9eIBlVU7U1lQM7xrKOBSrm9W00v+KG0paWa5IlUMLIe4BGCfWU4GiFg2W2Kw+3FeZcL/wyIJ4HAt0YqRgn89Pzg9TDtJveHPRc0VZ/u3E5kb+6jPnIpJYf1/C+IMYuXf5PyHeTm3+JqMLii6sDfJ6t6RFSnGOx8C+RzhrmhZyn6Rx0bkneg5jJ96rUZZS2nuay6JWxl3A+ruYm5o4HpDSM2G2q/TarZ08krBNjeCagwtmdfTIswhJ7gS/BvacWIlTcKhEPVwQSXOrjFIkqNve4rHhxaNuwTC4a4lXd8Ypallh5zje+JBfI7dHhJgEXZZ758qGkC1OHJNRuC78boDDzC4NQJPfh1PI1Fa5QMuEjIAq4gqybFy2x8SRjZywHWgfcXko/DRIRhBzBCZsNnWfCO2+JM0mvtA1r/tstvUhXjZUueET/USg2Yf+40IBbbvH8bdeLoKtcbY5NLup+vy3KY9BVQgmiwvbtQIbdRBlfcA5LZqef8/oJdze2TcoRf3rbGUUusKoD54XRg3EiBH8oR6IzS7Rv+/4FvE/boboKvih4vpLeFGTU3fIQFImduqAC4vW38/yVlkYraYrIuw21TjQZuhY69nfiGU/gt5khbWRCUmJNxpd9AvBLC8HdlLYOHKonenT8/JZoJ2ffzPk//ryBN4dcSo6sNE69pdmn9UxmpqyFbV9eHixuwW+lyCn5HZRh7BqU0Hq/vjZQLK3NVDIdmw9PQVWvzCGSBn6b00/oITEi05EBBLWCe8YtIc4aVAH16+9BJP4oN/zpeMpqwxzvxK9O0YdZXR/FfK2+j2vjIEvRD4/NngXPUmIESX4CAigv8xr+XS0ny1FBzDVpfS/6njtb8ncxU+Oc+iJUgQICb4OU+o/Xh+Mhe82YCshr7NznsXhutLfoKntmrNJLkarfzsdGOyzVUR5DwyouVB/9yXp9NLWy7/LKEyKdEKk3n9zeYyrhBA1ahx+hIhAbyH2CAkDqJMUrT7gapQvjY245jIrSaiGTnXn/qZ8MYYjuKihXIm4dHBsmFb4mx109YJMOfPWnSSp/p6FOBOnk7Im5Rqlf8tmt8aRJKYBWXYkDUqM//U8nlvleQq1gT/s6HneiXNMU4IVk4zIlGE0RMtWVrZ8no7uQ4Ix23h5s3A1p7xpVY3wiW+QigE+xGPGwZrhO91LXYSuh4HuQT3GYpTUsA33oj27XQ8nkn3B8SLiuDlAPd5k9sJ0oKuRAIVLlSp4F/cVoqs2Jjl/f1DOfFUWjRKvuEgzIri/IAZeGCq3bs8v7OqRJZLTSIRXfxd/C1NtMaUSQcPUSefD1U2D2VNRkoBwLVj/bM4gZgtL15iaCtj9UOdU3FID6zfi1q3zLPKimmgSLjBMBLaanXPFtKA2FT5jLwp6kP8hQmt+iJwar6e1AZHdHZ6VMYVKC0Hpaoborr8djuncfRNVKkmzjFjp40fCQSuJCiIBDrtobGxzLvZpV+lhpqISG2TpO9H/WzqP9l2GKTM4t4bex6OJ/WSEqBzLcu84hj1+49LCGzczQjR1qMzDjJfpu96Meskzx9cvP9vWRPT5PlPIgnQsDsDHQ6VfUwl8e+3+Y7z8vA1hjQvfy4rH6hOoyy76F4T3RosOKO+Uh0Si/YytVSVnllDsxa5BD/0j+r/2IDXxrXI9GiqyM9Jqx8Sh/u1aegVdMwU5L4poYaWC8+T7su65fq1ZxQi/gLzRBrZO9LnS2mZf2N1ZvL260Qt8/7OxsSVL7kna4i91vrp6lW5PnQrt2h/WjMKphZSMltSzcxZIujDGW+cvIZixFK9IJH5PqYSjh1JX5gd3+PRoyDd5pfpyCgumss1ploLXBkK7erSJ/7DiWvr52BuIS0O8bMeRt9i+iWEYjj98sCclU5F6B2xSTbsprUCizZOoSi4e4VQd+OGka7OineUn1ZG/WfGza+tMi+JqyPej8ajKnHn4lC8LcrfROnzZN1ka4iQkE9j7VgzTnWd/vpYr9g8yCKry8i5Hj1cXnHUJXtTMqfnA88nYmICf4pFp1C7S69roVHB0/5sv85NqYmr9uDzS6sxFdf5O3i9JP8k6bl7Uwl3xVy36HR/rhxmITVJSG4eyIG8Wt67n3Ps8YRk+4yqZAvWBmomcRHIeufReflOG8f2uiONplwvXo7Jz2AICE86XGX5o58tBx+Ir4nmDZlUGU3yiH3n8thgELOPkZST7YP/y2plkcfk9vbOyv0jt/WFReAriCKQkSqI6aWu4HLvjGrP3giffJOun2ZWnNxYv0UY7ltnWOh0fILtjcyN8Kk+wvx4M+lU9pEw7G65EyM0e/INvSOAwz3Ve3OZJzf2E4aaIn1DwzlONoAlU+nHQjRkl3Y/f3oPGDvSKbI1J6E4dvg87pRzixH+8YOvB79R91zaHU/ogJxpkTzb5asNhhvWaywumqKAP3lG1zRz8vm1vcwG3t2xlSfPihDkYi8xzMfP7ySpK2clxHInP+xbbUKYxDyxCGfIgJVLfd71FBVrZFn9FlVC9aN9e3JFr3XqLx5o6mO6sxGNWLBoPVwj2G8lXZYS0UBno39hFwzToYQyfW7EWcoXc2ITIZRu36jijS9zJI/noQhdjOzPWOwdde9IwY1RVdWUNO4LZGIF5GcZ0wsMJ7uBtSLfnrPlrvz4OKwGouKACnnEa1wlAGUsgXj8BhkeliOtvOkNo54LcIuVSvDtHf0HoHHZeKpmBv8/76ZYYwcYy3JKqZ0I71FUT1bUfCrOHq1rPHShNUpYMw2WwXpVeb6FYnwLHKhEJpKkZqEd1UnRluQM7zBsX4qOxqLjYPY9t1Rjw8uLDOmKPeKMt0iVaeT40ZHMVP6jsEIB1zaO7BaynCNvE+GZH/8USppZxB5AadtGqE4tuMueGdKnu9Wjlb8G6nJ01Ox03LbI8FxvgOC26v93b/KHkPQ8KhZw7RRXRwm5SG9u/flBL/Fzw9PAPjSewRi3ye/BAFh74ObLYUYiPX72mfZpOqw3o7jnC6p8EEbdbfFBN/hNI2WNBkMgYzOmoUSJ0384KhXFxPnIrqVOlctWowfrmzrtRaSMUOczw1xmhf3B2e3qmvpeyAOww+ofJWl6j8tL8TZClTisicSfaSFVoS18Oxxv2CThyP5qWWRtgOw2jgRWzf2QEKh5whQ/1MZOqFNAwcTK+G5055Ww5UaR5vWdRx6nnuh4BiEWwRIMh6N7rvEkDT7n93Pk8HYOl2rroHAjF08uCiug1ObH6UUKP/AIeoQ2LjXggP6bzVYhWw4ze9wZ7sYjflsbb/nPF8LfHm+AKW1kpNR4rLYvrZ98KwCoU/mEVSbU9nMSKh67hj/jMP2e0FNEhU1VkPuzAZJ9v6PcmyFU4jyDWQEr65oWATk7G2f/6IU4jMvlDFz+OkSSZnQxXwHGq1q3fG+l7B6MM69vH5mfUMeso0HoEh1caOrnepagQTlPRDqLgFc14RZlO691K7MEnFra/CuPK15muW0ulSnEvLNDvlFI7PEfUF3j8V+E2A1vZob3o6UybCIwqu+sO4/Jf36nlbn+x4ee7DRcOYRvylTid+qtJX1rIvQwHiXqfRHPcjNOSNXKbcnhTHDA3kEtl1bG/anSfxon4MwJWBMbBgi+hf3JBieBiCfwHAZXZB5o053NynvchWIwKoiaQ9Z0Jz09h5cqwICSER1vC0Xv6183CfWA2Q+XK5kz5PrJrKsC0IWeG9VEaXV59pVq108bjbaG4RfrDxbthOSLbR14fYYcxhr8neQ0LN1iYXJvvCRow8eRwlqLXgg+ptU0G7pKc7GByiifEq1/Z7EWl6vjp0E11Nkh0iCOhDsy+9cR3GtjC89EICTMyEUl4rIfv0YbyfjdDfn5YVf1bAnKF7FcbG1DFtosreCCD/gE5bpWqTsZi+vomTBQWgujONikrYR7Qwm2TU62CyjOxOVacLTtrvnukDzh60M4VzvCxewK9ZJYunllSTeMtItGHENl86q8EGoTmUAJniLL2MLqc8bF6V4vopB/ij0l1Vf6hm0OcPlPS/bkSU3oOzkzAFnXmQDUVBFcTGvuVV1a42fuOgzrGtJMUvIOmLMQf4uiOf5sgvDynPrCspmmU9T2w+ogRU1w7YZBAa+2AKKo4CYrcgLuN3nvKy7bfM5LtLP6tdfRF/291Mar9ZE5sYcPvKyrvVSV/0G9taO7IysHhn4fPJJXRtKT75PnvqrVtG3a6GPQJQ82WpTpO15IJQugl2DFv2hThSwapZo2efaG6jCxsn8V8Jkpp7G3Qb/2Ko6ZRwz7f3yZAiwIVLoh2m2/xxQ2j3jOnjdFXObt5/AhFnwTbs9LWvNNgV5WCwx3XKzg0I4A3zY+9Q1aDVGIetS8CH59iMWO/j4lDbOQr8Tkfk7H3hFCzO320Mod+3D6mAl3R0UlS2rELps/DZy3iB7aVRNpdU6q14p6bSQlAJK3W7v6Qw+dSJ+4LU9G06DSVC2fpeLvJIkZQ964Q9fuHJImR1h/L7P5SyNYE8p87PFQY2dMIOaPohMT/CVBg8Fng9/AjuieAuJwNhnO0GIoRj6wysKv9TehD/NletjsSTRT+ElMX1fisqQzmn7HH29+CtdpAqztUiK78b9I04Zcf4aOc5X/xPCj9F1DdtZ9RoPjOSNlDazDcZJ09Z6iOAPnSyJImVQWBHVr/q8WvZDfsBXLvz0319wRC7V7OfX7ShdguYqBJ4QtcHaxlupk0YlnCJZtt/9Jqz8eRrhao1yP1XjH0ZV86g8NGQptboKKND+55i6e/skiocK42G1u4AlGVwu9fV+9vEhxXcWEvUyOCBCFzeKD1EXwy2rU6Nx+QP/51PF1C0DO1bUJ6NbHZ16xL+nElS7RHilz6beKwwa0EXxrTLA7l4m7k8JYRP2DOfBEZz+eno90JznyIPH+GYxLwAXdLwanUtz55RBKwoPq2ZR2Y1zw3P7vn0rj5FTFPZzNxpYOsg741/sVG7JOCT3AlAGveo2kiTiA8cILg+8YT26OLkwRSUQR5vAf+c72gmxXxUcr4l9elLW8jfMg+Nvpj7SA1cjIXa/YAIZVe/C8YvtM5/p/P3+kv7DAUac9gKygKb5uhoD+kIYgQwXGSJv6eGg7CubjblPHf8j1t7thFDYtMaHvHYosgIe0jhl0UBFpmMHWKR/C2frE56UUVPs2fcIFAvNvNlkyS1LzYP/JSqJiTww7JA2S0qis5Y2RTo1/6AQyEa9etfKGmijafK5zvzA3HTeD0ZufWMwFrWhfUsuF6ke1jGyTimrIERwMtMKxHtRMffODmem3ILprOwrr6oA3teX0NBv5lvoz0xTeSoymULp735I6tDe3Xf2EzNP+NUvKdtb9pO4P0+gqQAl9HzLTCn0gV2c1WPK5An2ZsvVcOd7kf5N2ZPw/3SSFAaD7YBkzF2EQr7J0Pw+ZyZsZsttwhosRCzxyK4/M1v7xSMg5PScrGVUcH3WQu8VMITR55/2PpOrYkRWLgL+HNEe8KT+FueArv3dcv2bO3eTPdNVQiKSIkpRTBD+UQhazOGN73FofLUVFZKZtKTsWxAvtow9/+afYnT+wl1Qf6KyrOsqWioe8HOT46og93gHdY1WeegrfwHRHcHqWUtPHiN1Erl/zKusx8q/IQQFLt7xJyXY/W4KdB0zJyKfHQ2WNZH+bJom++nypwMOch8kYMxpWFqkrxS5i+bg7DmHek4phbqHl5xwdG9/tFgSv9+XVi9kUEfcX2kib6cJKblKobOh7nHGJFZYRXf/At1nwJrqr0T+kb6Ha0qraLPR5oaycXmHtLytSNOYYExrM2kumwH92QaowK1PWTLEuaLFbU563aMp3UP3nbQoRueY0Te4wzhHviX+M+MT4qiE3yMWLY8nU1x77VH71ZJooivZgn/YJ/1dvaQXlqOfHYDXJnDT0l8cSrf07RtC4zG+GKfZ7VEAJBnQVygF/yISGMZ76MfM5poX0y86KJql1793NAH6t01T660WsNpzpSHnrqERp/nKJCYVLL9nIvUYgseZCGkxzjjXtqfCrpBWhHBrR7u+SZ1vFFeE3jd7mQx18+ftawCVjAa2+0cF3LudC+JO8Q0drBCkh9njdMhn/p8RUdP06LAThXefNiRLjFIHSOtpRHRxl2ui1uCEUiGNxcFemhpHGERywhrXcsCrJ5R6udMvDpx2sQNM7TaZY26BTyLldCFJG6EHZAStTa9uSMPXjT7ZUKzkLnfPKzqd+rfrrxSbAsiSx1I66SLH1chVxQBLCkv5xbSe8ituWOwbI8f+VtZDRa62nPorJ/k4iWEcRGCUxtWmGhZrBjS9CsajnSS+BRbKkjJKntYnsmAmP6Y1rpcCSeywr5loUPGAyubltoM4zCsKojiF8CBECUUSF2gpQvix9/hT9i0tqg/la8wfDx6SkHP8fKCgUznVGc1ahidA5i+2vZ9lAYXO9FQR14tQJIPOr7JLKu8Vynb7dS5xi4but2xnA9w46sUFsIhcZ1eBGvv0bVvFo6dsBEDFXq0e1R5Qgf9OS7DDUhaPglSXPpdlnx8sMqXP/XpfoDTW/5pyWlJ/z8rK0VX+l6jin6UiEM3tMlnu91BKnFMMkhau+dkKZX7/McsiTdT8OExXHn/epT8NOiMh/cOhPrxqK8tkwHzE9v4GM9+JwJpy6lF9ZXRwMDYKkib8hOEG1/hqwxlfom5FJ3tSsLvJ0JRIE9BKx+hTI5L411NpD2Aoim9+XNHNNKLa1/Qq8LAN17mYT7gzmUZ8DSUnH/HQGDQ7zlzX8tMrpLrrb8LL8aoko1AVNLC1c7uMi7hToSWwUH00r/qBBc+78Z8M9qVJvTCfpfysfBiEMIgeP4LWmim9yKLd55p6PyvSbTAuppATK/aml8dkTsUijLKZJFSXog/f/vpBl2h+3dHSOYlyNY5GKYsdgOWqLBEqKsCaRrdx8Xech5CbpXnpEqmp04gMdlJhqGzdB/jfp+rcLO4ROeU0DAM+Ggin2LYakknrGRGXop6Caowfw4tvfSzAp0e4GbD3ltaE4CxzCc5yGL6e9WcY4elvXh1KyJl1hRBEYa+dfQv8HnxSfr0qTQyIwKx74PGYQ0H9egwquMLGUx+gZFbJyWfyLWhDi7aIMpEDfn0cyEjohjB6fyBXyDOXBq15AzA9pmyT9ySf7RKsAOJ/iuxfFMiPihjMGyHlqc2dQu5crd8yF+0nhM0gz7NI8/yKP23bIPA+swzFAvV6pHFyaw32K7IX96GDFcTfDr1c2KamjT61ekoKFmsJtYDDakJ6/m5CvmsfRjIcM5zk4TU196zTEpWzJVLr96daDxxbPVjx5p1MDLRDhIvieeXoVpbHJBZbpf9AsHTAE7/fZjSFm5F+/XMRudVThzKoV6xQM12nyBJnTQ+7LPeTZjehDHfRP0garQsN+3osHLZD+18rMgZmlNGcUkkc8G2qIM/D5kUsPoK+M/Yu9bczDBVXbSvx8LVR+x0an3NSlE0X/Syi4IZLB1kkb/sgBX8xHu6I5T9fDh6eyy7U4YUIWUPYz+ktUOOlaOxxjsi1IYh8XJSoqteJW+A+okTZZ513voz0gcwRYO6OVui9j3tvciVsYAazPE3jSuuQ8M0GIw7F2QKO2PQhZyPYb4jh6H6nG0uHySmclr2avPK7p/mbwRBdumg8igw4XP4RUi/HGTPNr/LnDXXjRfOvhXCNWz0kKX+6+RaSGOD4BQ/fUUr7oWTlwpfh+qFzPK+p7qdKtrqSxFETuANU31DxbC0W8IhjE/4uhdw6ODsA5UpNgDN7KCNAqzv6KUGSc7HwFhQvfkvcB8X0lmevLMASNLyf4SbuNTz9gSEQX3AcT0pRFAjYZHxG7TSCIIuvMpvAOLtoejl0ChuDk9ebfoVSTBldvXCDrGowfmvL7CfX+oGS/JY65Twlz+7x0ZmELMvyT5C6nS4LHbsVK9ibuX+wwWS+RGMKwege86lyuCKAnsd6vWWo0hx+XdzNk4UHk9C5edlq4XGzn9zHAqPnlFipCo1PLXSJQbswLgaGxmUCZTRcOSBQvj4zuPGhbKgJOrwRdLhCFMdLrjNzRuCjreSaomKv76ctxLqJcfx1d8yDsQZXm+7TSekaP7K0QMJKIvVzMg+2/2uF/8TQtl5zg/0hXapUUWQcV2Kb7wC0rLEklsoXsHJ4NyLKwXUxXl/CcjeGggFJC5Y3xlFXoXrpQrnj3nJJfvJOT9XKB9NzD1Vtp5hFPSJWBr10TQzE+2I9h1ti76cz32BfbA/XgtgrDKClhQ1UN+Uz/R6jHR1RazXHdhxct84Wnqn8k0PhcRC3vYEfM9QT6fTZE1ge6O2wSTKsFDYml+sZhnkQLSFMCMTOr7aJfQrcpnKM2pP9mU0phT34hKWnc7t0HF+fnFGob9Su+nAg9MJp3ZhhndodjgSS8n55MSo84PpZWW6B/R57pnDh654zEneydpxOCAGpBuou0YHK1JW59hIXzGnzCBy8thO2Mzp4kovyxNfzp8jAZkwxDkRU94oXsY2ZC9Y/NUCbX6cWueKMqt6GnhZ+UgZMs/q8oqhuUSdz1GmoH0IFyAFDFOPwpdLqIEBEFCV+mCeYFupE+hiBtWvfxs4b570Z3v4E03LL52J5QVmNOe9l+sMbCCYc8Bx7BSn20KJ3CzBIXyl0OVPOVzpQyUlGM1xo7acIAvGQnu7f6hwRel4QUQDau5nsIoa8QAg7LVBYGZ8nncb96DfiVWe2oaPTZ8JOsCoCUcLt5OojNNwmZxexsNQfXN+8Lv9tYRJQN/7H/9SAVAp67YICBhs7qYowXg8ii7YcND2hs3Q2gAhfMj8L8HJaEYmakvVwzeaT/I+vUan9Vh7IsY0aXNxE/fXDpB0yhtAoszYyYySXWC35AhBSwUJuMqmwOkGh8/mUP/WeEFb7hiTFf693W0TxJ7LpY6RYyI2IIQ+xZORCq7Kh/2C4KlcHG6q6vqei8520ZvhgPV84+EYADbpEEnJY+K+Mkj6R//lmyyAPmRTCP6k6dfFN++3vmzf5weXS/j7hIY3nY67/e7J10i3AkjosyiSNFFtGb2Tl9wpaq/tioWZZeKXp6wmzAE5u0xC+d61RfN7pYAh/X4N1MEIi3vO9Yi+YvAoYnAJw9Rv88XM7fPVXAbx0PPAQQuEx3HiLgqK1fvv2RJF3zdSY0gypyMdd+0XKnYcffql061Tq452NA7qLktWy4FH+7X615kpkckK9z2sxPCa9ukvz4HEeZmHvoI+Z5n/F3kn714Y1ckj5AHMsErpm0x4fpwqlBIltpbeSnPUO/xmvXtf6RcWGC7Ggh77RsKiqOCvsq/fFchDfCY4lR+6WzYgWt0O3r9TfT0Pf9D40JRIr3bl8XLWISXcuGe8XLRBhE40AKADGi67E92MYynefo27DC4JEdmJMrCdOP8ZG2RHPBj6Pyb5gWm+c1yPMpw5Izq3c5wqIjVv/gpU78jh+Lse1XXnPS6jgle1f+8V2T4RZPVBUQew0BTmQLjNMUs3Z7dKVqhP4lJhLZa/W1otX2nUPyL92DEfGs4p/fyNwCIxXNVEcKcg4yeYDVY4uZ9/WTGnwaSL0rjatL4yzRgPXsXlQp3COj+2RoN2liUII0H5INfVgCQsYBoAEMhli3WdT4Olg4oGU7LAZd0BgZdgvr/NoDAGVB0iXyQgy/oECzCfB3lfUb8b65gbVRUQ7ngj/6nwV+1A84cxrWHBtcgvqk9d+HsWB5oiFs4xBDtxLnDscGllkrUYlCqNXLKY3gelNiDWSqsAQYMdMH99q6XBPJbLVP2Q5yX3ZWnmnXMaRjv53KGL2xqQg2S6k8j1vHx6/s5fgbveZ/llUAduXYSeL3wbwP8N00NPVJG2mywXzGE+0x+X8EiOpH6Nx5KloOJ35LP2rmKHGj8w3uicLcgSm104Y2nBKrAC0XtKf/UiAQVVvw7ePQfJXgIwRpK4vQtKnXP+fN+tdD8pYw1T2ltXf5IrwRMoUmcrsWsjVadtCkak1vD63zMSMk48Em8JqZjB6fMQ8RqVKVpO7+VzjGricjka++VVb6xXGWSEKHXAvYEJZNu6UYl6hQwGOAPppsMW59qR3K9mucEFLxeuUAYW2OXczFcUgqJWGTZHHv2uX5jz+DrRBshu7ATUuptoVOeTXSLA5dqWhcVyh3C64wOtd9NA9I77XoiqKkYULYph2nF9JPUz0r6cfVyEa3DciBFoe2fXvwEcBfoUWdBO0zLnnLvT1ggIAyyN7gZ/Gra9/9b0iiO1kjHi0FtxTa/fv0nAJjz/ZGZ8eUniLH/hrgE7i+P5/i0LDSYI59HE9W7uc1bf2EDy9G4wdmCl9tfCqGLNjJPN9/fsh7D2EXh7NSRf1hn+0YkxlOwnY3n/GFprc00nIdB46dkEDVu8JdzaUHT00fP8k8A2Qar36T+1L8ocjcRHtznQITlqZxbMynNsu2Xonu1E68TLSnwEBsf+o2313l61AuA+d8UdohQGN6i6hIBPeiUlYEuPdC2zO5pxCutoTqsi2/b9hzh6c9W1OBfz00t6QjUzhdlHaMFczOIXts72dvSmd6zeIe4MJi5WQznjM4IPJrhM0C6Ang3R/r3TPltzibHNM4+DO+P1DAwTJKFZBaXCdyxX2J3EH5pHqD9PQQy8zUAwXUdJLmdpA6I0D137lbniVrQ+D70RIIUtdZCSheLv+kNLnH5SejDP4S25hwLQd86dqwLE8M3T/7NtaehQ/hVwm8x77R2xNVv1VFk+UMRV7HerG2hz1/F9CCIpYvxlBIaJA2s2wPDkSESvoEaPxuG92NPDHuFCJfh69nS0SYfn+u976ULUjBlcfFVkTGRRyurqKyIlFZkOIZMklybep03jIfnL6wkTL49+drPK1l6suT9ooYF3kiRyDqhn6gViIHeucnY3oVDtnZYukkRSejYKwPbmfRWD59//g7lsifciMlTlyTdq/zhfQkhIRpklg4MyXr22ixdVnZku1aeoCy5GX6x9cbwc8bAB4w/aXjxpI8uTz1qCy6av0riFQXa50VuEHVA+aVDLZLv9vbzfeO2r9t255JOkY7h3+UiuYW4i1tWfM/LdL6X38chchkBIfF8QBA3FPH+t4FefGB82Wky3j/iq0DhbiLDlJSdZ/U8E42UL5a7/rUsc0ROuoiYHUTKZkjDc54ari6NXzUB6+VFP1lmDEKcRFzlexmjJqgj2qW34ZONe8s8fMr9tI/aubDSJVR7iy48JfPeSQUCcTXeF9qGoLMXKWLDoJukkN5m/DLm1QYtFAnX36jvny9T2Mv3YeoLMxbu/V+amOgaOYChjHqE7/SS/Ct3lRv2njH6YjRI54CdOqwP6t5xuH2ndvkJ2PH6FT2DzopEHBGvRxxxbFO59BABc3fPh3mgZgfxJhDuanbR3BUX7GJ5oP+nWaSm9UH0cSC2aHUYuduRMbvEHvf2/KZBJpSNAjJzftwvdYSORM0qPrvPQHR/40m+6Bq2JIru5tErJvyUr2CHjKRGx1I+n047znIMNZsDuZ8hHQLckAni4j3JW9dUEKNqXXmMeZR+Y6LCAC0o4k2Grps0SpqQ06kANdtSEYAxk0/M/kaheAm9bBn8/slQ9qh8dILwbBBLQIk6BXEb5w17CcNsZrkk0cxtoOu0vI7jcU0Z40EVISiOFH3pnuX9YlArXIUTN8V9nj3QcEjTmn/tUd1bn7PzyQGYozFYJG6bAlsUbJLTGel7a9p9ZS6adxw9b7CgS2Qk5msxzAd32jE2Vp0f2TXbsXHll5GFuOibiV9uMf+WDJlx9fMCuHiNjiQwWCI8iWgSm+fHKqHQBSFX6XuunXqdWO7kQq9VyxHOFKp7lTEKxKf0QyHTbWcrD4g3HZSlUcr2cn+b8hTBQWnnwOdzTVtyuu/dMTbPlIdfo4hc7Qoj4cMIuO/AyoznuxNRoMP8wTbXuPJlKkmAYlNxlYfs/XU31Zf5penPxEROttBtpumb9Znp+nfvIxVmCMbzx5lpmrZztEBM2uCmlx2C0tbXb3eecu9s/mqZPWps+HNqm6dWfdQsrLx6yaQWvlf8SZXQ5n0tQP6nS7PgczPQOQLapQ6cRpMarjjn4GzV2iqvqZ8DvNWDBJqU3EB/N4syDI3j+o0Kf4NjwPUk4lL37SolgbE4JQEaU/iWMcxT+dzRFegrMmdUGkH9H3JDFG7dnS+qfcmF0bSe5RhAmmLAepyk5Zn1oJDh5ah4n/krNF/1mwm2/sKtY6vxGn++67Wa8be/j/gmrYmlm3OKEj9TYXEwoauUs8s545hKcDCtltY2HrCu1RIzFCGgsBk6cTzeWDgNWWdn35rz39hhH2mX9b+Kd18uInykD+Oupqe47eLszhTZlj4IsqP611HFCCJZQxfKsMaRmGIae0JpoKTSKyFKB+y+TiHkxDOeejXDLDSjsR7ohgr9rTMrwWc9i2IgqBtwxlJ68wFdFUjXYoqI12bFm5o8TSCnRImvUQq3OZ9RGDMJhnA792EIyPc21SeXFOFRMIWXHdOcW61S+AbyIXmMXPaOCtIX++yrGUaulu7hW5B4zGUWoBUsrDtWGjPPhDNIukL46gBXGS1AU3WAK5FI/V6xe7u9RGXnM/lpEjqQP3duj962iMZa7ijUeZOYCu80Lt2v9JxRtzuCP678nejcTopeu5EKmA1nfSwDR0xyKz3QZZgyp52vAcg9iXBjZLXquKee/FhT8yG+l3LtiDtEXjpRKvMDnUaTQvdTl3mBivFmRbOC3cD3WLKl/hP1Hg1CUgrEcDagDWhvAIwJ5EVDwJI+BEy/soQCdzc1M7dYLKoJcqCfNP+AH/5DTfA0wUYJ03CmIHTleEA8iIeH1QES2ZnBH/tyUxZmLfUw/E2yiQaw75TVLK7yyvRZBhIFFsdQMo1djEaTw1n41v1AD7COtKHiyYTIeGi+52DBfKDk1MmAN5WZz8gGHJZqKCx/jPylaYzCT4+zYzDPeTqDeS62UKR7pYkLf3cty08D0ji0tmOQMRXnHV39mDB2K+MIvP+UYjUaGapiw7bn2UHRFQYb+7Y+mXmQIb/5RxWOJwVfsrQiIPc2Fy6mMiOCH+nvSrkT4yW9CB2zWCDu5KsVd9ngC2J2WpYd+lLCgoGKb9eucrh/+B8HGRYCMgy5qe9YMf7Nrz/ueOUM/kKtAYWoJMrd3OxXAQYPXOiJGu0Qe71k5sZ0v+56VgIKcKxkAgjyQPib3cc1LMGioEEthwEyjz82kFWtzesqM7cwLipr7kyAelZlsBhfVtexnwTBmqb0d99LDiFe29Mmgs7S+0Bbckidc5j8q4m0D72N24KtqHlrIAVN1DTKUaYYo6yBtV/1VoaJzEvIPKkxagO+Qm27HGqanB21m39oJ/aofOMFgSpKROxFyjk03hbzvs7pNWzGpb5/G8A03DinQ5I15+bVSKzp3UO/ySPnzZF9b05Wp1897VBb7oOnYV3NvhB1vBMXaaBT+ic9vq8ryIDpx9qR2ZN975zKfiPkPi4V/jTV3LBtOrJl3vw2lHry9dmu4sN4vLLJfuP17Zc1IV1ZgHEq4PSXUvsGl8fzm2bBA2sBgEKYVLnWLtjZdW/GQhAa2EbMZRdJ09CusPbDKQQSGD41naND8+WiK6SKDdlYeOMcL7GMYckpEkDYk/I3lU1GQDD1Nw/njWUqDs3mp2+HA2h6zwRZBQSQMosE72kzggK3Z9LJVZSkGTT8LIuIArdOVAs2q3BtbovAUYLeUzWTK3YjRCtscOC1U0UxNdmEjx8C3Sem3ZwlDfOAE+vUDssXo/l034DT6NmEVoz51nVZltRlv6x6E6FlZazb0+tcNiKgaWT1B3dzO8KgAvtRCzRalAmtYYFizMCNKZHxOEc1txNDJ000vA6edviHh1qACHfmfvK0DDUB3sitK+Z+hxDk1l8WKkdnzgefKYJfizVF83cQf5tFWMpByOsfPV01N9/5NfYgQviA+DXSGEdrAqPv7vDg+KRPQ4Tz7i7y5lFq1nLjX5ozCevjTbGRLVLsozI+dWwE/YHzh6/Smw4NwOad+e90iKfx6DN/v7NWfwJcJ6mVPU1s8teP6gfir4AonIYfsC5Q5AF3HbPIlO5Ys+gAddz7ij6GtjMcZsCeg19Dwu6eoOokQrZY38NCzLAYeOckz5KjhKTgfhkr6kGWK/n3sMay5xP0cC6CKVLagmFtaUlyo+fRtEexHKrZHmaGnFnG4JU++CC/4My7IHP2b8iDWFl51+wtyXhgYKzWudpY/7nu/Hi+MYrfYbB7/es76sK2ZfwhddVz9Vfj1MmcNl7a+YtFwO1lHEWqNI1+M1bXGKUfIDceOtptRJx70O7rVBgc90TD3zObaK5o163ygeANm4L58J1EF8Mi9jd/wQOkvgR6O+TUv5oaGOzOLT8Vh72DskjsbwLxOkxf2KTWv9w24ECfH/ohVXO1SSRukt1yfX7c5b/1V4A7xfTEgutCSJONyd4MGIrS59MUYWmBRin/0nEirvJ8wvdQO4RDnUnv8Zextu0Pevi7TDiwUm7WpHA19Duq/WWDSOp9C3om6aZtruFzoJIcwTmCEOVfUyaJtXG4q2E/TJ86J15dDHBROrnPvuFTS8JoiFNO0O26zu65uOHa/5sAXlugNRglurN1eJ5ePBD6S4Lc5fFVRcxOtWP3haxXLwzqsMRoTExIlhG9fAOQEIlNxeMVZ7QSeB4syYQoJ82Wh+LzmZGNpiwnmvFtMSLp4B8SHyYVW2Qx1PC+pTZDSH08NQFDVbGtRiYp/xuODTJIpn/MdyFmzwWsmJ1l0Fz0ocS8p5rnBXMH0/MXEun0Qz3W03TRN4AXed2e6UcaH+v1QHioqM1z0NA/xispSm06dNp0m5Rqh/UbiynXRsqmnM3vbHVEYDleNELiKo5H7JK6cE9roR90Z/jmO/62q53FPjDd94SeUtHFDmudLBWRusI+feUzBopbxYSQlcFonyezCVbDtLhW1nxbjsPo2/FBhz06SVudNsyy3aRMJiOZsxF0uxD1y9WhGydvxuBkAhxAqtO2MX9wUk45TfBzqEsUpDVKh+zYWtL6OXP0QRLrdhoM/PC+lZRPA8jYWvvnc5J5Q69hd5BmSh4KnfXwhUFUxIxY9STslf/KHB7EPUuAyTPM4etuo8NuLGYvwTiVvfSbOBMFM5eLscFbJr9J++ejCkjEcd77836hHI2jwlAiSlQk3/G8JXv65Vc7FcZ+elgfHyPuPvzccz4kNmMzjAJiSxRbNqPJdCLcpJkX9KVMeqOXMEFfUqBJFwCWKc+coss0rp+E/rGqlkyZLINsWHlas2TvZfqX8p/c9zFiNoMLcIZI2uTzvm1OnR86ECRSFqXQiaT5U30t4TR6MipKPiFr9/qrH2dEQHPSyWYlxyss75IsXAyAkcvRYctXMzflxzukP/tjsJAsRPIgzuRbGH954HYII0QTTBDu/x8HCwJ0698j0rpEm1/LQV29OSaU7Hq3+mDIh/o778Nh68q5lJeEexZYuSquCGZ5/dAPOrfs2w4zbCfHG8FUQ8RROClMeU9UD+dNtEEugXX+teK/Tge89TdAPpB/aV5PVvAgjD9RfDhLDKIyIUbAgF2Bk4nI+fiWF/iVvcQVCkaCmADRwwS/HcSfp9u4+Y2VG8OFDwIqgg4z3n2SALK8CReRlXMPzQMobRITPP1lzcT5DTez5an7IdghjMdE+RXKNU3tPAu5Nee5D2mZ9v65Ylrt5/zD9Y8z/yCsAWykQRPS/Aavkld7XOR6IQYGNoNYy/7g3/E34xJCAMvnGw9OP065UH9lRDSYKQh/8JqF29FFroenKvxK8y3YF7iY55p+vpRWf5WEKRNXYtGVIsMcn6Y2kpAGD+Knw+Z9wNMjz9m0MjHmcn2xPMJ5Soj9AxAXgw5/Tv11MHm25zD9c2HRZSm74XgqJY9KyvDbuXUgB2VGN0aaz17Y5Inat5A8TnFWvEdDZg1LFslXWcIuEqvCG9J0chU5PuALrMJL6V7MyDTvOCEppJnN6ivelV59Ij7BDlGJ9mftpZVrFhGkQ8hK7dmufirXx8V5cxecq32kF1q/+N7jJ8JQqo9EFY49pDSnEVPZi2dGdVKNMcX4Q1STHb4qzUMlGzEoM4DzNaSMb+VoXkibZeK9/nK4cykZL4AKs2nmWxkYQoIrmcaM7lKqH4aqhS+sU/bvwi96XkRpX022XuD79DelBaiSYL0lKOsDUfol1EpVVILhzyaq00KiDpzZhZHRAmgl5vgrtY8/i2mMV0nPHctVN9Zq79CnHbfw84uJv4kNotBBVdFa0tGUf9dhvL8q+5PdopgDihIhNmvD0U5CnJZSQjOyg8Flg3FiF45VGLkceA9+DzuZMX1QEGEr5i/dWloWmV8x0HLoZ1qboJebGhnOrpKVb7OPtzc+jCkJT0x/OUHfr7YmctunuYM7qyMNS/T70uPfoa1Y7scaYt/YtMDplo/zCFKVxA3DsvwjKqnb+8iMvkOlBS8uOnf3rfBudIgzJ5uM/2q7GNF2wUc9vTrbIo0IOQTKBge/rfT3kWh/ZJNm7a+HQlN/irHMCzlRW2kcRmlF06nEndUQUQWN5SW9kOjrKfT4o73PXMpOaqEBBbK3yb/tTA0JOSVhfB73QKadTiQUBg8rmigUw8KU9syQkFli5qR2lVJB8BZElGKZTgEO6KEGI91NbyI+H58bwhAIJQPg0FSJAMnOwqbkVVMuk5IuLUJZF7+6hodi6W/PtRliYgF3/qXEarifD/PhSN0Rnv17PEOZCFj387SaWwyQrmKGBe8duAgHn6CLIISVWWa4Kpn0pOWFbGNwpuGzHCLtPJR6SX5P0WmbNiOpe3rfpNHPVlxxBuu1C1PglZ6HAsYly4PWEI6BPMO62XIZvpxqSpaewrAR98483Q0tsHnSPBzCRI0bFKSoEBL0n4w/3InPpG6YRx4G6E8fHqmyrfF1brauv2nCsArDtD/Z31a8Sf8uvYqStjgeXHylVRVQvTGbdYPITFRnhqF7B5LmV7fFdsJvheqI4TzfeTzklLeI31bfUIadFdDu6XxrP9oSVjhd2xXAZA/2uxFfdacM6XfCAvMRptH5HNqgpnAvq3JkHJmXhNhxz3+5m5d7aEe3Vawpc3jFOiD/MT0pkgRSniDNURhw+LuQkBn6XwPj7cw1jtSNyr56D/j9ZLpfLUHWzfJFKJDKLdcfS085Kew8qPz8KLiBQXLH8d3yTtAotuTs9xHlSPeGOEZqZA+ZIlCHyo1nYbV9L+kYCYh3nvj0zPeQ0e9aW6fnEeYRoF/lyIo5OJdPsufbEAxfX5lsc/gyyrMuXf2tZbFzn/dAwSFjcsczZ9y+UkjgVXlEE6UiM0ydA/XJomWWwy1dbVNYiAE/f8105ctM7IP6tNLKU1b0M+L92baVP+Q9zOkn+gRUr7gqVUdciQaZ2FhStSo9xmRmvyIIxCBVGI9gTy+ErHISmUQcAV4teAtzXSFIyym7iZONox3b1pQKaI9x5oSEJUosEyehIbCuVrQnGnZRFECfb3slAaUkamzmc8tU4K06QsBbTI7uNKDf5jhCxQcn3IPgBYjQhLyIZKyGbeWJ+H2eELb3sJhS0nabMv8FYwOzjK1Sxd+GNWhwY4kMGvOAVblMdCVJN8S8aQL0oMx83mszUqv5+MYL0ClwsCB7doOxtNCHUulj4dOZjqpvioTLlyLbvPfAT4C19O145EVR1hVpVTgmXDkp2q80g/6wdPB+OI/kyfdA+2sFji0gZ0+GQCXjJwmverzlk5ffdbiLY/RoeushDFkOIcMwFSN0wmssISvNvYfIK90cBFIghCc8+Coh6KYjyd9cdHvuJYIHBAG2llfGgVJQo/7NHiHjVPclUF2alX1f/3UFyrxt1KZ3dDBiyqMFKaW5VgMaqerD0IXEZi1a6Blvxa98a3Q9RaSPoGDhr/9DuRhrSLysKOYmL+pev9LVuZXC7J90rDBm+d2xGwEqY1SwqxpQyqQBNHzafnWka5EA8dsNL2aa0VsW1oF7O5CoZsUy+6PHVHpB/a7wMeewF3SHd3XLBTVRnvZ53ddl3J8r9uYarLGL3efNcAXTkuPP1p5VlDfvB8fy4VZBEaY+aUMQck0kaThtolwrwcrVwicpQbmpxAvqTjvMMIzxTlcDzhWZf1e/pjWgaiZQam+TKZUe8dCSLxtkh6eKZT/1Qe+n2okNWfOy/jagv3ABdz8mbCouUGy4xzs03iQbutCP8os1NwceKiHwOKLebfkO90gku7YKNSCdDSzkFsif6+gv40HHFjiKlHWHAPvsmMDIt3tmojA45NFX5nnSogLjWBR6RgIVHcu/uz90Ba38edRhsgMOgg7hDZe18kDTz+cQgQxdH8Jvzl8Jr7XRn0UWxfoD63fZdKDkAetRHTHQrZJk3DPST4NoK0xtkXawq492UYpXhOuJZmHhoCNmH5cdqewaI2F9NoRDUV3t0EsOQZp2SI7L7ya8tqeD5GvhrqTgsF/kgOyZ/nbnqwuAK9oGrWEo7NAiSNaQCAoDBAXXMHAgT7hvSYAN7exfrc3XDarjkxG2ZxEwTrm8dPSc0aI2MoICZGgrcTHX0PL3x/AfwnBBXMWl4xqoOsXKw2Dj3QACWzSev65jWlBClTxo5X3DcwhqYWL5G8T1iEP1fBn/a4N/3RomB90+JA19Zx1sIdF1WQQ5gdH+H7QxzQGn80pvSJro1BM44gQT3chZQBGJRAfjjX2bPCU7UJSf2JmEo8m/bpXLVPHw0o/zpIvaiZIJM6k+PjWiGx3w1ydD6eIDMdHKKqCN8gUF5Mzd26gumPo9KVR+//YlEX/zD5NT/r46eB4+XQpkWHEdeHGCvFwgp6A50gE9scW/PN22GaF05S3OiYQ0hIIGnbqL+UsF1XVs8A10Z+0nW6v1by+W5qwUw7/RuGDXhenvdI4Pbf67T/wdZWb8jC+cRhjCMbD1i4I5ujzDwCCd165aYVgRq6MDIjp2qnHL9qdt/tDU0glfm5nPqrVE6V5uvPm8gHejj0TvbuCvXNYykrsgYq364pZHhIpFmOtZVSGy0upJhif0aPKXcsJg3VU/sWFDJ5Cl2lc8BVDeBVUP8IbYtVwdfkS51vWSBylW+DhicfaR50uHa1q4GVQHlzf/KEAA9z5MZNf4CPohHHH3S5PfuEQOR59z9vvZ4EXYx7x9aU9tv13UybWg5cjM2UMLrpoAKp65Nccp4O1DLA4C5dG+9BINYaK1O54i8Wc39Jc4pj8ll6OtCLoaAszUeKa8JNGD/2S3WQphRLJUFeI5zgF5n3ROfM0353izRpd7JsMkWCfJBfPBAYlAWmNB8zvi52nGp2qjjnOzS0noqqQHIm0IaOtFJs8sKV4XKz6xpVtS/8bJvmnnSFWI98hMQpflADb/QtxsWsf3oEEilrFyxzNo06o8i3a79EU/vkoi5LtKJ0Z6zKHh5dfUBob6CTKhj4x4KSSN/vm1RQOixPn0JBYpgaJuf9Civr9QUj1HdenS+1bQrdcG255RSZveB/MI3T+m3Tdrf+XN1+jhy8RCG/i9b51/NzAe/ANS9YMEQUSAGmskQm77egqITVHafHlcdSH0ja0ICj0WDQbNIgS0Fn+lNfpvJranjvQbA0CQKEwMBoco+OR4L0JCou5AoDwYJiT6O/13JQUUD5ZSIkKi+mdd0CRIYej8FZXxOycMYyBTk7ZAVRxr55QYrCNCdi4yP+NffeYxUPgvUSJK9rHt4JlgKitvpOJpb8X81RSwwGwig2kfx4aTNDFQZsrM2zErCqXa+PVNfd8iZwEAz9lYFHliPi+8PxknZLywJ4QBbtVdHzRp2iFuywS2kVdJctFc7iNSBzGp+Geju5N8FJgHMtDLso5H3F+CeHqTtwUk20FxLe3L1DTWU/npbO1Sdl/dt0ti+7sJQzLt3nMn+Jt0PxSpfd8dk7alqrrv4RlrXPjXawmEyk2epo7mT89W7QzkFox0tfn9Eq6TWJvI3PPhF66OL+1eM8rtQ8fyGuY/exx2kcrskYW/E6hhCHfh9J/OP3YuIfztCsTt3vDsb+9qZTBhe59rlnJz/lgvJHczeS7GgBU3f3h+xqw2E7urL2CYpzA39+26TMN6phV+Fj/2DrZvRHuPetAGLEUpDwd/EvxZBw7XxWKGJYGyl2F5TdBmk50q788aS+pLSHtu/GHr98YskV3y7w5J02deRdMhDa0nIZI+YNOhDWmnn3Dr+VX+lJzxbFze3UruxvFM3gLulm7M0WzR1DVI2EUooJL7gh85nQUJUVzRT5xAOVHF/woaCqgJAR1S6w+l6uH75gdkP/6YKmDCesl26FIfNFPm6G7s92aAbaisDwJlQfgB+Wtys4LA54gzSHtB6RCyB88y8VmmRGJVr23ly6sz/GN23s9eQ6GTj7Xm9O/USHs4dpZZxQ6ZLlsSa+nLElm24R/DIc2KgENzsgR5R4jlMW+/iPPn5kTIHp2awJr8b1RfLiPW9SoCTAar+aAqUQKG4gB+O91+wH/D7vYYk0aXBE2EhgO6Qyo4QtSJVHnZHISyci7TcpFi10LzYOyG1IrBA2VzcTmGhd+rY/scNf8XLCBszw0dJDUBRaICGiUW2Cd+cQyOF5z5h/x1iK7IHX6ahCT/LYX/h5IgePV7WaMg7hwh0yw+L64sTUF3Q70C35wLZ2ZCKqtoww9+hvXR9coeFhnOuRGH21nSF9HbBMq/4n4MH2rLBpAopc6/hST84OdJVx6Puz+GYlDndiHu/FoMpYbh8UOuNBJDq0nIyhC/ye4VQa/mcpHasvzVvkNV8sem0cOFRU8VxYHP2M/1sdm/6dSP6y+GCkjW5s8mUrgK7sp8qoFh/2K8rSP18i3r8m/E4ek1916TMSPCYBTEcyaaltzjb4JF+PspFTFy6ig8x+uNKirNRZ5OOYtHwmS2cxc3fB92wfTUu2GPJPOIP7+FvVTSyTCBlU9RToWBj2a/QFfYDdzqyxA0N5MRhCI2qOqXsjjEV6erHH7FEgiJsCYuTAy8aaW8Y0o4lInyBPdBdS3ZdeFoGGtfKPE85VuqpBQEx2sag/bs3WgvjhLSIBivW04A+F18J3g204N+DvEbYDjb02HMbKhiS+JEVeGjqsqh5cznsyS0/IM/+WUAhsSlvhnUqCVt8A4yBNtxykXiu9rXMzLclmnEN6eXhvbjIHlUoqfZ7yX0Jw9PevtRHVWzvUG2E/X5cgNcbeTfSLppCvblmjfPzGk+P9yX87WBZIJgnEfh5/ImMQL8t52saqIWTqO/7E3BdPWHHeIil7MZD/imgvIkK1p0iI6AjcDAsHHtr6ED8NGQxP4Gd2yFpodQBLA8BsRmKEGxGdtLgqZE5ThH1LQy7voaff3TkxbSkaf3qQXowy4n/jqaQKkbJmit6AVrXQtNigYn618mNXsGXIiyLjdcgmSckj9Tr5R08rfNsm/zILtKhzNstdZ1b2Q09AM+ailA0otJLoHxXsz3EBcKx8d+WpNe1ZiLkWqq0Xk0zKkIzcRy6xLxgw8oGPw89BuUs7B84HI4k53c7JivrxSEQtHVzbYzEK03QQYGLH4ShRgcRwLSBPIVERwy5kUKLnVQHh0SZ0n8QrqrdFyhya8BXCJYSCC5xqrMmMHu9pYERTl5Jy4KgSuq+/yiqHSafKqmWFOh9fTbNtpyBZf4nPDPBHE3NS7rl9xeRDI1iaGVNbIsgQGfEcKpfIGWxgVhhI1UitE4P1BLleksuRJ43+5r9F5pOt6ZPAUYcisYDVTZPVx4sPsvQCpaJ0202bh18Sr90jvTJoAog1uo67748uwR1+i64+6G5UeTZnPOHhWvgsuwM+xPh020KSVY8zb/cHvQD4YOnIBbWK61v3/3FZkRpr4GXPmtJc3+ldWQVRhrTBhJc+IOz2CZZZZ5JwB6XTzuYQhQanm05YtJwf8KH68NhFdaJQlxojePK0r83NoihH/s0o+nfksjXNb2gYcwDXyzJ91ik1bB5Qpj+70KcTDN0abUFmbX28KnEP76knSNnSfTjCjiWNP20uB/cu2EtYGFlaCb5zfO5J4+QbLZoFkCZ4JznHZzO1N8LiWSNG5qXkgkk9FcbcsSbUxNGy7mfr6pI4wDHhHD9ookCbM5NhpYYUo8HkpB9B+9rx061S5zNqAYX1MONMc6o6aiRxkCfH7yXhEqaWSo851xJCtgjkY2E8GwBCEmBekGo5RlWy/2UA6+CCG3vNhJ/7VLWLTKdubvwcS5HMvPXlmgjuQQk9RgGmxV46d0lnW1S5eEkvIvK6Wi+0/OEhAcTuqAP5/GpyHzNswvQUkb/fxp5DamZww47whtW3KQeZ6wpIdoE/VBb8BWnxv3nb8uVoCUnD1l490WTjBo1jQyBGY06WrzN9xhcq9FH2XrLKUKG28ge07FvJnf2Q9ziiHgaMUULVQDAPJLGGVZzpVOThbyHInAWmB8gShdMXoocx/n2tIP5eUvBSWAuDQe50F7YOXG+ySjeUIDxY9yIdR7BdzEMJd9wB0Yg5faOzLOXQR/T1p3ISvV3yrj1QHK2KrRX+qKBEGKOKwPrfPkKRMZq3uy357bIq72R9A0fsnWHwVH3VqQTVDApfIY3a8lf8oWcMYnVy3CnPCAW9UA9mLb/CHfxjkatpLbtSJhqDDzuDfcuewS8tWzF9f8zJSI9zmob+JnYP2e1Y3GDGaJSCT0RlRFSLARp6e7D163QmgvSuWJsED2PCXBMNN1Fg3ALXzp559T1LIi+xSm/sBYKNUV1K0nE43TLe5kAgUQrEEspXAcr+BQ3jyPasTjSVv5OHN/w3qzdPhC2fNBskhTJ0BTOr4WmQntAuJwzzWHREWWaDfyFKx3HBDi7NHAPmz9eUkATSVKeWB6KMZBgyTdMxfwK21f7UMEk2IJabcuDk3xmsRezXeeW6y08mk2h1hllcWFCIrO09k4pB+MXIby5JnsoJs4GcNjouhxQp9U9qQE5FX01zML4xUjFY7OL7HzXnnPUfAwbc1KJM3zemMVgPDtfg1LRg/JjQvpQ1fUfdE41O8OVkZXhkJ4dwZ/I5xtic9aROAaQfbf86Ujz+ymoB+ID1tuqAmRQ65YLPTK1xZ0JkNmjVVdzQQznArIYMz58RjqHx5uqFCNvH6hG6AObVAdJga5ZdSvb0hF/LZqjkOUIcZ2sbJOEbZif+sr1OYsvBjAoKX0vKYLws2cwLwv/T3305y/3cT0JxAvpJNBU5UPX6Dh54hhGJf1Bcr7/N09k6zLPkBJWmxiXO5KDEQcOLoG7u5PDnz8RJxH8VPah3H6rfKqklPhH0Tm22ShdVImJOzVkKCMEuXcR+cK3xEFZREX6V5pvbUhn5zs5gEC/GxQlpWnfNZ/qvar+poj+Mmvpcqk7jDxiBjf4H15Qtff2J7a0C51jauluf2tMVxezLUwiWYgkluKJTOt0CrIb7ms3rDVOba2ZKurg/pRZZCQQgV1jhvCOlii+Vv0mv0tn0hW9w1YpzwzDxK3X9WQ8ucqkqfIe3UwELqN1dWIf2sn66N8uLgb24GrIffzTc9C5iL3E3DSw67Nt3ENvp4M7/Wgbp1VA4/9s8FcGw2oa7+zj9snmiNx07lGNbP0WwtvSquhX0jJr32iy+GYE8/ZaHzdQkPd+K2vvO8lpdYSXH4+LRztla5RYvCQ/FUtRBtRRihR+2STgaY6QVYj1e09fOCLaUjBTpW7mi7O2F9aTh+vZ9RixRb2oIZwD2gkrmFKFCT7Zn5gTCwGyoxzHHRW8zP+xBfJxoLFyt0B3JT9gnrgAoyGJE/EejUudubkFvQkMqAZGRubNfy4j7vzzo8OlJIwT+3rc8M4E/D9IFsApCIpq5buDT5P/4QgQI74XuTrWleomdgyp+ew1ukXc0wF5ENOpkO+k3uObDn0Bnu3mD3s02s2oV7DOFLnZ0TeF5tykMBEipIx271/cFSAmi4KWxxHjSqX2dA4Nn/bkOlmFT/Hd9HEJW7+C9gudJFflI00yUq8cvPCPMJ4tpzM77wNEgsyso4HR4LzYapG3/4r772aWFeSNLFfM493Ax7EIxxhCEd44A3ee49fLxTv7dH0dI9WIU1vKFYnzolDFkCgTJovs7Iyxfa9YS9IGOo9l6M5aMIvVhdX/Wk+LEVJx53Ypre1+wb4eMN2QXYNY++2wh4RMrk5PEO0McFq3KLD2C99TmjrlR5/e6rmFZAx1GINyO80pUGHw+hcPCYxxbNHzOjYPZEcAGm+wZaQyM8zrW7G2V0f2ot/WyoSc4kwFS4eo/pmVXQhzhpS34AYha/RR0xj3H0/SIZ+OHlqSGENjuXt7Bfd7c/Hxx/tBnzdQs9u+Itk2jNiXvihxVIDhEECktO+qVEjUuuAHqMqxsvUXkPfdV5wvHrlR5+wiqSbG5h4NHqSZHtSjH4CpRDSn18wWjTGupNUhpEuv1DkXiy18yCRlbDPKwymVkLf52Xsld7IlUSkKNg1oPwT+AZiOsMAUnPEelGbxsp9+QqGlXysyfFDpkAXNCECR/WnZBu7FxRkLM1v+13aygwOdbt5lGa+zKO4pFTFhnjt0Xk21bRTP4ri+j2Cnp11IAMt3tLqtkOW9M1rtkMmnfzZimp73ljS7mxWphnt41L1IlAfIBvTzWkEHNOs+Za+J9HR6yjEEKXqjsriqP6gFRp7UJn1FZmO9IXbeeD5y3kEWb3WWNXovsT0tGOmQcPOseQx4s5qpjrLwMpoUqGj2ToXmeGYiIYKru/b8ne6KHD/micZgr3C/NxUcR8C5/NAul+iL/82ppmDM3+FGbw04ruAsF4D1qfpjAYmS8jvb5x5M8prD9Blxa2EC5B7hiGtS7g1AoLbWxCgSrc53e/Wqzw/mI1hzNorOqmFwG8LdGir9Cpgo9YlvdmW/OM4ZoJym40lfGuJXWiYbPXtRHFMxl4U9NxrcAlxexilUBHy+6GTlFOreMNpWWxRtLhO+/ya8hG+4+kc+LEUg6QnSfsNk3bf+oeizl8vG69vO/nVsgqCX2Loac8EqmKxABd8osGkjtAqhw2tI6LRVLcLvN7FnAmjNZknPBVv7uAIa5pMuyC+33gsyaUN4asx3+GLCTZgUGwrrI9617ux/Aig0LoyZGW54yH9K3LmGsMigCetK1zh1xJlObcjuAqRmWWgnB5ZBOIT8K1/121X7oXzrPvo96FNFRasD/CTmoa+9wvN0oWnd5eEcMsdKr6KcyjCIpqOtv49C7LuZfn3M9l263uT5SzAgPStvjLYuw+8HEgNqcFAVxLSOpF03uPPlb9HSWyiT262H6U6ysTo0arfP3MOMLks9oUB0YkuWi/Uf3Pyc3PvtJ539Qmvqp/U48cuVDOZ5dfHqGaTAReB2TnxqhbsLKYWYVZtesVr6sDO4vxFeYyCzACSgaj0+G9bLotZXp0jAP8egPZbctpWAvS1Rq7EUpz1mHll/UqA7Z9c32g+DBK/9gXYIjqTEcObYziayezaVo3Arb/SnWBf8iw6sQxEl5OPi6aJr1ryMlGU5uL4ALcTkoPXD3AnDZe5zjg+3jYwPS6CMw+aQrxlr3Eyw4nn37Uqi3XK8HjoHF++Rc7CUviXylEqamB671cdwqyahbX2y2vATopZFxg/QMxMeiXndWoXdX02GP4YpVhXFQljzUERWvBRXPs36hOpUE4y7V4hrIIDnLbFS/amBMUKPOwvk/Y2ioWy3dPwwxlP4rriWUAXohtFW298tPDm93UJ8ecOsk1Ljob45FtnxKZy5MvpEDdZEeL3s8As3+nFkbyU6UA+O8WDDfc3yQ1aRcmyiOOD/a3dGip/2WD0l2nQFsWb/GarlzTE8xtDC37rQRYx6lX6KRWNZsyjMeUkKzLs3qnZsFoJHLy7OpKWUEOSBGGn1b3Aasbte4Msqu98bi7eCCgvdWF1S5yITrVXO0dHzObMyC2ICQwALWyc3orKfkOR3ZZd0TWpnu+3a81K9+o2LEsLAdGrdqa7Ca1Ipl+sje1AiN1bmiKzeDi2MUakr12tgA6QPIapLftVcxy8wNOLJGgbBCWyn3ehUTmIMhi7fu46qMj7GSlKkQ75jz2zyLey7SlEzfxFRi83o9HBmAAiF+EHAxqSujf5jhJrQhp+NtVTNWq86fJKG3xwn3aZFTre3rdK1EDrGhWrEHMYEP4+H1P1o5AJKViu3qFioIOeK5wp3jYadxO/vvaqjhpWWQUTgw3xJVbmkheuqlfJJGlOyH8rzol+hT+Zy9DXfkJyWMjuuzbbxzB+03lBcxP35UbstQgZSaM2Weg2qZT5SviZXoUzMvfBxHPeYj0GBN5NmEdxNkSug/NY5SkKeuS4KLPOlw6UfR9IPKSfdzVLh0RRZ0bHRe8fltFlzFRsUPmIh0ERBxgjby7JSjMglhhGmvMM7C/YaeSurjJp3nj3CGlAsp2xvzQCCNFaTX0lhcVI3WuTHf/tTDpA/Pr0Qt0yOJ857TVL6l9T8SDLHWYVpK0gqrswEwxfepuO+Fpk5XSRAZGWRJKOl5ZdA69AtKppARVHQLcVgjqg7wVDvjTp7OZHsfsBeh0H/wp1Sgn03JDXoU1u+lUZlRIV19ZMPutqlZj4xkVoAYfjax92WWP46vf1PkUDryQS+uDuo6utyFr3wocHmYSvKon3QnvPj8xqX7x9+YectDraGLj3MpJRuOWEYILXS0ZW3Zs9sQ+n3hMzKNraGTecg4XiNyaVcZakFzY+gCOdE9JjAxXCTsKKzD2E8DDGqVhtM6Fq95xxNP4rklb6wCBhd/EqpUK9/lAZj94oNwOXa4GeY44Tr4kYJixVOUq/NamE6u27R8+v0od0dIG5RbH7vN0vurhs4fOXHG1v2WfVwu+xxe74SVRJX0IBliEIYnCR30YDs5PTT1tIaZUax7cMSAaTdBakkNRVbsGuJLQ/06Gsqx3SasNsjkabTpmFQtB4+uqQ7w84u5gzD50IEE6/a5AgyX7JZWGSZBi91JBuCToZDf/UI/g0d12qPdJcPUQtWDkkxTjuqLnCnS9Nywd+eCZCf97Nq54ADI6EfZLHSRjtCXLVlvY+j7n6SSMX8c41KHHtC3/nmUPsuvFbCR8qoXtbr/suebKTKVrJrP5jTv6GqDT2CwGXtS/lwOPwfMhZR1zyuE+UY/HZeYR56eB5T6MLfcXm6NI7ZBbw7XVyVZ8xwyhKfrRXkkN/v0ujp+93r6a0tPdNJC3uo06AMy6OSorzN+ERgTVsqcvmhL+CWFvo+dJHkmq6JqKIgbQ5OO88M0mHvaIPBvlNZcOGW+ptRBdU0awwLHZqaJ17wU1DmTirbpAfHabMpCsd3ns0v/guEqFeqapts6yo5e/1rlaA2Wjti7njOMcq7mRw7bqv9lNnW8M05KdiZcUI8B5PH5lbetVXv1lNJayPZjaJcDbT7ocTKcsfVLEcm4zrtAk3GIRcIDsdrL8D+YevHFC7AXvkLVmJnnzfyFDctQwcJEGiariwf2ijiomxPCv2rpN+3rp6yH0Th+xf1aCk/XaPlMvVnngX9wnFJXRTe+CI20WLe4QtdOOJ3Z4ijx1ipsTvtGqPVFPdO79UoZEt8WOFl9sjy/I9tWO4VsT3TuvmZOboHfcZC4Pu6XhI9iTGAn0cyys7sbNHXb8YZIGzO3ylNxrxQcAgE8ZWQgOYVXC3b+bTOCCwrF1XFt4ZiuRDjKIWgA8idxg3yJJz5sghbnS8cFxDH4+apVLjsTx0Q3LNQGSzz3F0n0qjilnI2BgR2VEe6LdKy05zzEGLVqO6cZkZQs2p7+1IKnJfkt5re3++evlmfNuaqgaMtqlqPjt15HMdbrB/PCkqGvvyrgPiyk6yVpCWjRXGU2sNO9Y92EMfLMI+5q5aINHsuoKafcy5DkEAglKZzZulNtyp+vxyrVL9Nl5dxSNCvCSpZIz34QALIevUQqiicOiuaWunKMAtX5bmqoyf654+Rrxt1dCtRYJT/bIFAkXtmQ0CpaVTFgSQW3AH49MgMUX/Gpk0tDf79MdzrBgVD+AvXycPZ/ZsYoGTlfX7sawsNvLUismlryijroo/o94m03mTwWcYO9B9ORsRWMTzKtqPNVrdMXFehYb6XlMq2OSsTiLcI6DWMemjBolKL387vu1b4zpMHwd38W5fO2i7qy9BfFEQXjFbIVL/5lkl1VdNw6XBt5Uz8aVlmr58z0GPDD7Kzo954tEIBD16RYPRBnM934x8pMG1822KNgj4QVR1gWmTXHNR2MWJCydh8ogdkdKYt8c2jpc6QuDqu8R0syLbMq7TGHPRh3ikIFnQKD72I6bbszvQJ3BmgZg0RtUuXwKx3UfFXlMmGCjKOm6w5vQSWcp2HPAaDHbN47jULJNWJbl56Ql2okDueAMN8yH2K01HA7Q0JfgJsZbOi0vIvwh0ZLxeTMN9mvGB2z0QnvaOzzCi3IyAHbhpX+3WlRRLkO9XVH7SNMQ+qz/szDKTZkgUqBuBudsqe/detuERr9ldWRLefhGyo0pF87gyUetiCAh4QRrxsbscpK5hM8BfkdQub6SfnXlF2tBPownjZnep/CYnQNxLLCFotMR4URIpPN93Z2TvPqeN+XU/t02tBpjcsvGGrQlwAOLtAGMEgmDSQMi2I0N+Q+B7jqftxcU29z1P8ZtseMF3k3RioIYbE/o7OIuDMxTGUR8Ro/V76wQoQHrYULwHOU0uHkD+ivLX7MlMdjABtsrsbYeowkHZZ+d1OJ+ai+5NOwvMhftOcGCpFyxZ0WSEN5y+oySQ3wwjgmRmopkwzhJkMZaEVS2WzKzQNVeL57cNBU6Q0um7Ic/j8OYqpxr2iSLtgfG943zk6xM8U18hzaeirRhQ/4OZ28paYO2VTLu8w4mpRMCPE4lRozdCyr9mUMLuzUa2iVzuJNP+qE4Ej7vlcConqIbHFKs4dXHKDq84+RyzaKUTVmFtC5ypvvaW3aPx8NVyzIfK1ApdLl2YvsD1NU9setHbJgOzYzG++Ud7e+8FcuNPbhlvMX3kSkyOnrwP0RVHZ75zOcdRjWkWSTSpjCGYbOLdwuGTJoJ6INzEgQuaUB96sbJtix/EdayXTg0ZsudxRONRYW6u88yt4xK/MA5nvjFeV/B35fvnUNr6ai+mH/KYb0lwvzXpEDGZYum6h3GcN5nErJgfbZtbEYKVI9su2XcYaEJLZJq9V/qiIv5aZjFqa9pYiXsKlWpyzd19VyJvKt3JnikmW5TSComBv30cifr7ID/z/fGFj5pMyPoxMwRsy9FRyIKVyDk9zI0kE5fbMv2o6ocHccdvIWIWwCH09KJpZtyf6WXc91TiOhblQctk+k6vb3ab7ti+7thMg00kYQKNo9un3Mq3I4IAm+sVYucWYX3h14vAIEwbEJpJAbRTsA2Brly7jXSVHcSPhIXy7XBsymwVMMr3s7DIMuz5dceitk3mPuAi9HZrAwEGcG6OC8ioxHTb8E4yj+xjY5S3DjljDqXkIwHhMS6r4JsbzxtldHtPjCPnx2mM+l8yfzoMK45IjTvRXKRnUyvHU2kCIbHrdrF79rOr+L7d5nOiU1wEBN366XsxBtk0oqzLnV+pTOvVRe0KTsBmn4kYfdITp3J7ZM318PN67xbRXeNYk/6ytiMao7Y37mOoUjz8MXXSKtN0mur7ebdJ5iDJxFuffRClmtPwoRCJvK4G1WhY1rqZ8/B6YJncupnh0qizxoVa+/7Wpsd36TiNhDy836E9pm/WjDXXr8i2tNSWCt7Ru4Of7uG9sHgiUoaKBJzrOaHVzVKZEOWLL8KMPPHDz7+TI66w4KCWwfttx8kak3mkHTVnb9zquhQ+dFQKojIdc0wI9hUxpoN/yteoGqDALjWnXsbxmYmtQgnyU4auGtVIFNU4JafRcKXU7Yei1YAqyVpRuA8TPnMGAo4mFb9Tn+iQzPx26LHTnQZ2ZCs1bRlqBnYbqcL1ssjjyJvwvGrIPO2Zslh8zqwXGgNfj+4+eCMYrHlNn1ELSJH0XeUZ79C9OGW3laG+4+2dNu5Ic55u/Ma7adha25q2jV1HBqLnenjXasbQxfL2aFWXBTrHqb7YStHSGfOFIDrJDdh77wI/Nkt5dpn38Znt05SvZLVimhO/du64fatvh6WE4yc0/aHJqaBCggolNrjiKAuhA2KiqdWkeKuJn8khMO5tjqOJ3hDSqt4tf60qFAsz8VZ8ddXOk3wCbo3VYLNIgphVT661PvS+KpeEtc9WsUJuHYxW0e+o+yg8iUhcBXv1PEpJ+KwO18EeF5OYLMieGvMcMhZ48XJM2ND2oEG29ZFPIMX3W3zgcUIdBaoHmIdePRso+b7hYMi+C09a6v4S2cACjiowTP1SYblvnRJvqj1Q1AEi3alR60KvsocdH+m6dr8wYzSgerfO5/v08N1krOpipHK0p6ngPSTe61UpZq3RI33UGpOab688SuNmW9+5mRljmUTXDwBYr32O6dukB4aNJL0Ps5EDXDMun5hYpRlx96koquRwFP+zHFNJJiC8vWUdHy4diNcAqcz4M+LP+qv/zQrIPi7uS1tda/pACGzKVgVJtRRSKGtw674yttmFOMmQs2cJiefvUQdCghiYiEaNcvJ3gCK/dK1etT0PwdGpBFtbDx6TH+FqJHPzSqGOyyqeaaLytK2gAiVXW7AbBdVxPFE3mbkocwYAmmon4qRF8acJPIN0bW+bVg4bGswP1lYHAXFf0t2Ot74KDNeNlbo8vFhTltAFD0MazJqeCAwPfAnPWGeHD77DjAWpQD0yhpE8IlQ1LWSSTwXVpmWXLHBewp8z/hjONadbe8nSDcNF6fcvjau9kTTwbiwdWcaKiPi4xMznH0M28SmJTU9Nh4muVJiPIu3WtE9zGDgSqkaAdfrQ6a0Q2DE4XtoM8PUYdJbcT5a0QsODBL8t+lEm0Q2wB7hGa3onZNWZhFlb3ya+PGbD6o7Ql6ESLZM/0MtUQRzk4EWfNfVkB3iFnSTev9bTFc+KBSJAqcl+VJ28yUXFeRVAEEviIC9K6p6h+zfdoE70VrRVWBQx+9qinyi9nYifdfw0r7jSr1l9Bda6fovn2ip+5u0RY67Fvi63gMi5KR6DocZkGR+EIcT8yo41n08GPvXHdHx9ERfpE49nYJb4TLkCUCLS77fyih9mAt6NEbIFmuavzL1aZBebSh3tlvgFoQOF/ArFWhfDxeo3U5IIvCZPg7ItqczDDP8meG+k0q096MV3Uff5J9rcMFskKZDuo10hm6gkOCRxAq1eLkVJ73jIZ1NZLud7MPGDFvwoWclvWykmnn9StOm6hw2cgoOTty17Qu//jA7C01NYQSu5FW2FMYHjVPY3RuF/+QPX9hspysMeL0pF5LdiE5/uhiVk0FH3uO/cWircMWo7SJVlrfokw2f3/rZSR1QJXuGnn9RUApzEmV/E96qmDJIQFpEQtJvpQwa40zpPprbUBmYf60qGW7YxnFtffcy596DUH/U9zby8FkS7DScosE6QkublBZROB5QRkBugRrS1FucgNG8SQqO0QST7UNDIKrke4ZGVvO5T4sukcimmk98RhzKBqII1XiWCorXKvbJ9vcwtBHuXdjdQUsiNo9+uHyGZDlof1HxH9G8GK2LemJSbc4mpemKPzFy1rqpbDCqmH5QCIP/eUQjro6HHpXbhfTATO/iX7czw7X4ZXZwI43wxJBvPufmMAMt/KUgXi6i2KCqxJjvvMlNgF+7DkBl150tw9+DKm+KuypFPq4x8FsNGv5E8DyrYE0NVT0C6MC1nYbscLkYvY7VAhXRmlGF9FEYXU/UXHOSdTGm91XUyr7UJIQBbKd4NBieU1B6cnLN60VzLRrSHNMLj0RFbOx64PthXs0S8jY/D/kuvmrWSZuN1hj7DtfyaQhfBm+8imLNW4p4UDxKtOrCieJG5VLLjYVnUoRnZ5h1rVg3OQmNapjmhXtfyfXknzNjysR7vEh8mGDcOMBtICqltOhP3TH0e8YCNxRXD3eGGPRagBDc0URq4ydLQ3+nNIh1YM3RbrPThagqrmkuDl5colmek1N/aBuhmG2DP2vT0vb51y6wnTSe0x1aTSdKURuWcNa/hestqh0n0TVcJdJfqGA71zPQaTgH06QHEISP/Ul/s9qytnC1r2UKKX1/3sx5owfdnYKT2RGfa4+9oDVGPdENZEIBHZ6Me4w3/NmsqLU78WLRmhxfa3HfwY8/7aptF2ECOpi7fo2zhHmm1fv4ZFssIIBkkAGURW645COk2h1rJA3OPCdsgdxgQllrPx4RRWPhYgfcTIuD7u6/fOoiuTKLUdNuUUsaWDDOc9zNl9erIlvbMmzt5SWf23zJXAjf65gnPjb387c5Vq4z3MKxOsz6mHXuRJ8fUCz1KqfD5jvoBQ+8uozyszZnWqUh0ZPm9bMkEgcSlSExK0i69qLDm5XKDGCaRdKAFJgY8ddVpJ+SOtHZ+EtaZrJfoaGiYuAkI9axLwokTQPLNdURAROJ4Imd5+TsnquNlknDPSAzNjjssyzhBLPqn05wY7OaZyTxA7ajQ8yp19Yom7VeqCQ/cbr8f+6YPFtpa6OnK6Ta8Y4kN+mGXGjXNM5ksa9WaOaSHl1vnp71qQxshYQpfL+07HktRx/L3XToS8CxZ2df8FHi2UKcU+diLKSDu0tpIuJpHB6WLiH4Zzn976tQVZ1iOtrW8dTk3Z7GLvdqbw/uxvuGCiNWgxhqM0Kn00D+YA0xYvir6o+bnMv0ol6xpi3vtgTZMlf8YEIo6eo8iEqz7uEBJeWbLUmSI7v6rpA8EWCBs0U/iDPV0qw7oO2DM3Vvsl8CZisBtPv1GRSOnPtsrWeOmoUS+Id4HHkbEZC+lHAdEvLyxVuyjDtRHVikhfFJaAVer6ket9nLf2yJMGVpzJB4z3EedV3k+QrZ2A8mpOKDrarT8neH+gEC/uq1FVaXoRH4IiOqmPLrfqtIMC3BNsaTkmp72rgBnuEXgBqSVXWbRjnch37yErBxzFm5M/bjF8DDoYLNm9r2D4GCI3bSodHg1rB1rfne9L6jwIxWtyQnjIY3fTlOLisoEwKEieJUbUNAwfq0Pa60L5p6eJlaGbamOnRsKRIzaJ3DHoSRh+hQG/btxjre+wM71jmJ4naU2e/Be+uDcjmJK5iEajRHYey5Xh02WgbMpLP7WlrJOWiw2UTCOa31DD/N+M+FtUI9a9+WvutfixMzDfq/wewSo5qXsTC5zWZ81hH44YoNo/WgYxiECfL0zmUY90OWX42K0A0TQVpTDFSw36iVNNo0cC3HEnO+QJPe323xlEYEmYAOdi6zb1pKPnvUEC4JZ6OjnU9qVP9OTMahnPIxjpTJ9Tw2ut/uObr/6nL8SrsQks72jeIRjYsLnUq6ow4J3OwoYxPYCt9DRW+raQwwyEJzzaRzTfWcdZKr+/I685yUMbM5mRz1Y/sUalj+KQbnJsuAR33D1/qonjJfm2w2J0vTjVUtD99CTfsrOorO/SPiVpRkVFtbfUrWTnbIetC9fNa0UOh32jRhUfIw8infRCz35RdcbKHSXvha/qOU7XuIU6CQV05yuSYMd3JVOzfzOQ/vdBsT3+xG/MdHP6JlFyZws1qk1XQWRnMN8M9GJAKb/ckn6aNBCjno4GGQF5j+3OHvrN15LSNAQ4U2btpVPUGsb0Ho72mcbIOAo4Jx3qqS9KsJeO4l7swWN4lHp+B5yLDjTsXNw95x6jzfO9oukVUlcO1RbfBUxL3Pkls/tsoPlcjhnODUxonT7Qh04doRgzDN+ux5lclgyN4CJvy+ExPpN5SfplCxN+lirv7uDADVrNGCf1Z3bag2+WBIT+ahobpi5U3mjJwZ2LxgM6SdfX22V1Wm2QTpklnwd7LL9KoIgYD81Vr9qBQfgXVCrF6Ii9Vr7NSnkGhPfXSUNAiJrtcTNg/d2wBCOzwxSzUkGSPD2NXepf6PmnRAGOGP5OX/1ZWZ3X+P9ncOfNQHG0HQ8aNhNizKJ63pupNGdE1TxuYvjRdJXUKVdX9ibyXtPQVOPe2CgIVAZnoz+GHUKvK7RRmWPGIFbs9NKyO0zXYIdEh7hx/g1wlqg5tXz5sxpjaqFDy9X3MjXblX8rpjx2eA5bu/FnSgZ2vpGMEeM4rTVj2+MA/FMhEdihtsB9aN+Xf9zb1z1yzE1a7PPcPk9am+e8beROaPRUqvWmau1BKxNzR5X5dhOLpxiL14KCmtoA8oVlB9O1MW2kPLeapsE0WUjc0fe6Ou0zBpbT22LCLgRy1X+fWR+g6tisRYcWJNAzRTFDJrN0ESw+TVrLghTA+Fu+xjFcW6n+uT1bg0trkPzyUO4thmbCDmlwm5CHog4uODqsYpTbpDepE6pkIfUD0SJDWQ7QCiuppglbYE69GZqva6uBIEftbRo/S6zNhmr+yMeP5c3CHJsHOhHOmTvPUy/iKAs+Jrb8uGCQrLbkT788uQVC1d7W0y84FKshSih2eeYbBCNdv3NKmtDi008NjBwsGmJ6vLd+4wyghliR9dXKZKswEAPyqBc0RD1NxN1vsEfLXIL49f7VMcpQ3PH2ZwJB4H1GSX7Y7L0biuBykr0bEgaXX99YSSWA38oASl+x5uPYCicbeHeh1pRGhpXmKKNtjkhhU57jHL6/p2DRTgy4Tsa/CyGsnmoa84K3tGVqCuh4TuiBetEyYsQ+UAKjvrBp7tTEOxns7GZSdIaP1hRUmM+PtaSk1V78qqYCug4fwgID2JHcqi+iMAOpDISUZcZfTu9TER+eaWQ8t1CPMMjRbM6QjReauFBzrD+4A/zmg9kqB2yR5qrdu1N6OA9qaDsDgH+nRW4qPEr0kOobavy02HTbYajANyNEOelr9YrU3mc1CL1d5MHmqEKSCw9hWkODq9tslqLp6H8ldaK1fYzf8w5ootG2u8uk8dRmOPosUcjkUeW+xPz37AYCkKSsLNLatmsFlhALWAIfwgkjcyA/Paw381huC6s2WQHGaAe0svDaoW+H+7L6TuEa7OyyUAmlo7DiM3t4H6O+U6wy4G97QXFMXxvqSHjswrc1AH1Quc+dERl5pZyep/9i0zU18FkTAXjcXCFRUKpj+AAala8El09Cx3W/DRlVbHpv3HK3DB5pZ+5Tbr2pLASi6kob4UvO7DGILf+akVJPTQhfeu2736XMnSVqg0F+SpMiMeDPS4bFGo6G9pv6qKFhQeMbCfe3Ol3Z+ZNQgX2/KiRSZFw7twgtDL8N0r5vRd0/YL8LBwwR3Q9mK/W3LjywStssXmxYDOhR1zRYqGJQ+JuLNm+bPb5BvxxDzytxOD4CnzmxcVFSB8WJ45QsO31MYg3JbQme2XExwruz5zkIGkuSA4U5yUktbGDoxAw4ktUIiZ6MSqRalDdyuztH+2W5R5DHiyLrWlGJ4J7M+JtTKt9QnVAK9d5uMqqOXT954lQJujfghiqQYlpHEJVPc7yQHp4nMu/dGcJtNIaEvRaIxUIqFLPyONsTZGUoH7zv3ZKPTi3qhDgr/HOLXfmI1Ix4K4SyPqdV6akFbl82KVg0L5jvGl2BEUMFA3XoNUeKTLZENGKZCV6IDMdBtCWMLB2HAcPxLbV08gwMuDcm/IIO4ls/QyTfdY/yJwJcxo7i6+qldSivt/viMVwlWZm4Ug49BSD6ZONQJqtOkKyL8Z+fe15UVPkTLd6PpVhLsKKrWqwH3qvhgq1J/FaHnQsajN3IYp+NgReKETlX4FdjAqXcdvcHJx0vz2RQfJ0Z6n6pBsXWCv0Pe/nrzZ6NoodLnDMYVHiY68F9Ispv1wvsAQ8N12T72Ab/BQxTRyuD99afYjkyIstbPWR+ylqwUPNm6cNN5dNqlkhsDBWCvH3YV9pSJWNWiKW0tq3EOyRrdZkxeRtv5B9V5GNEspQg2zQY9+ns3M8WBlIipqtR10t8EgamRhx31WBP3Z6Y1+/c/0uhqSt/InFX01vzNClLH+fia+VfCkxnMDmtv3Z41+e8vZZC/yNEUEFduXhgbz2Luk8M2wy/z6QyYxyEGX6ZXIyQVcqEFhpMxmVGAEO7h507R6ATB6uhW4Ez2Xgb2bSflrmT8ILg7FHRIxQW6/YOrWGzGa+SCLJy+C4o4DHbLBrxLLLhRuD9waJKxhPHurSdLJgqqBBNgaVm6zzA5tuJtSLnT2Wz03/av9K8akCUrhyIZl9gd6u14elHeMY7tLzXT9aH2sgrpmG+eQh+u53YSU0wZZRft3zB4G0rjncKvW6GcPX2SPl0McwDcdZe8WO0jwI0+runv6a5Agf0lS/5bvBhaAY9ZXaNO8x58O0da5b75XlQsSdiKdp9JA7QBhckvnaVL/trOJUmPVGROU7+nlJLK+/X0tMY5H6ANzx89H7LL5Lu2UjfPYEmjPWDzJ9CHiLW+sBHZr5CiP8sYsAxYP9l1zggSb+Vb/JrJQ2kox/UGxCUVcnhZbCzV72mBfPVYrscy+yDs3TpAtia9R5DWQpNLvrFEhlkHiHUIvDGYFPnti8wB2ZX4PIt0uJeK9f4Nf3AlHjbx1UwwZwJgvm0zweXd3+aajoYsT0ozkYnvo2GtkWiAUW6YertnDfZyIi/PF8X+h3Y8qMpbJdYfprJ5NXxS+2bu7A5bj4wQv7CnIxkyBfD6OkChb+KByT0nmxb3P/891A20Fh0YXf7zuoFbCBgI72FTNw7Qm/uiNCDxmJfxM4yEb5ux9IPDAANclvp03azpuu5jN79wXlOYm9fMhwfr4ng3qUM0lZbpqw/hxExDeTXnWe593OU0M+RwTs/VK07KOgCIJqfQnEwmHNu0Mo5CW/cliL2OY/X7vN5F87BSHMzXaKeiuadI1z8zuDLPDbbPn461n8K99l3oVTn1pJcPTuTdODTxGp59bcS/gYzWqzgrC2Lyr/sNQF9sY+KhStuWGrsshGtu1lQo5Z8XWlBieQGX3u1DftYiodAs79EA/WVywUvUk/FS6+jd+D73WkiyA4QPZUtuYffG2Lgb5PpPDhv5JjP39hDNUISpvrhtJJA1Xl70dBdcZlPHB1j9BfHQkTe6WRwgQCKMlSkY+t7qxFvZFtTNxEeNYrQOIFgwXqn2lX37Gyo71XHyKIr+pFiLhSJPidaKAzZRnLLGh808ADdlV+dTJWcx0owpAsObuC/IKtRrusj0JCr1jl9KRsBYZ5QzmOuqYJ/eK8cs+8yQ8+vFaOPKNjs77wdlPjGWKtRvj1bQmygoaxBEnS3nKccIY76Jgu/hRdxefgSMqbPZlAjJEE7oLjGr7CzAPLXRySvbxfX1XiaUxib4bDWZqwVBdNiWPZpZviEyDL5G97vLIMJfTSH4WsSfbrlyj4GjaC3KsvdCBioIaHKUc7ymvFTD19Lkq3ud4b5X1Qw6R1LGygmqv5R9g+T2wP+0DyX3XoVTDRHW76aBZtj7h3boL6T4Yp/bpPQ31Aw367lXe2y/f2Vjh45dJgaQi1+3J9m8YRx6kwrsMJe2DDMPFpzr7AcUZZk1vddT2PF15NVBb0FrwJ6LrsHV0gdO1erxmN3xsHiky+Mc13KyGxfEaDhh43D6XHFA6QhG9AhwJO8TKDkkFtYsw3loHFX6iUDZQ+B0IrsUR36S3kAJyJfJXda7v3BlieqQlbncNGKtKYc0BCNudS+liBqm8qb5bvj7Yh8ZkVFh9GOvZm0aCoyTvrVaLL5DRT3ZfHwvGPcjjL8C1fTYbfCsqyuGo3AfTpGso+Tsvsl3ocX6KmtGSX+yG2cFnynTlTjgPq5wdGotLIWtwyXCjOaTAcGwTLPt0tgGq7DOwbv4SZPD86ZEFL+amxHDuxJLMzQqUPni4KK0cODQJpBpDTVfy0oTKWsy21+MZSTSrhEh4IL/N04xFjRt4vKNM3zeHNTiAlVI6V/pEZfjxTo7Z6iDthxyVwjfD+8CEz0p04PsBm7d+B4dAqknyYpRyyalEi+jjBtJHs53dMrXmsHesEMLY/VDtcO0BNqkTid1sIBvlYzCxl3MeJIB2LEfAE2xE8arOG6JsUV6NjlX/KeYjOwncfx626ZMr4UnewKbpKxGhyMe0ncaxr9EutDJQ+5PLdRL+i7eKEG+fBYQxwWkEoToA9AAiYM5SuZP1LQ8ldbAJYwUBw92vHEi2PLfoQHu5CXz/Zva4F5djlcYLBGJi/qtiPETsKxKbFPZzJ1SPyqZ8jMfPsZ/rA+Q7et3J4BeQl9sDV+eYsGKA5u/9TDg25VLpDAgLMPBQ/JCqd5VIoQg9JfqkkHgA/QyXqEZlYGnkmouiZGgXKIwUKTgKR4r7fDY0CR80MI+RO3tf6IugEntW9gH2R94+M+UtF5mT8wvD7F02ZUlUA+jGj9AJUBBsu2x3+ktkX/mNCl6CR1Je+f/lTECgH2mkkcMpsItgFvMWCtQdVi8Ka++3WgeH4996CyUi8PCwMmgMp1PRPbuug1jrT17/iD+C5goFNSey/rKAAvzOau8qzNtceJCzuCMKhqQ/LSIypV/+I1ywnbxhQC6jUlR0KEPF7jiIRBlSHpHk9hp24THG1ofr4C+DIG43eFzVDP6+jlzTVTlAjDp6R7xTJKTroM8rEhFmpwLUQpGx2llmSA4tRAQhT++J3o4oEVKjEDm7pDWfuRbCkyM/1Wf9qs6JkDhKIlEijQyew1HIU0Okj3YDngHWw+nxwjdFRo/FnCbg3TeXizR3V62FNCjESy4TzP1W0EiU0N9CvX0EZWhB04Bnv1fTPq6qaK1zzK6wpHPnB3BwOOpOYQNIuYE4eLJBBv0xfBlE/is5OVfzXucxwX3dTe04u0OAPI5sOzs+NXBTFv6Hc7+/TtafH0J7Na3aCFgSB/2waoznr1//QhPL/hrLdKWRDl63zQxPQXz/4A8awP39z/dXwt+9Hla7lX4+gkD/byqwqyr89Fyb+bIyWPxuKf3/4L9j/90qA8E82a9u/9eD3GYGq9M/fEKBo4m8QUbtlf7b9G0K0zzuYtHpWHFrWq/3zAjFtA2h/Brv+EbWPYfhv6KMcoOQZajb/n9efT8Vf//+eE/+tYc6i9o+16h7pA6XRUsZDNKfL324DAOMffjr/5xbAhqBff9/639XVfHhW7Z89CFz4Y6nu7M/nwNh4/uNT8mEGywEmmIi68Wnp42X8+87/+Yb/zrdmD/DqsjkCy9oPafZMKPs/eeG/dhKXEeQQ+bNtyeYdBCBA8fVfTcq/L3qfrWm0PlAN6qLlzzf8l4QBMMl/eM1/NTDk7waEgJE87eXaPfzAwT+SfKY3in83QM/3caj69cdPOPNvOODxaFuHP5fg94O/5oFrsxw8CvB+lUQt/VfzOox/zkBS9YUNvnB/YH+tpPXXU7D/JsmB4tDfSQ6EgP5Rcrygf5Qcf/vd/zvBQfyvExztcPyRZmtUtT/ahtqhL8CYqmUdQLf/L+nkX0DpYLaq5C9G+6dE/R+J86ie1fivJcI/o+N/H0cxR3kEMkP83x/i/940j6J/ry0R5B9pHv8nNI/+N9A8DkcwQaIZTLxIDMKiP/4ZEzxmItAC2yP5lv+PLgbx37QYCAb/3WKQ5OsfFoP8J2uB/GvWgvwnAuk/zf9SRiP4WHVRkf39QvzzifxbqxLFWWs867BWA7gaD+s6dEA0gQtMlDTFPGx9yg7tAwLAu9D89+e55fcyehmzZP1rkaO/fcmr89GOf93yfC/XdVx+sgfYOUnaw/+jSoY+r/o0m/9HMgBT8E8d+QbtwKkIZm74Y6v+SIek+QO0/rFk6x+/T8sf8fVHGjXVHP9S+CEA6GrDWuXPmMBIlv8xPpL0X8Oqf5v+v4gDRv+RONB/Amv/1vbfTByv/w2JA/qfEscybc+C/dEOxfBHvD29+rXioATJozSWZJjTPx4TBHn96+gAJv8TGZD/SAbYPyED7F9CBtQ/kMG/o85/naj+C0b8PxfWv+9/dQ3+7+DNvwnqvy3K6x+RI/G/THBj0D8syr/Dnv8/LcrrP0EbEv1XadPn6zwARPvv14Q5Gkv1sR7BHf8H</diagram></mxfile> \ No newline at end of file
diff --git a/diagrams/netdata-proxies-example.xml b/diagrams/netdata-proxies-example.xml
new file mode 100644
index 000000000..956bdaf10
--- /dev/null
+++ b/diagrams/netdata-proxies-example.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" version="6.2.4" editor="www.draw.io" type="github"><diagram name="Page-1">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</diagram></mxfile> \ No newline at end of file
diff --git a/install-sh b/install-sh
index 0b0fdcbba..a9244eb07 100755
--- a/install-sh
+++ b/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2013-12-25.23; # UTC
+scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -35,21 +35,25 @@ scriptversion=2013-12-25.23; # UTC
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
-# 'make' implicit rules from creating a file called install from it
+# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
-tab=' '
nl='
'
-IFS=" $tab$nl"
+IFS=" "" $nl"
-# Set DOITPROG to "echo" to test this script.
+# set DOITPROG to echo to test this script
+# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
-doit_exec=${doit:-exec}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@@ -64,6 +68,17 @@ mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
posix_mkdir=
# Desired mode of installed file.
@@ -82,7 +97,7 @@ dir_arg=
dst_arg=
copy_on_change=false
-is_target_a_directory=possibly
+no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@@ -122,57 +137,46 @@ while test $# -ne 0; do
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
- shift;;
+ shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
- case $mode in
- *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
-o) chowncmd="$chownprog $2"
- shift;;
+ shift;;
-s) stripcmd=$stripprog;;
- -t)
- is_target_a_directory=always
- dst_arg=$2
- # Protect names problematic for 'test' and other utilities.
- case $dst_arg in
- -* | [=\(\)!]) dst_arg=./$dst_arg;;
- esac
- shift;;
+ -t) dst_arg=$2
+ # Protect names problematic for `test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
- -T) is_target_a_directory=never;;
+ -T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
- --) shift
- break;;
+ --) shift
+ break;;
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
*) break;;
esac
shift
done
-# We allow the use of options -d and -T together, by making -d
-# take the precedence; this is for compatibility with GNU install.
-
-if test -n "$dir_arg"; then
- if test -n "$dst_arg"; then
- echo "$0: target directory not allowed when installing a directory." >&2
- exit 1
- fi
-fi
-
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
@@ -186,7 +190,7 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
fi
shift # arg
dst_arg=$arg
- # Protect names problematic for 'test' and other utilities.
+ # Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
@@ -198,21 +202,12 @@ if test $# -eq 0; then
echo "$0: no input file specified." >&2
exit 1
fi
- # It's OK to call 'install-sh -d' without argument.
+ # It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
- if test $# -gt 1 || test "$is_target_a_directory" = always; then
- if test ! -d "$dst_arg"; then
- echo "$0: $dst_arg: Is not a directory." >&2
- exit 1
- fi
- fi
-fi
-
-if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
@@ -228,16 +223,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
- u_plus_rw=
+ u_plus_rw=
else
- u_plus_rw='% 200'
+ u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
- u_plus_rw=
+ u_plus_rw=
else
- u_plus_rw=,u+rw
+ u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@@ -245,7 +240,7 @@ fi
for src
do
- # Protect names problematic for 'test' and other utilities.
+ # Protect names problematic for `test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
@@ -274,15 +269,41 @@ do
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
- if test "$is_target_a_directory" = never; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
- dstdir=`dirname "$dst"`
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
test -d "$dstdir"
dstdir_status=$?
fi
@@ -293,74 +314,74 @@ do
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
- # Create intermediate dirs using mode 755 as modified by the umask.
- # This is like FreeBSD 'install' as of 1997-10-28.
- umask=`umask`
- case $stripcmd.$umask in
- # Optimize common cases.
- *[2367][2367]) mkdir_umask=$umask;;
- .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
- *[0-7])
- mkdir_umask=`expr $umask + 22 \
- - $umask % 100 % 40 + $umask % 20 \
- - $umask % 10 % 4 + $umask % 2
- `;;
- *) mkdir_umask=$umask,go-w;;
- esac
-
- # With -d, create the new directory with the user-specified mode.
- # Otherwise, rely on $mkdir_umask.
- if test -n "$dir_arg"; then
- mkdir_mode=-m$mode
- else
- mkdir_mode=
- fi
-
- posix_mkdir=false
- case $umask in
- *[123567][0-7][0-7])
- # POSIX mkdir -p sets u+wx bits regardless of umask, which
- # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
- ;;
- *)
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
- trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
- if (umask $mkdir_umask &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
- then
- if test -z "$dir_arg" || {
- # Check for POSIX incompatibilities with -m.
- # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
- # other-writable bit of parent directory when it shouldn't.
- # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
- ls_ld_tmpdir=`ls -ld "$tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/d" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
- fi
- trap '' 0;;
- esac;;
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
esac
if
$posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
@@ -370,51 +391,53 @@ do
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
- /*) prefix='/';;
- [-=\(\)!]*) prefix='./';;
- *) prefix='';;
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
esac
+ eval "$initialize_posix_glob"
+
oIFS=$IFS
IFS=/
- set -f
+ $posix_glob set -f
set fnord $dstdir
shift
- set +f
+ $posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
- test X"$d" = X && continue
-
- prefix=$prefix$d
- if test -d "$prefix"; then
- prefixes=
- else
- if $posix_mkdir; then
- (umask=$mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
- # Don't fail if two instances are running concurrently.
- test -d "$prefix" || exit 1
- else
- case $prefix in
- *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
- *) qprefix=$prefix;;
- esac
- prefixes="$prefixes '$qprefix'"
- fi
- fi
- prefix=$prefix/
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
done
if test -n "$prefixes"; then
- # Don't fail if two instances are running concurrently.
- (umask $mkdir_umask &&
- eval "\$doit_exec \$mkdirprog $prefixes") ||
- test -d "$dstdir" || exit 1
- obsolete_mkdir_used=true
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
fi
fi
fi
@@ -449,12 +472,15 @@ do
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
- old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
- new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
- set -f &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
- set +f &&
+ $posix_glob set +f &&
+
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
@@ -467,24 +493,24 @@ do
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- test ! -f "$dst" ||
- $doit $rmcmd -f "$dst" 2>/dev/null ||
- { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
- } ||
- { echo "$0: cannot unlink or rename $dst" >&2
- (exit 1); exit 1
- }
- } &&
-
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dst"
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
diff --git a/installer/functions.sh b/installer/functions.sh
new file mode 100644
index 000000000..36d10ec70
--- /dev/null
+++ b/installer/functions.sh
@@ -0,0 +1,344 @@
+# no shebang necessary - this is a library to be sourced
+
+# -----------------------------------------------------------------------------
+# checking the availability of commands
+
+which_cmd() {
+ which "${1}" 2>/dev/null || \
+ command -v "${1}" 2>/dev/null
+}
+
+check_cmd() {
+ which_cmd "${1}" >/dev/null 2>&1 && return 0
+ return 1
+}
+
+
+# -----------------------------------------------------------------------------
+
+setup_terminal() {
+ TPUT_RESET=""
+ TPUT_BLACK=""
+ TPUT_RED=""
+ TPUT_GREEN=""
+ TPUT_YELLOW=""
+ TPUT_BLUE=""
+ TPUT_PURPLE=""
+ TPUT_CYAN=""
+ TPUT_WHITE=""
+ TPUT_BGBLACK=""
+ TPUT_BGRED=""
+ TPUT_BGGREEN=""
+ TPUT_BGYELLOW=""
+ TPUT_BGBLUE=""
+ TPUT_BGPURPLE=""
+ TPUT_BGCYAN=""
+ TPUT_BGWHITE=""
+ TPUT_BOLD=""
+ TPUT_DIM=""
+ TPUT_UNDERLINED=""
+ TPUT_BLINK=""
+ TPUT_INVERTED=""
+ TPUT_STANDOUT=""
+ TPUT_BELL=""
+ TPUT_CLEAR=""
+
+ # Is stderr on the terminal? If not, then fail
+ test -t 2 || return 1
+
+ if check_cmd tput
+ then
+ if [ $(( $(tput colors 2>/dev/null) )) -ge 8 ]
+ then
+ # Enable colors
+ TPUT_RESET="$(tput sgr 0)"
+ TPUT_BLACK="$(tput setaf 0)"
+ TPUT_RED="$(tput setaf 1)"
+ TPUT_GREEN="$(tput setaf 2)"
+ TPUT_YELLOW="$(tput setaf 3)"
+ TPUT_BLUE="$(tput setaf 4)"
+ TPUT_PURPLE="$(tput setaf 5)"
+ TPUT_CYAN="$(tput setaf 6)"
+ TPUT_WHITE="$(tput setaf 7)"
+ TPUT_BGBLACK="$(tput setab 0)"
+ TPUT_BGRED="$(tput setab 1)"
+ TPUT_BGGREEN="$(tput setab 2)"
+ TPUT_BGYELLOW="$(tput setab 3)"
+ TPUT_BGBLUE="$(tput setab 4)"
+ TPUT_BGPURPLE="$(tput setab 5)"
+ TPUT_BGCYAN="$(tput setab 6)"
+ TPUT_BGWHITE="$(tput setab 7)"
+ TPUT_BOLD="$(tput bold)"
+ TPUT_DIM="$(tput dim)"
+ TPUT_UNDERLINED="$(tput smul)"
+ TPUT_BLINK="$(tput blink)"
+ TPUT_INVERTED="$(tput rev)"
+ TPUT_STANDOUT="$(tput smso)"
+ TPUT_BELL="$(tput bel)"
+ TPUT_CLEAR="$(tput clear)"
+ fi
+ fi
+
+ return 0
+}
+setup_terminal
+
+progress() {
+ echo >&2 " --- ${TPUT_DIM}${TPUT_BOLD}${*}${TPUT_RESET} --- "
+}
+
+# -----------------------------------------------------------------------------
+
+netdata_banner() {
+ local l1=" ^" \
+ l2=" |.-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-" \
+ l3=" | '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' " \
+ l4=" +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->" \
+ sp=" " \
+ netdata="netdata" start end msg="${*}" chartcolor="${TPUT_DIM}"
+
+ [ ${#msg} -lt ${#netdata} ] && msg="${msg}${sp:0:$(( ${#netdata} - ${#msg}))}"
+ [ ${#msg} -gt $(( ${#l2} - 20 )) ] && msg="${msg:0:$(( ${#l2} - 23 ))}..."
+
+ start="$(( ${#l2} / 2 - 4 ))"
+ [ $(( start + ${#msg} + 4 )) -gt ${#l2} ] && start=$((${#l2} - ${#msg} - 4))
+ end=$(( ${start} + ${#msg} + 4 ))
+
+ echo >&2
+ echo >&2 "${chartcolor}${l1}${TPUT_RESET}"
+ echo >&2 "${chartcolor}${l2:0:start}${sp:0:2}${TPUT_RESET}${TPUT_BOLD}${TPUT_GREEN}${netdata}${TPUT_RESET}${chartcolor}${sp:0:$((end - start - 2 - ${#netdata}))}${l2:end:$((${#l2} - end))}${TPUT_RESET}"
+ echo >&2 "${chartcolor}${l3:0:start}${sp:0:2}${TPUT_RESET}${TPUT_BOLD}${TPUT_CYAN}${msg}${TPUT_RESET}${chartcolor}${sp:0:2}${l3:end:$((${#l2} - end))}${TPUT_RESET}"
+ echo >&2 "${chartcolor}${l4}${TPUT_RESET}"
+ echo >&2
+}
+
+# -----------------------------------------------------------------------------
+# portable service command
+
+service_cmd="$(which_cmd service)"
+systemctl_cmd="$(which_cmd systemctl)"
+service() {
+ local cmd="${1}" action="${2}"
+
+ if [ ! -z "${service_cmd}" ]
+ then
+ run "${service_cmd}" "${cmd}" "${action}"
+ return $?
+ elif [ ! -z "${systemctl_cmd}" ]
+ then
+ run "${systemctl_cmd}" "${action}" "${cmd}"
+ return $?
+ fi
+ return 1
+}
+
+# -----------------------------------------------------------------------------
+
+run_ok() {
+ printf >&2 "${TPUT_BGGREEN}${TPUT_WHITE}${TPUT_BOLD} OK ${TPUT_RESET} ${*} \n\n"
+}
+
+run_failed() {
+ printf >&2 "${TPUT_BGRED}${TPUT_WHITE}${TPUT_BOLD} FAILED ${TPUT_RESET} ${*} \n\n"
+}
+
+run_logfile="/dev/null"
+run() {
+ local user="${USER}" dir="$(basename "${PWD}")" info info_console
+
+ if [ "${UID}" = "0" ]
+ then
+ info="[root ${dir}]# "
+ info_console="[${TPUT_DIM}${dir}${TPUT_RESET}]# "
+ else
+ info="[${user} ${dir}]$ "
+ info_console="[${TPUT_DIM}${dir}${TPUT_RESET}]$ "
+ fi
+
+ printf >> "${run_logfile}" "${info}"
+ printf >> "${run_logfile}" "%q " "${@}"
+ printf >> "${run_logfile}" " ... "
+
+ printf >&2 "${info_console}${TPUT_BOLD}${TPUT_YELLOW}"
+ printf >&2 "%q " "${@}"
+ printf >&2 "${TPUT_RESET}\n"
+
+ "${@}"
+
+ local ret=$?
+ if [ ${ret} -ne 0 ]
+ then
+ run_failed
+ printf >> "${run_logfile}" "FAILED with exit code ${ret}\n"
+ else
+ run_ok
+ printf >> "${run_logfile}" "OK\n"
+ fi
+
+ return ${ret}
+}
+
+portable_add_user() {
+ local username="${1}"
+
+ getent passwd "${username}" > /dev/null 2>&1
+ [ $? -eq 0 ] && echo >&2 "User '${username}' already exists." && return 0
+
+ echo >&2 "Adding ${username} user account ..."
+
+ local nologin="$(which nologin 2>/dev/null || command -v nologin 2>/dev/null || echo '/bin/false')"
+
+ # Linux
+ if check_cmd useradd
+ then
+ run useradd -r -g "${username}" -c "${username}" -s "${nologin}" -d / "${username}" && return 0
+ fi
+
+ # FreeBSD
+ if check_cmd pw
+ then
+ run pw useradd "${username}" -d / -g "${username}" -s "${nologin}" && return 0
+ fi
+
+ # BusyBox
+ if check_cmd adduser
+ then
+ run adduser -D -G "${username}" "${username}" && return 0
+ fi
+
+ echo >&2 "Failed to add ${username} user account !"
+
+ return 1
+}
+
+portable_add_group() {
+ local groupname="${1}"
+
+ getent group "${groupname}" > /dev/null 2>&1
+ [ $? -eq 0 ] && echo >&2 "Group '${groupname}' already exists." && return 0
+
+ echo >&2 "Adding ${groupname} user group ..."
+
+ # Linux
+ if check_cmd groupadd
+ then
+ run groupadd -r "${groupname}" && return 0
+ fi
+
+ # FreeBSD
+ if check_cmd pw
+ then
+ run pw groupadd "${groupname}" && return 0
+ fi
+
+ # BusyBox
+ if check_cmd addgroup
+ then
+ run addgroup "${groupname}" && return 0
+ fi
+
+ echo >&2 "Failed to add ${groupname} user group !"
+ return 1
+}
+
+portable_add_user_to_group() {
+ local groupname="${1}" username="${2}"
+
+ getent group "${groupname}" > /dev/null 2>&1
+ [ $? -ne 0 ] && echo >&2 "Group '${groupname}' does not exist." && return 1
+
+ # find the user is already in the group
+ local users=$(getent group "${groupname}" | cut -d ':' -f 4)
+ if [[ ",${users}," =~ ,${username}, ]]
+ then
+ # username is already there
+ echo >&2 "User '${username}' is already in group '${groupname}'."
+ return 0
+ else
+ # username is not in group
+ echo >&2 "Adding ${username} user to the ${groupname} group ..."
+
+ # Linux
+ if check_cmd usermod
+ then
+ run usermod -a -G "${groupname}" "${username}" && return 0
+ fi
+
+ # FreeBSD
+ if check_cmd pw
+ then
+ run pw groupmod "${groupname}" -m "${username}" && return 0
+ fi
+
+ # BusyBox
+ if check_cmd addgroup
+ then
+ run addgroup "${username}" "${groupname}" && return 0
+ fi
+
+ echo >&2 "Failed to add user ${username} to group ${groupname} !"
+ return 1
+ fi
+}
+
+iscontainer() {
+ # man systemd-detect-virt
+ local cmd=$(which_cmd systemd-detect-virt)
+ if [ ! -z "${cmd}" -a -x "${cmd}" ]
+ then
+ "${cmd}" --container >/dev/null 2>&1 && return 0
+ fi
+
+ # /proc/1/sched exposes the host's pid of our init !
+ # http://stackoverflow.com/a/37016302
+ local pid=$( cat /proc/1/sched 2>/dev/null | head -n 1 | { IFS='(),#:' read name pid th threads; echo $pid; } )
+ pid=$(( pid + 0 ))
+ [ ${pid} -ne 1 ] && return 0
+
+ # lxc sets environment variable 'container'
+ [ ! -z "${container}" ] && return 0
+
+ # docker creates /.dockerenv
+ # http://stackoverflow.com/a/25518345
+ [ -f "/.dockerenv" ] && return 0
+
+ # ubuntu and debian supply /bin/running-in-container
+ # https://www.apt-browse.org/browse/ubuntu/trusty/main/i386/upstart/1.12.1-0ubuntu4/file/bin/running-in-container
+ if [ -x "/bin/running-in-container" ]
+ then
+ "/bin/running-in-container" >/dev/null 2>&1 && return 0
+ fi
+
+ return 1
+}
+
+issystemd() {
+ local pids p myns ns systemctl
+
+ # if the directory /etc/systemd/system does not exit, it is not systemd
+ [ ! -d /etc/systemd/system ] && return 1
+
+ # if there is no systemctl command, it is not systemd
+ systemctl=$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null)
+ [ -z "${systemctl}" -o ! -x "${systemctl}" ] && return 1
+
+ # if pid 1 is systemd, it is systemd
+ [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
+
+ # if systemd is not running, it is not systemd
+ pids=$(pidof systemd 2>/dev/null)
+ [ -z "${pids}" ] && return 1
+
+ # check if the running systemd processes are not in our namespace
+ myns="$(readlink /proc/self/ns/pid 2>/dev/null)"
+ for p in ${pids}
+ do
+ ns="$(readlink /proc/${p}/ns/pid 2>/dev/null)"
+
+ # if pid of systemd is in our namespace, it is systemd
+ [ ! -z "${myns}" && "${myns}" = "${ns}" ] && return 0
+ done
+
+ # else, it is not systemd
+ return 1
+}
diff --git a/m4/ax_c_lto.m4 b/m4/ax_c_lto.m4
new file mode 100644
index 000000000..7e6bc0119
--- /dev/null
+++ b/m4/ax_c_lto.m4
@@ -0,0 +1,21 @@
+# AC_C_LTO
+# -------------
+# Define HAVE_LTO if -flto works.
+AN_IDENTIFIER([lto], [AC_C_LTO])
+AC_DEFUN([AC_C_LTO],
+[AC_CACHE_CHECK([if -flto builds executables], ac_cv_c_lto,
+[AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#include <stdio.h>
+ int main(int argc, char **argv) {
+ return 0;
+ }
+ ]])],
+ [ac_cv_c_lto=yes],
+ [ac_cv_c_lto=no],
+ [ac_cv_c_lto=${ac_cv_c_lto_cross_compile}])])
+if test "${ac_cv_c_lto}" = "yes"; then
+ AC_DEFINE([HAVE_LTO], 1,
+ [Define to 1 if -flto works.])
+fi
+])# AC_C_LTO
diff --git a/missing b/missing
index f62bbae30..86a8fc31e 100755
--- a/missing
+++ b/missing
@@ -1,10 +1,11 @@
#! /bin/sh
-# Common wrapper for a few potentially missing GNU programs.
+# Common stub for a few missing GNU programs while installing.
-scriptversion=2013-10-28.13; # UTC
+scriptversion=2012-01-06.13; # UTC
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -25,40 +26,68 @@ scriptversion=2013-10-28.13; # UTC
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
- echo 1>&2 "Try '$0 --help' for more information"
+ echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
-case $1 in
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
- --is-lightweight)
- # Used by our autoconf macros to check whether the available missing
- # script is modern enough.
- exit 0
- ;;
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
- --run)
- # Back-compat with the calling convention used by older automake.
- shift
- ;;
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
-Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
-to PROGRAM being missing or too old.
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
- aclocal autoconf autoheader autom4te automake makeinfo
- bison yacc flex lex help2man
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
-Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
-'g' are ignored when checking the name.
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
@@ -70,141 +99,228 @@ Send bug reports to <bug-automake@gnu.org>."
;;
-*)
- echo 1>&2 "$0: unknown '$1' option"
- echo 1>&2 "Try '$0 --help' for more information"
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
-# Run the given program, remember its exit status.
-"$@"; st=$?
-
-# If it succeeded, we are done.
-test $st -eq 0 && exit 0
-
-# Also exit now if we it failed (or wasn't found), and '--version' was
-# passed; such an option is passed most likely to detect whether the
-# program is present and works.
-case $2 in --version|--help) exit $st;; esac
-
-# Exit code 63 means version mismatch. This often happens when the user
-# tries to use an ancient version of a tool on a file that requires a
-# minimum version.
-if test $st -eq 63; then
- msg="probably too old"
-elif test $st -eq 127; then
- # Program was missing.
- msg="missing on your system"
-else
- # Program was found and executed, but failed. Give up.
- exit $st
-fi
+# normalize program name to check for.
+program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program). This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+ lex*|yacc*)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
-perl_URL=http://www.perl.org/
-flex_URL=http://flex.sourceforge.net/
-gnu_software_URL=http://www.gnu.org/software
-
-program_details ()
-{
- case $1 in
- aclocal|automake)
- echo "The '$1' program is part of the GNU Automake package:"
- echo "<$gnu_software_URL/automake>"
- echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
- echo "<$gnu_software_URL/autoconf>"
- echo "<$gnu_software_URL/m4/>"
- echo "<$perl_URL>"
- ;;
- autoconf|autom4te|autoheader)
- echo "The '$1' program is part of the GNU Autoconf package:"
- echo "<$gnu_software_URL/autoconf/>"
- echo "It also requires GNU m4 and Perl in order to run:"
- echo "<$gnu_software_URL/m4/>"
- echo "<$perl_URL>"
- ;;
- esac
-}
-
-give_advice ()
-{
- # Normalize program name to check for.
- normalized_program=`echo "$1" | sed '
- s/^gnu-//; t
- s/^gnu//; t
- s/^g//; t'`
-
- printf '%s\n' "'$1' is $msg."
-
- configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
- case $normalized_program in
- autoconf*)
- echo "You should only need it if you modified 'configure.ac',"
- echo "or m4 files included by it."
- program_details 'autoconf'
- ;;
- autoheader*)
- echo "You should only need it if you modified 'acconfig.h' or"
- echo "$configure_deps."
- program_details 'autoheader'
- ;;
- automake*)
- echo "You should only need it if you modified 'Makefile.am' or"
- echo "$configure_deps."
- program_details 'automake'
- ;;
- aclocal*)
- echo "You should only need it if you modified 'acinclude.m4' or"
- echo "$configure_deps."
- program_details 'aclocal'
- ;;
- autom4te*)
- echo "You might have modified some maintainer files that require"
- echo "the 'autom4te' program to be rebuilt."
- program_details 'autom4te'
- ;;
- bison*|yacc*)
- echo "You should only need it if you modified a '.y' file."
- echo "You may want to install the GNU Bison package:"
- echo "<$gnu_software_URL/bison/>"
- ;;
- lex*|flex*)
- echo "You should only need it if you modified a '.l' file."
- echo "You may want to install the Fast Lexical Analyzer package:"
- echo "<$flex_URL>"
- ;;
- help2man*)
- echo "You should only need it if you modified a dependency" \
- "of a man page."
- echo "You may want to install the GNU Help2man package:"
- echo "<$gnu_software_URL/help2man/>"
+ autoheader*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
;;
- makeinfo*)
- echo "You should only need it if you modified a '.texi' file, or"
- echo "any other file indirectly affecting the aspect of the manual."
- echo "You might want to install the Texinfo package:"
- echo "<$gnu_software_URL/texinfo/>"
- echo "The spurious makeinfo call might also be the consequence of"
- echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
- echo "want to install GNU make:"
- echo "<$gnu_software_URL/make/>"
- ;;
- *)
- echo "You might have modified some files without having the proper"
- echo "tools for further handling them. Check the 'README' file, it"
- echo "often tells you about the needed prerequisites for installing"
- echo "this package. You may also peek at any GNU archive site, in"
- echo "case some other package contains this missing '$1' program."
- ;;
- esac
-}
-
-give_advice "$1" | sed -e '1s/^/WARNING: /' \
- -e '2,$s/^/ /' >&2
-
-# Propagate the correct exit status (expected to be 127 for a program
-# not found, 63 for a program that failed due to version mismatch).
-exit $st
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te*)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison*|yacc*)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG=\${$#}
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex*|flex*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG=\${$#}
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit $?
+ fi
+ ;;
+
+ makeinfo*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
diff --git a/netdata-installer.sh b/netdata-installer.sh
index fa69de196..6b672a242 100755
--- a/netdata-installer.sh
+++ b/netdata-installer.sh
@@ -1,11 +1,42 @@
#!/usr/bin/env bash
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
+
+netdata_source_dir="$(pwd)"
+installer_dir="$(dirname "${0}")"
+
+if [ "${netdata_source_dir}" != "${installer_dir}" -a "${installer_dir}" != "." ]
+ then
+ echo >&2 "Warninng: you are currently in '${netdata_source_dir}' but the installer is in '${installer_dir}'."
+fi
+
+
+# -----------------------------------------------------------------------------
# reload the user profile
+
[ -f /etc/profile ] && . /etc/profile
-export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
+# make sure /etc/profile does not change our current directory
+cd "${netdata_source_dir}" || exit 1
+
+
+# -----------------------------------------------------------------------------
+# load the required functions
+
+if [ -f "${installer_dir}/installer/functions.sh" ]
+ then
+ source "${installer_dir}/installer/functions.sh" || exit 1
+else
+ source "${netdata_source_dir}/installer/functions.sh" || exit 1
+fi
+
+# make sure we save all commands we run
+run_logfile="netdata-installer.log"
+
+# -----------------------------------------------------------------------------
# fix PKG_CHECK_MODULES error
+
if [ -d /usr/share/aclocal ]
then
ACLOCAL_PATH=${ACLOCAL_PATH-/usr/share/aclocal}
@@ -18,7 +49,7 @@ umask 002
# Be nice on production environments
renice 19 $$ >/dev/null 2>/dev/null
-processors=$(cat /proc/cpuinfo | grep ^processor | wc -l)
+processors=$(cat /proc/cpuinfo 2>/dev/null | grep ^processor | wc -l)
[ $(( processors )) -lt 1 ] && processors=1
# you can set CFLAGS before running installer
@@ -35,54 +66,17 @@ printf "\n" >>netdata-installer.log
REINSTALL_PWD="${PWD}"
REINSTALL_COMMAND="$(printf "%q " "$0" "${@}"; printf "\n")"
-banner() {
- local l1=" ^" \
- l2=" |.-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-" \
- l3=" | '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' " \
- l4=" +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->" \
- sp=" " \
- netdata="netdata" start end msg="${*}"
-
- [ ${#msg} -lt ${#netdata} ] && msg="${msg}${sp:0:$(( ${#netdata} - ${#msg}))}"
- [ ${#msg} -gt $(( ${#l2} - 20 )) ] && msg="${msg:0:$(( ${#l2} - 23 ))}..."
-
- start="$(( ${#l2} / 2 - 4 ))"
- [ $(( start + ${#msg} + 4 )) -gt ${#l2} ] && start=$((${#l2} - ${#msg} - 4))
- end=$(( ${start} + ${#msg} + 4 ))
-
- echo >&2
- echo >&2 "${l1}"
- echo >&2 "${l2:0:start}${sp:0:2}${netdata}${sp:0:$((end - start - 2 - ${#netdata}))}${l2:end:$((${#l2} - end))}"
- echo >&2 "${l3:0:start}${sp:0:2}${msg}${sp:0:2}${l3:end:$((${#l2} - end))}"
- echo >&2 "${l4}"
- echo >&2
-}
-
-service="$(which service 2>/dev/null || command -v service 2>/dev/null)"
-systemctl="$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null)"
-service() {
- local cmd="${1}" action="${2}"
-
- if [ ! -z "${service}" ]
- then
- run "${service}" "${cmd}" "${action}"
- return $?
- elif [ ! -z "${systemctl}" ]
- then
- run "${systemctl}" "${action}" "${cmd}"
- return $?
- fi
- return 1
-}
+setcap="$(which setcap 2>/dev/null || command -v setcap 2>/dev/null)"
ME="$0"
DONOTSTART=0
DONOTWAIT=0
NETDATA_PREFIX=
LIBS_ARE_HERE=0
+NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS-}"
usage() {
- banner "installer command line options"
+ netdata_banner "installer command line options"
cat <<USAGE
${ME} <installer options>
@@ -91,7 +85,7 @@ Valid <installer options> are:
--install /PATH/TO/INSTALL
- If your give: --install /opt
+ If you give: --install /opt
netdata will be installed in /opt/netdata
--dont-start-it
@@ -104,6 +98,24 @@ Valid <installer options> are:
Do not wait for the user to press ENTER.
Start immediately building it.
+ --enable-plugin-freeipmi
+ --disable-plugin-freeipmi
+
+ Enable/disable the FreeIPMI plugin.
+ Default: enable it when libipmimonitoring is available.
+
+ --enable-plugin-nfacct
+ --disable-plugin-nfacct
+
+ Enable/disable the nfacct plugin.
+ Default: enable it when libmnl and libnetfilter_acct are available.
+
+ --enable-lto
+ --disable-lto
+
+ Enable/disable Link-Time-Optimization
+ Default: enabled
+
--zlib-is-really-here
--libs-are-really-here
@@ -131,7 +143,7 @@ For the plugins, you will at least need:
USAGE
}
-md5sum="$(which md5sum 2>/dev/null || command -v md5sum 2>/dev/null)"
+md5sum="$(which md5sum 2>/dev/null || command -v md5sum 2>/dev/null || command -v md5 2>/dev/null)"
get_git_config_signatures() {
local x s file md5
@@ -147,7 +159,7 @@ get_git_config_signatures() {
for c in $(git log --follow "conf.d/${x}" | grep ^commit | cut -d ' ' -f 2)
do
git checkout ${c} "conf.d/${x}" || continue
- s="$(cat "conf.d/${x}" | md5sum | cut -d ' ' -f 1)"
+ s="$(cat "conf.d/${x}" | ${md5sum} | cut -d ' ' -f 1)"
echo >>configs.signatures.tmp "${s}:${x}"
echo " ${s}"
done
@@ -191,6 +203,30 @@ do
then
DONOTWAIT=1
shift 1
+ elif [ "$1" = "--enable-plugin-freeipmi" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-plugin-freeipmi"
+ shift 1
+ elif [ "$1" = "--disable-plugin-freeipmi" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-plugin-freeipmi"
+ shift 1
+ elif [ "$1" = "--enable-plugin-nfacct" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-plugin-nfacct"
+ shift 1
+ elif [ "$1" = "--disable-plugin-nfacct" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-plugin-nfacct"
+ shift 1
+ elif [ "$1" = "--enable-lto" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-lto"
+ shift 1
+ elif [ "$1" = "--disable-lto" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-lto"
+ shift 1
elif [ "$1" = "--help" -o "$1" = "-h" ]
then
usage
@@ -208,66 +244,74 @@ do
fi
done
-banner "real-time performance monitoring, done right!"
-cat <<BANNER
+netdata_banner "real-time performance monitoring, done right!"
+cat <<BANNER1
You are about to build and install netdata to your system.
It will be installed at these locations:
- - the daemon at ${NETDATA_PREFIX}/usr/sbin/netdata
- - config files at ${NETDATA_PREFIX}/etc/netdata
- - web files at ${NETDATA_PREFIX}/usr/share/netdata
- - plugins at ${NETDATA_PREFIX}/usr/libexec/netdata
- - cache files at ${NETDATA_PREFIX}/var/cache/netdata
- - db files at ${NETDATA_PREFIX}/var/lib/netdata
- - log files at ${NETDATA_PREFIX}/var/log/netdata
- - pid file at ${NETDATA_PREFIX}/var/run
+ - the daemon at ${TPUT_CYAN}${NETDATA_PREFIX}/usr/sbin/netdata${TPUT_RESET}
+ - config files in ${TPUT_CYAN}${NETDATA_PREFIX}/etc/netdata${TPUT_RESET}
+ - web files in ${TPUT_CYAN}${NETDATA_PREFIX}/usr/share/netdata${TPUT_RESET}
+ - plugins in ${TPUT_CYAN}${NETDATA_PREFIX}/usr/libexec/netdata${TPUT_RESET}
+ - cache files in ${TPUT_CYAN}${NETDATA_PREFIX}/var/cache/netdata${TPUT_RESET}
+ - db files in ${TPUT_CYAN}${NETDATA_PREFIX}/var/lib/netdata${TPUT_RESET}
+ - log files in ${TPUT_CYAN}${NETDATA_PREFIX}/var/log/netdata${TPUT_RESET}
+BANNER1
+
+[ "${UID}" -eq 0 ] && cat <<BANNER2
+ - pid file at ${TPUT_CYAN}${NETDATA_PREFIX}/var/run/netdata.pid${TPUT_RESET}
+ - logrotate file at ${TPUT_CYAN}/etc/logrotate.d/netdata${TPUT_RESET}
+BANNER2
+
+cat <<BANNER3
This installer allows you to change the installation path.
Press Control-C and run the same command with --help for help.
-BANNER
+BANNER3
if [ "${UID}" -ne 0 ]
then
if [ -z "${NETDATA_PREFIX}" ]
then
- banner "wrong command line options!"
+ netdata_banner "wrong command line options!"
cat <<NONROOTNOPREFIX
-
-Sorry! This will fail!
-
-You are attempting to install netdata as non-root, but you plan to install it
-in system paths.
-
-Please set an installation prefix, like this:
-
- $0 ${@} --install /tmp
-
-or, run the installer as root:
-
- sudo $0 ${@}
-
-We suggest to install it as root, or certain data collectors will not be able
-to work. Netdata drops root privileges when running. So, if you plan to keep
-it, install it as root to get the full functionality.
-
+
+ ${TPUT_RED}${TPUT_BOLD}Sorry! This will fail!${TPUT_RESET}
+
+ You are attempting to install netdata as non-root, but you plan
+ to install it in system paths.
+
+ Please set an installation prefix, like this:
+
+ $0 ${@} --install /tmp
+
+ or, run the installer as root:
+
+ sudo $0 ${@}
+
+ We suggest to install it as root, or certain data collectors will
+ not be able to work. Netdata drops root privileges when running.
+ So, if you plan to keep it, install it as root to get the full
+ functionality.
+
NONROOTNOPREFIX
exit 1
else
cat <<NONROOT
-
-IMPORTANT:
-You are about to install netdata as a non-root user.
-Netdata will work, but a few data collection modules that
-require root access will fail.
-
-If you installing permanently on your system, run the
-installer like this:
-
- sudo $0 ${@}
+
+ ${TPUT_RED}${TPUT_BOLD}IMPORTANT${TPUT_RESET}:
+ You are about to install netdata as a non-root user.
+ Netdata will work, but a few data collection modules that
+ require root access will fail.
+
+ If you installing netdata permanently on your system, run
+ the installer like this:
+
+ ${TPUT_YELLOW}${TPUT_BOLD}sudo $0 ${@}${TPUT_RESET}
NONROOT
fi
@@ -306,7 +350,7 @@ then
then
echo "Will skip autoreconf step"
else
- banner "autotools v2.60 required"
+ netdata_banner "autotools v2.60 required"
cat <<"EOF"
-------------------------------------------------------------------------------
@@ -333,14 +377,14 @@ if [ ${DONOTWAIT} -eq 0 ]
then
if [ ! -z "${NETDATA_PREFIX}" ]
then
- read -p "Press ENTER to build and install netdata to '${NETDATA_PREFIX}' > "
+ eval "read >&2 -ep \$'\001${TPUT_BOLD}${TPUT_GREEN}\002Press ENTER to build and install netdata to \'\001${TPUT_CYAN}\002${NETDATA_PREFIX}\001${TPUT_YELLOW}\002\'\001${TPUT_RESET}\002 > ' -e -r REPLY"
else
- read -p "Press ENTER to build and install netdata to your system > "
+ eval "read >&2 -ep \$'\001${TPUT_BOLD}${TPUT_GREEN}\002Press ENTER to build and install netdata to your system\001${TPUT_RESET}\002 > ' -e -r REPLY"
fi
fi
build_error() {
- banner "sorry, it failed to build..."
+ netdata_banner "sorry, it failed to build..."
cat <<EOF
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -375,31 +419,6 @@ EOF
exit 1
}
-run() {
- printf >>netdata-installer.log "# "
- printf >>netdata-installer.log "%q " "${@}"
- printf >>netdata-installer.log " ... "
-
- printf >&2 "\n"
- printf >&2 ":-----------------------------------------------------------------------------\n"
- printf >&2 "Running command:\n"
- printf >&2 "\n"
- printf >&2 "%q " "${@}"
- printf >&2 "\n"
-
- "${@}"
-
- local ret=$?
- if [ ${ret} -ne 0 ]
- then
- printf >>netdata-installer.log "FAILED!\n"
- else
- printf >>netdata-installer.log "OK\n"
- fi
-
- return ${ret}
-}
-
if [ ${LIBS_ARE_HERE} -eq 1 ]
then
shift
@@ -412,6 +431,11 @@ fi
trap build_error EXIT
+
+# -----------------------------------------------------------------------------
+echo >&2
+progress "Run autotools to configure the build environment"
+
if [ "$have_autotools" ]
then
run ./autogen.sh || exit 1
@@ -421,29 +445,28 @@ run ./configure \
--prefix="${NETDATA_PREFIX}/usr" \
--sysconfdir="${NETDATA_PREFIX}/etc" \
--localstatedir="${NETDATA_PREFIX}/var" \
- --with-zlib --with-math --with-user=netdata \
+ --with-zlib \
+ --with-math \
+ --with-user=netdata \
+ ${NETDATA_CONFIGURE_OPTIONS} \
CFLAGS="${CFLAGS}" || exit 1
# remove the build_error hook
trap - EXIT
-if [ -f src/netdata ]
- then
- echo >&2 "Cleaning a possibly old compilation ..."
- run make clean
-fi
+# -----------------------------------------------------------------------------
+progress "Cleanup compilation directory"
+
+[ -f src/netdata ] && run make clean
+
+# -----------------------------------------------------------------------------
+progress "Compile netdata"
-echo >&2 "Compiling netdata ..."
run make -j${processors} || exit 1
-if [ "${BASH_VERSINFO[0]}" -ge "4" ]
-then
- declare -A configs_signatures=()
- if [ -f "configs.signatures" ]
- then
- source "configs.signatures" || echo >&2 "ERROR: Failed to load configs.signatures !"
- fi
-fi
+
+# -----------------------------------------------------------------------------
+progress "Migrate configuration files for node.d.plugin and charts.d.plugin"
# migrate existing configuration files
# for node.d and charts.d
@@ -486,6 +509,36 @@ if [ -d "${NETDATA_PREFIX}/etc/netdata" ]
done
fi
+# -----------------------------------------------------------------------------
+progress "Backup existing netdata configuration before installing it"
+
+if [ "${BASH_VERSINFO[0]}" -ge "4" ]
+then
+ declare -A configs_signatures=()
+ if [ -f "configs.signatures" ]
+ then
+ source "configs.signatures" || echo >&2 "ERROR: Failed to load configs.signatures !"
+ fi
+fi
+
+config_signature_matches() {
+ local md5="${1}" file="${2}"
+
+ if [ "${BASH_VERSINFO[0]}" -ge "4" ]
+ then
+ [ "${configs_signatures[${md5}]}" = "${file}" ] && return 0
+ return 1
+ fi
+
+ if [ -f "configs.signatures" ]
+ then
+ grep "\['${md5}'\]='${file}'" "configs.signatures" >/dev/null
+ return $?
+ fi
+
+ return 1
+}
+
# backup user configurations
installer_backup_suffix="${PID}.${RANDOM}"
for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
@@ -498,7 +551,8 @@ do
if [ -z "${md5sum}" -o ! -x "${md5sum}" ]
then
# we don't have md5sum - keep it
- cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
+ echo >&2 "File '${TPUT_CYAN}${x}${TPUT_RESET}' ${TPUT_RET}is not known to distribution${TPUT_RESET}. Keeping it."
+ run cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
else
# find it relative filename
f="${x/*\/etc\/netdata\//}"
@@ -512,20 +566,14 @@ do
cp "conf.d/${f}" "${x}.orig"
fi
- if [ "${BASH_VERSINFO[0]}" -ge "4" ]
- then
- if [ "${configs_signatures[${md5}]}" = "${f}" ]
+ if config_signature_matches "${md5}" "${f}"
then
- # it is a stock version - don't keep it
- echo >&2 "File '${x}' is stock version."
- else
- # edited by user - keep it
- echo >&2 "File '${x}' has been edited by user."
- cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
- fi
+ # it is a stock version - don't keep it
+ echo >&2 "File '${TPUT_CYAN}${x}${TPUT_RESET}' is stock version."
else
- echo >&2 "File '${x}' cannot be check for custom edits."
- cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
+ # edited by user - keep it
+ echo >&2 "File '${TPUT_CYAN}${x}${TPUT_RESET}' ${TPUT_RED} has been edited by user${TPUT_RESET}. Keeping it."
+ run cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
fi
fi
@@ -535,194 +583,79 @@ do
fi
done
-echo >&2 "Installing netdata ..."
+
+# -----------------------------------------------------------------------------
+progress "Install netdata"
+
run make install || exit 1
-# restore user configurations
+
+# -----------------------------------------------------------------------------
+progress "Restore user edited netdata configuration files"
+
for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
do
if [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
then
- cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}"
- rm -f "${x}.installer_backup.${installer_backup_suffix}"
+ run cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}" && \
+ run rm -f "${x}.installer_backup.${installer_backup_suffix}"
fi
done
-echo >&2 "Fixing permissions ..."
-
-check_cmd() {
- which "${1}" >/dev/null 2>&1 && return 0
- command -v "${1}" >/dev/null 2>&1 && return 0
- return 1
-}
-
-portable_add_user() {
- local username="${1}"
-
- getent passwd "${username}" > /dev/null 2>&1
- [ $? -eq 0 ] && return 0
-
- echo >&2 "Adding ${username} user account ..."
-
- local nologin="$(which nologin 2>/dev/null || command -v nologin 2>/dev/null || echo '/bin/false')"
-
- # Linux
- if check_cmd useradd
- then
- run useradd -r -g "${username}" -c "${username}" -s "${nologin}" -d / "${username}" && return 0
- fi
-
- # FreeBSD
- if check_cmd pw
- then
- run pw useradd "${username}" -d / -g "${username}" -s "${nologin}" && return 0
- fi
-
- # BusyBox
- if check_cmd adduser
- then
- run adduser -D -G "${username}" "${username}" && return 0
- fi
-
- echo >&2 "Failed to add ${username} user account !"
-
- return 1
-}
-
-portable_add_group() {
- local groupname="${1}"
-
- getent group "${groupname}" > /dev/null 2>&1
- [ $? -eq 0 ] && return 0
-
- echo >&2 "Adding ${groupname} user group ..."
-
- # Linux
- if check_cmd groupadd
- then
- run groupadd -r "${groupname}" && return 0
- fi
-
- # FreeBSD
- if check_cmd pw
- then
- run pw groupadd "${groupname}" && return 0
- fi
-
- # BusyBox
- if check_cmd addgroup
- then
- run addgroup "${groupname}" && return 0
- fi
-
- echo >&2 "Failed to add ${groupname} user group !"
- return 1
-}
-
-portable_add_user_to_group() {
- local groupname="${1}" username="${2}"
-
- getent group "${groupname}" > /dev/null 2>&1
- [ $? -ne 0 ] && return 1
-
- # find the user is already in the group
- local users=$(getent group "${groupname}" | cut -d ':' -f 4)
- if [[ ",${users}," =~ ,${username}, ]]
- then
- # username is already there
- return 0
- else
- # username is not in group
- echo >&2 "Adding ${username} user to the ${groupname} group ..."
-
- # Linux
- if check_cmd usermod
- then
- run usermod -a -G "${groupname}" "${username}" && return 0
- fi
-
- # FreeBSD
- if check_cmd pw
- then
- run pw groupmod "${groupname}" -m "${username}" && return 0
- fi
-
- # BusyBox
- if check_cmd addgroup
- then
- run addgroup "${username}" "${groupname}" && return 0
- fi
- echo >&2 "Failed to add user ${username} to group ${groupname} !"
- return 1
- fi
-}
-
-iscontainer() {
- # man systemd-detect-virt
- local cmd=$(which systemd-detect-virt 2>/dev/null || command -v systemd-detect-virt 2>/dev/null)
- if [ ! -z "${cmd}" -a -x "${cmd}" ]
- then
- "${cmd}" --container >/dev/null 2>&1 && return 0
- fi
-
- # /proc/1/sched exposes the host's pid of our init !
- # http://stackoverflow.com/a/37016302
- local pid=$( cat /proc/1/sched | head -n 1 | { IFS='(),#:' read name pid th threads; echo $pid; } )
- local p=$(( pid + 0 ))
- [ ${pid} -ne 1 ] && return 0
-
- # lxc sets environment variable 'container'
- [ ! -z "${container}" ] && return 0
-
- # docker creates /.dockerenv
- # http://stackoverflow.com/a/25518345
- [ -f "/.dockerenv" ] && return 0
+# -----------------------------------------------------------------------------
+progress "Fix generated files permissions"
- # ubuntu and debian supply /bin/running-in-container
- # https://www.apt-browse.org/browse/ubuntu/trusty/main/i386/upstart/1.12.1-0ubuntu4/file/bin/running-in-container
- if [ -x "/bin/running-in-container" ]
- then
- "/bin/running-in-container" >/dev/null 2>&1 && return 0
- fi
+run find ./system/ -type f -a \! -name \*.in -a \! -name Makefile\* -a \! -name \*.conf -a \! -name \*.service -a \! -name \*.logrotate -exec chmod 755 {} \;
- return 1
-}
-run find ./system/ -type f -a \! -name \*.in -a \! -name Makefile\* -a \! -name \*.conf -a \! -name \*.service -a \! -name \*.logrotate -exec chmod 755 {} \;
+# -----------------------------------------------------------------------------
+progress "Add user netdata to required user groups"
NETDATA_ADDED_TO_DOCKER=0
NETDATA_ADDED_TO_NGINX=0
NETDATA_ADDED_TO_VARNISH=0
NETDATA_ADDED_TO_HAPROXY=0
+NETDATA_ADDED_TO_ADM=0
+NETDATA_ADDED_TO_NSD=0
if [ ${UID} -eq 0 ]
then
portable_add_group netdata
portable_add_user netdata
- portable_add_user_to_group docker netdata && NETDATA_ADDED_TO_DOCKER=1
- portable_add_user_to_group nginx netdata && NETDATA_ADDED_TO_NGINX=1
+ portable_add_user_to_group docker netdata && NETDATA_ADDED_TO_DOCKER=1
+ portable_add_user_to_group nginx netdata && NETDATA_ADDED_TO_NGINX=1
portable_add_user_to_group varnish netdata && NETDATA_ADDED_TO_VARNISH=1
portable_add_user_to_group haproxy netdata && NETDATA_ADDED_TO_HAPROXY=1
+ portable_add_user_to_group adm netdata && NETDATA_ADDED_TO_ADM=1
+ portable_add_user_to_group nsd netdata && NETDATA_ADDED_TO_NSD=1
+ run_ok
+else
+ run_failed "The installer does not run as root."
+fi
+
+# -----------------------------------------------------------------------------
+progress "Install logrotate configuration for netdata"
+if [ ${UID} -eq 0 ]
+ then
if [ -d /etc/logrotate.d -a ! -f /etc/logrotate.d/netdata ]
then
- echo >&2 "Adding netdata logrotate configuration ..."
run cp system/netdata.logrotate /etc/logrotate.d/netdata
fi
if [ -f /etc/logrotate.d/netdata ]
then
- echo >&2 "Fixing netdata logrotate permissions ..."
run chmod 644 /etc/logrotate.d/netdata
fi
fi
# -----------------------------------------------------------------------------
-# load options from the configuration file
+progress "Read installation options from netdata.conf"
# create an empty config if it does not exist
-[ ! -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ] && touch "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+[ ! -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ] && \
+ touch "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
# function to extract values from the config file
config_option() {
@@ -775,17 +708,14 @@ NETDATA_RUN_DIR="${NETDATA_PREFIX}/var/run"
# -----------------------------------------------------------------------------
-# prepare the directories
+progress "Fix permissions of netdata directories (using user '${NETDATA_USER}')"
-# this is needed if NETDATA_PREFIX is not empty
if [ ! -d "${NETDATA_RUN_DIR}" ]
then
- mkdir -p "${NETDATA_RUN_DIR}" || exit 1
+ # this is needed if NETDATA_PREFIX is not empty
+ run mkdir -p "${NETDATA_RUN_DIR}" || exit 1
fi
-echo >&2
-echo >&2 "Fixing directories (user: ${NETDATA_USER})..."
-
# --- conf dir ----
for x in "python.d" "charts.d" "node.d"
@@ -832,7 +762,13 @@ run chmod 755 "${NETDATA_LOG_DIR}"
if [ ${UID} -eq 0 ]
then
- run chown "${NETDATA_USER}:root" "${NETDATA_LOG_DIR}"
+ # find the admin group
+ admin_group=
+ test -z "${admin_group}" && getent group root >/dev/null 2>&1 && admin_group="root"
+ test -z "${admin_group}" && getent group daemon >/dev/null 2>&1 && admin_group="daemon"
+ test -z "${admin_group}" && admin_group="${NETDATA_USER}"
+
+ run chown "${NETDATA_USER}:${admin_group}" "${NETDATA_LOG_DIR}"
run chown -R root "${NETDATA_PREFIX}/usr/libexec/netdata"
run find "${NETDATA_PREFIX}/usr/libexec/netdata" -type d -exec chmod 0755 {} \;
run find "${NETDATA_PREFIX}/usr/libexec/netdata" -type f -exec chmod 0644 {} \;
@@ -842,15 +778,18 @@ if [ ${UID} -eq 0 ]
setcap_ret=1
if ! iscontainer
then
- run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
- setcap_ret=$?
+ if [ ! -z "${setcap}" ]
+ then
+ run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+ setcap_ret=$?
+ fi
if [ ${setcap_ret} -eq 0 ]
then
# if we managed to setcap
# but we fail to execute apps.plugin
# trigger setuid to root
- "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin" -v >/dev/null 2>&1
+ "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin" -t >/dev/null 2>&1
setcap_ret=$?
fi
fi
@@ -861,6 +800,13 @@ if [ ${UID} -eq 0 ]
run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
fi
+
+ if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin" ]
+ then
+ run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
+ run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
+ fi
+
else
run chown "${NETDATA_USER}:${NETDATA_USER}" "${NETDATA_LOG_DIR}"
run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${NETDATA_PREFIX}/usr/libexec/netdata"
@@ -870,33 +816,82 @@ fi
# --- fix #1292 bug ---
-[ -d "${NETDATA_PREFIX}/usr/libexec" ] && run chmod a+rX "${NETDATA_PREFIX}/usr/libexec"
+[ -d "${NETDATA_PREFIX}/usr/libexec" ] && run chmod a+rX "${NETDATA_PREFIX}/usr/libexec"
[ -d "${NETDATA_PREFIX}/usr/share/netdata" ] && run chmod a+rX "${NETDATA_PREFIX}/usr/share/netdata"
+
# -----------------------------------------------------------------------------
-# check if we can re-start netdata
+progress "Install netdata at system init"
-if [ ${DONOTSTART} -eq 1 ]
- then
- if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
+installed_init_d=0
+install_non_systemd_init() {
+ [ "${UID}" != 0 ] && return 1
+
+ local key="unknown"
+ if [ -f /etc/os-release ]
then
- echo >&2 "Generating empty config file in: ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
- echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ source /etc/os-release || return 1
+ key="${ID}-${VERSION_ID}"
- if [ "${UID}" -eq 0 ]
+ elif [ -f /etc/centos-release ]
+ then
+ key=$(</etc/centos-release)
+ fi
+
+ if [ -d /etc/init.d -a ! -f /etc/init.d/netdata ]
+ then
+ if [ "${key}" = "gentoo" ]
then
- chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ run cp system/netdata-openrc /etc/init.d/netdata && \
+ run chmod 755 /etc/init.d/netdata && \
+ run rc-update add netdata default && \
+ installed_init_d=1
+
+ elif [ "${key}" = "ubuntu-12.04" -o "${key}" = "ubuntu-14.04" -o "${key}" = "debian-7" ]
+ then
+ run cp system/netdata-lsb /etc/init.d/netdata && \
+ run chmod 755 /etc/init.d/netdata && \
+ run update-rc.d netdata defaults && \
+ run update-rc.d netdata enable && \
+ installed_init_d=1
+
+ elif [ "${key}" = "CentOS release 6.8 (Final)" -o "${key}" = "amzn-2016.09" ]
+ then
+ run cp system/netdata-init-d /etc/init.d/netdata && \
+ run chmod 755 /etc/init.d/netdata && \
+ run chkconfig netdata on && \
+ installed_init_d=1
fi
- chmod 0644 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
fi
- banner "is installed now!"
- echo >&2 " enjoy real-time performance and health monitoring..."
- exit 0
+
+ return 0
+}
+
+if [ "${UID}" -eq 0 ]
+ then
+
+ if issystemd
+ then
+ # systemd is running on this system
+
+ if [ ! -f /etc/systemd/system/netdata.service ]
+ then
+ echo >&2 "Installing systemd service..."
+ run cp system/netdata.service /etc/systemd/system/netdata.service && \
+ run systemctl daemon-reload && \
+ run systemctl enable netdata
+ fi
+ else
+ install_non_systemd_init
+ fi
fi
+
# -----------------------------------------------------------------------------
-# stop a running netdata
+# check if we can re-start netdata
+
+started=0
isnetdata() {
if [ -d /proc/self ]
@@ -946,7 +941,7 @@ stop_all_netdata() {
myns="$(readlink /proc/self/ns/pid 2>/dev/null)"
- echo >&2 "Stopping a (possibly) running netdata..."
+ # echo >&2 "Stopping a (possibly) running netdata (namespace '${myns}')..."
for p in $(cat "${NETDATA_RUN_DIR}/netdata.pid" 2>/dev/null) \
$(cat /var/run/netdata.pid 2>/dev/null) \
@@ -962,111 +957,25 @@ stop_all_netdata() {
done
}
-# -----------------------------------------------------------------------------
-# check for systemd
-
-issystemd() {
- local pids p myns ns systemctl
-
- # if the directory /etc/systemd/system does not exit, it is not systemd
- [ ! -d /etc/systemd/system ] && return 1
-
- # if there is no systemctl command, it is not systemd
- systemctl=$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null)
- [ -z "${systemctl}" -o ! -x "${systemctl}" ] && return 1
-
- # if pid 1 is systemd, it is systemd
- [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
-
- # if systemd is not running, it is not systemd
- pids=$(pidof systemd 2>/dev/null)
- [ -z "${pids}" ] && return 1
-
- # check if the running systemd processes are not in our namespace
- myns="$(readlink /proc/self/ns/pid 2>/dev/null)"
- for p in ${pids}
- do
- ns="$(readlink /proc/${p}/ns/pid 2>/dev/null)"
-
- # if pid of systemd is in our namespace, it is systemd
- [ ! -z "${myns}" && "${myns}" = "${ns}" ] && return 0
- done
-
- # else, it is not systemd
- return 1
-}
-
-installed_init_d=0
-install_non_systemd_init() {
- [ "${UID}" != 0 ] && return 1
-
- local key="unknown"
- if [ -f /etc/os-release ]
- then
- source /etc/os-release || return 1
- key="${ID}-${VERSION_ID}"
-
- elif [ -f /etc/centos-release ]
- then
- key=$(</etc/centos-release)
- fi
-
- if [ -d /etc/init.d -a ! -f /etc/init.d/netdata ]
+if [ ${DONOTSTART} -eq 1 ]
+ then
+ if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
then
- if [ "${key}" = "gentoo" ]
- then
- run cp system/netdata-openrc /etc/init.d/netdata && \
- run chmod 755 /etc/init.d/netdata && \
- run rc-update add netdata default && \
- installed_init_d=1
-
- elif [ "${key}" = "ubuntu-12.04" -o "${key}" = "ubuntu-14.04" -o "${key}" = "debian-7" ]
- then
- run cp system/netdata-lsb /etc/init.d/netdata && \
- run chmod 755 /etc/init.d/netdata && \
- run update-rc.d netdata defaults && \
- run update-rc.d netdata enable && \
- installed_init_d=1
+ echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
- elif [ "${key}" = "CentOS release 6.8 (Final)" -o "${key}" = "amzn-2016.09" ]
+ if [ "${UID}" -eq 0 ]
then
- run cp system/netdata-init-d /etc/init.d/netdata && \
- run chmod 755 /etc/init.d/netdata && \
- run chkconfig netdata on && \
- installed_init_d=1
+ chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
fi
+ chmod 0644 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
fi
- return 0
-}
-
-started=0
-if [ "${UID}" -eq 0 ]
- then
+else
- if issystemd
- then
- # systemd is running on this system
+ progress "Start netdata"
- if [ ! -f /etc/systemd/system/netdata.service ]
+ if [ "${UID}" -eq 0 ]
then
- echo >&2 "Installing systemd service..."
- run cp system/netdata.service /etc/systemd/system/netdata.service && \
- run systemctl daemon-reload && \
- run systemctl enable netdata
- else
- service netdata stop
- fi
-
- stop_all_netdata
- service netdata restart && started=1
- else
- install_non_systemd_init
- fi
-
- if [ ${started} -eq 0 ]
- then
- # check if we can use the system service
service netdata stop
stop_all_netdata
service netdata restart && started=1
@@ -1075,89 +984,88 @@ if [ "${UID}" -eq 0 ]
service netdata start && started=1
fi
fi
-fi
-if [ ${started} -eq 0 ]
-then
- # still not started...
+ if [ ${started} -eq 0 ]
+ then
+ # still not started...
- stop_all_netdata
+ stop_all_netdata
+
+ echo >&2 "Starting netdata..."
+ run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}"
+ if [ $? -ne 0 ]
+ then
+ echo >&2
+ echo >&2 "SORRY! FAILED TO START NETDATA!"
+ exit 1
+ else
+ echo >&2 "OK. NetData Started!"
+ fi
- echo >&2 "Starting netdata..."
- run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}"
- if [ $? -ne 0 ]
- then
echo >&2
- echo >&2 "SORRY! FAILED TO START NETDATA!"
- exit 1
- else
- echo >&2 "OK. NetData Started!"
fi
- echo >&2
-fi
-
-# -----------------------------------------------------------------------------
-# save a config file, if it is not already there
-
-if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
- then
- echo >&2
- echo >&2 "-------------------------------------------------------------------------------"
- echo >&2
- echo >&2 "Downloading default configuration from netdata..."
- sleep 5
+ # -----------------------------------------------------------------------------
+ # save a config file, if it is not already there
- # remove a possibly obsolete download
- [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
+ if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
+ then
+ echo >&2
+ echo >&2 "-------------------------------------------------------------------------------"
+ echo >&2
+ echo >&2 "Downloading default configuration from netdata..."
+ sleep 5
- # disable a proxy to get data from the local netdata
- export http_proxy=
- export https_proxy=
+ # remove a possibly obsolete download
+ [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
- # try wget
- wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
- ret=$?
+ # disable a proxy to get data from the local netdata
+ export http_proxy=
+ export https_proxy=
- # try curl
- if [ ${ret} -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
- then
- curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
+ # try wget
+ wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
ret=$?
- fi
- if [ ${ret} -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
- then
- mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
- echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ # try curl
+ if [ ${ret} -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
+ then
+ curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
+ ret=$?
+ fi
- if [ "${UID}" -eq 0 ]
+ if [ ${ret} -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
then
- chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+
+ if [ "${UID}" -eq 0 ]
+ then
+ chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ fi
+ chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ else
+ echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
+ [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
fi
- chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
- else
- echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
- [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
fi
fi
# -----------------------------------------------------------------------------
-# Check for KSM
+progress "Check KSM (kernel memory deduper)"
ksm_is_available_but_disabled() {
cat <<KSM1
--------------------------------------------------------------------------------
-Memory de-duplication instructions
+${TPUT_BOLD}Memory de-duplication instructions${TPUT_RESET}
You have kernel memory de-duper (called Kernel Same-page Merging,
or KSM) available, but it is not currently enabled.
To enable it run:
-echo 1 >/sys/kernel/mm/ksm/run
-echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
+ ${TPUT_YELLOW}${TPUT_BOLD}echo 1 >/sys/kernel/mm/ksm/run${TPUT_RESET}
+ ${TPUT_YELLOW}${TPUT_BOLD}echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs${TPUT_RESET}
If you enable it, you will save 40-60% of netdata memory.
@@ -1167,8 +1075,7 @@ KSM1
ksm_is_not_available() {
cat <<KSM2
--------------------------------------------------------------------------------
-Memory de-duplication not present in your kernel
+${TPUT_BOLD}Memory de-duplication not present in your kernel${TPUT_RESET}
It seems you do not have kernel memory de-duper (called Kernel Same-page
Merging, or KSM) available.
@@ -1191,14 +1098,13 @@ else
fi
# -----------------------------------------------------------------------------
-# Check for version.txt
+progress "Check version.txt"
if [ ! -s web/version.txt ]
then
cat <<VERMSG
--------------------------------------------------------------------------------
-Version update check warning
+${TPUT_BOLD}Version update check warning${TPUT_RESET}
The way you downloaded netdata, we cannot find its version. This means the
Update check on the dashboard, will not work.
@@ -1212,14 +1118,13 @@ VERMSG
fi
# -----------------------------------------------------------------------------
-# apps.plugin warning
+progress "Check apps.plugin"
if [ "${UID}" -ne 0 ]
then
cat <<SETUID_WARNING
--------------------------------------------------------------------------------
-apps.plugin needs privileges
+${TPUT_BOLD}apps.plugin needs privileges${TPUT_RESET}
Since you have installed netdata as a normal user, to have apps.plugin collect
all the needed data, you have to give it the access rights it needs, by running
@@ -1227,14 +1132,14 @@ either of the following sets of commands:
To run apps.plugin with escalated capabilities:
- sudo chown root:${NETDATA_USER} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
- sudo chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
- sudo setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+ ${TPUT_YELLOW}${TPUT_BOLD}sudo chown root:${NETDATA_USER} \"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin\"${TPUT_RESET}
+ ${TPUT_YELLOW}${TPUT_BOLD}sudo chmod 0750 \"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin\"${TPUT_RESET}
+ ${TPUT_YELLOW}${TPUT_BOLD}sudo setcap cap_dac_read_search,cap_sys_ptrace+ep \"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin\"${TPUT_RESET}
or, to run apps.plugin as root:
- sudo chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
- sudo chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+ ${TPUT_YELLOW}${TPUT_BOLD}sudo chown root \"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin\"${TPUT_RESET}
+ ${TPUT_YELLOW}${TPUT_BOLD}sudo chmod 4755 \"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin\"${TPUT_RESET}
apps.plugin is performing a hard-coded function of data collection for all
running processes. It cannot be instructed from the netdata daemon to perform
@@ -1244,7 +1149,7 @@ SETUID_WARNING
fi
# -----------------------------------------------------------------------------
-# Keep un-install info
+progress "Generate netdata-uninstaller.sh"
cat >netdata-uninstaller.sh <<UNINSTALL
#!/usr/bin/env bash
@@ -1366,37 +1271,49 @@ if [ $? -eq 0 -a "${NETDATA_ADDED_TO_HAPROXY}" = "1" ]
echo " gpasswd -d netdata haproxy"
fi
+getent group adm > /dev/null
+if [ $? -eq 0 -a "${NETDATA_ADDED_TO_ADM}" = "1" ]
+ then
+ echo
+ echo "You may also want to remove the netdata user from the adm group"
+ echo "by running:"
+ echo " gpasswd -d netdata adm"
+fi
+
+getent group nsd > /dev/null
+if [ $? -eq 0 -a "${NETDATA_ADDED_TO_NSD}" = "1" ]
+ then
+ echo
+ echo "You may also want to remove the netdata user from the nsd group"
+ echo "by running:"
+ echo " gpasswd -d netdata nsd"
+fi
+
UNINSTALL
chmod 750 netdata-uninstaller.sh
# -----------------------------------------------------------------------------
+progress "Basic netdata instructions"
cat <<END
-
--------------------------------------------------------------------------------
-
-OK. NetData is installed and it is running.
-
--------------------------------------------------------------------------------
-
-By default netdata listens on all IPs on port ${NETDATA_PORT},
+netdata by default listens on all IPs on port ${NETDATA_PORT},
so you can access it with:
-http://this.machine.ip:${NETDATA_PORT}/
+ ${TPUT_CYAN}${TPUT_BOLD}http://this.machine.ip:${NETDATA_PORT}/${TPUT_RESET}
To stop netdata, just kill it, with:
- killall netdata
+ ${TPUT_YELLOW}${TPUT_BOLD}killall netdata${TPUT_RESET}
To start it, just run it:
- ${NETDATA_PREFIX}/usr/sbin/netdata
+ ${TPUT_YELLOW}${TPUT_BOLD}${NETDATA_PREFIX}/usr/sbin/netdata${TPUT_RESET}
END
-echo >&2 "Uninstall script generated: ./netdata-uninstaller.sh"
+echo >&2 "Uninstall script generated: ${TPUT_RED}${TPUT_BOLD}./netdata-uninstaller.sh${TPUT_RESET}"
if [ -d .git ]
then
@@ -1408,6 +1325,7 @@ force=0
export PATH="\${PATH}:${PATH}"
export CFLAGS="${CFLAGS}"
+export NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS}"
INSTALL_UID="${UID}"
if [ "\${INSTALL_UID}" != "\${UID}" ]
@@ -1436,7 +1354,7 @@ if [ -t 2 ]
else
# we are headless
# create a temporary file for the log
- tmp=\$(mktemp /tmp/netdata-updater-log-XXXXXX.log)
+ tmp=\$(mktemp /tmp/netdata-updater.log.XXXXXX)
# open fd 3 and send it to tmp
exec 3>\${tmp}
fi
@@ -1512,13 +1430,40 @@ update && exit 0
REINSTALL
chmod 755 netdata-updater.sh.new
mv -f netdata-updater.sh.new netdata-updater.sh
- echo >&2 "Update script generated : ./netdata-updater.sh"
+ echo >&2 "Update script generated : ${TPUT_GREEN}${TPUT_BOLD}./netdata-updater.sh${TPUT_RESET}"
+ echo >&2
+ echo >&2 "${TPUT_DIM}${TPUT_BOLD}netdata-updater.sh${TPUT_RESET}${TPUT_DIM} can work from cron. It will trigger an email from cron"
+ echo >&2 "only if it fails (it does not print anything if it can update netdata).${TPUT_RESET}"
+ if [ "${UID}" -eq "0" ]
+ then
+ if [ -d "/etc/cron.daily" -a ! -f "/etc/cron.daily/netdata-updater.sh" ]
+ then
+ echo >&2 "${TPUT_DIM}Run this to automatically check and install netdata updates once per day:${TPUT_RESET}"
+ echo >&2
+ echo >&2 "${TPUT_YELLOW}${TPUT_BOLD}ln -s ${PWD}/netdata-updater.sh /etc/cron.daily/netdata-updater.sh${TPUT_RESET}"
+ elif [ -d "/etc/periodic/daily" -a ! -f "/etc/periodic/daily/netdata-updater" ]
+ then
+ echo >&2 "${TPUT_DIM}Run this to automatically check and install netdata updates once per day:${TPUT_RESET}"
+ echo >&2
+ echo >&2 "${TPUT_YELLOW}${TPUT_BOLD}ln -s ${PWD}/netdata-updater.sh /etc/periodic/daily/netdata-updater${TPUT_RESET}"
+ fi
+ fi
elif [ -f "netdata-updater.sh" ]
then
rm "netdata-updater.sh"
fi
-banner "is installed and running now!"
+# -----------------------------------------------------------------------------
+echo >&2
+progress "We are done!"
+
+if [ ${started} -eq 1 ]
+ then
+ netdata_banner "is installed and running now!"
+else
+ netdata_banner "is installed now!"
+fi
+
echo >&2 " enjoy real-time performance and health monitoring..."
echo >&2
exit 0
diff --git a/netdata.spec b/netdata.spec
index 1d0988579..6a3d63f87 100644
--- a/netdata.spec
+++ b/netdata.spec
@@ -1,20 +1,9 @@
-%define contentdir %{_datadir}/netdata
-%if 0%{?suse_version}
-%define distro_post %service_add_post netdata.service
-%define distro_preun %service_del_preun netdata.service
-%define distro_postun %service_del_postun netdata.service
-%define distro_buildrequires BuildRequires:\ systemd-rpm-macros
-%else
-%define distro_post %systemd_post netdata.service
-%define distro_preun %systemd_preun netdata.service
-%define distro_postun %systemd_postun_with_restart netdata.service
-%define distro_buildrequires %{nil}
-%endif
+%global contentdir %{_datadir}/netdata
# This is temporary and should eventually be resolved. This bypasses
# the default rhel __os_install_post which throws a python compile
# error.
-%define __os_install_post %{nil}
+%global __os_install_post %{nil}
#
# Conditional build:
@@ -26,33 +15,79 @@
%undefine with_systemd
%endif
+%if %{with systemd}
+%if 0%{?suse_version}
+%global netdata_initd_buildrequires \
+BuildRequires: systemd-rpm-macros \
+%{nil}
+%global netdata_initd_requires \
+%{?systemd_requires} \
+%{nil}
+%global netdata_init_post %service_add_post netdata.service
+%global netdata_init_preun %service_del_preun netdata.service
+%global netdata_init_postun %service_del_postun netdata.service
+%else
+%global netdata_initd_buildrequires %{nil}
+%global netdata_initd_requires \
+Requires(preun): systemd-units \
+Requires(postun): systemd-units \
+Requires(post): systemd-units \
+%{nil}
+%global netdata_init_post %systemd_post netdata.service
+%global netdata_init_preun %systemd_preun netdata.service
+%global netdata_init_postun %systemd_postun_with_restart netdata.service
+%endif
+%else
+%global netdata_initd_buildrequires %{nil}
+%global netdata_initd_requires \
+Requires(post): chkconfig \
+%{nil}
+%global netdata_init_post \
+/sbin/chkconfig --add netdata \
+%{nil}
+%global netdata_init_preun %{nil} \
+if [ $1 = 0 ]; then \
+ /sbin/service netdata stop > /dev/null 2>&1 \
+ /sbin/chkconfig --del netdata \
+fi \
+%{nil}
+%global netdata_init_postun %{nil} \
+if [ $1 != 0 ]; then \
+ /sbin/service netdata condrestart 2>&1 > /dev/null \
+fi \
+%{nil}
+%endif
+
+%if 0%{?_fedora}
+%global netdata_recommends \
+Recommends: curl \
+Recommends: iproute-tc \
+Recommends: lm_sensors \
+Recommends: nmap-ncat \
+Recommends: nodejs \
+Recommends: python \
+Recommends: PyYAML \
+Recommends: python2-PyMySQL \
+Recommends: python2-psycopg2 \
+%{nil}
+%else
+%global netdata_recommends %{nil}
+%endif
+
Summary: Real-time performance monitoring, done right
Name: netdata
-Version: 1.5.0
+Version: 1.6.0
Release: 1%{?dist}
-License: GPL v3+
+License: GPLv3+
Group: Applications/System
-Source0: http://firehol.org/download/netdata/releases/v1.5.0/%{name}-1.5.0.tar.xz
-URL: http://my-netdata.io/
-%distro_buildrequires
-BuildRequires: /usr/bin/autoconf
-BuildRequires: /usr/bin/automake
+Source0: https://firehol.org/download/netdata/releases/v1.6.0/%{name}-1.6.0.tar.xz
+URL: http://my-netdata.io
BuildRequires: pkgconfig
BuildRequires: xz
BuildRequires: zlib-devel
BuildRequires: libuuid-devel
Requires: zlib
Requires: libuuid
-Requires(post): libcap
-Recommends: curl
-Recommends: iproute-tc
-Recommends: lm_sensors
-Recommends: nmap-ncat
-Recommends: nodejs
-Recommends: python
-Recommends: PyYAML
-Recommends: python2-PyMySQL
-Recommends: python2-psycopg2
# Packages can be found in the EPEL repo
%if %{with nfacct}
@@ -64,18 +99,11 @@ Requires: libnetfilter_acct
Requires(pre): /usr/sbin/groupadd
Requires(pre): /usr/sbin/useradd
+Requires(post): libcap
-%if %{with systemd}
-%if 0%{?suse_version}
-%{?systemd_requires}
-%else
-Requires(preun): systemd-units
-Requires(postun): systemd-units
-Requires(post): systemd-units
-%endif
-%else
-Requires(post): chkconfig
-%endif
+%{netdata_initd_buildrequires}
+%{netdata_recommends}
+%{netdata_initd_requires}
%description
netdata is the fastest way to visualize metrics. It is a resource
@@ -88,10 +116,9 @@ so that you can get insights of what is happening now and what just
happened, on your systems and applications.
%prep
-%setup -q
+%setup -q -n netdata-1.6.0
%build
-./autogen.sh
%configure \
--with-zlib \
--with-math \
@@ -100,80 +127,43 @@ happened, on your systems and applications.
%{__make} %{?_smp_mflags}
%install
-rm -rf $RPM_BUILD_ROOT
-%{__make} %{?_smp_mflags} DESTDIR=$RPM_BUILD_ROOT install
+rm -rf "${RPM_BUILD_ROOT}"
+%{__make} %{?_smp_mflags} DESTDIR="${RPM_BUILD_ROOT}" install
-find $RPM_BUILD_ROOT -name .keep -delete
+find "${RPM_BUILD_ROOT}" -name .keep -delete
-install -m 644 -p system/netdata.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
-install -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d
-install -m 644 -p system/netdata.logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/%{name}
+install -m 644 -p system/netdata.conf "${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}"
+install -m 755 -d "${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d"
+install -m 644 -p system/netdata.logrotate "${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}"
%if %{with systemd}
-install -d $RPM_BUILD_ROOT%{_unitdir}
-install -m 644 -p system/netdata.service $RPM_BUILD_ROOT%{_unitdir}/netdata.service
+install -m 755 -d "${RPM_BUILD_ROOT}%{_unitdir}"
+install -m 644 -p system/netdata.service "${RPM_BUILD_ROOT}%{_unitdir}/netdata.service"
%else
# install SYSV init stuff
-install -d $RPM_BUILD_ROOT/etc/rc.d/init.d
-install -m755 system/netdata-init-d \
- $RPM_BUILD_ROOT/etc/rc.d/init.d/netdata
+install -d "${RPM_BUILD_ROOT}/etc/rc.d/init.d"
+install -m 755 system/netdata-init-d \
+ "${RPM_BUILD_ROOT}/etc/rc.d/init.d/netdata"
%endif
-%if %{with systemd}
%pre
-# Add the "netdata" user
-/usr/sbin/groupadd -r netdata 2> /dev/null || :
-/usr/sbin/useradd -c "netdata" -g netdata \
- -s /sbin/nologin -r -d %{contentdir} netdata 2> /dev/null || :
-
-%post
-%distro_post
-setcap cap_dac_read,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin || chmod 1755 /usr/libexec/netdata/plugins.d/apps.plugin
-
-%preun
-%distro_preun
-
-%postun
-%distro_postun
-%else
-%pre
-# Add the "netdata" user
getent group netdata >/dev/null || groupadd -r netdata
getent group docker >/dev/null || groupadd -r docker
getent passwd netdata >/dev/null || \
useradd -r -g netdata -G docker -s /sbin/nologin \
-d %{contentdir} -c "netdata" netdata
-exit 0
%post
-setcap cap_dac_read,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin || chmod 1755 /usr/libexec/netdata/plugins.d/apps.plugin
-# Register the netdata service
-/sbin/chkconfig --add netdata
-# Only gets run on initial install (not upgrades or uninstalls)
-if [ $1 = 1 ]; then
- # Start the netdata service
- /sbin/service netdata start
-fi
-exit 0
+%{netdata_init_post}
%preun
-# Only gets run on uninstall (not upgrades)
-if [ $1 = 0 ]; then
- /sbin/service netdata stop > /dev/null 2>&1
- /sbin/chkconfig --del netdata
-fi
-exit 0
+%{netdata_init_preun}
%postun
-# Only gets run on upgrade (not uninstalls)
-if [ $1 != 0 ]; then
- /sbin/service netdata condrestart 2>&1 > /dev/null
-fi
-exit 0
-%endif
+%{netdata_init_postun}
%clean
-rm -rf $RPM_BUILD_ROOT
+rm -rf "${RPM_BUILD_ROOT}"
%files
%doc README.md
@@ -190,12 +180,11 @@ rm -rf $RPM_BUILD_ROOT
# To be eventually moved to %%_defaultdocdir
%{_sysconfdir}/%{name}/node.d/*.md
-
-%caps(cap_dac_read_search,cap_sys_ptrace=ep) %{_libexecdir}/%{name}/plugins.d/apps.plugin
-
%{_libexecdir}/%{name}
%{_sbindir}/%{name}
+%caps(cap_dac_read_search,cap_sys_ptrace=ep) %attr(0555,root,root) %{_libexecdir}/%{name}/plugins.d/apps.plugin
+
%attr(0700,netdata,netdata) %dir %{_localstatedir}/cache/%{name}
%attr(0700,netdata,netdata) %dir %{_localstatedir}/log/%{name}
%attr(0700,netdata,netdata) %dir %{_localstatedir}/lib/%{name}
@@ -216,6 +205,17 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/%{name}/web
%changelog
+* Mon Mar 20 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.6.0-1
+- central netdata
+- monitoring ephemeral nodes
+- monitoring ephemeral containers and VM guests
+- apps.plugin ported for FreeBSD
+- web_log plugin
+- JSON backends
+- IPMI monitoring
+- several new and improved plugins
+- several new and improved alarms and notifications
+- dozens more improvements and bug fixes
* Sun Jan 22 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.5.0-1
- FreeBSD, MacOS, FreeNAS
- Backends support
diff --git a/netdata.spec.in b/netdata.spec.in
index 2fc4e99e4..685d6e0e7 100644
--- a/netdata.spec.in
+++ b/netdata.spec.in
@@ -1,20 +1,9 @@
-%define contentdir %{_datadir}/netdata
-%if 0%{?suse_version}
-%define distro_post %service_add_post netdata.service
-%define distro_preun %service_del_preun netdata.service
-%define distro_postun %service_del_postun netdata.service
-%define distro_buildrequires BuildRequires:\ systemd-rpm-macros
-%else
-%define distro_post %systemd_post netdata.service
-%define distro_preun %systemd_preun netdata.service
-%define distro_postun %systemd_postun_with_restart netdata.service
-%define distro_buildrequires %{nil}
-%endif
+%global contentdir %{_datadir}/netdata
# This is temporary and should eventually be resolved. This bypasses
# the default rhel __os_install_post which throws a python compile
# error.
-%define __os_install_post %{nil}
+%global __os_install_post %{nil}
#
# Conditional build:
@@ -26,33 +15,79 @@
%undefine with_systemd
%endif
+%if %{with systemd}
+%if 0%{?suse_version}
+%global netdata_initd_buildrequires \
+BuildRequires: systemd-rpm-macros \
+%{nil}
+%global netdata_initd_requires \
+%{?systemd_requires} \
+%{nil}
+%global netdata_init_post %service_add_post netdata.service
+%global netdata_init_preun %service_del_preun netdata.service
+%global netdata_init_postun %service_del_postun netdata.service
+%else
+%global netdata_initd_buildrequires %{nil}
+%global netdata_initd_requires \
+Requires(preun): systemd-units \
+Requires(postun): systemd-units \
+Requires(post): systemd-units \
+%{nil}
+%global netdata_init_post %systemd_post netdata.service
+%global netdata_init_preun %systemd_preun netdata.service
+%global netdata_init_postun %systemd_postun_with_restart netdata.service
+%endif
+%else
+%global netdata_initd_buildrequires %{nil}
+%global netdata_initd_requires \
+Requires(post): chkconfig \
+%{nil}
+%global netdata_init_post \
+/sbin/chkconfig --add netdata \
+%{nil}
+%global netdata_init_preun %{nil} \
+if [ $1 = 0 ]; then \
+ /sbin/service netdata stop > /dev/null 2>&1 \
+ /sbin/chkconfig --del netdata \
+fi \
+%{nil}
+%global netdata_init_postun %{nil} \
+if [ $1 != 0 ]; then \
+ /sbin/service netdata condrestart 2>&1 > /dev/null \
+fi \
+%{nil}
+%endif
+
+%if 0%{?_fedora}
+%global netdata_recommends \
+Recommends: curl \
+Recommends: iproute-tc \
+Recommends: lm_sensors \
+Recommends: nmap-ncat \
+Recommends: nodejs \
+Recommends: python \
+Recommends: PyYAML \
+Recommends: python2-PyMySQL \
+Recommends: python2-psycopg2 \
+%{nil}
+%else
+%global netdata_recommends %{nil}
+%endif
+
Summary: Real-time performance monitoring, done right
Name: @PACKAGE_NAME@
Version: @PACKAGE_RPM_VERSION@
Release: 1%{?dist}
-License: GPL v3+
+License: GPLv3+
Group: Applications/System
-Source0: http://firehol.org/download/netdata/releases/v@PACKAGE_VERSION@/%{name}-@PACKAGE_VERSION@.tar.xz
-URL: http://my-netdata.io/
-%distro_buildrequires
-BuildRequires: /usr/bin/autoconf
-BuildRequires: /usr/bin/automake
+Source0: https://firehol.org/download/netdata/releases/v@PACKAGE_VERSION@/%{name}-@PACKAGE_VERSION@.tar.xz
+URL: http://my-netdata.io
BuildRequires: pkgconfig
BuildRequires: xz
BuildRequires: zlib-devel
BuildRequires: libuuid-devel
Requires: zlib
Requires: libuuid
-Requires(post): libcap
-Recommends: curl
-Recommends: iproute-tc
-Recommends: lm_sensors
-Recommends: nmap-ncat
-Recommends: nodejs
-Recommends: python
-Recommends: PyYAML
-Recommends: python2-PyMySQL
-Recommends: python2-psycopg2
# Packages can be found in the EPEL repo
%if %{with nfacct}
@@ -64,18 +99,11 @@ Requires: libnetfilter_acct
Requires(pre): /usr/sbin/groupadd
Requires(pre): /usr/sbin/useradd
+Requires(post): libcap
-%if %{with systemd}
-%if 0%{?suse_version}
-%{?systemd_requires}
-%else
-Requires(preun): systemd-units
-Requires(postun): systemd-units
-Requires(post): systemd-units
-%endif
-%else
-Requires(post): chkconfig
-%endif
+%{netdata_initd_buildrequires}
+%{netdata_recommends}
+%{netdata_initd_requires}
%description
netdata is the fastest way to visualize metrics. It is a resource
@@ -88,10 +116,9 @@ so that you can get insights of what is happening now and what just
happened, on your systems and applications.
%prep
-%setup -q
+%setup -q -n @PACKAGE_NAME@-@PACKAGE_VERSION@
%build
-./autogen.sh
%configure \
--with-zlib \
--with-math \
@@ -100,80 +127,43 @@ happened, on your systems and applications.
%{__make} %{?_smp_mflags}
%install
-rm -rf $RPM_BUILD_ROOT
-%{__make} %{?_smp_mflags} DESTDIR=$RPM_BUILD_ROOT install
+rm -rf "${RPM_BUILD_ROOT}"
+%{__make} %{?_smp_mflags} DESTDIR="${RPM_BUILD_ROOT}" install
-find $RPM_BUILD_ROOT -name .keep -delete
+find "${RPM_BUILD_ROOT}" -name .keep -delete
-install -m 644 -p system/netdata.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
-install -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d
-install -m 644 -p system/netdata.logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/%{name}
+install -m 644 -p system/netdata.conf "${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}"
+install -m 755 -d "${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d"
+install -m 644 -p system/netdata.logrotate "${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}"
%if %{with systemd}
-install -d $RPM_BUILD_ROOT%{_unitdir}
-install -m 644 -p system/netdata.service $RPM_BUILD_ROOT%{_unitdir}/netdata.service
+install -m 755 -d "${RPM_BUILD_ROOT}%{_unitdir}"
+install -m 644 -p system/netdata.service "${RPM_BUILD_ROOT}%{_unitdir}/netdata.service"
%else
# install SYSV init stuff
-install -d $RPM_BUILD_ROOT/etc/rc.d/init.d
-install -m755 system/netdata-init-d \
- $RPM_BUILD_ROOT/etc/rc.d/init.d/netdata
+install -d "${RPM_BUILD_ROOT}/etc/rc.d/init.d"
+install -m 755 system/netdata-init-d \
+ "${RPM_BUILD_ROOT}/etc/rc.d/init.d/netdata"
%endif
-%if %{with systemd}
%pre
-# Add the "netdata" user
-/usr/sbin/groupadd -r netdata 2> /dev/null || :
-/usr/sbin/useradd -c "netdata" -g netdata \
- -s /sbin/nologin -r -d %{contentdir} netdata 2> /dev/null || :
-
-%post
-%distro_post
-setcap cap_dac_read,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin || chmod 1755 /usr/libexec/netdata/plugins.d/apps.plugin
-
-%preun
-%distro_preun
-
-%postun
-%distro_postun
-%else
-%pre
-# Add the "netdata" user
getent group netdata >/dev/null || groupadd -r netdata
getent group docker >/dev/null || groupadd -r docker
getent passwd netdata >/dev/null || \
useradd -r -g netdata -G docker -s /sbin/nologin \
-d %{contentdir} -c "netdata" netdata
-exit 0
%post
-setcap cap_dac_read,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin || chmod 1755 /usr/libexec/netdata/plugins.d/apps.plugin
-# Register the netdata service
-/sbin/chkconfig --add netdata
-# Only gets run on initial install (not upgrades or uninstalls)
-if [ $1 = 1 ]; then
- # Start the netdata service
- /sbin/service netdata start
-fi
-exit 0
+%{netdata_init_post}
%preun
-# Only gets run on uninstall (not upgrades)
-if [ $1 = 0 ]; then
- /sbin/service netdata stop > /dev/null 2>&1
- /sbin/chkconfig --del netdata
-fi
-exit 0
+%{netdata_init_preun}
%postun
-# Only gets run on upgrade (not uninstalls)
-if [ $1 != 0 ]; then
- /sbin/service netdata condrestart 2>&1 > /dev/null
-fi
-exit 0
-%endif
+%{netdata_init_postun}
%clean
-rm -rf $RPM_BUILD_ROOT
+rm -rf "${RPM_BUILD_ROOT}"
%files
%doc README.md
@@ -190,12 +180,11 @@ rm -rf $RPM_BUILD_ROOT
# To be eventually moved to %%_defaultdocdir
%{_sysconfdir}/%{name}/node.d/*.md
-
-%caps(cap_dac_read_search,cap_sys_ptrace=ep) %{_libexecdir}/%{name}/plugins.d/apps.plugin
-
%{_libexecdir}/%{name}
%{_sbindir}/%{name}
+%caps(cap_dac_read_search,cap_sys_ptrace=ep) %attr(0555,root,root) %{_libexecdir}/%{name}/plugins.d/apps.plugin
+
%attr(0700,netdata,netdata) %dir %{_localstatedir}/cache/%{name}
%attr(0700,netdata,netdata) %dir %{_localstatedir}/log/%{name}
%attr(0700,netdata,netdata) %dir %{_localstatedir}/lib/%{name}
@@ -216,6 +205,17 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/%{name}/web
%changelog
+* Mon Mar 20 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.6.0-1
+- central netdata
+- monitoring ephemeral nodes
+- monitoring ephemeral containers and VM guests
+- apps.plugin ported for FreeBSD
+- web_log plugin
+- JSON backends
+- IPMI monitoring
+- several new and improved plugins
+- several new and improved alarms and notifications
+- dozens more improvements and bug fixes
* Sun Jan 22 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.5.0-1
- FreeBSD, MacOS, FreeNAS
- Backends support
diff --git a/node.d/Makefile.in b/node.d/Makefile.in
index 66803fc02..2af9a4a65 100644
--- a/node.d/Makefile.in
+++ b/node.d/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -15,61 +16,6 @@
@SET_MAKE@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -89,9 +35,12 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = node.d
+DIST_COMMON = $(dist_node_DATA) $(dist_nodemodules_DATA) \
+ $(dist_nodemodulesber_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -100,32 +49,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_node_DATA) \
- $(dist_nodemodules_DATA) $(dist_nodemodulesber_DATA) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-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 =
SOURCES =
DIST_SOURCES =
-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/||"`;; \
@@ -157,12 +86,9 @@ am__installdirs = "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" \
"$(DESTDIR)$(nodemodulesberdir)"
DATA = $(dist_node_DATA) $(dist_nodemodules_DATA) \
$(dist_nodemodulesber_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -186,7 +112,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -200,6 +130,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -337,6 +271,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu node.d/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu node.d/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -356,11 +291,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_nodeDATA: $(dist_node_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(nodedir)" || $(MKDIR_P) "$(DESTDIR)$(nodedir)"
@list='$(dist_node_DATA)'; test -n "$(nodedir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodedir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodedir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -377,11 +309,8 @@ uninstall-dist_nodeDATA:
dir='$(DESTDIR)$(nodedir)'; $(am__uninstall_files_from_dir)
install-dist_nodemodulesDATA: $(dist_nodemodules_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(nodemodulesdir)" || $(MKDIR_P) "$(DESTDIR)$(nodemodulesdir)"
@list='$(dist_nodemodules_DATA)'; test -n "$(nodemodulesdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodemodulesdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodemodulesdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -398,11 +327,8 @@ uninstall-dist_nodemodulesDATA:
dir='$(DESTDIR)$(nodemodulesdir)'; $(am__uninstall_files_from_dir)
install-dist_nodemodulesberDATA: $(dist_nodemodulesber_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(nodemodulesberdir)" || $(MKDIR_P) "$(DESTDIR)$(nodemodulesberdir)"
@list='$(dist_nodemodulesber_DATA)'; test -n "$(nodemodulesberdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodemodulesberdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodemodulesberdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -417,11 +343,11 @@ uninstall-dist_nodemodulesberDATA:
@list='$(dist_nodemodulesber_DATA)'; test -n "$(nodemodulesberdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(nodemodulesberdir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
-
-ctags CTAGS:
+tags: TAGS
+TAGS:
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -562,23 +488,20 @@ uninstall-am: uninstall-dist_nodeDATA uninstall-dist_nodemodulesDATA \
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-dist_nodeDATA \
- install-dist_nodemodulesDATA install-dist_nodemodulesberDATA \
- 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-ps \
- install-ps-am install-strip installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
- uninstall uninstall-am uninstall-dist_nodeDATA \
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_nodeDATA install-dist_nodemodulesDATA \
+ install-dist_nodemodulesberDATA 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-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am uninstall uninstall-am uninstall-dist_nodeDATA \
uninstall-dist_nodemodulesDATA \
uninstall-dist_nodemodulesberDATA
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/node.d/snmp.node.js b/node.d/snmp.node.js
index 5a478937e..57b37ffa0 100644
--- a/node.d/snmp.node.js
+++ b/node.d/snmp.node.js
@@ -1,6 +1,7 @@
'use strict';
-
+// netdata snmp module
// This program will connect to one or more SNMP Agents
+//
// example configuration in /etc/netdata/node.d/snmp.conf
/*
@@ -26,13 +27,15 @@
"oid": ".1.3.6.1.2.1.2.2.1.10.1",
"algorithm": "incremental",
"multiplier": 8,
- "divisor": 1024
+ "divisor": 1024,
+ "offset": 0
},
"out": {
"oid": ".1.3.6.1.2.1.2.2.1.16.1",
"algorithm": "incremental",
"multiplier": -8,
- "divisor": 1024
+ "divisor": 1024,
+ "offset": 0
}
}
},
@@ -46,13 +49,15 @@
"oid": ".1.3.6.1.2.1.2.2.1.10.2",
"algorithm": "incremental",
"multiplier": 8,
- "divisor": 1024
+ "divisor": 1024,
+ "offset": 0
},
"out": {
"oid": ".1.3.6.1.2.1.2.2.1.16.2",
"algorithm": "incremental",
"multiplier": -8,
- "divisor": 1024
+ "divisor": 1024,
+ "offset": 0
}
}
}
@@ -89,13 +94,15 @@
"oid": ".1.3.6.1.2.1.2.2.1.10.",
"algorithm": "incremental",
"multiplier": 8,
- "divisor": 1024
+ "divisor": 1024,
+ "offset": 0
},
"out": {
"oid": ".1.3.6.1.2.1.2.2.1.16.",
"algorithm": "incremental",
"multiplier": -8,
- "divisor": 1024
+ "divisor": 1024,
+ "offset": 0
}
}
}
@@ -265,7 +272,7 @@ netdata.processors.snmp = {
if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
- if(varbinds[i].type === net_snmp.ObjectType.OctetString)
+ if(varbinds[i].type === net_snmp.ObjectType.OctetString && service.snmp_oids_index[varbinds[i].oid].type !== 'title')
value = parseFloat(varbinds[i].value) * 1000;
else
value = varbinds[i].value;
@@ -360,8 +367,12 @@ var snmp = {
for(var j = 0; j < dim_keys_len ; j++) {
var d = dim_keys[j];
- if (dimensions[d].value !== null)
- service.set(d, dimensions[d].value);
+ if (dimensions[d].value !== null) {
+ if(typeof dimensions[d].offset === 'number')
+ service.set(d, dimensions[d].value + dimensions[d].offset);
+ else
+ service.set(d, dimensions[d].value);
+ }
}
service.end();
diff --git a/plugins.d/Makefile.in b/plugins.d/Makefile.in
index 7e90c9808..2a8806cb1 100644
--- a/plugins.d/Makefile.in
+++ b/plugins.d/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,9 +36,11 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = plugins.d
+DIST_COMMON = $(dist_plugins_DATA) $(dist_plugins_SCRIPTS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -101,8 +49,6 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \
- $(dist_plugins_DATA) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
@@ -136,32 +82,12 @@ am__uninstall_files_from_dir = { \
}
am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(pluginsdir)"
SCRIPTS = $(dist_plugins_SCRIPTS)
-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 =
SOURCES =
DIST_SOURCES =
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
DATA = $(dist_plugins_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -185,7 +111,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -199,6 +129,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -333,6 +267,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins.d/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu plugins.d/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -352,11 +287,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS)
@$(NORMAL_INSTALL)
+ test -z "$(pluginsdir)" || $(MKDIR_P) "$(DESTDIR)$(pluginsdir)"
@list='$(dist_plugins_SCRIPTS)'; 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 \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
@@ -387,11 +319,8 @@ uninstall-dist_pluginsSCRIPTS:
dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
install-dist_pluginsDATA: $(dist_plugins_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(pluginsdir)" || $(MKDIR_P) "$(DESTDIR)$(pluginsdir)"
@list='$(dist_plugins_DATA)'; 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 \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -406,11 +335,11 @@ uninstall-dist_pluginsDATA:
@list='$(dist_plugins_DATA)'; test -n "$(pluginsdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
-
-ctags CTAGS:
+tags: TAGS
+TAGS:
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -549,20 +478,18 @@ uninstall-am: uninstall-dist_pluginsDATA uninstall-dist_pluginsSCRIPTS
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-dist_pluginsDATA \
- install-dist_pluginsSCRIPTS 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-ps install-ps-am install-strip \
- installcheck installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
- pdf-am ps ps-am tags-am uninstall uninstall-am \
- uninstall-dist_pluginsDATA uninstall-dist_pluginsSCRIPTS
-
-.PRECIOUS: Makefile
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pluginsDATA install-dist_pluginsSCRIPTS \
+ 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-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
+ uninstall-am uninstall-dist_pluginsDATA \
+ uninstall-dist_pluginsSCRIPTS
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/plugins.d/alarm-notify.sh b/plugins.d/alarm-notify.sh
index d6f3d8b2a..d0188fe3b 100755
--- a/plugins.d/alarm-notify.sh
+++ b/plugins.d/alarm-notify.sh
@@ -16,6 +16,7 @@
# Supported notification methods:
# - emails by @ktsaou
# - slack.com notifications by @ktsaou
+# - discordapp.com notifications by @lowfive
# - pushover.net notifications by @ktsaou
# - pushbullet.com push notifications by Tiago Peralta @tperalta82 PR #1070
# - telegram.org notifications by @hashworks PR #1002
@@ -23,7 +24,7 @@
# - kafka notifications by @ktsaou #1342
# - pagerduty.com notifications by Jim Cooley @jimcooley PR #1373
# - messagebird.com notifications by @tech_no_logical #1453
-# - hipchart notifications by @ktsaou #1561
+# - hipchat notifications by @ktsaou #1561
# -----------------------------------------------------------------------------
# testing notifications
@@ -46,7 +47,7 @@ then
echo >&2
echo >&2 "# SENDING TEST ${x} ALARM TO ROLE: ${recipient}"
- "${0}" "${recipient}" "$(hostname)" 1 1 "${id}" "$(date +%s)" "test_alarm" "test.chart" "test.family" "${x}" "${last}" 100 90 "${0}" 1 $((0 + id)) "units" "this is a test alarm to verify notifications work"
+ "${0}" "${recipient}" "$(hostname)" 1 1 "${id}" "$(date +%s)" "test_alarm" "test.chart" "test.family" "${x}" "${last}" 100 90 "${0}" 1 $((0 + id)) "units" "this is a test alarm to verify notifications work" "new value" "old value"
if [ $? -ne 0 ]
then
echo >&2 "# FAILED"
@@ -138,6 +139,15 @@ duration="${15}" # the duration in seconds of the previous alarm state
non_clear_duration="${16}" # the total duration in seconds this is/was non-clear
units="${17}" # the units of the value
info="${18}" # a short description of the alarm
+value_string="${19}" # friendly value (with units)
+old_value_string="${20}" # friendly old value (with units)
+
+# -----------------------------------------------------------------------------
+# find a suitable hostname to use, if netdata did not supply a hostname
+
+[ -z "${host}" ] && host="${NETDATA_HOSTNAME}"
+[ -z "${host}" ] && host="${NETDATA_REGISTRY_HOSTNAME}"
+[ -z "${host}" ] && host="$(hostname 2>/dev/null)"
# -----------------------------------------------------------------------------
# screen statuses we don't need to send a notification
@@ -145,14 +155,14 @@ info="${18}" # a short description of the alarm
# don't do anything if this is not WARNING, CRITICAL or CLEAR
if [ "${status}" != "WARNING" -a "${status}" != "CRITICAL" -a "${status}" != "CLEAR" ]
then
- info "not sending notification for ${status} on '${chart}.${name}'"
+ info "not sending notification for ${status} of '${host}.${chart}.${name}'"
exit 1
fi
# don't do anything if this is CLEAR, but it was not WARNING or CRITICAL
if [ "${old_status}" != "WARNING" -a "${old_status}" != "CRITICAL" -a "${status}" = "CLEAR" ]
then
- info "not sending notification for ${status} on '${chart}.${name}' (last status was ${old_status})"
+ info "not sending notification for ${status} of '${host}.${chart}.${name}' (last status was ${old_status})"
exit 1
fi
@@ -172,6 +182,7 @@ sendmail=
# enable / disable features
SEND_SLACK="YES"
+SEND_DISCORD="YES"
SEND_PUSHOVER="YES"
SEND_TWILIO="YES"
SEND_HIPCHAT="YES"
@@ -187,6 +198,11 @@ SLACK_WEBHOOK_URL=
DEFAULT_RECIPIENT_SLACK=
declare -A role_recipients_slack=()
+# discord configs
+DISCORD_WEBHOOK_URL=
+DEFAULT_RECIPIENT_DISCORD=
+declare -A role_recipients_discord=()
+
# pushover configs
PUSHOVER_APP_TOKEN=
DEFAULT_RECIPIENT_PUSHOVER=
@@ -205,6 +221,7 @@ DEFAULT_RECIPIENT_TWILIO=
declare -A role_recipients_twilio=()
# hipchat configs
+HIPCHAT_SERVER=
HIPCHAT_AUTH_TOKEN=
DEFAULT_RECIPIENT_HIPCHAT=
declare -A role_recipients_hipchat=()
@@ -283,6 +300,7 @@ filter_recipient_by_criticality() {
# find the recipients' addresses per method
declare -A arr_slack=()
+declare -A arr_discord=()
declare -A arr_pushover=()
declare -A arr_pushbullet=()
declare -A arr_twilio=()
@@ -363,6 +381,14 @@ do
[ "${r}" != "disabled" ] && filter_recipient_by_criticality slack "${r}" && arr_slack[${r/|*/}]="1"
done
+ # discord
+ a="${role_recipients_discord[${x}]}"
+ [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_DISCORD}"
+ for r in ${a//,/ }
+ do
+ [ "${r}" != "disabled" ] && filter_recipient_by_criticality discord "${r}" && arr_discord[${r/|*/}]="1"
+ done
+
# pagerduty.com
a="${role_recipients_pd[${x}]}"
[ -z "${a}" ] && a="${DEFAULT_RECIPIENT_PD}"
@@ -376,6 +402,10 @@ done
to_slack="${!arr_slack[*]}"
[ -z "${to_slack}" ] && SEND_SLACK="NO"
+# build the list of discord recipients (channels)
+to_discord="${!arr_discord[*]}"
+[ -z "${to_discord}" ] && SEND_DISCORD="NO"
+
# build the list of pushover recipients (user tokens)
to_pushover="${!arr_pushover[*]}"
[ -z "${to_pushover}" ] && SEND_PUSHOVER="NO"
@@ -420,6 +450,9 @@ done
# check slack
[ -z "${SLACK_WEBHOOK_URL}" ] && SEND_SLACK="NO"
+# check discord
+[ -z "${DISCORD_WEBHOOK_URL}" ] && SEND_DISCORD="NO"
+
# check pushover
[ -z "${PUSHOVER_APP_TOKEN}" ] && SEND_PUSHOVER="NO"
@@ -459,6 +492,7 @@ fi
if [ \( \
"${SEND_PUSHOVER}" = "YES" \
-o "${SEND_SLACK}" = "YES" \
+ -o "${SEND_DISCORD}" = "YES" \
-o "${SEND_HIPCHAT}" = "YES" \
-o "${SEND_TWILIO}" = "YES" \
-o "${SEND_MESSAGEBIRD}" = "YES" \
@@ -476,6 +510,7 @@ if [ \( \
SEND_PUSHBULLET="NO"
SEND_TELEGRAM="NO"
SEND_SLACK="NO"
+ SEND_DISCORD="NO"
SEND_TWILIO="NO"
SEND_HIPCHAT="NO"
SEND_MESSAGEBIRD="NO"
@@ -495,6 +530,7 @@ if [ "${SEND_EMAIL}" != "YES" \
-a "${SEND_PUSHOVER}" != "YES" \
-a "${SEND_TELEGRAM}" != "YES" \
-a "${SEND_SLACK}" != "YES" \
+ -a "${SEND_DISCORD}" != "YES" \
-a "${SEND_TWILIO}" != "YES" \
-a "${SEND_HIPCHAT}" != "YES" \
-a "${SEND_MESSAGEBIRD}" != "YES" \
@@ -503,17 +539,10 @@ if [ "${SEND_EMAIL}" != "YES" \
-a "${SEND_PD}" != "YES" \
]
then
- fatal "All notification methods are disabled. Not sending notification to '${roles}' for '${name}' = '${value}' of chart '${chart}' for status '${status}'."
+ fatal "All notification methods are disabled. Not sending notification for host '${host}', chart '${chart}' to '${roles}' for '${name}' = '${value}' for status '${status}'."
fi
# -----------------------------------------------------------------------------
-# find a suitable hostname to use, if netdata did not supply a hostname
-
-[ -z "${host}" ] && host="${NETDATA_HOSTNAME}"
-[ -z "${host}" ] && host="${NETDATA_REGISTRY_HOSTNAME}"
-[ -z "${host}" ] && host="$(hostname 2>/dev/null)"
-
-# -----------------------------------------------------------------------------
# get the date the alarm happened
date="$(date --date=@${when} 2>/dev/null)"
@@ -747,13 +776,13 @@ send_pd() {
then
for PD_SERVICE_KEY in ${recipients}
do
- d="${status} ${name}=${value} ${units} - ${host}, ${family}"
+ d="${status} ${name} = ${value_string} - ${host}, ${family}"
${pd_send} -k ${PD_SERVICE_KEY} \
-t ${t} \
-d "${d}" \
-i ${alarm_id} \
-f 'info'="${info}" \
- -f 'value_w_units'="${value} ${units}" \
+ -f 'value_w_units'="${value_string}" \
-f 'when'="${when}" \
-f 'duration'="${duration}" \
-f 'roles'="${roles}" \
@@ -774,10 +803,10 @@ send_pd() {
retval=$?
if [ ${retval} -eq 0 ]
then
- info "sent pagerduty.com notification using service key ${PD_SERVICE_KEY::-26}....: ${d}"
+ info "sent pagerduty.com notification for host ${host} ${chart}.${name} using service key ${PD_SERVICE_KEY::-26}....: ${d}"
sent=$((sent + 1))
else
- error "failed to send pagerduty.com notification using service key ${PD_SERVICE_KEY::-26}.... (error code ${retval}): ${d}"
+ error "failed to send pagerduty.com notification for ${host} ${chart}.${name} using service key ${PD_SERVICE_KEY::-26}.... (error code ${retval}): ${d}"
fi
done
@@ -826,16 +855,15 @@ send_twilio() {
send_hipchat() {
local authtoken="${1}" recipients="${2}" message="${3}" httpcode sent=0 room color sender msg_format notify
- if [ "${SEND_HIPCHAT}" = "YES" -a ! -z "${authtoken}" -a ! -z "${recipients}" -a ! -z "${message}" ]
- then
-
+ if [ "${SEND_HIPCHAT}" = "YES" -a ! -z "${HIPCHAT_SERVER}" -a ! -z "${authtoken}" -a ! -z "${recipients}" -a ! -z "${message}" ]
+ then
# A label to be shown in addition to the sender's name
# Valid length range: 0 - 64.
sender="netdata"
# Valid values: html, text.
# Defaults to 'html'.
- msg_format="text"
+ msg_format="html"
# Background color for message. Valid values: yellow, green, red, purple, gray, random. Defaults to 'yellow'.
case "${status}" in
@@ -856,9 +884,9 @@ send_hipchat() {
-H "Content-type: application/json" \
-H "Authorization: Bearer ${authtoken}" \
-d "{\"color\": \"${color}\", \"from\": \"${netdata}\", \"message_format\": \"${msg_format}\", \"message\": \"${message}\", \"notify\": \"${notify}\"}" \
- "https://api.hipchat.com/v2/room/${room}/notification")
-
- if [ "${httpcode}" == "200" ]
+ "https://${HIPCHAT_SERVER}/v2/room/${room}/notification")
+
+ if [ "${httpcode}" == "204" ]
then
info "sent HipChat notification for: ${host} ${chart}.${name} is ${status} to '${room}'"
sent=$((sent + 1))
@@ -1008,6 +1036,66 @@ EOF
return 1
}
+# -----------------------------------------------------------------------------
+# discord sender
+
+send_discord() {
+ local webhook="${1}/slack" channels="${2}" httpcode sent=0 channel color payload
+
+ [ "${SEND_DISCORD}" != "YES" ] && return 1
+
+ case "${status}" in
+ WARNING) color="warning" ;;
+ CRITICAL) color="danger" ;;
+ CLEAR) color="good" ;;
+ *) color="#777777" ;;
+ esac
+
+ for channel in ${channels}
+ do
+ payload="$(cat <<EOF
+ {
+ "channel": "#${channel}",
+ "username": "netdata on ${host}",
+ "text": "${host} ${status_message}, \`${chart}\` (_${family}_), *${alarm}*",
+ "icon_url": "${images_base_url}/images/seo-performance-128.png",
+ "attachments": [
+ {
+ "color": "${color}",
+ "title": "${alarm}",
+ "title_link": "${goto_url}",
+ "text": "${info}",
+ "fields": [
+ {
+ "title": "${chart}",
+ "value": "${family}"
+ }
+ ],
+ "thumb_url": "${image}",
+ "footer_icon": "${images_base_url}/images/seo-performance-128.png",
+ "footer": "${host}",
+ "ts": ${when}
+ }
+ ]
+ }
+EOF
+ )"
+
+ httpcode=$(${curl} --write-out %{http_code} --silent --output /dev/null -X POST --data-urlencode "payload=${payload}" "${webhook}")
+ if [ "${httpcode}" == "200" ]
+ then
+ info "sent discord notification for: ${host} ${chart}.${name} is ${status} to '${channel}'"
+ sent=$((sent + 1))
+ else
+ error "failed to send discord notification for: ${host} ${chart}.${name} is ${status} to '${channel}', with HTTP error code ${httpcode}."
+ fi
+ done
+
+ [ ${sent} -gt 0 ] && return 0
+
+ return 1
+}
+
# -----------------------------------------------------------------------------
# prepare the content of the notification
@@ -1034,7 +1122,7 @@ status_message="status unknown"
color="grey"
# the alarm value
-alarm="${name//_/ } = ${value} ${units}"
+alarm="${name//_/ } = ${value_string}"
# the image of the alarm
image="${images_base_url}/images/seo-performance-128.png"
@@ -1109,6 +1197,15 @@ send_slack "${SLACK_WEBHOOK_URL}" "${to_slack}"
SENT_SLACK=$?
# -----------------------------------------------------------------------------
+# send the discord notification
+
+# discord aggregates posts from the same username
+# so we use "${host} ${status}" as the bot username, to make them diff
+
+send_discord "${DISCORD_WEBHOOK_URL}" "${to_discord}"
+SENT_DISCORD=$?
+
+# -----------------------------------------------------------------------------
# send the pushover notification
send_pushover "${PUSHOVER_APP_TOKEN}" "${to_pushover}" "${when}" "${goto_url}" "${status}" "${host} ${status_message} - ${name//_/ } - ${chart}" "
@@ -1187,14 +1284,13 @@ SENT_PD=$?
# -----------------------------------------------------------------------------
# send hipchat message
-send_hipchat "${HIPCHAT_AUTH_TOKEN}" "${to_hipchat}" "
-<b>${alarm}</b> ${info_html}<br/>&nbsp;
-<small><b>${chart}</b><br/>Chart<br/>&nbsp;</small>
-<small><b>${family}</b><br/>Family<br/>&nbsp;</small>
-<small><b>${severity}</b><br/>Severity<br/>&nbsp;</small>
-<small><b>${date}${raised_for_html}</b><br/>Time<br/>&nbsp;</small>
-<a href=\"${goto_url}\">View Netdata</a><br/>&nbsp;
-<small><small>The source of this alarm is line ${src}</small></small>
+send_hipchat "${HIPCHAT_AUTH_TOKEN}" "${to_hipchat}" " \
+${host} ${status_message}<br/> \
+<b>${alarm}</b> ${info_html}<br/> \
+<b>${chart}</b> (family <b>${family}</b>)<br/> \
+<b>${date}${raised_for_html}</b><br/> \
+<a href=\\\"${goto_url}\\\">View netdata dashboard</a> \
+(source of alarm ${src}) \
"
SENT_HIPCHAT=$?
@@ -1301,6 +1397,7 @@ if [ ${SENT_EMAIL} -eq 0 \
-o ${SENT_PUSHOVER} -eq 0 \
-o ${SENT_TELEGRAM} -eq 0 \
-o ${SENT_SLACK} -eq 0 \
+ -o ${SENT_DISCORD} -eq 0 \
-o ${SENT_TWILIO} -eq 0 \
-o ${SENT_HIPCHAT} -eq 0 \
-o ${SENT_MESSAGEBIRD} -eq 0 \
@@ -1315,3 +1412,4 @@ fi
# we did not send anything
exit 1
+
diff --git a/plugins.d/cgroup-name.sh b/plugins.d/cgroup-name.sh
index 9bb3bcabb..a1e3abe08 100755
--- a/plugins.d/cgroup-name.sh
+++ b/plugins.d/cgroup-name.sh
@@ -98,6 +98,8 @@ if [ -z "${NAME}" ]
then
if [[ "${CGROUP}" =~ ^.*docker[-_/\.][a-fA-F0-9]+[-_\.]?.*$ ]]
then
+ # docker containers
+
DOCKERID="$( echo "${CGROUP}" | sed "s|^.*docker[-_/]\([a-fA-F0-9]\+\)[-_\.]\?.*$|\1|" )"
# echo "DOCKERID=${DOCKERID}"
@@ -117,6 +119,11 @@ if [ -z "${NAME}" ]
info "docker container '${DOCKERID}' is named '${NAME}'"
fi
fi
+ elif [[ "${CGROUP}" =~ machine.slice_machine.*-qemu ]]
+ then
+ # libvirtd / qemu virtual machines
+
+ NAME="$(echo ${CGROUP} | sed 's/machine.slice_machine.*-qemu//; s/\/x2d//; s/\/x2d/\-/g; s/\.scope//g')"
fi
[ -z "${NAME}" ] && NAME="${CGROUP}"
diff --git a/plugins.d/fping.plugin b/plugins.d/fping.plugin
index d523f4474..232c00630 100755
--- a/plugins.d/fping.plugin
+++ b/plugins.d/fping.plugin
@@ -22,20 +22,39 @@ if [ "${1}" = "install" ]
"${@}" || exit 1
}
+ download() {
+ local curl="$(which curl 2>/dev/null || command -v curl 2>/dev/null)"
+ [ ! -z "${curl}" ] && run curl -s -L "${1}" && return 0
+
+ local wget="$(which wget 2>/dev/null || command -v wget 2>/dev/null)"
+ [ ! -z "${wget}" ] && run wget -q -O - "${1}" && return 0
+
+ echo >&2 "Cannot find 'curl' or 'wget' in this system." && exit 1
+ }
+
[ ! -d /usr/src ] && run mkdir -p /usr/src
[ ! -d /usr/local/bin ] && run mkdir -p /usr/local/bin
run cd /usr/src
- if [ -d fping-ktsaou.git ]
+ if [ -d fping-3.15 ]
then
- run cd fping-ktsaou.git
- run git pull
- else
- run git clone https://github.com/ktsaou/fping.git fping-ktsaou.git
- run cd fping-ktsaou.git
+ run rm -rf fping-3.15 || exit 1
fi
+ download 'https://github.com/schweikert/fping/archive/3.15.tar.gz' | run tar -zxvpf -
+ [ $? -ne 0 ] && exit 1
+ run cd fping-3.15 || exit 1
+
+ #if [ -d fping-ktsaou.git ]
+ # then
+ # run cd fping-ktsaou.git
+ # run git pull
+ #else
+ # run git clone https://github.com/ktsaou/fping.git fping-ktsaou.git
+ # run cd fping-ktsaou.git
+ #fi
+
run ./autogen.sh
run ./configure --prefix=/usr/local
run make clean
diff --git a/plugins.d/python.d.plugin b/plugins.d/python.d.plugin
index b4e6473a6..efa62cbc5 100755
--- a/plugins.d/python.d.plugin
+++ b/plugins.d/python.d.plugin
@@ -67,6 +67,34 @@ try:
except ImportError:
msg.fatal('Cannot find yaml library')
+try:
+ from collections import OrderedDict
+ ORDERED = True
+ DICT = OrderedDict
+ msg.info('YAML output is ordered')
+except ImportError:
+ try:
+ from ordereddict import OrderedDict
+ ORDERED = True
+ DICT = OrderedDict
+ msg.info('YAML output is ordered')
+ except ImportError:
+ ORDERED = False
+ DICT = dict
+ msg.info('YAML output is unordered')
+if ORDERED:
+ def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
+ class OrderedLoader(Loader):
+ pass
+
+ def construct_mapping(loader, node):
+ loader.flatten_mapping(node)
+ return object_pairs_hook(loader.construct_pairs(node))
+ OrderedLoader.add_constructor(
+ yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
+ construct_mapping)
+ return yaml.load(stream, OrderedLoader)
+
class PythonCharts(object):
"""
@@ -77,12 +105,16 @@ class PythonCharts(object):
modules=None,
modules_path='../python.d/',
modules_configs='../conf.d/',
- modules_disabled=None):
+ modules_disabled=None,
+ modules_enabled=None,
+ default_run=None):
"""
:param modules: list
:param modules_path: str
:param modules_configs: str
:param modules_disabled: list
+ :param modules_enabled: list
+ :param default_run: bool
"""
if modules is None:
@@ -95,13 +127,13 @@ class PythonCharts(object):
self.configs = modules_configs
# load modules
- loaded_modules = self._load_modules(modules_path, modules, modules_disabled)
+ loaded_modules = self._load_modules(modules_path, modules, modules_disabled, modules_enabled, default_run)
# load configuration files
configured_modules = self._load_configs(loaded_modules)
# good economy and prosperity:
- self.jobs = self._create_jobs(configured_modules) # type: list
+ self.jobs = self._create_jobs(configured_modules) # type <list>
# enable timetable override like `python.d.plugin mysql debug 1`
if DEBUG_FLAG and OVERRIDE_UPDATE_EVERY:
@@ -131,7 +163,7 @@ class PythonCharts(object):
msg.error("Problem loading", name, str(e))
return None
- def _load_modules(self, path, modules, disabled):
+ def _load_modules(self, path, modules, disabled, enabled, default_run):
"""
Load modules from 'modules' list or dynamically every file from 'path' (only .chart.py files)
:param path: str
@@ -157,7 +189,10 @@ class PythonCharts(object):
msg.fatal('no modules found.')
else:
# scan directory specified in path and load all modules from there
- names = os.listdir(path)
+ if default_run is False:
+ names = [module for module in os.listdir(path) if module[:-9] in enabled]
+ else:
+ names = os.listdir(path)
for mod in names:
if mod.replace(MODULE_EXTENSION, "") in disabled:
msg.error(mod + ": disabled module ", mod.replace(MODULE_EXTENSION, ""))
@@ -235,7 +270,7 @@ class PythonCharts(object):
# check if there are dict in config dict
many_jobs = False
for name in config:
- if type(config[name]) is dict:
+ if isinstance(config[name], DICT):
many_jobs = True
break
@@ -343,7 +378,8 @@ class PythonCharts(object):
if job.override_name is not None:
new_name = job.__module__ + '_' + sub(r'\s+', '_', job.override_name)
if new_name in overridden:
- msg.info("DROPPED:", job.name, ", job '" + job.override_name + "' is already served by another job.")
+ msg.info("DROPPED:", job.name, ", job '" + job.override_name +
+ "' is already served by another job.")
self._stop(job)
i -= 1
else:
@@ -420,7 +456,10 @@ def read_config(path):
"""
try:
with open(path, 'r') as stream:
- config = yaml.load(stream)
+ if ORDERED:
+ config = ordered_load(stream, yaml.SafeLoader)
+ else:
+ config = yaml.load(stream)
except (OSError, IOError):
msg.error(str(path), "is not a valid configuration file")
return None
@@ -452,7 +491,7 @@ def parse_cmdline(directory, *commands):
elif cmd == "trace" or cmd == "all":
TRACE_FLAG = True
elif os.path.isfile(directory + cmd + ".chart.py") or os.path.isfile(directory + cmd):
- #DEBUG_FLAG = True
+ # DEBUG_FLAG = True
mods.append(cmd.replace(".chart.py", ""))
else:
try:
@@ -477,7 +516,9 @@ def run():
global DEBUG_FLAG, TRACE_FLAG, BASE_CONFIG
# read configuration file
- disabled = []
+ disabled = ['nginx_log', 'gunicorn_log']
+ enabled = list()
+ default_run = True
configfile = CONFIG_DIR + "python.d.conf"
msg.PROGRAM = PROGRAM
msg.info("reading configuration file:", configfile)
@@ -519,12 +560,17 @@ def run():
except (KeyError, TypeError):
pass
+ default_run = True if ('default_run' not in conf or conf.get('default_run')) else False
+
for k, v in conf.items():
- if k in ("update_every", "debug", "enabled"):
+ if k in ("update_every", "debug", "enabled", "default_run"):
continue
- if v is False:
- disabled.append(k)
-
+ if default_run:
+ if v is False:
+ disabled.append(k)
+ else:
+ if v is True:
+ enabled.append(k)
# parse passed command line arguments
modules = parse_cmdline(MODULES_DIR, *sys.argv)
msg.DEBUG_FLAG = DEBUG_FLAG
@@ -539,7 +585,7 @@ def run():
", ONLY_MODULES=" + str(modules))
# run plugins
- charts = PythonCharts(modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled)
+ charts = PythonCharts(modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled, enabled, default_run)
charts.check()
charts.create()
charts.update()
diff --git a/plugins.d/tc-qos-helper.sh b/plugins.d/tc-qos-helper.sh
index e9253c8f2..074fece9a 100755
--- a/plugins.d/tc-qos-helper.sh
+++ b/plugins.d/tc-qos-helper.sh
@@ -12,12 +12,58 @@
export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
export LC_ALL=C
+
+# -----------------------------------------------------------------------------
+# find /var/run/fireqos
+
+# the default
+fireqos_run_dir="/var/run/fireqos"
+
+function realdir {
+ local r="$1"
+ local t=$(readlink "$r")
+
+ while [ "$t" ]
+ do
+ r=$(cd $(dirname "$r") && cd $(dirname "$t") && pwd -P)/$(basename "$t")
+ t=$(readlink "$r")
+ done
+
+ dirname "$r"
+}
+
+if [ ! -d "${fireqos_run_dir}" ]
+ then
+
+ # the fireqos executable - we will use it to find its config
+ fireqos="$(which fireqos 2>/dev/null || command -v fireqos 2>/dev/null)"
+
+ if [ ! -z "${fireqos}" ]
+ then
+
+ fireqos_exec_dir="$(realdir ${fireqos})"
+
+ if [ ! -z "${fireqos_exec_dir}" -a "${fireqos_exec_dir}" != "." -a -f "${fireqos_exec_dir}/install.config" ]
+ then
+
+ LOCALSTATEDIR=
+ source "${fireqos_exec_dir}/install.config"
+
+ if [ -d "${LOCALSTATEDIR}/run/fireqos" ]
+ then
+ fireqos_run_dir="${LOCALSTATEDIR}/run/fireqos"
+ fi
+ fi
+ fi
+fi
+
+# -----------------------------------------------------------------------------
+# logging functions
+
PROGRAM_FILE="$0"
PROGRAM_NAME="$(basename $0)"
PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
-# -----------------------------------------------------------------------------
-
logdate() {
date "+%Y-%m-%d %H:%M:%S"
}
@@ -52,6 +98,7 @@ debug() {
[ $debug -eq 1 ] && log DEBUG "${@}"
}
+
# -----------------------------------------------------------------------------
plugins_dir="${NETDATA_PLUGINS_DIR}"
@@ -59,23 +106,52 @@ plugins_dir="${NETDATA_PLUGINS_DIR}"
config_dir=${NETDATA_CONFIG_DIR-/etc/netdata}
tc="$(which tc 2>/dev/null || command -v tc 2>/dev/null)"
-fireqos_run_dir="/var/run/fireqos"
+
+
+# -----------------------------------------------------------------------------
+# user configuration
+
+# time in seconds to refresh QoS class/qdisc names
qos_get_class_names_every=120
+
+# time in seconds to exit - netdata will restart the script
qos_exit_every=3600
+# what to use? classes or qdiscs?
+tc_show="qdisc" # can also be "class"
+
+
+# -----------------------------------------------------------------------------
# check if we have a valid number for interval
+
t=${1}
update_every=$((t))
[ $((update_every)) -lt 1 ] && update_every=${NETDATA_UPDATE_EVERY}
[ $((update_every)) -lt 1 ] && update_every=1
+
+# -----------------------------------------------------------------------------
# allow the user to override our defaults
+
if [ -f "${config_dir}/tc-qos-helper.conf" ]
then
source "${config_dir}/tc-qos-helper.conf"
fi
+case "${tc_show}" in
+ qdisc|class)
+ ;;
+
+ *)
+ error "tc_show variable can be either 'qdisc' or 'class' but is set to '${tc_show}'. Assuming it is 'qdisc'."
+ tc_show="qdisc"
+ ;;
+esac
+
+
+# -----------------------------------------------------------------------------
# default sleep function
+
LOOPSLEEPMS_LASTWORK=0
loopsleepms() {
sleep $1
@@ -85,6 +161,10 @@ loopsleepms() {
# with a high resolution timer function for precise looping.
. "${plugins_dir}/loopsleepms.sh.inc"
+
+# -----------------------------------------------------------------------------
+# final checks we can run
+
if [ -z "${tc}" -o ! -x "${tc}" ]
then
fatal "cannot find command 'tc' in this system."
@@ -93,11 +173,20 @@ fi
tc_devices=
fix_names=
+# -----------------------------------------------------------------------------
+
setclassname() {
- echo "SETCLASSNAME $3 $2"
+ if [ "${tc_show}" = "qdisc" ]
+ then
+ echo "SETCLASSNAME $4 $2"
+ else
+ echo "SETCLASSNAME $3 $2"
+ fi
}
show_tc_cls() {
+ [ "${tc_show}" = "qdisc" ] && return 1
+
local x="${1}"
if [ -f /etc/iproute2/tc_cls ]
@@ -110,7 +199,6 @@ show_tc_cls() {
done </etc/iproute2/tc_cls
return 0
fi
-
return 1
}
@@ -144,7 +232,7 @@ show_tc() {
echo "BEGIN ${x}"
# netdata can parse the output of tc
- ${tc} -s class show dev ${x}
+ ${tc} -s ${tc_show} show dev ${x}
# check FireQOS names for classes
if [ ! -z "${fix_names}" ]
diff --git a/python.d/Makefile.am b/python.d/Makefile.am
index 883f06c4c..bfe28ff28 100644
--- a/python.d/Makefile.am
+++ b/python.d/Makefile.am
@@ -8,6 +8,11 @@ include $(top_srcdir)/build/subst.inc
SUFFIXES = .in
dist_python_SCRIPTS = \
+ python-modules-installer.sh \
+ $(NULL)
+
+dist_python_DATA = \
+ README.md \
apache.chart.py \
apache_cache.chart.py \
bind_rndc.chart.py \
@@ -19,16 +24,16 @@ dist_python_SCRIPTS = \
exim.chart.py \
fail2ban.chart.py \
freeradius.chart.py \
- gunicorn_log.chart.py \
haproxy.chart.py \
hddtemp.chart.py \
ipfs.chart.py \
isc_dhcpd.chart.py \
mdstat.chart.py \
memcached.chart.py \
+ mongodb.chart.py \
mysql.chart.py \
nginx.chart.py \
- nginx_log.chart.py \
+ nsd.chart.py \
ovpn_status_log.chart.py \
phpfpm.chart.py \
postfix.chart.py \
@@ -37,13 +42,10 @@ dist_python_SCRIPTS = \
retroshare.chart.py \
sensors.chart.py \
squid.chart.py \
+ smartd_log.chart.py \
tomcat.chart.py \
varnish.chart.py \
- python-modules-installer.sh \
- $(NULL)
-
-dist_python_DATA = \
- README.md \
+ web_log.chart.py \
$(NULL)
pythonmodulesdir=$(pythondir)/python_modules
diff --git a/python.d/Makefile.in b/python.d/Makefile.in
index 018e8b3eb..9b7846682 100644
--- a/python.d/Makefile.in
+++ b/python.d/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -89,10 +35,14 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+DIST_COMMON = $(dist_python_DATA) $(dist_python_SCRIPTS) \
+ $(dist_pythonmodules_DATA) $(dist_pythonyaml2_DATA) \
+ $(dist_pythonyaml3_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(top_srcdir)/build/subst.inc
subdir = python.d
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -101,10 +51,6 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_python_SCRIPTS) \
- $(dist_python_DATA) $(dist_pythonmodules_DATA) \
- $(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
@@ -140,33 +86,13 @@ am__installdirs = "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(pythondir)" \
"$(DESTDIR)$(pythonmodulesdir)" "$(DESTDIR)$(pythonyaml2dir)" \
"$(DESTDIR)$(pythonyaml3dir)"
SCRIPTS = $(dist_python_SCRIPTS)
-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 =
SOURCES =
DIST_SOURCES =
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
DATA = $(dist_python_DATA) $(dist_pythonmodules_DATA) \
$(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/build/subst.inc
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -190,7 +116,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -204,6 +134,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -307,6 +241,11 @@ CLEANFILES = \
SUFFIXES = .in
dist_python_SCRIPTS = \
+ python-modules-installer.sh \
+ $(NULL)
+
+dist_python_DATA = \
+ README.md \
apache.chart.py \
apache_cache.chart.py \
bind_rndc.chart.py \
@@ -318,16 +257,16 @@ dist_python_SCRIPTS = \
exim.chart.py \
fail2ban.chart.py \
freeradius.chart.py \
- gunicorn_log.chart.py \
haproxy.chart.py \
hddtemp.chart.py \
ipfs.chart.py \
isc_dhcpd.chart.py \
mdstat.chart.py \
memcached.chart.py \
+ mongodb.chart.py \
mysql.chart.py \
nginx.chart.py \
- nginx_log.chart.py \
+ nsd.chart.py \
ovpn_status_log.chart.py \
phpfpm.chart.py \
postfix.chart.py \
@@ -336,13 +275,10 @@ dist_python_SCRIPTS = \
retroshare.chart.py \
sensors.chart.py \
squid.chart.py \
+ smartd_log.chart.py \
tomcat.chart.py \
varnish.chart.py \
- python-modules-installer.sh \
- $(NULL)
-
-dist_python_DATA = \
- README.md \
+ web_log.chart.py \
$(NULL)
pythonmodulesdir = $(pythondir)/python_modules
@@ -411,6 +347,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu python.d/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu python.d/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -419,7 +356,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
-$(top_srcdir)/build/subst.inc $(am__empty):
+$(top_srcdir)/build/subst.inc:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -431,11 +368,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_pythonSCRIPTS: $(dist_python_SCRIPTS)
@$(NORMAL_INSTALL)
+ test -z "$(pythondir)" || $(MKDIR_P) "$(DESTDIR)$(pythondir)"
@list='$(dist_python_SCRIPTS)'; test -n "$(pythondir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pythondir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pythondir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
@@ -466,11 +400,8 @@ uninstall-dist_pythonSCRIPTS:
dir='$(DESTDIR)$(pythondir)'; $(am__uninstall_files_from_dir)
install-dist_pythonDATA: $(dist_python_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(pythondir)" || $(MKDIR_P) "$(DESTDIR)$(pythondir)"
@list='$(dist_python_DATA)'; test -n "$(pythondir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pythondir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pythondir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -487,11 +418,8 @@ uninstall-dist_pythonDATA:
dir='$(DESTDIR)$(pythondir)'; $(am__uninstall_files_from_dir)
install-dist_pythonmodulesDATA: $(dist_pythonmodules_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(pythonmodulesdir)" || $(MKDIR_P) "$(DESTDIR)$(pythonmodulesdir)"
@list='$(dist_pythonmodules_DATA)'; test -n "$(pythonmodulesdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pythonmodulesdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pythonmodulesdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -508,11 +436,8 @@ uninstall-dist_pythonmodulesDATA:
dir='$(DESTDIR)$(pythonmodulesdir)'; $(am__uninstall_files_from_dir)
install-dist_pythonyaml2DATA: $(dist_pythonyaml2_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(pythonyaml2dir)" || $(MKDIR_P) "$(DESTDIR)$(pythonyaml2dir)"
@list='$(dist_pythonyaml2_DATA)'; test -n "$(pythonyaml2dir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pythonyaml2dir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pythonyaml2dir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -529,11 +454,8 @@ uninstall-dist_pythonyaml2DATA:
dir='$(DESTDIR)$(pythonyaml2dir)'; $(am__uninstall_files_from_dir)
install-dist_pythonyaml3DATA: $(dist_pythonyaml3_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(pythonyaml3dir)" || $(MKDIR_P) "$(DESTDIR)$(pythonyaml3dir)"
@list='$(dist_pythonyaml3_DATA)'; test -n "$(pythonyaml3dir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pythonyaml3dir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pythonyaml3dir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -548,11 +470,11 @@ uninstall-dist_pythonyaml3DATA:
@list='$(dist_pythonyaml3_DATA)'; test -n "$(pythonyaml3dir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pythonyaml3dir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
-
-ctags CTAGS:
+tags: TAGS
+TAGS:
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -696,24 +618,22 @@ uninstall-am: uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-dist_pythonDATA \
- install-dist_pythonSCRIPTS install-dist_pythonmodulesDATA \
- install-dist_pythonyaml2DATA install-dist_pythonyaml3DATA \
- 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-ps \
- install-ps-am install-strip installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
- uninstall uninstall-am uninstall-dist_pythonDATA \
- uninstall-dist_pythonSCRIPTS uninstall-dist_pythonmodulesDATA \
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pythonDATA install-dist_pythonSCRIPTS \
+ install-dist_pythonmodulesDATA install-dist_pythonyaml2DATA \
+ install-dist_pythonyaml3DATA 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-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \
+ uninstall-dist_pythonmodulesDATA \
uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA
-.PRECIOUS: Makefile
-
.in:
if sed \
-e 's#[@]localstatedir_POST@#$(localstatedir)#g' \
diff --git a/python.d/README.md b/python.d/README.md
index 75f5614a7..7df6e3e86 100644
--- a/python.d/README.md
+++ b/python.d/README.md
@@ -704,6 +704,149 @@ If no configuration is given, module will attempt to connect to memcached instan
---
+# mongodb
+
+Module monitor mongodb performance and health metrics
+
+**Requirements:**
+ * `python-pymongo` package.
+
+You need to install it manually.
+
+
+Number of charts depends on mongodb version, storage engine and other features (replication):
+
+1. **Read requests**:
+ * query
+ * getmore (operation the cursor executes to get additional data from query)
+
+2. **Write requests**:
+ * insert
+ * delete
+ * update
+
+3. **Active clients**:
+ * readers (number of clients with read operations in progress or queued)
+ * writers (number of clients with write operations in progress or queued)
+
+4. **Journal transactions**:
+ * commits (count of transactions that have been written to the journal)
+
+5. **Data written to the journal**:
+ * volume (volume of data)
+
+6. **Background flush** (MMAPv1):
+ * average ms (average time taken by flushes to execute)
+ * last ms (time taken by the last flush)
+
+8. **Read tickets** (WiredTiger):
+ * in use (number of read tickets in use)
+ * available (number of available read tickets remaining)
+
+9. **Write tickets** (WiredTiger):
+ * in use (number of write tickets in use)
+ * available (number of available write tickets remaining)
+
+10. **Cursors**:
+ * opened (number of cursors currently opened by MongoDB for clients)
+ * timedOut (number of cursors that have timed)
+ * noTimeout (number of open cursors with timeout disabled)
+
+11. **Connections**:
+ * connected (number of clients currently connected to the database server)
+ * unused (number of unused connections available for new clients)
+
+12. **Memory usage metrics**:
+ * virtual
+ * resident (amount of memory used by the database process)
+ * mapped
+ * non mapped
+
+13. **Page faults**:
+ * page faults (number of times MongoDB had to request from disk)
+
+14. **Cache metrics** (WiredTiger):
+ * percentage of bytes currently in the cache (amount of space taken by cached data)
+ * percantage of tracked dirty bytes in the cache (amount of space taken by dirty data)
+
+15. **Pages evicted from cache** (WiredTiger):
+ * modified
+ * unmodified
+
+16. **Queued requests**:
+ * readers (number of read request currently queued)
+ * writers (number of write request currently queued)
+
+17. **Errors**:
+ * msg (number of message assertions raised)
+ * warning (number of warning assertions raised)
+ * regular (number of regular assertions raised)
+ * user (number of assertions corresponding to errors generated by users)
+
+18. **Storage metrics** (one chart for every database)
+ * dataSize (size of all documents + padding in the database)
+ * indexSize (size of all indexes in the database)
+ * storageSize (size of all extents in the database)
+
+19. **Documents in the database** (one chart for all databases)
+ * documents (number of objects in the database among all the collections)
+
+20. **tcmalloc metrics**
+ * central cache free
+ * current total thread cache
+ * pageheap free
+ * pageheap unmapped
+ * thread cache free
+ * transfer cache free
+ * heap size
+
+21. **Commands total/failed rate**
+ * count
+ * createIndex
+ * delete
+ * eval
+ * findAndModify
+ * insert
+
+22. **Locks metrics** (acquireCount metrics - number of times the lock was acquired in the specified mode)
+ * Global lock
+ * Database lock
+ * Collection lock
+ * Metadata lock
+ * oplog lock
+
+23. **Replica set members state**
+ * state
+
+24. **Oplog window**
+ * window (interval of time between the oldest and the latest entries in the oplog)
+
+25. **Replication lag**
+ * member (time when last entry from the oplog was applied for every member)
+
+26. **Replication set member heartbeat latency**
+ * member (time when last heartbeat was received from replica set member)
+
+
+### configuration
+
+Sample:
+
+```yaml
+local:
+ name : 'local'
+ host : '127.0.0.1'
+ port : 27017
+ user : 'netdata'
+ pass : 'netdata'
+
+```
+
+If no configuration is given, module will attempt to connect to mongodb daemon on `127.0.0.1:27017` address
+
+---
+
+
# mysql
Module monitors one or more mysql servers
@@ -841,30 +984,58 @@ Without configuration, module attempts to connect to `http://localhost/stub_stat
---
-# nginx_log
+# nsd
-Module monitors nginx access log and produces only one chart:
+Module uses the `nsd-control stats_noreset` command to provide `nsd` statistics.
-1. **nginx status codes** in requests/s
- * 2xx
- * 3xx
- * 4xx
- * 5xx
+**Requirements:**
+ * Version of `nsd` must be 4.0+
+ * Netdata must have permissions to run `nsd-control stats_noreset`
-### configuration
+It produces:
-Sample for two vhosts:
+1. **Queries**
+ * queries
-```yaml
-site_A:
- path: '/var/log/nginx/access-A.log'
+2. **Zones**
+ * master
+ * slave
-site_B:
- name: 'local'
- path: '/var/log/nginx/access-B.log'
-```
+3. **Protocol**
+ * udp
+ * udp6
+ * tcp
+ * tcp6
+
+4. **Query Type**
+ * A
+ * NS
+ * CNAME
+ * SOA
+ * PTR
+ * HINFO
+ * MX
+ * NAPTR
+ * TXT
+ * AAAA
+ * SRV
+ * ANY
+
+5. **Transfer**
+ * NOTIFY
+ * AXFR
+
+6. **Return Code**
+ * NOERROR
+ * FORMERR
+ * SERVFAIL
+ * NXDOMAIN
+ * NOTIMP
+ * REFUSED
+ * YXDOMAIN
-When no configuration file is found, module tries to parse `/var/log/nginx/access.log` file.
+
+Configuration is not needed.
---
@@ -958,6 +1129,75 @@ Configuration is not needed.
---
+# postgres
+
+Module monitors one or more postgres servers.
+
+**Requirements:**
+
+ * `python-psycopg2` package. You have to install to manually.
+
+Following charts are drawn:
+
+1. **Database size** MB
+ * size
+
+2. **Current Backend Processes** processes
+ * active
+
+3. **Write-Ahead Logging Statistics** files/s
+ * total
+ * ready
+ * done
+
+4. **Checkpoints** writes/s
+ * scheduled
+ * requested
+
+5. **Current connections to db** count
+ * connections
+
+6. **Tuples returned from db** tuples/s
+ * sequential
+ * bitmap
+
+7. **Tuple reads from db** reads/s
+ * disk
+ * cache
+
+8. **Transactions on db** transactions/s
+ * commited
+ * rolled back
+
+9. **Tuples written to db** writes/s
+ * inserted
+ * updated
+ * deleted
+ * conflicts
+
+10. **Locks on db** count per type
+ * locks
+
+### configuration
+
+```yaml
+socket:
+ name : 'socket'
+ user : 'postgres'
+ database : 'postgres'
+
+tcp:
+ name : 'tcp'
+ user : 'postgres'
+ database : 'postgres'
+ host : 'localhost'
+ port : 5432
+```
+
+When no configuration file is found, module tries to connect to TCP/IP socket: `localhost:5432`.
+
+---
+
# redis
Get INFO data from redis instance.
@@ -1052,6 +1292,45 @@ Without any configuration module will try to autodetect where squid presents its
---
+# smartd_log
+
+Module monitor `smartd` log files to collect HDD/SSD S.M.A.R.T attributes.
+
+It produces following charts (you can add additional attributes in the module configuration file):
+
+1. **Read Error Rate** attribute 1
+
+2. **Start/Stop Count** attribute 4
+
+3. **Reallocated Sectors Count** attribute 5
+
+4. **Seek Error Rate** attribute 7
+
+5. **Power-On Hours Count** attribute 9
+
+6. **Power Cycle Count** attribute 12
+
+7. **Load/Unload Cycles** attribute 193
+
+8. **Temperature** attribute 194
+
+9. **Current Pending Sectors** attribute 197
+
+10. **Off-Line Uncorrectable** attribute 198
+
+11. **Write Error Rate** attribute 200
+
+### configuration
+
+```yaml
+local:
+ log_path : '/var/log/smartd/'
+```
+
+If no configuration is given, module will attempt to read log files in /var/log/smartd/ directory.
+
+---
+
# tomcat
Present tomcat containers memory utilization.
@@ -1151,3 +1430,68 @@ It produces:
No configuration is needed.
---
+
+# web_log
+
+Tails the apache/nginx/lighttpd/gunicorn log files to collect real-time web-server statistics.
+
+It produces following charts:
+
+1. **Response by type** requests/s
+ * success (1xx, 2xx, 304)
+ * error (5xx)
+ * redirect (3xx except 304)
+ * bad (4xx)
+ * other (all other responses)
+
+2. **Response by code family** requests/s
+ * 1xx (informational)
+ * 2xx (successful)
+ * 3xx (redirect)
+ * 4xx (bad)
+ * 5xx (internal server errors)
+ * other (non-standart responses)
+ * unmatched (the lines in the log file that are not matched)
+
+3. **Detailed Response Codes** requests/s (number of responses for each response code family individually)
+
+4. **Bandwidth** KB/s
+ * received (bandwidth of requests)
+ * send (bandwidth of responses)
+
+5. **Timings** ms (request processing time)
+ * min (bandwidth of requests)
+ * max (bandwidth of responses)
+ * average (bandwidth of responses)
+
+6. **Request per url** requests/s (configured by user)
+
+7. **Http Methods** requests/s (requests per http method)
+
+8. **Http Versions** requests/s (requests per http version)
+
+9. **IP protocols** requests/s (requests per ip protocol version)
+
+10. **Curent Poll Unique Client IPs** unique ips/s (unique client IPs per data collection iteration)
+
+11. **All Time Unique Client IPs** unique ips/s (unique client IPs since the last restart of netdata)
+
+
+### configuration
+
+```yaml
+nginx_log:
+ name : 'nginx_log'
+ path : '/var/log/nginx/access.log'
+
+apache_log:
+ name : 'apache_log'
+ path : '/var/log/apache/other_vhosts_access.log'
+ categories:
+ cacti : 'cacti.*'
+ observium : 'observium'
+```
+
+Module has preconfigured jobs for nginx, apache and gunicorn on various distros.
+
+---
diff --git a/python.d/bind_rndc.chart.py b/python.d/bind_rndc.chart.py
index e11c751f5..a4d753703 100644
--- a/python.d/bind_rndc.chart.py
+++ b/python.d/bind_rndc.chart.py
@@ -4,7 +4,7 @@
from base import SimpleService
from re import compile, findall
-from os.path import getsize, isfile, split
+from os.path import getsize, split
from os import access as is_accessible, R_OK
from subprocess import Popen
@@ -12,7 +12,6 @@ priority = 60000
retries = 60
update_every = 30
-DIRECTORIES = ['/bin/', '/usr/bin/', '/sbin/', '/usr/sbin/']
NMS = ['requests', 'responses', 'success', 'auth_answer', 'nonauth_answer', 'nxrrset', 'failure',
'nxdomain', 'recursion', 'duplicate', 'rejections']
QUERIES = ['RESERVED0', 'A', 'NS', 'CNAME', 'SOA', 'PTR', 'MX', 'TXT', 'X25', 'AAAA', 'SRV', 'NAPTR',
@@ -29,16 +28,12 @@ class Service(SimpleService):
# 'Cache DB RRsets', 'Socket I/O Statistics']
self.options = ['Name Server Statistics', 'Incoming Queries', 'Outgoing Queries']
self.regex_options = [r'(%s(?= \+\+)) \+\+([^\+]+)' % option for option in self.options]
- try:
- self.rndc = [''.join([directory, 'rndc']) for directory in DIRECTORIES
- if isfile(''.join([directory, 'rndc']))][0]
- except IndexError:
- self.rndc = False
+ self.rndc = self.find_binary('rndc')
def check(self):
# We cant start without 'rndc' command
if not self.rndc:
- self.error('Command "rndc" not found')
+ self.error('Can\'t locate \'rndc\' binary or binary is not executable by netdata')
return False
# We cant start if stats file is not exist or not readable by netdata user
@@ -55,15 +50,15 @@ class Service(SimpleService):
if not run_rndc.returncode:
# 'rndc' was found, stats file is exist and readable and we can run 'rndc stats'. Lets go!
self.create_charts()
-
+
# BIND APPEND dump on every run 'rndc stats'
# that is why stats file size can be VERY large if update_interval too small
dump_size_24hr = round(86400 / self.update_every * (int(size_after) - int(size_before)) / 1048576, 3)
-
+
# If update_every too small we should WARN user
if self.update_every < 30:
self.info('Update_every %s is NOT recommended for use. Increase the value to > 30' % self.update_every)
-
+
self.info('With current update_interval it will be + %s MB every 24hr. '
'Don\'t forget to create logrotate conf file for %s' % (dump_size_24hr, self.named_stats_path))
@@ -82,12 +77,11 @@ class Service(SimpleService):
named.stats file size
)
"""
-
try:
current_size = getsize(self.named_stats_path)
except OSError:
return None, None
-
+
run_rndc = Popen([self.rndc, 'stats'], shell=False)
run_rndc.wait()
@@ -115,23 +109,23 @@ class Service(SimpleService):
return None
rndc_stats = dict()
-
+
# Result: dict.
# topic = Cache DB RRsets; body = A 178303 NS 86790 ... ; desc = A; value = 178303
# {'Cache DB RRsets': [('A', 178303), ('NS', 286790), ...],
# {Incoming Queries': [('RESERVED0', 8), ('A', 4557317680), ...],
# ......
for regex in self.regex_options:
- rndc_stats.update({topic: [(desc, int(value)) for value, desc in self.regex_values.findall(body)]
- for topic, body in findall(regex, raw_data)})
-
+ rndc_stats.update(dict([(topic, [(desc, int(value)) for value, desc in self.regex_values.findall(body)])
+ for topic, body in findall(regex, raw_data)]))
+
nms = dict(rndc_stats.get('Name Server Statistics', []))
- inc_queries = {'i' + k: 0 for k in QUERIES}
- inc_queries.update({'i' + k: v for k, v in rndc_stats.get('Incoming Queries', [])})
- out_queries = {'o' + k: 0 for k in QUERIES}
- out_queries.update({'o' + k: v for k, v in rndc_stats.get('Outgoing Queries', [])})
-
+ inc_queries = dict([('i' + k, 0) for k in QUERIES])
+ inc_queries.update(dict([('i' + k, v) for k, v in rndc_stats.get('Incoming Queries', [])]))
+ out_queries = dict([('o' + k, 0) for k in QUERIES])
+ out_queries.update(dict([('o' + k, v) for k, v in rndc_stats.get('Outgoing Queries', [])]))
+
to_netdata = dict()
to_netdata['requests'] = sum([v for k, v in nms.items() if 'request' in k and 'received' in k])
to_netdata['responses'] = sum([v for k, v in nms.items() if 'responses' in k and 'sent' in k])
@@ -145,7 +139,7 @@ class Service(SimpleService):
to_netdata['duplicate'] = nms.get('duplicate queries received', 0)
to_netdata['rejections'] = nms.get('recursive queries rejected', 0)
to_netdata['stats_size'] = size
-
+
to_netdata.update(inc_queries)
to_netdata.update(out_queries)
return to_netdata
@@ -154,20 +148,20 @@ class Service(SimpleService):
self.order = ['stats_size', 'bind_stats', 'incoming_q', 'outgoing_q']
self.definitions = {
'bind_stats': {
- 'options': [None, 'Name Server Statistics', 'stats', 'Name Server Statistics', 'bind_rndc.stats', 'line'],
+ 'options': [None, 'Name Server Statistics', 'stats', 'name server statistics', 'bind_rndc.stats', 'line'],
'lines': [
]},
'incoming_q': {
- 'options': [None, 'Incoming queries', 'queries','Incoming queries', 'bind_rndc.incq', 'line'],
+ 'options': [None, 'Incoming queries', 'queries','incoming queries', 'bind_rndc.incq', 'line'],
'lines': [
]},
'outgoing_q': {
- 'options': [None, 'Outgoing queries', 'queries','Outgoing queries', 'bind_rndc.outq', 'line'],
+ 'options': [None, 'Outgoing queries', 'queries','outgoing queries', 'bind_rndc.outq', 'line'],
'lines': [
]},
'stats_size': {
'options': [None, '%s file size' % split(self.named_stats_path)[1].capitalize(), 'megabytes',
- '%s size' % split(self.named_stats_path)[1].capitalize(), 'bind_rndc.size', 'line'],
+ '%s size' % split(self.named_stats_path)[1], 'bind_rndc.size', 'line'],
'lines': [
["stats_size", None, "absolute", 1, 1048576]
]}
diff --git a/python.d/cpufreq.chart.py b/python.d/cpufreq.chart.py
index c761aae88..e28bdea8f 100644
--- a/python.d/cpufreq.chart.py
+++ b/python.d/cpufreq.chart.py
@@ -62,6 +62,7 @@ class Service(SimpleService):
return data
else:
self.alert("accurate method failed, falling back")
+ self.accurate_exists = False
for name, paths in self.assignment.items():
diff --git a/python.d/elasticsearch.chart.py b/python.d/elasticsearch.chart.py
index ff841f17c..430227f69 100644
--- a/python.d/elasticsearch.chart.py
+++ b/python.d/elasticsearch.chart.py
@@ -3,13 +3,14 @@
# Author: l2isbad
from base import UrlService
-from requests import get
-from socket import gethostbyname
+from socket import gethostbyname, gaierror
try:
from queue import Queue
except ImportError:
from Queue import Queue
from threading import Thread
+from collections import namedtuple
+from json import loads
# default module values (can be overridden per job in `config`)
# update_every = 2
@@ -17,45 +18,125 @@ update_every = 5
priority = 60000
retries = 60
+METHODS = namedtuple('METHODS', ['get_data_function', 'url'])
+
+NODE_STATS = [
+ ('indices.search.fetch_current', None, None),
+ ('indices.search.fetch_total', None, None),
+ ('indices.search.query_current', None, None),
+ ('indices.search.query_total', None, None),
+ ('indices.search.query_time_in_millis', None, None),
+ ('indices.search.fetch_time_in_millis', None, None),
+ ('indices.indexing.index_total', 'indexing_index_total', None),
+ ('indices.indexing.index_current', 'indexing_index_current', None),
+ ('indices.indexing.index_time_in_millis', 'indexing_index_time_in_millis', None),
+ ('indices.refresh.total', 'refresh_total', None),
+ ('indices.refresh.total_time_in_millis', 'refresh_total_time_in_millis', None),
+ ('indices.flush.total', 'flush_total', None),
+ ('indices.flush.total_time_in_millis', 'flush_total_time_in_millis', None),
+ ('jvm.gc.collectors.young.collection_count', 'young_collection_count', None),
+ ('jvm.gc.collectors.old.collection_count', 'old_collection_count', None),
+ ('jvm.gc.collectors.young.collection_time_in_millis', 'young_collection_time_in_millis', None),
+ ('jvm.gc.collectors.old.collection_time_in_millis', 'old_collection_time_in_millis', None),
+ ('jvm.mem.heap_used_percent', 'jvm_heap_percent', None),
+ ('jvm.mem.heap_committed_in_bytes', 'jvm_heap_commit', None),
+ ('thread_pool.bulk.queue', 'bulk_queue', None),
+ ('thread_pool.bulk.rejected', 'bulk_rejected', None),
+ ('thread_pool.index.queue', 'index_queue', None),
+ ('thread_pool.index.rejected', 'index_rejected', None),
+ ('thread_pool.search.queue', 'search_queue', None),
+ ('thread_pool.search.rejected', 'search_rejected', None),
+ ('thread_pool.merge.queue', 'merge_queue', None),
+ ('thread_pool.merge.rejected', 'merge_rejected', None),
+ ('indices.fielddata.memory_size_in_bytes', 'index_fdata_memory', None),
+ ('indices.fielddata.evictions', None, None),
+ ('breakers.fielddata.tripped', None, None),
+ ('http.current_open', 'http_current_open', None),
+ ('transport.rx_size_in_bytes', 'transport_rx_size_in_bytes', None),
+ ('transport.tx_size_in_bytes', 'transport_tx_size_in_bytes', None),
+ ('process.max_file_descriptors', None, None),
+ ('process.open_file_descriptors', None, None)
+]
+
+CLUSTER_STATS = [
+ ('nodes.count.data_only', 'count_data_only', None),
+ ('nodes.count.master_data', 'count_master_data', None),
+ ('nodes.count.total', 'count_total', None),
+ ('nodes.count.master_only', 'count_master_only', None),
+ ('nodes.count.client', 'count_client', None),
+ ('indices.docs.count', 'docs_count', None),
+ ('indices.query_cache.hit_count', 'query_cache_hit_count', None),
+ ('indices.query_cache.miss_count', 'query_cache_miss_count', None),
+ ('indices.store.size_in_bytes', 'store_size_in_bytes', None),
+ ('indices.count', 'indices_count', None),
+ ('indices.shards.total', 'shards_total', None)
+]
+
+HEALTH_STATS = [
+ ('number_of_nodes', 'health_number_of_nodes', None),
+ ('number_of_data_nodes', 'health_number_of_data_nodes', None),
+ ('number_of_pending_tasks', 'health_number_of_pending_tasks', None),
+ ('number_of_in_flight_fetch', 'health_number_of_in_flight_fetch', None),
+ ('active_shards', 'health_active_shards', None),
+ ('relocating_shards', 'health_relocating_shards', None),
+ ('unassigned_shards', 'health_unassigned_shards', None),
+ ('delayed_unassigned_shards', 'health_delayed_unassigned_shards', None),
+ ('initializing_shards', 'health_initializing_shards', None),
+ ('active_shards_percent_as_number', 'health_active_shards_percent_as_number', None)
+]
+
# charts order (can be overridden if you want less charts, or different order)
-ORDER = ['search_perf_total', 'search_perf_time', 'search_latency', 'index_perf_total', 'index_perf_time',
- 'index_latency', 'jvm_mem_heap', 'jvm_gc_count', 'jvm_gc_time', 'host_metrics_file_descriptors',
- 'host_metrics_http', 'host_metrics_transport', 'thread_pool_qr', 'fdata_cache', 'fdata_ev_tr',
- 'cluster_health_status', 'cluster_health_nodes', 'cluster_health_shards', 'cluster_stats_nodes',
- 'cluster_stats_query_cache', 'cluster_stats_docs', 'cluster_stats_store', 'cluster_stats_indices_shards']
+ORDER = ['search_perf_total', 'search_perf_current', 'search_perf_time', 'search_latency', 'index_perf_total',
+ 'index_perf_current', 'index_perf_time', 'index_latency', 'jvm_mem_heap', 'jvm_gc_count',
+ 'jvm_gc_time', 'host_metrics_file_descriptors', 'host_metrics_http', 'host_metrics_transport',
+ 'thread_pool_qr_q', 'thread_pool_qr_r', 'fdata_cache', 'fdata_ev_tr', 'cluster_health_status',
+ 'cluster_health_nodes', 'cluster_health_shards', 'cluster_stats_nodes', 'cluster_stats_query_cache',
+ 'cluster_stats_docs', 'cluster_stats_store', 'cluster_stats_indices_shards']
CHARTS = {
'search_perf_total': {
- 'options': [None, 'Number of queries, fetches', 'queries', 'Search performance', 'es.search_query', 'stacked'],
+ 'options': [None, 'Total number of queries, fetches', 'number of', 'search performance',
+ 'es.search_query_total', 'stacked'],
+ 'lines': [
+ ['query_total', 'queries', 'incremental'],
+ ['fetch_total', 'fetches', 'incremental']
+ ]},
+ 'search_perf_current': {
+ 'options': [None, 'Number of queries, fetches in progress', 'number of', 'search performance',
+ 'es.search_query_current', 'stacked'],
'lines': [
- ['query_total', 'search_total', 'incremental'],
- ['fetch_total', 'fetch_total', 'incremental'],
- ['query_current', 'search_current', 'absolute'],
- ['fetch_current', 'fetch_current', 'absolute']
+ ['query_current', 'queries', 'absolute'],
+ ['fetch_current', 'fetches', 'absolute']
]},
'search_perf_time': {
- 'options': [None, 'Time spent on queries, fetches', 'seconds', 'Search performance', 'es.search_time', 'stacked'],
+ 'options': [None, 'Time spent on queries, fetches', 'seconds', 'search performance',
+ 'es.search_time', 'stacked'],
'lines': [
['query_time_in_millis', 'query', 'incremental', 1, 1000],
['fetch_time_in_millis', 'fetch', 'incremental', 1, 1000]
]},
'search_latency': {
- 'options': [None, 'Query and fetch latency', 'ms', 'Search performance', 'es.search_latency', 'stacked'],
+ 'options': [None, 'Query and fetch latency', 'ms', 'search performance', 'es.search_latency', 'stacked'],
'lines': [
['query_latency', 'query', 'absolute', 1, 1000],
['fetch_latency', 'fetch', 'absolute', 1, 1000]
]},
'index_perf_total': {
- 'options': [None, 'Number of documents indexed, index refreshes, flushes', 'documents/indexes',
- 'Indexing performance', 'es.index_doc', 'stacked'],
+ 'options': [None, 'Total number of documents indexed, index refreshes, index flushes to disk', 'number of',
+ 'indexing performance', 'es.index_performance_total', 'stacked'],
'lines': [
['indexing_index_total', 'indexed', 'incremental'],
['refresh_total', 'refreshes', 'incremental'],
- ['flush_total', 'flushes', 'incremental'],
- ['indexing_index_current', 'indexed_current', 'absolute'],
+ ['flush_total', 'flushes', 'incremental']
+ ]},
+ 'index_perf_current': {
+ 'options': [None, 'Number of documents currently being indexed', 'currently indexed',
+ 'indexing performance', 'es.index_performance_current', 'stacked'],
+ 'lines': [
+ ['indexing_index_current', 'documents', 'absolute']
]},
'index_perf_time': {
- 'options': [None, 'Time spent on indexing, refreshing, flushing', 'seconds', 'Indexing performance',
+ 'options': [None, 'Time spent on indexing, refreshing, flushing', 'seconds', 'indexing performance',
'es.search_time', 'stacked'],
'lines': [
['indexing_index_time_in_millis', 'indexing', 'incremental', 1, 1000],
@@ -63,67 +144,72 @@ CHARTS = {
['flush_total_time_in_millis', 'flushing', 'incremental', 1, 1000]
]},
'index_latency': {
- 'options': [None, 'Indexing and flushing latency', 'ms', 'Indexing performance',
+ 'options': [None, 'Indexing and flushing latency', 'ms', 'indexing performance',
'es.index_latency', 'stacked'],
'lines': [
['indexing_latency', 'indexing', 'absolute', 1, 1000],
['flushing_latency', 'flushing', 'absolute', 1, 1000]
]},
'jvm_mem_heap': {
- 'options': [None, 'JVM heap currently in use/committed', 'percent/MB', 'Memory usage and gc',
+ 'options': [None, 'JVM heap currently in use/committed', 'percent/MB', 'memory usage and gc',
'es.jvm_heap', 'area'],
'lines': [
['jvm_heap_percent', 'inuse', 'absolute'],
['jvm_heap_commit', 'commit', 'absolute', -1, 1048576]
]},
'jvm_gc_count': {
- 'options': [None, 'Count of garbage collections', 'counts', 'Memory usage and gc', 'es.gc_count', 'stacked'],
+ 'options': [None, 'Count of garbage collections', 'counts', 'memory usage and gc', 'es.gc_count', 'stacked'],
'lines': [
['young_collection_count', 'young', 'incremental'],
['old_collection_count', 'old', 'incremental']
]},
'jvm_gc_time': {
- 'options': [None, 'Time spent on garbage collections', 'ms', 'Memory usage and gc', 'es.gc_time', 'stacked'],
+ 'options': [None, 'Time spent on garbage collections', 'ms', 'memory usage and gc', 'es.gc_time', 'stacked'],
'lines': [
['young_collection_time_in_millis', 'young', 'incremental'],
['old_collection_time_in_millis', 'old', 'incremental']
]},
- 'thread_pool_qr': {
- 'options': [None, 'Number of queued/rejected threads in thread pool', 'threads', 'Queues and rejections',
- 'es.qr', 'stacked'],
+ 'thread_pool_qr_q': {
+ 'options': [None, 'Number of queued threads in thread pool', 'queued threads', 'queues and rejections',
+ 'es.thread_pool_queued', 'stacked'],
'lines': [
- ['bulk_queue', 'bulk_queue', 'absolute'],
- ['index_queue', 'index_queue', 'absolute'],
- ['search_queue', 'search_queue', 'absolute'],
- ['merge_queue', 'merge_queue', 'absolute'],
- ['bulk_rejected', 'bulk_rej', 'absolute'],
- ['index_rejected', 'index_rej', 'absolute'],
- ['search_rejected', 'search_rej', 'absolute'],
- ['merge_rejected', 'merge_rej', 'absolute']
+ ['bulk_queue', 'bulk', 'absolute'],
+ ['index_queue', 'index', 'absolute'],
+ ['search_queue', 'search', 'absolute'],
+ ['merge_queue', 'merge', 'absolute']
+ ]},
+ 'thread_pool_qr_r': {
+ 'options': [None, 'Number of rejected threads in thread pool', 'rejected threads', 'queues and rejections',
+ 'es.thread_pool_rejected', 'stacked'],
+ 'lines': [
+ ['bulk_rejected', 'bulk', 'absolute'],
+ ['index_rejected', 'index', 'absolute'],
+ ['search_rejected', 'search', 'absolute'],
+ ['merge_rejected', 'merge', 'absolute']
]},
'fdata_cache': {
- 'options': [None, 'Fielddata cache size', 'MB', 'Fielddata cache', 'es.fdata_cache', 'line'],
+ 'options': [None, 'Fielddata cache size', 'MB', 'fielddata cache', 'es.fdata_cache', 'line'],
'lines': [
- ['index_fdata_mem', 'mem_size', 'absolute', 1, 1048576]
+ ['index_fdata_memory', 'cache', 'absolute', 1, 1048576]
]},
'fdata_ev_tr': {
'options': [None, 'Fielddata evictions and circuit breaker tripped count', 'number of events',
- 'Fielddata cache', 'es.fdata_ev_tr', 'line'],
+ 'fielddata cache', 'es.evictions_tripped', 'line'],
'lines': [
- ['index_fdata_evic', 'evictions', 'incremental'],
- ['breakers_fdata_trip', 'tripped', 'incremental']
+ ['evictions', None, 'incremental'],
+ ['tripped', None, 'incremental']
]},
'cluster_health_nodes': {
- 'options': [None, 'Nodes and tasks statistics', 'units', 'Cluster health API',
- 'es.cluster_health', 'stacked'],
+ 'options': [None, 'Nodes and tasks statistics', 'units', 'cluster health API',
+ 'es.cluster_health_nodes', 'stacked'],
'lines': [
['health_number_of_nodes', 'nodes', 'absolute'],
['health_number_of_data_nodes', 'data_nodes', 'absolute'],
['health_number_of_pending_tasks', 'pending_tasks', 'absolute'],
- ['health_number_of_in_flight_fetch', 'inflight_fetch', 'absolute']
+ ['health_number_of_in_flight_fetch', 'in_flight_fetch', 'absolute']
]},
'cluster_health_status': {
- 'options': [None, 'Cluster status', 'status', 'Cluster health API',
+ 'options': [None, 'Cluster status', 'status', 'cluster health API',
'es.cluster_health_status', 'area'],
'lines': [
['status_green', 'green', 'absolute'],
@@ -134,8 +220,8 @@ CHARTS = {
['status_yellow', 'yellow', 'absolute']
]},
'cluster_health_shards': {
- 'options': [None, 'Shards statistics', 'shards', 'Cluster health API',
- 'es.cluster_health_sharts', 'stacked'],
+ 'options': [None, 'Shards statistics', 'shards', 'cluster health API',
+ 'es.cluster_health_shards', 'stacked'],
'lines': [
['health_active_shards', 'active_shards', 'absolute'],
['health_relocating_shards', 'relocating_shards', 'absolute'],
@@ -145,8 +231,8 @@ CHARTS = {
['health_active_shards_percent_as_number', 'active_percent', 'absolute']
]},
'cluster_stats_nodes': {
- 'options': [None, 'Nodes statistics', 'nodes', 'Cluster stats API',
- 'es.cluster_stats_nodes', 'stacked'],
+ 'options': [None, 'Nodes statistics', 'nodes', 'cluster stats API',
+ 'es.cluster_nodes', 'stacked'],
'lines': [
['count_data_only', 'data_only', 'absolute'],
['count_master_data', 'master_data', 'absolute'],
@@ -155,47 +241,47 @@ CHARTS = {
['count_client', 'client', 'absolute']
]},
'cluster_stats_query_cache': {
- 'options': [None, 'Query cache statistics', 'queries', 'Cluster stats API',
- 'es.cluster_stats_query_cache', 'stacked'],
+ 'options': [None, 'Query cache statistics', 'queries', 'cluster stats API',
+ 'es.cluster_query_cache', 'stacked'],
'lines': [
['query_cache_hit_count', 'hit', 'incremental'],
['query_cache_miss_count', 'miss', 'incremental']
]},
'cluster_stats_docs': {
- 'options': [None, 'Docs statistics', 'count', 'Cluster stats API',
- 'es.cluster_stats_docs', 'line'],
+ 'options': [None, 'Docs statistics', 'count', 'cluster stats API',
+ 'es.cluster_docs', 'line'],
'lines': [
['docs_count', 'docs', 'absolute']
]},
'cluster_stats_store': {
- 'options': [None, 'Store statistics', 'MB', 'Cluster stats API',
- 'es.cluster_stats_store', 'line'],
+ 'options': [None, 'Store statistics', 'MB', 'cluster stats API',
+ 'es.cluster_store', 'line'],
'lines': [
['store_size_in_bytes', 'size', 'absolute', 1, 1048567]
]},
'cluster_stats_indices_shards': {
- 'options': [None, 'Indices and shards statistics', 'count', 'Cluster stats API',
- 'es.cluster_stats_ind_sha', 'stacked'],
+ 'options': [None, 'Indices and shards statistics', 'count', 'cluster stats API',
+ 'es.cluster_indices_shards', 'stacked'],
'lines': [
['indices_count', 'indices', 'absolute'],
['shards_total', 'shards', 'absolute']
]},
'host_metrics_transport': {
- 'options': [None, 'Cluster communication transport metrics', 'kbit/s', 'Host metrics',
- 'es.host_metrics_transport', 'area'],
+ 'options': [None, 'Cluster communication transport metrics', 'kbit/s', 'host metrics',
+ 'es.host_transport', 'area'],
'lines': [
['transport_rx_size_in_bytes', 'in', 'incremental', 8, 1000],
['transport_tx_size_in_bytes', 'out', 'incremental', -8, 1000]
]},
'host_metrics_file_descriptors': {
- 'options': [None, 'Available file descriptors in percent', 'percent', 'Host metrics',
- 'es.host_metrics_descriptors', 'area'],
+ 'options': [None, 'Available file descriptors in percent', 'percent', 'host metrics',
+ 'es.host_descriptors', 'area'],
'lines': [
['file_descriptors_used', 'used', 'absolute', 1, 10]
]},
'host_metrics_http': {
- 'options': [None, 'Opened HTTP connections', 'connections', 'Host metrics',
- 'es.host_metrics_http', 'line'],
+ 'options': [None, 'Opened HTTP connections', 'connections', 'host metrics',
+ 'es.host_http_connections', 'line'],
'lines': [
['http_current_open', 'opened', 'absolute', 1, 1]
]}
@@ -208,78 +294,72 @@ class Service(UrlService):
self.order = ORDER
self.definitions = CHARTS
self.host = self.configuration.get('host')
- self.port = self.configuration.get('port')
- self.user = self.configuration.get('user')
- self.password = self.configuration.get('pass')
+ self.port = self.configuration.get('port', 9200)
+ self.scheme = self.configuration.get('scheme', 'http')
self.latency = dict()
+ self.methods = list()
def check(self):
# We can't start if <host> AND <port> not specified
- if not all([self.host, self.port]):
+ if not all([self.host, self.port, isinstance(self.host, str), isinstance(self.port, (str, int))]):
+ self.error('Host is not defined in the module configuration file')
return False
# It as a bad idea to use hostname.
- # Hostname -> ipaddress
+ # Hostname -> ip address
try:
self.host = gethostbyname(self.host)
- except Exception as e:
- self.error(str(e))
+ except gaierror as error:
+ self.error(str(error))
return False
- # HTTP Auth? NOT TESTED
- self.auth = self.user and self.password
-
+ scheme = 'http' if self.scheme else 'https'
+ # Add handlers (auth, self signed cert accept)
+ self.url = '%s://%s:%s' % (scheme, self.host, self.port)
+ self._UrlService__add_openers()
# Create URL for every Elasticsearch API
- url_node_stats = 'http://%s:%s/_nodes/_local/stats' % (self.host, self.port)
- url_cluster_health = 'http://%s:%s/_cluster/health' % (self.host, self.port)
- url_cluster_stats = 'http://%s:%s/_cluster/stats' % (self.host, self.port)
+ url_node_stats = '%s://%s:%s/_nodes/_local/stats' % (scheme, self.host, self.port)
+ url_cluster_health = '%s://%s:%s/_cluster/health' % (scheme, self.host, self.port)
+ url_cluster_stats = '%s://%s:%s/_cluster/stats' % (scheme, self.host, self.port)
# Create list of enabled API calls
user_choice = [bool(self.configuration.get('node_stats', True)),
bool(self.configuration.get('cluster_health', True)),
bool(self.configuration.get('cluster_stats', True))]
-
- avail_methods = [(self._get_node_stats, url_node_stats),
- (self._get_cluster_health, url_cluster_health),
- (self._get_cluster_stats, url_cluster_stats)]
+
+ avail_methods = [METHODS(get_data_function=self._get_node_stats_, url=url_node_stats),
+ METHODS(get_data_function=self._get_cluster_health_, url=url_cluster_health),
+ METHODS(get_data_function=self._get_cluster_stats_, url=url_cluster_stats)]
# Remove disabled API calls from 'avail methods'
- self.methods = [avail_methods[_] for _ in range(len(avail_methods)) if user_choice[_]]
+ self.methods = [avail_methods[e[0]] for e in enumerate(avail_methods) if user_choice[e[0]]]
# Run _get_data for ALL active API calls.
- api_result = {}
+ api_check_result = dict()
+ data_from_check = dict()
for method in self.methods:
- api_result[method[1]] = (bool(self._get_raw_data(method[1])))
+ try:
+ api_check_result[method.url] = method.get_data_function(None, method.url)
+ data_from_check.update(api_check_result[method.url] or dict())
+ except KeyError as error:
+ self.error('Failed to parse %s. Error: %s' % (method.url, str(error)))
+ return False
# We can start ONLY if all active API calls returned NOT None
- if not all(api_result.values()):
+ if not all(api_check_result.values()):
self.error('Plugin could not get data from all APIs')
- self.error('%s' % api_result)
return False
else:
- self.info('%s' % api_result)
- self.info('Plugin was started successfully')
-
+ self._data_from_check = data_from_check
return True
- def _get_raw_data(self, url):
- try:
- if not self.auth:
- raw_data = get(url)
- else:
- raw_data = get(url, auth=(self.user, self.password))
- except Exception:
- return None
-
- return raw_data
-
def _get_data(self):
threads = list()
queue = Queue()
result = dict()
for method in self.methods:
- th = Thread(target=method[0], args=(queue, method[1]))
+ th = Thread(target=method.get_data_function, args=(queue, method.url))
th.start()
threads.append(th)
@@ -289,102 +369,79 @@ class Service(UrlService):
return result or None
- def _get_cluster_health(self, queue, url):
+ def _get_cluster_health_(self, queue, url):
"""
Format data received from http request
:return: dict
"""
- data = self._get_raw_data(url)
+ raw_data = self._get_raw_data(url)
- if not data:
- queue.put({})
+ if not raw_data:
+ return queue.put(dict()) if queue else None
else:
- data = data.json()
+ data = loads(raw_data)
+
+ to_netdata = fetch_data_(raw_data=data, metrics_list=HEALTH_STATS)
- to_netdata = dict()
- to_netdata.update(update_key('health', data))
to_netdata.update({'status_green': 0, 'status_red': 0, 'status_yellow': 0,
'status_foo1': 0, 'status_foo2': 0, 'status_foo3': 0})
- to_netdata[''.join(['status_', to_netdata.get('health_status', '')])] = 1
+ current_status = 'status_' + data['status']
+ to_netdata[current_status] = 1
- queue.put(to_netdata)
+ return queue.put(to_netdata) if queue else to_netdata
- def _get_cluster_stats(self, queue, url):
+ def _get_cluster_stats_(self, queue, url):
"""
Format data received from http request
:return: dict
"""
- data = self._get_raw_data(url)
+ raw_data = self._get_raw_data(url)
- if not data:
- queue.put({})
+ if not raw_data:
+ return queue.put(dict()) if queue else None
else:
- data = data.json()
+ data = loads(raw_data)
- to_netdata = dict()
- to_netdata.update(update_key('count', data['nodes']['count']))
- to_netdata.update(update_key('query_cache', data['indices']['query_cache']))
- to_netdata.update(update_key('docs', data['indices']['docs']))
- to_netdata.update(update_key('store', data['indices']['store']))
- to_netdata['indices_count'] = data['indices']['count']
- to_netdata['shards_total'] = data['indices']['shards']['total']
+ to_netdata = fetch_data_(raw_data=data, metrics_list=CLUSTER_STATS)
- queue.put(to_netdata)
+ return queue.put(to_netdata) if queue else to_netdata
- def _get_node_stats(self, queue, url):
+ def _get_node_stats_(self, queue, url):
"""
Format data received from http request
:return: dict
"""
- data = self._get_raw_data(url)
+ raw_data = self._get_raw_data(url)
- if not data:
- queue.put({})
+ if not raw_data:
+ return queue.put(dict()) if queue else None
else:
- data = data.json()
+ data = loads(raw_data)
+
node = list(data['nodes'].keys())[0]
- to_netdata = dict()
- # Search performance metrics
- to_netdata.update(data['nodes'][node]['indices']['search'])
- to_netdata['query_latency'] = self.find_avg(to_netdata['query_total'],
- to_netdata['query_time_in_millis'], 'query_latency')
- to_netdata['fetch_latency'] = self.find_avg(to_netdata['fetch_total'],
- to_netdata['fetch_time_in_millis'], 'fetch_latency')
-
- # Indexing performance metrics
- for key in ['indexing', 'refresh', 'flush']:
- to_netdata.update(update_key(key, data['nodes'][node]['indices'].get(key, {})))
- to_netdata['indexing_latency'] = self.find_avg(to_netdata['indexing_index_total'],
- to_netdata['indexing_index_time_in_millis'], 'index_latency')
- to_netdata['flushing_latency'] = self.find_avg(to_netdata['flush_total'],
- to_netdata['flush_total_time_in_millis'], 'flush_latency')
- # Memory usage and garbage collection
- to_netdata.update(update_key('young', data['nodes'][node]['jvm']['gc']['collectors']['young']))
- to_netdata.update(update_key('old', data['nodes'][node]['jvm']['gc']['collectors']['old']))
- to_netdata['jvm_heap_percent'] = data['nodes'][node]['jvm']['mem']['heap_used_percent']
- to_netdata['jvm_heap_commit'] = data['nodes'][node]['jvm']['mem']['heap_committed_in_bytes']
-
- # Thread pool queues and rejections
- for key in ['bulk', 'index', 'search', 'merge']:
- to_netdata.update(update_key(key, data['nodes'][node]['thread_pool'].get(key, {})))
-
- # Fielddata cache
- to_netdata['index_fdata_mem'] = data['nodes'][node]['indices']['fielddata']['memory_size_in_bytes']
- to_netdata['index_fdata_evic'] = data['nodes'][node]['indices']['fielddata']['evictions']
- to_netdata['breakers_fdata_trip'] = data['nodes'][node]['breakers']['fielddata']['tripped']
-
- # Host metrics
- to_netdata.update(update_key('http', data['nodes'][node]['http']))
- to_netdata.update(update_key('transport', data['nodes'][node]['transport']))
- to_netdata['file_descriptors_used'] = round(float(data['nodes'][node]['process']['open_file_descriptors'])
- / data['nodes'][node]['process']['max_file_descriptors'] * 1000)
-
- queue.put(to_netdata)
-
- def find_avg(self, value1, value2, key):
+ to_netdata = fetch_data_(raw_data=data['nodes'][node], metrics_list=NODE_STATS)
+
+ # Search performance latency
+ to_netdata['query_latency'] = self.find_avg_(to_netdata['query_total'],
+ to_netdata['query_time_in_millis'], 'query_latency')
+ to_netdata['fetch_latency'] = self.find_avg_(to_netdata['fetch_total'],
+ to_netdata['fetch_time_in_millis'], 'fetch_latency')
+
+ # Indexing performance latency
+ to_netdata['indexing_latency'] = self.find_avg_(to_netdata['indexing_index_total'],
+ to_netdata['indexing_index_time_in_millis'], 'index_latency')
+ to_netdata['flushing_latency'] = self.find_avg_(to_netdata['flush_total'],
+ to_netdata['flush_total_time_in_millis'], 'flush_latency')
+
+ to_netdata['file_descriptors_used'] = round(float(to_netdata['open_file_descriptors'])
+ / to_netdata['max_file_descriptors'] * 1000)
+
+ return queue.put(to_netdata) if queue else to_netdata
+
+ def find_avg_(self, value1, value2, key):
if key not in self.latency:
self.latency.update({key: [value1, value2]})
return 0
@@ -398,5 +455,17 @@ class Service(UrlService):
return 0
-def update_key(string, dictionary):
- return {'_'.join([string, k]): v for k, v in dictionary.items()}
+def fetch_data_(raw_data, metrics_list):
+ to_netdata = dict()
+ for metric, new_name, function in metrics_list:
+ value = raw_data
+ for key in metric.split('.'):
+ try:
+ value = value[key]
+ except KeyError:
+ break
+ if not isinstance(value, dict) and key:
+ to_netdata[new_name or key] = value if not function else function(value)
+
+ return to_netdata
+
diff --git a/python.d/fail2ban.chart.py b/python.d/fail2ban.chart.py
index 2d80282c6..c7d24e8c1 100644
--- a/python.d/fail2ban.chart.py
+++ b/python.d/fail2ban.chart.py
@@ -4,16 +4,18 @@
from base import LogService
from re import compile
+
try:
from itertools import filterfalse
except ImportError:
from itertools import ifilterfalse as filterfalse
from os import access as is_accessible, R_OK
+from os.path import isdir
+from glob import glob
priority = 60000
retries = 60
-regex = compile(r'([A-Za-z-]+\]) enabled = ([a-z]+)')
-
+REGEX = compile(r'\[([A-Za-z-_]+)][^\[\]]*?(?<!# )enabled = true')
ORDER = ['jails_group']
@@ -23,22 +25,17 @@ class Service(LogService):
self.order = ORDER
self.log_path = self.configuration.get('log_path', '/var/log/fail2ban.log')
self.conf_path = self.configuration.get('conf_path', '/etc/fail2ban/jail.local')
- self.default_jails = ['ssh']
+ self.conf_dir = self.configuration.get('conf_dir', '')
try:
self.exclude = self.configuration['exclude'].split()
except (KeyError, AttributeError):
self.exclude = []
-
def _get_data(self):
"""
Parse new log lines
:return: dict
"""
-
- # If _get_raw_data returns empty list (no new lines in log file) we will send to Netdata this
- self.data = {jail: 0 for jail in self.jails_list}
-
try:
raw = self._get_raw_data()
if raw is None:
@@ -50,42 +47,86 @@ class Service(LogService):
# Fail2ban logs looks like
# 2016-12-25 12:36:04,711 fail2ban.actions[2455]: WARNING [ssh] Ban 178.156.32.231
- self.data = dict(
+ data = dict(
zip(
self.jails_list,
[len(list(filterfalse(lambda line: (jail + '] Ban') not in line, raw))) for jail in self.jails_list]
))
+ for jail in data:
+ self.data[jail] += data[jail]
+
return self.data
def check(self):
-
+
# Check "log_path" is accessible.
# If NOT STOP plugin
if not is_accessible(self.log_path, R_OK):
- self.error('Cannot access file %s' % (self.log_path))
+ self.error('Cannot access file %s' % self.log_path)
return False
+ jails_list = list()
+
+ if self.conf_dir:
+ dir_jails, error = parse_conf_dir(self.conf_dir)
+ jails_list.extend(dir_jails)
+ if not dir_jails:
+ self.error(error)
+
+ if self.conf_path:
+ path_jails, error = parse_conf_path(self.conf_path)
+ jails_list.extend(path_jails)
+ if not path_jails:
+ self.error(error)
- # Check "conf_path" is accessible.
- # If "conf_path" is accesible try to parse it to find enabled jails
- if is_accessible(self.conf_path, R_OK):
- with open(self.conf_path, 'rt') as jails_conf:
- jails_list = regex.findall(' '.join(jails_conf.read().split()))
- self.jails_list = [jail[:-1] for jail, status in jails_list if status == 'true']
- else:
- self.jails_list = []
- self.error('Cannot access jail.local file %s.' % (self.conf_path))
-
# If for some reason parse failed we still can START with default jails_list.
- self.jails_list = [jail for jail in self.jails_list if jail not in self.exclude]\
- if self.jails_list else self.default_jails
+ self.jails_list = list(set(jails_list) - set(self.exclude)) or ['ssh']
+ self.data = dict([(jail, 0) for jail in self.jails_list])
self.create_dimensions()
- self.info('Plugin succefully started. Jails: %s' % (self.jails_list))
+ self.info('Plugin successfully started. Jails: %s' % self.jails_list)
return True
def create_dimensions(self):
- self.definitions = {'jails_group':
- {'options':
- [None, "Jails ban statistics", "bans/s", 'Jails', 'jail.ban', 'line'], 'lines': []}}
+ self.definitions = {
+ 'jails_group': {'options': [None, "Jails ban statistics", "bans/s", 'jails', 'jail.ban', 'line'],
+ 'lines': []}}
for jail in self.jails_list:
- self.definitions['jails_group']['lines'].append([jail, jail, 'absolute'])
+ self.definitions['jails_group']['lines'].append([jail, jail, 'incremental'])
+
+
+def parse_conf_dir(conf_dir):
+ if not isdir(conf_dir):
+ return list(), '%s is not a directory' % conf_dir
+
+ jail_local = list(filter(lambda local: is_accessible(local, R_OK), glob(conf_dir + '/*.local')))
+ jail_conf = list(filter(lambda conf: is_accessible(conf, R_OK), glob(conf_dir + '/*.conf')))
+
+ if not (jail_local or jail_conf):
+ return list(), '%s is empty or not readable' % conf_dir
+
+ # According "man jail.conf" files could be *.local AND *.conf
+ # *.conf files parsed first. Changes in *.local overrides configuration in *.conf
+ if jail_conf:
+ jail_local.extend([conf for conf in jail_conf if conf[:-5] not in [local[:-6] for local in jail_local]])
+ jails_list = list()
+ for conf in jail_local:
+ with open(conf, 'rt') as f:
+ raw_data = f.read()
+
+ data = ' '.join(raw_data.split())
+ jails_list.extend(REGEX.findall(data))
+ jails_list = list(set(jails_list))
+
+ return jails_list, 'can\'t locate any jails in %s. Default jail is [\'ssh\']' % conf_dir
+
+
+def parse_conf_path(conf_path):
+ if not is_accessible(conf_path, R_OK):
+ return list(), '%s is not readable' % conf_path
+
+ with open(conf_path, 'rt') as jails_conf:
+ raw_data = jails_conf.read()
+
+ data = raw_data.split()
+ jails_list = REGEX.findall(' '.join(data))
+ return jails_list, 'can\'t locate any jails in %s. Default jail is [\'ssh\']' % conf_path
diff --git a/python.d/freeradius.chart.py b/python.d/freeradius.chart.py
index 2ac280f0e..f3de15735 100644
--- a/python.d/freeradius.chart.py
+++ b/python.d/freeradius.chart.py
@@ -3,7 +3,6 @@
# Author: l2isbad
from base import SimpleService
-from os.path import isfile
from re import findall
from subprocess import Popen, PIPE
@@ -11,7 +10,6 @@ from subprocess import Popen, PIPE
priority = 60000
retries = 60
update_every = 15
-directories = ['/bin/', '/usr/bin/', '/sbin/', '/usr/sbin/']
# charts order (can be overridden if you want less charts, or different order)
ORDER = ['authentication', 'accounting', 'proxy-auth', 'proxy-acct']
@@ -62,27 +60,23 @@ class Service(SimpleService):
self.acct = self.configuration.get('acct', False)
self.proxy_auth = self.configuration.get('proxy_auth', False)
self.proxy_acct = self.configuration.get('proxy_acct', False)
- try:
- self.echo = [''.join([directory, 'echo']) for directory in directories if isfile(''.join([directory, 'echo']))][0]
- self.radclient = [''.join([directory, 'radclient']) for directory in directories if isfile(''.join([directory, 'radclient']))][0]
- except IndexError:
- self.echo = []
- self.radclient = []
+ self.echo = self.find_binary('echo')
+ self.radclient = self.find_binary('radclient')
self.sub_echo = [self.echo, 'Message-Authenticator = 0x00, FreeRADIUS-Statistics-Type = 15, Response-Packet-Type = Access-Accept']
self.sub_radclient = [self.radclient, '-r', '1', '-t', '1', ':'.join([self.host, self.port]), 'status', self.secret]
def check(self):
if not all([self.echo, self.radclient]):
- self.error('Command radclient not found')
+ self.error('Can\'t locate \'radclient\' binary or binary is not executable by netdata')
return False
if self._get_raw_data():
chart_choice = [True, bool(self.acct), bool(self.proxy_auth), bool(self.proxy_acct)]
self.order = [chart for chart, choice in zip(ORDER, chart_choice) if choice]
- self.definitions = {k:v for k, v in CHARTS.items() if k in self.order}
+ self.definitions = dict([chart for chart in CHARTS.items() if chart[0] in self.order])
self.info('Plugin was started succesfully')
return True
else:
- self.error('Request returned no data. Is server alive? Used options: host {}, port {}, secret {}'.format(self.host, self.port, self.secret))
+ self.error('Request returned no data. Is server alive? Used options: host {0}, port {1}, secret {2}'.format(self.host, self.port, self.secret))
return False
@@ -92,7 +86,7 @@ class Service(SimpleService):
:return: dict
"""
result = self._get_raw_data()
- return {k.lower():int(v) for k, v in findall(r'((?<=-)[AP][a-zA-Z-]+) = (\d+)', result)}
+ return dict([(elem[0].lower(), int(elem[1])) for elem in findall(r'((?<=-)[AP][a-zA-Z-]+) = (\d+)', result)])
def _get_raw_data(self):
"""
diff --git a/python.d/gunicorn_log.chart.py b/python.d/gunicorn_log.chart.py
deleted file mode 100644
index 945963635..000000000
--- a/python.d/gunicorn_log.chart.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# -*- coding: utf-8 -*-
-# Description: nginx log netdata python.d module
-# Author: Pawel Krupa (paulfantom)
-# Modified for Gunicorn by: Jeff Willette (deltaskelta)
-
-from base import LogService
-import re
-
-priority = 60000
-retries = 60
-# update_every = 3
-
-ORDER = ['codes']
-CHARTS = {
- 'codes': {
- 'options': [None, 'gunicorn status codes', 'requests/s', 'requests', 'gunicorn_log.codes', 'stacked'],
- 'lines': [
- ["2xx", None, "incremental"],
- ["3xx", None, "incremental"],
- ["4xx", None, "incremental"],
- ["5xx", None, "incremental"]
- ]}
-}
-
-
-class Service(LogService):
- def __init__(self, configuration=None, name=None):
- LogService.__init__(self, configuration=configuration, name=name)
- if len(self.log_path) == 0:
- self.log_path = "/var/log/gunicorn/access.log"
- self.order = ORDER
- self.definitions = CHARTS
- pattern = r'" ([0-9]{3}) '
- #pattern = r'(?:" )([0-9][0-9][0-9]) ?'
- self.regex = re.compile(pattern)
-
- def _get_data(self):
- """
- Parse new log lines
- :return: dict
- """
- data = {'2xx': 0,
- '3xx': 0,
- '4xx': 0,
- '5xx': 0}
- try:
- raw = self._get_raw_data()
- if raw is None:
- return None
- elif not raw:
- return data
- except (ValueError, AttributeError):
- return None
-
- regex = self.regex
- for line in raw:
- code = regex.search(line)
- try:
- beginning = code.group(1)[0]
- except AttributeError:
- continue
-
- if beginning == '2':
- data["2xx"] += 1
- elif beginning == '3':
- data["3xx"] += 1
- elif beginning == '4':
- data["4xx"] += 1
- elif beginning == '5':
- data["5xx"] += 1
-
- return data
diff --git a/python.d/isc_dhcpd.chart.py b/python.d/isc_dhcpd.chart.py
index 54fbfb1f5..bb9ba5cbc 100644
--- a/python.d/isc_dhcpd.chart.py
+++ b/python.d/isc_dhcpd.chart.py
@@ -48,31 +48,31 @@ class Service(SimpleService):
except (ValueError, IndexError, AttributeError, SyntaxError) as e:
self.error('Pools configurations is incorrect', str(e))
return False
-
+
# Creating static charts
self.order = ['parse_time', 'leases_size', 'utilization', 'total']
self.definitions = {'utilization':
{'options':
- [None, 'Pools utilization', 'used %', 'Utilization', 'isc_dhcpd.util', 'line'],
+ [None, 'Pools utilization', 'used %', 'utilization', 'isc_dhcpd.util', 'line'],
'lines': []},
'total':
{'options':
- [None, 'Total all pools', 'leases', 'Utilization', 'isc_dhcpd.total', 'line'],
+ [None, 'Total all pools', 'leases', 'utilization', 'isc_dhcpd.total', 'line'],
'lines': [['total', 'leases', 'absolute']]},
'parse_time':
{'options':
- [None, 'Parse time', 'ms', 'Parse stats', 'isc_dhcpd.parse', 'line'],
+ [None, 'Parse time', 'ms', 'parse stats', 'isc_dhcpd.parse', 'line'],
'lines': [['ptime', 'time', 'absolute']]},
'leases_size':
{'options':
- [None, 'dhcpd.leases file size', 'kilobytes', 'Parse stats', 'isc_dhcpd.lsize', 'line'],
+ [None, 'dhcpd.leases file size', 'kilobytes', 'parse stats', 'isc_dhcpd.lsize', 'line'],
'lines': [['lsize', 'size', 'absolute']]}}
# Creating dynamic charts
for pool in self.pools:
self.definitions['utilization']['lines'].append([''.join(['ut_', pool]), pool, 'absolute'])
self.order.append(''.join(['leases_', pool]))
self.definitions[''.join(['leases_', pool])] = \
- {'options': [None, 'Active leases', 'leases', 'Pools', 'isc_dhcpd.lease', 'area'],
+ {'options': [None, 'Active leases', 'leases', 'pools', 'isc_dhcpd.lease', 'area'],
'lines': [[''.join(['le_', pool]), pool, 'absolute']]}
self.info('Plugin was started succesfully')
@@ -93,13 +93,10 @@ class Service(SimpleService):
part2 = filterfalse(find_ends, dhcp_leases)
raw_result = dict(zip(part1, part2))
time_end = time()
-
file_parse_time = round((time_end - time_start) * 1000)
-
except Exception as e:
self.error("Failed to parse leases file:", str(e))
return None
-
else:
result = (raw_result, file_parse_time)
return result
@@ -109,32 +106,31 @@ class Service(SimpleService):
:return: dict
"""
raw_leases = self._get_raw_data()
-
if not raw_leases:
return None
# Result: {ipaddress: end lease time, ...}
- all_leases = {k[6:len(k)-3]:v[7:len(v)-2] for k, v in raw_leases[0].items()}
+ all_leases = dict([(k[6:len(k)-3], v[7:len(v)-2]) for k, v in raw_leases[0].items()])
# Result: [active binding, active binding....]. (Expire time (ends date;) - current time > 0)
active_leases = [k for k, v in all_leases.items() if is_binding_active(all_leases[k])]
# Result: {pool: number of active bindings in pool, ...}
- pools_count = {pool: len([lease for lease in active_leases if is_address_in(lease, pool)])
- for pool in self.pools}
+ pools_count = dict([(pool, len([lease for lease in active_leases if is_address_in(lease, pool)]))
+ for pool in self.pools])
# Result: {pool: number of host ip addresses in pool, ...}
- pools_max = {pool: (2 ** (32 - int(pool.split('/')[1])) - 2)
- for pool in self.pools}
+ pools_max = dict([(pool, (2 ** (32 - int(pool.split('/')[1])) - 2))
+ for pool in self.pools])
# Result: {pool: % utilization, ....} (percent)
- pools_util = {pool:int(round(float(pools_count[pool]) / pools_max[pool] * 100, 0))
- for pool in self.pools}
+ pools_util = dict([(pool, int(round(float(pools_count[pool]) / pools_max[pool] * 100, 0)))
+ for pool in self.pools])
# Bulding dicts to send to netdata
- final_count = {''.join(['le_', k]): v for k, v in pools_count.items()}
- final_util = {''.join(['ut_', k]): v for k, v in pools_util.items()}
-
+ final_count = dict([(''.join(['le_', k]), v) for k, v in pools_count.items()])
+ final_util = dict([(''.join(['ut_', k]), v) for k, v in pools_util.items()])
+
to_netdata = {'total': len(active_leases)}
to_netdata.update({'lsize': int(stat(self.leases_path)[6] / 1024)})
to_netdata.update({'ptime': int(raw_leases[1])})
@@ -159,6 +155,7 @@ def find_lease(value):
def find_ends(value):
return value[2:6] != 'ends'
+
def return_utf(s):
# python2 returns "<type 'str'>" for simple strings
# python3 returns "<class 'str'>" for unicode strings
diff --git a/python.d/mongodb.chart.py b/python.d/mongodb.chart.py
new file mode 100644
index 000000000..c01bd293c
--- /dev/null
+++ b/python.d/mongodb.chart.py
@@ -0,0 +1,672 @@
+# -*- coding: utf-8 -*-
+# Description: mongodb netdata python.d module
+# Author: l2isbad
+
+from base import SimpleService
+from copy import deepcopy
+from datetime import datetime
+from sys import exc_info
+
+try:
+ from pymongo import MongoClient, ASCENDING, DESCENDING
+ from pymongo.errors import PyMongoError
+ PYMONGO = True
+except ImportError:
+ PYMONGO = False
+
+# default module values (can be overridden per job in `config`)
+# update_every = 2
+priority = 60000
+retries = 60
+
+REPLSET_STATES = [
+ ('1', 'primary'),
+ ('8', 'down'),
+ ('2', 'secondary'),
+ ('3', 'recovering'),
+ ('5', 'startup2'),
+ ('4', 'fatal'),
+ ('7', 'arbiter'),
+ ('6', 'unknown'),
+ ('9', 'rollback'),
+ ('10', 'removed'),
+ ('0', 'startup')]
+
+
+def multiply_by_100(value):
+ return value * 100
+
+DEFAULT_METRICS = [
+ ('opcounters.delete', None, None),
+ ('opcounters.update', None, None),
+ ('opcounters.insert', None, None),
+ ('opcounters.query', None, None),
+ ('opcounters.getmore', None, None),
+ ('globalLock.activeClients.readers', 'activeClients_readers', None),
+ ('globalLock.activeClients.writers', 'activeClients_writers', None),
+ ('connections.available', 'connections_available', None),
+ ('connections.current', 'connections_current', None),
+ ('mem.mapped', None, None),
+ ('mem.resident', None, None),
+ ('mem.virtual', None, None),
+ ('globalLock.currentQueue.readers', 'currentQueue_readers', None),
+ ('globalLock.currentQueue.writers', 'currentQueue_writers', None),
+ ('asserts.msg', None, None),
+ ('asserts.regular', None, None),
+ ('asserts.user', None, None),
+ ('asserts.warning', None, None),
+ ('extra_info.page_faults', None, None),
+ ('metrics.record.moves', None, None),
+ ('backgroundFlushing.average_ms', None, multiply_by_100),
+ ('backgroundFlushing.last_ms', None, multiply_by_100),
+ ('backgroundFlushing.flushes', None, multiply_by_100),
+ ('metrics.cursor.timedOut', None, None),
+ ('metrics.cursor.open.total', 'cursor_total', None),
+ ('metrics.cursor.open.noTimeout', None, None),
+ ('cursors.timedOut', None, None),
+ ('cursors.totalOpen', 'cursor_total', None)
+]
+
+DUR = [
+ ('dur.commits', None, None),
+ ('dur.journaledMB', None, multiply_by_100)
+]
+
+WIREDTIGER = [
+ ('wiredTiger.concurrentTransactions.read.available', 'wiredTigerRead_available', None),
+ ('wiredTiger.concurrentTransactions.read.out', 'wiredTigerRead_out', None),
+ ('wiredTiger.concurrentTransactions.write.available', 'wiredTigerWrite_available', None),
+ ('wiredTiger.concurrentTransactions.write.out', 'wiredTigerWrite_out', None),
+ ('wiredTiger.cache.bytes currently in the cache', None, None),
+ ('wiredTiger.cache.tracked dirty bytes in the cache', None, None),
+ ('wiredTiger.cache.maximum bytes configured', None, None),
+ ('wiredTiger.cache.unmodified pages evicted', 'unmodified', None),
+ ('wiredTiger.cache.modified pages evicted', 'modified', None)
+]
+
+TCMALLOC = [
+ ('tcmalloc.generic.current_allocated_bytes', None, None),
+ ('tcmalloc.generic.heap_size', None, None),
+ ('tcmalloc.tcmalloc.central_cache_free_bytes', None, None),
+ ('tcmalloc.tcmalloc.current_total_thread_cache_bytes', None, None),
+ ('tcmalloc.tcmalloc.pageheap_free_bytes', None, None),
+ ('tcmalloc.tcmalloc.pageheap_unmapped_bytes', None, None),
+ ('tcmalloc.tcmalloc.thread_cache_free_bytes', None, None),
+ ('tcmalloc.tcmalloc.transfer_cache_free_bytes', None, None)
+]
+
+COMMANDS = [
+ ('metrics.commands.count.total', 'count_total', None),
+ ('metrics.commands.createIndexes.total', 'createIndexes_total', None),
+ ('metrics.commands.delete.total', 'delete_total', None),
+ ('metrics.commands.eval.total', 'eval_total', None),
+ ('metrics.commands.findAndModify.total', 'findAndModify_total', None),
+ ('metrics.commands.insert.total', 'insert_total', None),
+ ('metrics.commands.delete.total', 'delete_total', None),
+ ('metrics.commands.count.failed', 'count_failed', None),
+ ('metrics.commands.createIndexes.failed', 'createIndexes_failed', None),
+ ('metrics.commands.delete.failed', 'delete_failed', None),
+ ('metrics.commands.eval.failed', 'eval_failed', None),
+ ('metrics.commands.findAndModify.failed', 'findAndModify_failed', None),
+ ('metrics.commands.insert.failed', 'insert_failed', None),
+ ('metrics.commands.delete.failed', 'delete_failed', None)
+]
+
+LOCKS = [
+ ('locks.Collection.acquireCount.R', 'Collection_R', None),
+ ('locks.Collection.acquireCount.r', 'Collection_r', None),
+ ('locks.Collection.acquireCount.W', 'Collection_W', None),
+ ('locks.Collection.acquireCount.w', 'Collection_w', None),
+ ('locks.Database.acquireCount.R', 'Database_R', None),
+ ('locks.Database.acquireCount.r', 'Database_r', None),
+ ('locks.Database.acquireCount.W', 'Database_W', None),
+ ('locks.Database.acquireCount.w', 'Database_w', None),
+ ('locks.Global.acquireCount.R', 'Global_R', None),
+ ('locks.Global.acquireCount.r', 'Global_r', None),
+ ('locks.Global.acquireCount.W', 'Global_W', None),
+ ('locks.Global.acquireCount.w', 'Global_w', None),
+ ('locks.Metadata.acquireCount.R', 'Metadata_R', None),
+ ('locks.Metadata.acquireCount.w', 'Metadata_w', None),
+ ('locks.oplog.acquireCount.r', 'oplog_r', None),
+ ('locks.oplog.acquireCount.w', 'oplog_w', None)
+]
+
+DBSTATS = [
+ 'dataSize',
+ 'indexSize',
+ 'storageSize',
+ 'objects'
+]
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = ['read_operations', 'write_operations', 'active_clients', 'journaling_transactions',
+ 'journaling_volume', 'background_flush_average', 'background_flush_last', 'background_flush_rate',
+ 'wiredtiger_read', 'wiredtiger_write', 'cursors', 'connections', 'memory', 'page_faults',
+ 'queued_requests', 'record_moves', 'wiredtiger_cache', 'wiredtiger_pages_evicted', 'asserts',
+ 'locks_collection', 'locks_database', 'locks_global', 'locks_metadata', 'locks_oplog',
+ 'dbstats_objects', 'tcmalloc_generic', 'tcmalloc_metrics', 'command_total_rate', 'command_failed_rate']
+
+CHARTS = {
+ 'read_operations': {
+ 'options': [None, 'Received read requests', 'requests/s', 'throughput metrics',
+ 'mongodb.read_operations', 'line'],
+ 'lines': [
+ ['query', None, 'incremental'],
+ ['getmore', None, 'incremental']
+ ]},
+ 'write_operations': {
+ 'options': [None, 'Received write requests', 'requests/s', 'throughput metrics',
+ 'mongodb.write_operations', 'line'],
+ 'lines': [
+ ['insert', None, 'incremental'],
+ ['update', None, 'incremental'],
+ ['delete', None, 'incremental']
+ ]},
+ 'active_clients': {
+ 'options': [None, 'Clients with read or write operations in progress or queued', 'clients',
+ 'throughput metrics', 'mongodb.active_clients', 'line'],
+ 'lines': [
+ ['activeClients_readers', 'readers', 'absolute'],
+ ['activeClients_writers', 'writers', 'absolute']
+ ]},
+ 'journaling_transactions': {
+ 'options': [None, 'Transactions that have been written to the journal', 'commits',
+ 'database performance', 'mongodb.journaling_transactions', 'line'],
+ 'lines': [
+ ['commits', None, 'absolute']
+ ]},
+ 'journaling_volume': {
+ 'options': [None, 'Volume of data written to the journal', 'MB', 'database performance',
+ 'mongodb.journaling_volume', 'line'],
+ 'lines': [
+ ['journaledMB', 'volume', 'absolute', 1, 100]
+ ]},
+ 'background_flush_average': {
+ 'options': [None, 'Average time taken by flushes to execute', 'ms', 'database performance',
+ 'mongodb.background_flush_average', 'line'],
+ 'lines': [
+ ['average_ms', 'time', 'absolute', 1, 100]
+ ]},
+ 'background_flush_last': {
+ 'options': [None, 'Time taken by the last flush operation to execute', 'ms', 'database performance',
+ 'mongodb.background_flush_last', 'line'],
+ 'lines': [
+ ['last_ms', 'time', 'absolute', 1, 100]
+ ]},
+ 'background_flush_rate': {
+ 'options': [None, 'Flushes rate', 'flushes', 'database performance', 'mongodb.background_flush_rate', 'line'],
+ 'lines': [
+ ['flushes', 'flushes', 'incremental', 1, 1]
+ ]},
+ 'wiredtiger_read': {
+ 'options': [None, 'Read tickets in use and remaining', 'tickets', 'database performance',
+ 'mongodb.wiredtiger_read', 'stacked'],
+ 'lines': [
+ ['wiredTigerRead_available', 'available', 'absolute', 1, 1],
+ ['wiredTigerRead_out', 'inuse', 'absolute', 1, 1]
+ ]},
+ 'wiredtiger_write': {
+ 'options': [None, 'Write tickets in use and remaining', 'tickets', 'database performance',
+ 'mongodb.wiredtiger_write', 'stacked'],
+ 'lines': [
+ ['wiredTigerWrite_available', 'available', 'absolute', 1, 1],
+ ['wiredTigerWrite_out', 'inuse', 'absolute', 1, 1]
+ ]},
+ 'cursors': {
+ 'options': [None, 'Currently openned cursors, cursors with timeout disabled and timed out cursors',
+ 'cursors', 'database performance', 'mongodb.cursors', 'stacked'],
+ 'lines': [
+ ['cursor_total', 'openned', 'absolute', 1, 1],
+ ['noTimeout', None, 'absolute', 1, 1],
+ ['timedOut', None, 'incremental', 1, 1]
+ ]},
+ 'connections': {
+ 'options': [None, 'Currently connected clients and unused connections', 'connections',
+ 'resource utilization', 'mongodb.connections', 'stacked'],
+ 'lines': [
+ ['connections_available', 'unused', 'absolute', 1, 1],
+ ['connections_current', 'connected', 'absolute', 1, 1]
+ ]},
+ 'memory': {
+ 'options': [None, 'Memory metrics', 'MB', 'resource utilization', 'mongodb.memory', 'stacked'],
+ 'lines': [
+ ['virtual', None, 'absolute', 1, 1],
+ ['resident', None, 'absolute', 1, 1],
+ ['nonmapped', None, 'absolute', 1, 1],
+ ['mapped', None, 'absolute', 1, 1]
+ ]},
+ 'page_faults': {
+ 'options': [None, 'Number of times MongoDB had to fetch data from disk', 'request/s',
+ 'resource utilization', 'mongodb.page_faults', 'line'],
+ 'lines': [
+ ['page_faults', None, 'incremental', 1, 1]
+ ]},
+ 'queued_requests': {
+ 'options': [None, 'Currently queued read and wrire requests', 'requests', 'resource saturation',
+ 'mongodb.queued_requests', 'line'],
+ 'lines': [
+ ['currentQueue_readers', 'readers', 'absolute', 1, 1],
+ ['currentQueue_writers', 'writers', 'absolute', 1, 1]
+ ]},
+ 'record_moves': {
+ 'options': [None, 'Number of times documents had to be moved on-disk', 'number',
+ 'resource saturation', 'mongodb.record_moves', 'line'],
+ 'lines': [
+ ['moves', None, 'incremental', 1, 1]
+ ]},
+ 'asserts': {
+ 'options': [None, 'Number of message, warning, regular, corresponding to errors generated'
+ ' by users assertions raised', 'number', 'errors (asserts)', 'mongodb.asserts', 'line'],
+ 'lines': [
+ ['msg', None, 'incremental', 1, 1],
+ ['warning', None, 'incremental', 1, 1],
+ ['regular', None, 'incremental', 1, 1],
+ ['user', None, 'incremental', 1, 1]
+ ]},
+ 'wiredtiger_cache': {
+ 'options': [None, 'The percentage of the wiredTiger cache that is in use and cache with dirty bytes',
+ 'percent', 'resource utilization', 'mongodb.wiredtiger_cache', 'stacked'],
+ 'lines': [
+ ['wiredTiger_percent_clean', 'inuse', 'absolute', 1, 1000],
+ ['wiredTiger_percent_dirty', 'dirty', 'absolute', 1, 1000]
+ ]},
+ 'wiredtiger_pages_evicted': {
+ 'options': [None, 'Pages evicted from the cache',
+ 'pages', 'resource utilization', 'mongodb.wiredtiger_pages_evicted', 'stacked'],
+ 'lines': [
+ ['unmodified', None, 'absolute', 1, 1],
+ ['modified', None, 'absolute', 1, 1]
+ ]},
+ 'dbstats_objects': {
+ 'options': [None, 'Number of documents in the database among all the collections', 'documents',
+ 'storage size metrics', 'mongodb.dbstats_objects', 'stacked'],
+ 'lines': [
+ ]},
+ 'tcmalloc_generic': {
+ 'options': [None, 'Tcmalloc generic metrics', 'MB', 'tcmalloc', 'mongodb.tcmalloc_generic', 'stacked'],
+ 'lines': [
+ ['current_allocated_bytes', 'allocated', 'absolute', 1, 1048576],
+ ['heap_size', 'heap_size', 'absolute', 1, 1048576]
+ ]},
+ 'tcmalloc_metrics': {
+ 'options': [None, 'Tcmalloc metrics', 'KB', 'tcmalloc', 'mongodb.tcmalloc_metrics', 'stacked'],
+ 'lines': [
+ ['central_cache_free_bytes', 'central_cache_free', 'absolute', 1, 1024],
+ ['current_total_thread_cache_bytes', 'current_total_thread_cache', 'absolute', 1, 1024],
+ ['pageheap_free_bytes', 'pageheap_free', 'absolute', 1, 1024],
+ ['pageheap_unmapped_bytes', 'pageheap_unmapped', 'absolute', 1, 1024],
+ ['thread_cache_free_bytes', 'thread_cache_free', 'absolute', 1, 1024],
+ ['transfer_cache_free_bytes', 'transfer_cache_free', 'absolute', 1, 1024]
+ ]},
+ 'command_total_rate': {
+ 'options': [None, 'Commands total rate', 'commands/s', 'commands', 'mongodb.command_total_rate', 'stacked'],
+ 'lines': [
+ ['count_total', 'count', 'incremental', 1, 1],
+ ['createIndexes_total', 'createIndexes', 'incremental', 1, 1],
+ ['delete_total', 'delete', 'incremental', 1, 1],
+ ['eval_total', 'eval', 'incremental', 1, 1],
+ ['findAndModify_total', 'findAndModify', 'incremental', 1, 1],
+ ['insert_total', 'insert', 'incremental', 1, 1],
+ ['update_total', 'update', 'incremental', 1, 1]
+ ]},
+ 'command_failed_rate': {
+ 'options': [None, 'Commands failed rate', 'commands/s', 'commands', 'mongodb.command_failed_rate', 'stacked'],
+ 'lines': [
+ ['count_failed', 'count', 'incremental', 1, 1],
+ ['createIndexes_failed', 'createIndexes', 'incremental', 1, 1],
+ ['delete_failed', 'delete', 'incremental', 1, 1],
+ ['eval_failed', 'eval', 'incremental', 1, 1],
+ ['findAndModify_failed', 'findAndModify', 'incremental', 1, 1],
+ ['insert_failed', 'insert', 'incremental', 1, 1],
+ ['update_failed', 'update', 'incremental', 1, 1]
+ ]},
+ 'locks_collection': {
+ 'options': [None, 'Collection lock. Number of times the lock was acquired in the specified mode',
+ 'locks', 'locks metrics', 'mongodb.locks_collection', 'stacked'],
+ 'lines': [
+ ['Collection_R', 'shared', 'incremental'],
+ ['Collection_W', 'exclusive', 'incremental'],
+ ['Collection_r', 'intent_shared', 'incremental'],
+ ['Collection_w', 'intent_exclusive', 'incremental']
+ ]},
+ 'locks_database': {
+ 'options': [None, 'Database lock. Number of times the lock was acquired in the specified mode',
+ 'locks', 'locks metrics', 'mongodb.locks_database', 'stacked'],
+ 'lines': [
+ ['Database_R', 'shared', 'incremental'],
+ ['Database_W', 'exclusive', 'incremental'],
+ ['Database_r', 'intent_shared', 'incremental'],
+ ['Database_w', 'intent_exclusive', 'incremental']
+ ]},
+ 'locks_global': {
+ 'options': [None, 'Global lock. Number of times the lock was acquired in the specified mode',
+ 'locks', 'locks metrics', 'mongodb.locks_global', 'stacked'],
+ 'lines': [
+ ['Global_R', 'shared', 'incremental'],
+ ['Global_W', 'exclusive', 'incremental'],
+ ['Global_r', 'intent_shared', 'incremental'],
+ ['Global_w', 'intent_exclusive', 'incremental']
+ ]},
+ 'locks_metadata': {
+ 'options': [None, 'Metadata lock. Number of times the lock was acquired in the specified mode',
+ 'locks', 'locks metrics', 'mongodb.locks_metadata', 'stacked'],
+ 'lines': [
+ ['Metadata_R', 'shared', 'incremental'],
+ ['Metadata_w', 'intent_exclusive', 'incremental']
+ ]},
+ 'locks_oplog': {
+ 'options': [None, 'Lock on the oplog. Number of times the lock was acquired in the specified mode',
+ 'locks', 'locks metrics', 'mongodb.locks_oplog', 'stacked'],
+ 'lines': [
+ ['Metadata_r', 'intent_shared', 'incremental'],
+ ['Metadata_w', 'intent_exclusive', 'incremental']
+ ]}
+}
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.order = ORDER[:]
+ self.definitions = deepcopy(CHARTS)
+ self.user = self.configuration.get('user')
+ self.password = self.configuration.get('pass')
+ self.host = self.configuration.get('host', '127.0.0.1')
+ self.port = self.configuration.get('port', 27017)
+ self.timeout = self.configuration.get('timeout', 100)
+ self.metrics_to_collect = deepcopy(DEFAULT_METRICS)
+ self.connection = None
+ self.do_replica = None
+ self.databases = list()
+
+ def check(self):
+ if not PYMONGO:
+ self.error('Pymongo module is needed to use mongodb.chart.py')
+ return False
+ self.connection, server_status, error = self._create_connection()
+ if error:
+ self.error(error)
+ return False
+
+ self.build_metrics_to_collect_(server_status)
+
+ try:
+ self._get_data()
+ except (LookupError, SyntaxError, AttributeError):
+ self.error('Type: %s, error: %s' % (str(exc_info()[0]), str(exc_info()[1])))
+ return False
+ else:
+ self.create_charts_(server_status)
+ return True
+
+ def build_metrics_to_collect_(self, server_status):
+
+ self.do_replica = 'repl' in server_status
+ if 'dur' in server_status:
+ self.metrics_to_collect.extend(DUR)
+ if 'tcmalloc' in server_status:
+ self.metrics_to_collect.extend(TCMALLOC)
+ if 'commands' in server_status['metrics']:
+ self.metrics_to_collect.extend(COMMANDS)
+ if 'wiredTiger' in server_status:
+ self.metrics_to_collect.extend(WIREDTIGER)
+ if 'Collection' in server_status['locks']:
+ self.metrics_to_collect.extend(LOCKS)
+
+ def create_charts_(self, server_status):
+
+ if 'dur' not in server_status:
+ self.order.remove('journaling_transactions')
+ self.order.remove('journaling_volume')
+
+ if 'backgroundFlushing' not in server_status:
+ self.order.remove('background_flush_average')
+ self.order.remove('background_flush_last')
+ self.order.remove('background_flush_rate')
+
+ if 'wiredTiger' not in server_status:
+ self.order.remove('wiredtiger_write')
+ self.order.remove('wiredtiger_read')
+ self.order.remove('wiredtiger_cache')
+
+ if 'tcmalloc' not in server_status:
+ self.order.remove('tcmalloc_generic')
+ self.order.remove('tcmalloc_metrics')
+
+ if 'commands' not in server_status['metrics']:
+ self.order.remove('command_total_rate')
+ self.order.remove('command_failed_rate')
+
+ if 'Collection' not in server_status['locks']:
+ self.order.remove('locks_collection')
+ self.order.remove('locks_database')
+ self.order.remove('locks_global')
+ self.order.remove('locks_metadata')
+
+ if 'oplog' not in server_status['locks']:
+ self.order.remove('locks_oplog')
+
+ for dbase in self.databases:
+ self.order.append('_'.join([dbase, 'dbstats']))
+ self.definitions['_'.join([dbase, 'dbstats'])] = {
+ 'options': [None, '%s: size of all documents, indexes, extents' % dbase, 'KB',
+ 'storage size metrics', 'mongodb.dbstats', 'line'],
+ 'lines': [
+ ['_'.join([dbase, 'dataSize']), 'documents', 'absolute', 1, 1024],
+ ['_'.join([dbase, 'indexSize']), 'indexes', 'absolute', 1, 1024],
+ ['_'.join([dbase, 'storageSize']), 'extents', 'absolute', 1, 1024]
+ ]}
+ self.definitions['dbstats_objects']['lines'].append(['_'.join([dbase, 'objects']), dbase, 'absolute'])
+
+ if self.do_replica:
+ def create_lines(hosts, string):
+ lines = list()
+ for host in hosts:
+ dim_id = '_'.join([host, string])
+ lines.append([dim_id, host, 'absolute', 1, 1000])
+ return lines
+
+ def create_state_lines(states):
+ lines = list()
+ for state, description in states:
+ dim_id = '_'.join([host, 'state', state])
+ lines.append([dim_id, description, 'absolute', 1, 1])
+ return lines
+
+ all_hosts = server_status['repl']['hosts']
+ this_host = server_status['repl']['me']
+ other_hosts = [host for host in all_hosts if host != this_host]
+
+ if 'local' in self.databases:
+ self.order.append('oplog_window')
+ self.definitions['oplog_window'] = {
+ 'options': [None, 'Interval of time between the oldest and the latest entries in the oplog',
+ 'seconds', 'replication and oplog', 'mongodb.oplog_window', 'line'],
+ 'lines': [['timeDiff', 'window', 'absolute', 1, 1000]]}
+ # Create "heartbeat delay" chart
+ self.order.append('heartbeat_delay')
+ self.definitions['heartbeat_delay'] = {
+ 'options': [None, 'Time when last heartbeat was received'
+ ' from the replica set member (lastHeartbeatRecv)',
+ 'seconds ago', 'replication and oplog', 'mongodb.replication_heartbeat_delay', 'stacked'],
+ 'lines': create_lines(other_hosts, 'heartbeat_lag')}
+ # Create "optimedate delay" chart
+ self.order.append('optimedate_delay')
+ self.definitions['optimedate_delay'] = {
+ 'options': [None, 'Time when last entry from the oplog was applied (optimeDate)',
+ 'seconds ago', 'replication and oplog', 'mongodb.replication_optimedate_delay', 'stacked'],
+ 'lines': create_lines(all_hosts, 'optimedate')}
+ # Create "replica set members state" chart
+ for host in all_hosts:
+ chart_name = '_'.join([host, 'state'])
+ self.order.append(chart_name)
+ self.definitions[chart_name] = {
+ 'options': [None, 'Replica set member (%s) current state' % host, 'state',
+ 'replication and oplog', 'mongodb.replication_state', 'line'],
+ 'lines': create_state_lines(REPLSET_STATES)}
+
+ def _get_raw_data(self):
+ raw_data = dict()
+
+ raw_data.update(self.get_serverstatus_() or dict())
+ raw_data.update(self.get_dbstats_() or dict())
+ raw_data.update(self.get_replsetgetstatus_() or dict())
+ raw_data.update(self.get_getreplicationinfo_() or dict())
+
+ return raw_data or None
+
+ def get_serverstatus_(self):
+ raw_data = dict()
+ try:
+ raw_data['serverStatus'] = self.connection.admin.command('serverStatus')
+ except PyMongoError:
+ return None
+ else:
+ return raw_data
+
+ def get_dbstats_(self):
+ if not self.databases:
+ return None
+
+ raw_data = dict()
+ raw_data['dbStats'] = dict()
+ try:
+ for dbase in self.databases:
+ raw_data['dbStats'][dbase] = self.connection[dbase].command('dbStats')
+ except PyMongoError:
+ return None
+ else:
+ return raw_data
+
+ def get_replsetgetstatus_(self):
+ if not self.do_replica:
+ return None
+
+ raw_data = dict()
+ try:
+ raw_data['replSetGetStatus'] = self.connection.admin.command('replSetGetStatus')
+ except PyMongoError:
+ return None
+ else:
+ return raw_data
+
+ def get_getreplicationinfo_(self):
+ if not (self.do_replica and 'local' in self.databases):
+ return None
+
+ raw_data = dict()
+ raw_data['getReplicationInfo'] = dict()
+ try:
+ raw_data['getReplicationInfo']['ASCENDING'] = self.connection.local.oplog.rs.find().sort(
+ "$natural", ASCENDING).limit(1)[0]
+ raw_data['getReplicationInfo']['DESCENDING'] = self.connection.local.oplog.rs.find().sort(
+ "$natural", DESCENDING).limit(1)[0]
+ except PyMongoError:
+ return None
+ else:
+ return raw_data
+
+ def _get_data(self):
+ """
+ :return: dict
+ """
+ raw_data = self._get_raw_data()
+
+ if not raw_data:
+ return None
+
+ to_netdata = dict()
+ serverStatus = raw_data['serverStatus']
+ dbStats = raw_data.get('dbStats')
+ replSetGetStatus = raw_data.get('replSetGetStatus')
+ getReplicationInfo = raw_data.get('getReplicationInfo')
+ utc_now = datetime.utcnow()
+
+ # serverStatus
+ for metric, new_name, function in self.metrics_to_collect:
+ value = serverStatus
+ for key in metric.split('.'):
+ try:
+ value = value[key]
+ except KeyError:
+ break
+
+ if not isinstance(value, dict) and key:
+ to_netdata[new_name or key] = value if not function else function(value)
+
+ to_netdata['nonmapped'] = to_netdata['virtual'] - serverStatus['mem'].get('mappedWithJournal',
+ to_netdata['mapped'])
+ if to_netdata.get('maximum bytes configured'):
+ maximum = to_netdata['maximum bytes configured']
+ to_netdata['wiredTiger_percent_clean'] = int(to_netdata['bytes currently in the cache']
+ * 100 / maximum * 1000)
+ to_netdata['wiredTiger_percent_dirty'] = int(to_netdata['tracked dirty bytes in the cache']
+ * 100 / maximum * 1000)
+
+ # dbStats
+ if dbStats:
+ for dbase in dbStats:
+ for metric in DBSTATS:
+ key = '_'.join([dbase, metric])
+ to_netdata[key] = dbStats[dbase][metric]
+
+ # replSetGetStatus
+ if replSetGetStatus:
+ other_hosts = list()
+ members = replSetGetStatus['members']
+ unix_epoch = datetime(1970, 1, 1, 0, 0)
+
+ for member in members:
+ if not member.get('self'):
+ other_hosts.append(member)
+ # Replica set time diff between current time and time when last entry from the oplog was applied
+ if member['optimeDate'] != unix_epoch:
+ member_optimedate = member['name'] + '_optimedate'
+ to_netdata.update({member_optimedate: int(delta_calculation(delta=utc_now - member['optimeDate'],
+ multiplier=1000))})
+ # Replica set members state
+ member_state = member['name'] + '_state'
+ for elem in REPLSET_STATES:
+ state = elem[0]
+ to_netdata.update({'_'.join([member_state, state]): 0})
+ to_netdata.update({'_'.join([member_state, str(member['state'])]): member['state']})
+ # Heartbeat lag calculation
+ for other in other_hosts:
+ if other['lastHeartbeatRecv'] != unix_epoch:
+ node = other['name'] + '_heartbeat_lag'
+ to_netdata[node] = int(delta_calculation(delta=utc_now - other['lastHeartbeatRecv'],
+ multiplier=1000))
+
+ if getReplicationInfo:
+ first_event = getReplicationInfo['ASCENDING']['ts'].as_datetime()
+ last_event = getReplicationInfo['DESCENDING']['ts'].as_datetime()
+ to_netdata['timeDiff'] = int(delta_calculation(delta=last_event - first_event, multiplier=1000))
+
+ return to_netdata
+
+ def _create_connection(self):
+ conn_vars = {'host': self.host, 'port': self.port}
+ if hasattr(MongoClient, 'server_selection_timeout'):
+ conn_vars.update({'serverselectiontimeoutms': self.timeout})
+ try:
+ connection = MongoClient(**conn_vars)
+ if self.user and self.password:
+ connection.admin.authenticate(name=self.user, password=self.password)
+ # elif self.user:
+ # connection.admin.authenticate(name=self.user, mechanism='MONGODB-X509')
+ server_status = connection.admin.command('serverStatus')
+ except PyMongoError as error:
+ return None, None, str(error)
+ else:
+ try:
+ self.databases = connection.database_names()
+ except PyMongoError as error:
+ self.info('Can\'t collect databases: %s' % str(error))
+ return connection, server_status, None
+
+
+def delta_calculation(delta, multiplier=1):
+ if hasattr(delta, 'total_seconds'):
+ return delta.total_seconds() * multiplier
+ else:
+ return (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10 ** 6) / 10.0 ** 6 * multiplier
diff --git a/python.d/mysql.chart.py b/python.d/mysql.chart.py
index 0e3a03299..abf6bf715 100644
--- a/python.d/mysql.chart.py
+++ b/python.d/mysql.chart.py
@@ -2,45 +2,132 @@
# Description: MySQL netdata python.d module
# Author: Pawel Krupa (paulfantom)
-from base import SimpleService
-import msg
-
-# import 3rd party library to handle MySQL communication
-try:
- import MySQLdb
-
- # https://github.com/PyMySQL/mysqlclient-python
- msg.info("using MySQLdb")
-except ImportError:
- try:
- import pymysql as MySQLdb
-
- # https://github.com/PyMySQL/PyMySQL
- msg.info("using pymysql")
- except ImportError:
- msg.error("MySQLdb or PyMySQL module is needed to use mysql.chart.py plugin")
- raise ImportError
+from base import MySQLService
# default module values (can be overridden per job in `config`)
# update_every = 3
priority = 90000
retries = 60
-# default configuration (overridden by python.d.plugin)
-# config = {
-# 'local': {
-# 'user': 'root',
-# 'pass': '',
-# 'socket': '/var/run/mysqld/mysqld.sock',
-# 'update_every': update_every,
-# 'retries': retries,
-# 'priority': priority
-# }
-#}
-
# query executed on MySQL server
-QUERY = "SHOW GLOBAL STATUS;"
-QUERY_SLAVE = "SHOW SLAVE STATUS;"
+QUERY_GLOBAL = 'SHOW GLOBAL STATUS;'
+QUERY_SLAVE = 'SHOW SLAVE STATUS;'
+
+GLOBAL_STATS = [
+ 'Bytes_received',
+ 'Bytes_sent',
+ 'Queries',
+ 'Questions',
+ 'Slow_queries',
+ 'Handler_commit',
+ 'Handler_delete',
+ 'Handler_prepare',
+ 'Handler_read_first',
+ 'Handler_read_key',
+ 'Handler_read_next',
+ 'Handler_read_prev',
+ 'Handler_read_rnd',
+ 'Handler_read_rnd_next',
+ 'Handler_rollback',
+ 'Handler_savepoint',
+ 'Handler_savepoint_rollback',
+ 'Handler_update',
+ 'Handler_write',
+ 'Table_locks_immediate',
+ 'Table_locks_waited',
+ 'Select_full_join',
+ 'Select_full_range_join',
+ 'Select_range',
+ 'Select_range_check',
+ 'Select_scan',
+ 'Sort_merge_passes',
+ 'Sort_range',
+ 'Sort_scan',
+ 'Created_tmp_disk_tables',
+ 'Created_tmp_files',
+ 'Created_tmp_tables',
+ 'Connections',
+ 'Aborted_connects',
+ 'Binlog_cache_disk_use',
+ 'Binlog_cache_use',
+ 'Threads_connected',
+ 'Threads_created',
+ 'Threads_cached',
+ 'Threads_running',
+ 'Thread_cache_misses',
+ 'Innodb_data_read',
+ 'Innodb_data_written',
+ 'Innodb_data_reads',
+ 'Innodb_data_writes',
+ 'Innodb_data_fsyncs',
+ 'Innodb_data_pending_reads',
+ 'Innodb_data_pending_writes',
+ 'Innodb_data_pending_fsyncs',
+ 'Innodb_log_waits',
+ 'Innodb_log_write_requests',
+ 'Innodb_log_writes',
+ 'Innodb_os_log_fsyncs',
+ 'Innodb_os_log_pending_fsyncs',
+ 'Innodb_os_log_pending_writes',
+ 'Innodb_os_log_written',
+ 'Innodb_row_lock_current_waits',
+ 'Innodb_rows_inserted',
+ 'Innodb_rows_read',
+ 'Innodb_rows_updated',
+ 'Innodb_rows_deleted',
+ 'Innodb_buffer_pool_pages_data',
+ 'Innodb_buffer_pool_pages_dirty',
+ 'Innodb_buffer_pool_pages_free',
+ 'Innodb_buffer_pool_pages_flushed',
+ 'Innodb_buffer_pool_pages_misc',
+ 'Innodb_buffer_pool_pages_total',
+ 'Innodb_buffer_pool_bytes_data',
+ 'Innodb_buffer_pool_bytes_dirty',
+ 'Innodb_buffer_pool_read_ahead',
+ 'Innodb_buffer_pool_read_ahead_evicted',
+ 'Innodb_buffer_pool_read_ahead_rnd',
+ 'Innodb_buffer_pool_read_requests',
+ 'Innodb_buffer_pool_write_requests',
+ 'Innodb_buffer_pool_reads',
+ 'Innodb_buffer_pool_wait_free',
+ 'Qcache_hits',
+ 'Qcache_lowmem_prunes',
+ 'Qcache_inserts',
+ 'Qcache_not_cached',
+ 'Qcache_queries_in_cache',
+ 'Qcache_free_memory',
+ 'Qcache_free_blocks',
+ 'Qcache_total_blocks',
+ 'Key_blocks_unused',
+ 'Key_blocks_used',
+ 'Key_blocks_not_flushed',
+ 'Key_read_requests',
+ 'Key_write_requests',
+ 'Key_reads',
+ 'Key_writes',
+ 'Open_files',
+ 'Opened_files',
+ 'Binlog_stmt_cache_disk_use',
+ 'Binlog_stmt_cache_use',
+ 'Connection_errors_accept',
+ 'Connection_errors_internal',
+ 'Connection_errors_max_connections',
+ 'Connection_errors_peer_address',
+ 'Connection_errors_select',
+ 'Connection_errors_tcpwrap']
+
+def slave_seconds(value):
+ return value if value else -1
+
+def slave_running(value):
+ return 1 if value == 'Yes' else -1
+
+
+SLAVE_STATS = [
+ ('Seconds_Behind_Master', slave_seconds),
+ ('Slave_SQL_Running', slave_running),
+ ('Slave_IO_Running', slave_running)
+]
ORDER = ['net',
'queries',
@@ -62,431 +149,290 @@ CHARTS = {
'net': {
'options': [None, 'mysql Bandwidth', 'kilobits/s', 'bandwidth', 'mysql.net', 'area'],
'lines': [
- ["Bytes_received", "in", "incremental", 8, 1024],
- ["Bytes_sent", "out", "incremental", -8, 1024]
+ ['Bytes_received', 'in', 'incremental', 8, 1024],
+ ['Bytes_sent', 'out', 'incremental', -8, 1024]
]},
'queries': {
'options': [None, 'mysql Queries', 'queries/s', 'queries', 'mysql.queries', 'line'],
'lines': [
- ["Queries", "queries", "incremental"],
- ["Questions", "questions", "incremental"],
- ["Slow_queries", "slow_queries", "incremental"]
+ ['Queries', 'queries', 'incremental'],
+ ['Questions', 'questions', 'incremental'],
+ ['Slow_queries', 'slow_queries', 'incremental']
]},
'handlers': {
'options': [None, 'mysql Handlers', 'handlers/s', 'handlers', 'mysql.handlers', 'line'],
'lines': [
- ["Handler_commit", "commit", "incremental"],
- ["Handler_delete", "delete", "incremental"],
- ["Handler_prepare", "prepare", "incremental"],
- ["Handler_read_first", "read_first", "incremental"],
- ["Handler_read_key", "read_key", "incremental"],
- ["Handler_read_next", "read_next", "incremental"],
- ["Handler_read_prev", "read_prev", "incremental"],
- ["Handler_read_rnd", "read_rnd", "incremental"],
- ["Handler_read_rnd_next", "read_rnd_next", "incremental"],
- ["Handler_rollback", "rollback", "incremental"],
- ["Handler_savepoint", "savepoint", "incremental"],
- ["Handler_savepoint_rollback", "savepoint_rollback", "incremental"],
- ["Handler_update", "update", "incremental"],
- ["Handler_write", "write", "incremental"]
+ ['Handler_commit', 'commit', 'incremental'],
+ ['Handler_delete', 'delete', 'incremental'],
+ ['Handler_prepare', 'prepare', 'incremental'],
+ ['Handler_read_first', 'read_first', 'incremental'],
+ ['Handler_read_key', 'read_key', 'incremental'],
+ ['Handler_read_next', 'read_next', 'incremental'],
+ ['Handler_read_prev', 'read_prev', 'incremental'],
+ ['Handler_read_rnd', 'read_rnd', 'incremental'],
+ ['Handler_read_rnd_next', 'read_rnd_next', 'incremental'],
+ ['Handler_rollback', 'rollback', 'incremental'],
+ ['Handler_savepoint', 'savepoint', 'incremental'],
+ ['Handler_savepoint_rollback', 'savepoint_rollback', 'incremental'],
+ ['Handler_update', 'update', 'incremental'],
+ ['Handler_write', 'write', 'incremental']
]},
'table_locks': {
'options': [None, 'mysql Tables Locks', 'locks/s', 'locks', 'mysql.table_locks', 'line'],
'lines': [
- ["Table_locks_immediate", "immediate", "incremental"],
- ["Table_locks_waited", "waited", "incremental", -1, 1]
+ ['Table_locks_immediate', 'immediate', 'incremental'],
+ ['Table_locks_waited', 'waited', 'incremental', -1, 1]
]},
'join_issues': {
'options': [None, 'mysql Select Join Issues', 'joins/s', 'issues', 'mysql.join_issues', 'line'],
'lines': [
- ["Select_full_join", "full_join", "incremental"],
- ["Select_full_range_join", "full_range_join", "incremental"],
- ["Select_range", "range", "incremental"],
- ["Select_range_check", "range_check", "incremental"],
- ["Select_scan", "scan", "incremental"]
+ ['Select_full_join', 'full_join', 'incremental'],
+ ['Select_full_range_join', 'full_range_join', 'incremental'],
+ ['Select_range', 'range', 'incremental'],
+ ['Select_range_check', 'range_check', 'incremental'],
+ ['Select_scan', 'scan', 'incremental']
]},
'sort_issues': {
'options': [None, 'mysql Sort Issues', 'issues/s', 'issues', 'mysql.sort_issues', 'line'],
'lines': [
- ["Sort_merge_passes", "merge_passes", "incremental"],
- ["Sort_range", "range", "incremental"],
- ["Sort_scan", "scan", "incremental"]
+ ['Sort_merge_passes', 'merge_passes', 'incremental'],
+ ['Sort_range', 'range', 'incremental'],
+ ['Sort_scan', 'scan', 'incremental']
]},
'tmp': {
'options': [None, 'mysql Tmp Operations', 'counter', 'temporaries', 'mysql.tmp', 'line'],
'lines': [
- ["Created_tmp_disk_tables", "disk_tables", "incremental"],
- ["Created_tmp_files", "files", "incremental"],
- ["Created_tmp_tables", "tables", "incremental"]
+ ['Created_tmp_disk_tables', 'disk_tables', 'incremental'],
+ ['Created_tmp_files', 'files', 'incremental'],
+ ['Created_tmp_tables', 'tables', 'incremental']
]},
'connections': {
'options': [None, 'mysql Connections', 'connections/s', 'connections', 'mysql.connections', 'line'],
'lines': [
- ["Connections", "all", "incremental"],
- ["Aborted_connects", "aborted", "incremental"]
+ ['Connections', 'all', 'incremental'],
+ ['Aborted_connects', 'aborted', 'incremental']
]},
'binlog_cache': {
'options': [None, 'mysql Binlog Cache', 'transactions/s', 'binlog', 'mysql.binlog_cache', 'line'],
'lines': [
- ["Binlog_cache_disk_use", "disk", "incremental"],
- ["Binlog_cache_use", "all", "incremental"]
+ ['Binlog_cache_disk_use', 'disk', 'incremental'],
+ ['Binlog_cache_use', 'all', 'incremental']
]},
'threads': {
'options': [None, 'mysql Threads', 'threads', 'threads', 'mysql.threads', 'line'],
'lines': [
- ["Threads_connected", "connected", "absolute"],
- ["Threads_created", "created", "incremental"],
- ["Threads_cached", "cached", "absolute", -1, 1],
- ["Threads_running", "running", "absolute"],
+ ['Threads_connected', 'connected', 'absolute'],
+ ['Threads_created', 'created', 'incremental'],
+ ['Threads_cached', 'cached', 'absolute', -1, 1],
+ ['Threads_running', 'running', 'absolute'],
]},
'thread_cache_misses': {
'options': [None, 'mysql Threads Cache Misses', 'misses', 'threads', 'mysql.thread_cache_misses', 'area'],
'lines': [
- ["Thread_cache_misses", "misses", "absolute", 1, 100]
+ ['Thread_cache_misses', 'misses', 'absolute', 1, 100]
]},
'innodb_io': {
'options': [None, 'mysql InnoDB I/O Bandwidth', 'kilobytes/s', 'innodb', 'mysql.innodb_io', 'area'],
'lines': [
- ["Innodb_data_read", "read", "incremental", 1, 1024],
- ["Innodb_data_written", "write", "incremental", -1, 1024]
+ ['Innodb_data_read', 'read', 'incremental', 1, 1024],
+ ['Innodb_data_written', 'write', 'incremental', -1, 1024]
]},
'innodb_io_ops': {
'options': [None, 'mysql InnoDB I/O Operations', 'operations/s', 'innodb', 'mysql.innodb_io_ops', 'line'],
'lines': [
- ["Innodb_data_reads", "reads", "incremental"],
- ["Innodb_data_writes", "writes", "incremental", -1, 1],
- ["Innodb_data_fsyncs", "fsyncs", "incremental"]
+ ['Innodb_data_reads', 'reads', 'incremental'],
+ ['Innodb_data_writes', 'writes', 'incremental', -1, 1],
+ ['Innodb_data_fsyncs', 'fsyncs', 'incremental']
]},
'innodb_io_pending_ops': {
'options': [None, 'mysql InnoDB Pending I/O Operations', 'operations', 'innodb', 'mysql.innodb_io_pending_ops', 'line'],
'lines': [
- ["Innodb_data_pending_reads", "reads", "absolute"],
- ["Innodb_data_pending_writes", "writes", "absolute", -1, 1],
- ["Innodb_data_pending_fsyncs", "fsyncs", "absolute"]
+ ['Innodb_data_pending_reads', 'reads', 'absolute'],
+ ['Innodb_data_pending_writes', 'writes', 'absolute', -1, 1],
+ ['Innodb_data_pending_fsyncs', 'fsyncs', 'absolute']
]},
'innodb_log': {
'options': [None, 'mysql InnoDB Log Operations', 'operations/s', 'innodb', 'mysql.innodb_log', 'line'],
'lines': [
- ["Innodb_log_waits", "waits", "incremental"],
- ["Innodb_log_write_requests", "write_requests", "incremental", -1, 1],
- ["Innodb_log_writes", "writes", "incremental", -1, 1],
+ ['Innodb_log_waits', 'waits', 'incremental'],
+ ['Innodb_log_write_requests', 'write_requests', 'incremental', -1, 1],
+ ['Innodb_log_writes', 'writes', 'incremental', -1, 1],
]},
'innodb_os_log': {
'options': [None, 'mysql InnoDB OS Log Operations', 'operations', 'innodb', 'mysql.innodb_os_log', 'line'],
'lines': [
- ["Innodb_os_log_fsyncs", "fsyncs", "incremental"],
- ["Innodb_os_log_pending_fsyncs", "pending_fsyncs", "absolute"],
- ["Innodb_os_log_pending_writes", "pending_writes", "absolute", -1, 1],
+ ['Innodb_os_log_fsyncs', 'fsyncs', 'incremental'],
+ ['Innodb_os_log_pending_fsyncs', 'pending_fsyncs', 'absolute'],
+ ['Innodb_os_log_pending_writes', 'pending_writes', 'absolute', -1, 1],
]},
'innodb_os_log_io': {
'options': [None, 'mysql InnoDB OS Log Bandwidth', 'kilobytes/s', 'innodb', 'mysql.innodb_os_log_io', 'area'],
'lines': [
- ["Innodb_os_log_written", "write", "incremental", -1, 1024],
+ ['Innodb_os_log_written', 'write', 'incremental', -1, 1024],
]},
'innodb_cur_row_lock': {
'options': [None, 'mysql InnoDB Current Row Locks', 'operations', 'innodb', 'mysql.innodb_cur_row_lock', 'area'],
'lines': [
- ["Innodb_row_lock_current_waits", "current_waits", "absolute"]
+ ['Innodb_row_lock_current_waits', 'current_waits', 'absolute']
]},
'innodb_rows': {
'options': [None, 'mysql InnoDB Row Operations', 'operations/s', 'innodb', 'mysql.innodb_rows', 'area'],
'lines': [
- ["Innodb_rows_inserted", "read", "incremental"],
- ["Innodb_rows_read", "deleted", "incremental", -1, 1],
- ["Innodb_rows_updated", "inserted", "incremental", 1, 1],
- ["Innodb_rows_deleted", "updated", "incremental", -1, 1],
+ ['Innodb_rows_inserted', 'read', 'incremental'],
+ ['Innodb_rows_read', 'deleted', 'incremental', -1, 1],
+ ['Innodb_rows_updated', 'inserted', 'incremental', 1, 1],
+ ['Innodb_rows_deleted', 'updated', 'incremental', -1, 1],
]},
'innodb_buffer_pool_pages': {
'options': [None, 'mysql InnoDB Buffer Pool Pages', 'pages', 'innodb', 'mysql.innodb_buffer_pool_pages', 'line'],
'lines': [
- ["Innodb_buffer_pool_pages_data", "data", "absolute"],
- ["Innodb_buffer_pool_pages_dirty", "dirty", "absolute", -1, 1],
- ["Innodb_buffer_pool_pages_free", "free", "absolute"],
- ["Innodb_buffer_pool_pages_flushed", "flushed", "incremental", -1, 1],
- ["Innodb_buffer_pool_pages_misc", "misc", "absolute", -1, 1],
- ["Innodb_buffer_pool_pages_total", "total", "absolute"]
+ ['Innodb_buffer_pool_pages_data', 'data', 'absolute'],
+ ['Innodb_buffer_pool_pages_dirty', 'dirty', 'absolute', -1, 1],
+ ['Innodb_buffer_pool_pages_free', 'free', 'absolute'],
+ ['Innodb_buffer_pool_pages_flushed', 'flushed', 'incremental', -1, 1],
+ ['Innodb_buffer_pool_pages_misc', 'misc', 'absolute', -1, 1],
+ ['Innodb_buffer_pool_pages_total', 'total', 'absolute']
]},
'innodb_buffer_pool_bytes': {
'options': [None, 'mysql InnoDB Buffer Pool Bytes', 'MB', 'innodb', 'mysql.innodb_buffer_pool_bytes', 'area'],
'lines': [
- ["Innodb_buffer_pool_bytes_data", "data", "absolute", 1, 1024 * 1024],
- ["Innodb_buffer_pool_bytes_dirty", "dirty", "absolute", -1, 1024 * 1024]
+ ['Innodb_buffer_pool_bytes_data', 'data', 'absolute', 1, 1024 * 1024],
+ ['Innodb_buffer_pool_bytes_dirty', 'dirty', 'absolute', -1, 1024 * 1024]
]},
'innodb_buffer_pool_read_ahead': {
'options': [None, 'mysql InnoDB Buffer Pool Read Ahead', 'operations/s', 'innodb', 'mysql.innodb_buffer_pool_read_ahead', 'area'],
'lines': [
- ["Innodb_buffer_pool_read_ahead", "all", "incremental"],
- ["Innodb_buffer_pool_read_ahead_evicted", "evicted", "incremental", -1, 1],
- ["Innodb_buffer_pool_read_ahead_rnd", "random", "incremental"]
+ ['Innodb_buffer_pool_read_ahead', 'all', 'incremental'],
+ ['Innodb_buffer_pool_read_ahead_evicted', 'evicted', 'incremental', -1, 1],
+ ['Innodb_buffer_pool_read_ahead_rnd', 'random', 'incremental']
]},
'innodb_buffer_pool_reqs': {
'options': [None, 'mysql InnoDB Buffer Pool Requests', 'requests/s', 'innodb', 'mysql.innodb_buffer_pool_reqs', 'area'],
'lines': [
- ["Innodb_buffer_pool_read_requests", "reads", "incremental"],
- ["Innodb_buffer_pool_write_requests", "writes", "incremental", -1, 1]
+ ['Innodb_buffer_pool_read_requests', 'reads', 'incremental'],
+ ['Innodb_buffer_pool_write_requests', 'writes', 'incremental', -1, 1]
]},
'innodb_buffer_pool_ops': {
'options': [None, 'mysql InnoDB Buffer Pool Operations', 'operations/s', 'innodb', 'mysql.innodb_buffer_pool_ops', 'area'],
'lines': [
- ["Innodb_buffer_pool_reads", "disk reads", "incremental"],
- ["Innodb_buffer_pool_wait_free", "wait free", "incremental", -1, 1]
+ ['Innodb_buffer_pool_reads', 'disk reads', 'incremental'],
+ ['Innodb_buffer_pool_wait_free', 'wait free', 'incremental', -1, 1]
]},
'qcache_ops': {
'options': [None, 'mysql QCache Operations', 'queries/s', 'qcache', 'mysql.qcache_ops', 'line'],
'lines': [
- ["Qcache_hits", "hits", "incremental"],
- ["Qcache_lowmem_prunes", "lowmem prunes", "incremental", -1, 1],
- ["Qcache_inserts", "inserts", "incremental"],
- ["Qcache_not_cached", "not cached", "incremental", -1, 1]
+ ['Qcache_hits', 'hits', 'incremental'],
+ ['Qcache_lowmem_prunes', 'lowmem prunes', 'incremental', -1, 1],
+ ['Qcache_inserts', 'inserts', 'incremental'],
+ ['Qcache_not_cached', 'not cached', 'incremental', -1, 1]
]},
'qcache': {
'options': [None, 'mysql QCache Queries in Cache', 'queries', 'qcache', 'mysql.qcache', 'line'],
'lines': [
- ["Qcache_queries_in_cache", "queries", "absolute"]
+ ['Qcache_queries_in_cache', 'queries', 'absolute']
]},
'qcache_freemem': {
'options': [None, 'mysql QCache Free Memory', 'MB', 'qcache', 'mysql.qcache_freemem', 'area'],
'lines': [
- ["Qcache_free_memory", "free", "absolute", 1, 1024 * 1024]
+ ['Qcache_free_memory', 'free', 'absolute', 1, 1024 * 1024]
]},
'qcache_memblocks': {
'options': [None, 'mysql QCache Memory Blocks', 'blocks', 'qcache', 'mysql.qcache_memblocks', 'line'],
'lines': [
- ["Qcache_free_blocks", "free", "absolute"],
- ["Qcache_total_blocks", "total", "absolute"]
+ ['Qcache_free_blocks', 'free', 'absolute'],
+ ['Qcache_total_blocks', 'total', 'absolute']
]},
'key_blocks': {
'options': [None, 'mysql MyISAM Key Cache Blocks', 'blocks', 'myisam', 'mysql.key_blocks', 'line'],
'lines': [
- ["Key_blocks_unused", "unused", "absolute"],
- ["Key_blocks_used", "used", "absolute", -1, 1],
- ["Key_blocks_not_flushed", "not flushed", "absolute"]
+ ['Key_blocks_unused', 'unused', 'absolute'],
+ ['Key_blocks_used', 'used', 'absolute', -1, 1],
+ ['Key_blocks_not_flushed', 'not flushed', 'absolute']
]},
'key_requests': {
'options': [None, 'mysql MyISAM Key Cache Requests', 'requests/s', 'myisam', 'mysql.key_requests', 'area'],
'lines': [
- ["Key_read_requests", "reads", "incremental"],
- ["Key_write_requests", "writes", "incremental", -1, 1]
+ ['Key_read_requests', 'reads', 'incremental'],
+ ['Key_write_requests', 'writes', 'incremental', -1, 1]
]},
'key_disk_ops': {
'options': [None, 'mysql MyISAM Key Cache Disk Operations', 'operations/s', 'myisam', 'mysql.key_disk_ops', 'area'],
'lines': [
- ["Key_reads", "reads", "incremental"],
- ["Key_writes", "writes", "incremental", -1, 1]
+ ['Key_reads', 'reads', 'incremental'],
+ ['Key_writes', 'writes', 'incremental', -1, 1]
]},
'files': {
'options': [None, 'mysql Open Files', 'files', 'files', 'mysql.files', 'line'],
'lines': [
- ["Open_files", "files", "absolute"]
+ ['Open_files', 'files', 'absolute']
]},
'files_rate': {
'options': [None, 'mysql Opened Files Rate', 'files/s', 'files', 'mysql.files_rate', 'line'],
'lines': [
- ["Opened_files", "files", "incremental"]
+ ['Opened_files', 'files', 'incremental']
]},
'binlog_stmt_cache': {
'options': [None, 'mysql Binlog Statement Cache', 'statements/s', 'binlog', 'mysql.binlog_stmt_cache', 'line'],
'lines': [
- ["Binlog_stmt_cache_disk_use", "disk", "incremental"],
- ["Binlog_stmt_cache_use", "all", "incremental"]
+ ['Binlog_stmt_cache_disk_use', 'disk', 'incremental'],
+ ['Binlog_stmt_cache_use', 'all', 'incremental']
]},
'connection_errors': {
'options': [None, 'mysql Connection Errors', 'connections/s', 'connections', 'mysql.connection_errors', 'line'],
'lines': [
- ["Connection_errors_accept", "accept", "incremental"],
- ["Connection_errors_internal", "internal", "incremental"],
- ["Connection_errors_max_connections", "max", "incremental"],
- ["Connection_errors_peer_address", "peer_addr", "incremental"],
- ["Connection_errors_select", "select", "incremental"],
- ["Connection_errors_tcpwrap", "tcpwrap", "incremental"]
+ ['Connection_errors_accept', 'accept', 'incremental'],
+ ['Connection_errors_internal', 'internal', 'incremental'],
+ ['Connection_errors_max_connections', 'max', 'incremental'],
+ ['Connection_errors_peer_address', 'peer_addr', 'incremental'],
+ ['Connection_errors_select', 'select', 'incremental'],
+ ['Connection_errors_tcpwrap', 'tcpwrap', 'incremental']
]},
'slave_behind': {
'options': [None, 'Slave Behind Seconds', 'seconds', 'slave', 'mysql.slave_behind', 'line'],
'lines': [
- ["slave_behind", "seconds", "absolute"]
+ ['Seconds_Behind_Master', 'seconds', 'absolute']
]},
'slave_status': {
'options': [None, 'Slave Status', 'status', 'slave', 'mysql.slave_status', 'line'],
'lines': [
- ["slave_sql", "sql_running", "absolute"],
- ["slave_io", "io_running", "absolute"]
+ ['Slave_SQL_Running', 'sql_running', 'absolute'],
+ ['Slave_IO_Running', 'io_running', 'absolute']
]}
}
-class Service(SimpleService):
+class Service(MySQLService):
def __init__(self, configuration=None, name=None):
- SimpleService.__init__(self, configuration=configuration, name=name)
- self._parse_config(configuration)
+ MySQLService.__init__(self, configuration=configuration, name=name)
self.order = ORDER
self.definitions = CHARTS
- self.connection = None
- self.do_slave = -1
-
- def _parse_config(self, configuration):
- """
- Parse configuration to collect data from MySQL server
- :param configuration: dict
- :return: dict
- """
- parameters = {}
- if self.name is None:
- self.name = 'local'
- if 'user' in configuration:
- parameters['user'] = self.configuration['user']
- if 'pass' in configuration:
- parameters['passwd'] = self.configuration['pass']
- if 'my.cnf' in configuration:
- parameters['read_default_file'] = self.configuration['my.cnf']
- elif 'socket' in configuration:
- parameters['unix_socket'] = self.configuration['socket']
- elif 'host' in configuration:
- parameters['host'] = self.configuration['host']
- if 'port' in configuration:
- parameters['port'] = int(self.configuration['port'])
- self.connection_parameters = parameters
-
- def _connect(self):
- """
- Try to connect to MySQL server
- """
- try:
- self.connection = MySQLdb.connect(connect_timeout=self.update_every, **self.connection_parameters)
- except MySQLdb.OperationalError as e:
- self.error("Cannot establish connection to MySQL.")
- self.debug(str(e))
- raise RuntimeError
- except Exception as e:
- self.error("problem connecting to server:", e)
- raise RuntimeError
-
- def _get_data_slave(self):
- """
- Get slave raw data from MySQL server
- :return: dict
- """
- if self.connection is None:
- try:
- self._connect()
- except RuntimeError:
- return None
-
- slave_data = None
- slave_raw_data = None
- try:
- cursor = self.connection.cursor()
- if cursor.execute(QUERY_SLAVE):
- slave_raw_data = dict(list(zip([elem[0] for elem in cursor.description], cursor.fetchone())))
-
- except MySQLdb.OperationalError as e:
- self.debug("Reconnecting for query", QUERY_SLAVE, ":", str(e))
- try:
- self._connect()
- cursor = self.connection.cursor()
- if cursor.execute(QUERY_SLAVE):
- slave_raw_data = dict(list(zip([elem[0] for elem in cursor.description], cursor.fetchone())))
- except Exception as e:
- self.error("retried, but cannot execute query", QUERY_SLAVE, ":", str(e))
- self.connection.close()
- self.connection = None
- return None
-
- except Exception as e:
- self.error("cannot execute query", QUERY_SLAVE, ":", str(e))
- self.connection.close()
- self.connection = None
- return None
-
- if slave_raw_data is not None:
- slave_data = {
- 'slave_behind': None,
- 'slave_sql': None,
- 'slave_io': None
- }
-
- try:
- slave_data['slave_behind'] = int(slave_raw_data.setdefault('Seconds_Behind_Master', -1))
- except:
- slave_data['slave_behind'] = None
-
- try:
- slave_data['slave_sql'] = 1 if slave_raw_data.get('Slave_SQL_Running') == 'Yes' else -1
- except:
- slave_data['slave_sql'] = None
-
- try:
- slave_data['slave_io'] = 1 if slave_raw_data.get('Slave_IO_Running') == 'Yes' else -1
- except:
- slave_data['slave_io'] = None
-
- return slave_data
+ self.queries = dict(global_status=QUERY_GLOBAL, slave_status=QUERY_SLAVE)
def _get_data(self):
- """
- Get raw data from MySQL server
- :return: dict
- """
- if self.connection is None:
- try:
- self._connect()
- except RuntimeError:
- return None
- try:
- cursor = self.connection.cursor()
- cursor.execute(QUERY)
- raw_data = cursor.fetchall()
- except MySQLdb.OperationalError as e:
- self.debug("Reconnecting for query", QUERY, ":", str(e))
- try:
- self._connect()
- cursor = self.connection.cursor()
- cursor.execute(QUERY)
- raw_data = cursor.fetchall()
- except Exception as e:
- self.error("retried, but cannot execute query", QUERY, ":", str(e))
- self.connection.close()
- self.connection = None
- return None
+ raw_data = self._get_raw_data(description=True)
- except Exception as e:
- self.error("cannot execute query", QUERY, ":", str(e))
- self.connection.close()
- self.connection = None
- return None
+ if not raw_data:
+ return None
- data = dict(raw_data)
+ to_netdata = dict()
- # check for slave data
- # the first time is -1 (so we do it)
- # then it is set to 1 or 0 and we keep it like that
- if self.do_slave != 0:
- slave_data = self._get_data_slave()
- if slave_data is not None:
- data.update(slave_data)
- if self.do_slave == -1:
- self.do_slave = 1
- else:
- if self.do_slave == -1:
- self.error("replication metrics will be disabled - please allow netdata to collect them.")
- self.do_slave = 0
+ if 'global_status' in raw_data:
+ global_status = dict(raw_data['global_status'][0])
+ for key in GLOBAL_STATS:
+ if key in global_status:
+ to_netdata[key] = global_status[key]
+ if 'Threads_created' in to_netdata and 'Connections' in to_netdata:
+ to_netdata['Thread_cache_misses'] = round(int(to_netdata['Threads_created']) / float(to_netdata['Connections']) * 10000)
- # do calculations
- try:
- data["Thread_cache_misses"] = round(float(data["Threads_created"]) / float(data["Connections"]) * 10000)
- except:
- data["Thread_cache_misses"] = None
+ if 'slave_status' in raw_data:
+ if raw_data['slave_status'][0]:
+ slave_raw_data = dict(zip([e[0] for e in raw_data['slave_status'][1]], raw_data['slave_status'][0][0]))
+ for key, function in SLAVE_STATS:
+ if key in slave_raw_data:
+ to_netdata[key] = function(slave_raw_data[key])
+ else:
+ self.queries.pop('slave_status')
- return data
+ return to_netdata or None
- def check(self):
- """
- Check if service is able to connect to server
- :return: boolean
- """
- try:
- self.connection = self._connect()
- return True
- except RuntimeError:
- self.connection = None
- return False
diff --git a/python.d/nginx_log.chart.py b/python.d/nginx_log.chart.py
deleted file mode 100644
index ef964a565..000000000
--- a/python.d/nginx_log.chart.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-# Description: nginx log netdata python.d module
-# Author: Pawel Krupa (paulfantom)
-
-from base import LogService
-import re
-
-priority = 60000
-retries = 60
-# update_every = 3
-
-ORDER = ['codes']
-CHARTS = {
- 'codes': {
- 'options': [None, 'nginx status codes', 'requests/s', 'requests', 'nginx_log.codes', 'stacked'],
- 'lines': [
- ["2xx", None, "incremental"],
- ["5xx", None, "incremental"],
- ["3xx", None, "incremental"],
- ["4xx", None, "incremental"],
- ["1xx", None, "incremental"],
- ["other", None, "incremental"]
- ]}
-}
-
-
-class Service(LogService):
- def __init__(self, configuration=None, name=None):
- LogService.__init__(self, configuration=configuration, name=name)
- if len(self.log_path) == 0:
- self.log_path = "/var/log/nginx/access.log"
- self.order = ORDER
- self.definitions = CHARTS
- pattern = r'" ([0-9]{3}) ?'
- #pattern = r'(?:" )([0-9][0-9][0-9]) ?'
- self.regex = re.compile(pattern)
-
- self.data = {
- '1xx': 0,
- '2xx': 0,
- '3xx': 0,
- '4xx': 0,
- '5xx': 0,
- 'other': 0
- }
-
- def _get_data(self):
- """
- Parse new log lines
- :return: dict
- """
- try:
- raw = self._get_raw_data()
- if raw is None:
- return None
- elif not raw:
- return self.data
- except (ValueError, AttributeError):
- return None
-
- regex = self.regex
- for line in raw:
- code = regex.search(line)
- try:
- beginning = code.group(1)[0]
- except AttributeError:
- continue
-
- if beginning == '2':
- self.data["2xx"] += 1
- elif beginning == '3':
- self.data["3xx"] += 1
- elif beginning == '4':
- self.data["4xx"] += 1
- elif beginning == '5':
- self.data["5xx"] += 1
- elif beginning == '1':
- self.data["1xx"] += 1
- else:
- self.data["other"] += 1
-
- return self.data
diff --git a/python.d/nsd.chart.py b/python.d/nsd.chart.py
new file mode 100644
index 000000000..68bb4f237
--- /dev/null
+++ b/python.d/nsd.chart.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Description: NSD `nsd-control stats_noreset` netdata python.d module
+# Author: <383c57 at gmail.com>
+
+
+from base import ExecutableService
+import re
+
+# default module values (can be overridden per job in `config`)
+priority = 60000
+retries = 5
+update_every = 30
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = ['queries', 'zones', 'protocol', 'type', 'transfer', 'rcode']
+
+CHARTS = {
+ 'queries': {
+ 'options': [
+ None, "queries", 'queries/s', 'queries', 'nsd.queries', 'line'],
+ 'lines': [
+ ['num_queries', 'queries', 'incremental'],]},
+ 'zones': {
+ 'options': [
+ None, "zones", 'zones', 'zones', 'nsd.zones', 'stacked'],
+ 'lines': [
+ ['zone_master', 'master', 'absolute'],
+ ['zone_slave', 'slave', 'absolute'],]},
+ 'protocol': {
+ 'options': [
+ None, "protocol", 'queries/s', 'protocol', 'nsd.protocols', 'stacked'],
+ 'lines': [
+ ['num_udp', 'udp', 'incremental'],
+ ['num_udp6', 'udp6', 'incremental'],
+ ['num_tcp', 'tcp', 'incremental'],
+ ['num_tcp6', 'tcp6', 'incremental'],]},
+ 'type': {
+ 'options': [
+ None, "query type", 'queries/s', 'query type', 'nsd.type', 'stacked'],
+ 'lines': [
+ ['num_type_A', 'A', 'incremental'],
+ ['num_type_NS', 'NS', 'incremental'],
+ ['num_type_CNAME', 'CNAME', 'incremental'],
+ ['num_type_SOA', 'SOA', 'incremental'],
+ ['num_type_PTR', 'PTR', 'incremental'],
+ ['num_type_HINFO', 'HINFO', 'incremental'],
+ ['num_type_MX', 'MX', 'incremental'],
+ ['num_type_NAPTR', 'NAPTR', 'incremental'],
+ ['num_type_TXT', 'TXT', 'incremental'],
+ ['num_type_AAAA', 'AAAA', 'incremental'],
+ ['num_type_SRV', 'SRV', 'incremental'],
+ ['num_type_TYPE255', 'ANY', 'incremental'],]},
+ 'transfer': {
+ 'options': [
+ None, "transfer", 'queries/s', 'transfer', 'nsd.transfer', 'stacked'],
+ 'lines': [
+ ['num_opcode_NOTIFY', 'NOTIFY', 'incremental'],
+ ['num_type_TYPE252', 'AXFR', 'incremental'],]},
+ 'rcode': {
+ 'options': [
+ None, "return code", 'queries/s', 'return code', 'nsd.rcode', 'stacked'],
+ 'lines': [
+ ['num_rcode_NOERROR', 'NOERROR', 'incremental'],
+ ['num_rcode_FORMERR', 'FORMERR', 'incremental'],
+ ['num_rcode_SERVFAIL', 'SERVFAIL', 'incremental'],
+ ['num_rcode_NXDOMAIN', 'NXDOMAIN', 'incremental'],
+ ['num_rcode_NOTIMP', 'NOTIMP', 'incremental'],
+ ['num_rcode_REFUSED', 'REFUSED', 'incremental'],
+ ['num_rcode_YXDOMAIN', 'YXDOMAIN', 'incremental'],]}
+}
+
+
+class Service(ExecutableService):
+ def __init__(self, configuration=None, name=None):
+ ExecutableService.__init__(
+ self, configuration=configuration, name=name)
+ self.command = "nsd-control stats_noreset"
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.regex = re.compile(r'([A-Za-z0-9.]+)=(\d+)')
+
+ def _get_data(self):
+ lines = self._get_raw_data()
+ if not lines:
+ return None
+
+ r = self.regex
+ stats = dict((k.replace('.', '_'), int(v))
+ for k, v in r.findall(''.join(lines)))
+ stats.setdefault('num_opcode_NOTIFY', 0)
+ stats.setdefault('num_type_TYPE252', 0)
+ stats.setdefault('num_type_TYPE255', 0)
+ return stats
diff --git a/python.d/phpfpm.chart.py b/python.d/phpfpm.chart.py
index b79a35d75..7a9835210 100755..100644
--- a/python.d/phpfpm.chart.py
+++ b/python.d/phpfpm.chart.py
@@ -4,6 +4,7 @@
from base import UrlService
import json
+import re
# default module values (can be overridden per job in `config`)
# update_every = 2
@@ -19,44 +20,75 @@ retries = 60
# }}
# charts order (can be overridden if you want less charts, or different order)
+
+POOL_INFO = [
+ ('active processes', 'active'),
+ ('max active processes', 'maxActive'),
+ ('idle processes', 'idle'),
+ ('accepted conn', 'requests'),
+ ('max children reached', 'reached'),
+ ('slow requests', 'slow')
+]
+
+PER_PROCESS_INFO = [
+ ('request duration', 'ReqDur'),
+ ('last request cpu', 'ReqCpu'),
+ ('last request memory', 'ReqMem')
+]
+
+
+def average(collection):
+ return sum(collection, 0.0) / max(len(collection), 1)
+
+CALC = [
+ ('min', min),
+ ('max', max),
+ ('avg', average)
+]
+
ORDER = ['connections', 'requests', 'performance', 'request_duration', 'request_cpu', 'request_mem']
CHARTS = {
'connections': {
- 'options': [None, 'PHP-FPM Active Connections', 'connections', 'active connections', 'phpfpm.connections', 'line'],
+ 'options': [None, 'PHP-FPM Active Connections', 'connections', 'active connections', 'phpfpm.connections',
+ 'line'],
'lines': [
- ["active"],
- ["maxActive", 'max active'],
- ["idle"]
+ ['active'],
+ ['maxActive', 'max active'],
+ ['idle']
]},
'requests': {
'options': [None, 'PHP-FPM Requests', 'requests/s', 'requests', 'phpfpm.requests', 'line'],
'lines': [
- ["requests", None, "incremental"]
+ ['requests', None, 'incremental']
]},
'performance': {
'options': [None, 'PHP-FPM Performance', 'status', 'performance', 'phpfpm.performance', 'line'],
'lines': [
- ["reached", 'max children reached'],
- ["slow", 'slow requests']
+ ['reached', 'max children reached'],
+ ['slow', 'slow requests']
]},
'request_duration': {
- 'options': [None, 'PHP-FPM Request Duration', 'milliseconds', 'request duration', 'phpfpm.request_duration', 'line'],
+ 'options': [None, 'PHP-FPM Request Duration', 'milliseconds', 'request duration', 'phpfpm.request_duration',
+ 'line'],
'lines': [
- ["maxReqDur", 'max request duration'],
- ["avgReqDur", 'average request duration']
+ ['minReqDur', 'min', 'absolute', 1, 1000],
+ ['maxReqDur', 'max', 'absolute', 1, 1000],
+ ['avgReqDur', 'avg', 'absolute', 1, 1000]
]},
'request_cpu': {
'options': [None, 'PHP-FPM Request CPU', 'percent', 'request CPU', 'phpfpm.request_cpu', 'line'],
'lines': [
- ["maxReqCPU", 'max request cpu'],
- ["avgReqCPU", 'average request cpu']
+ ['minReqCpu', 'min'],
+ ['maxReqCpu', 'max'],
+ ['avgReqCpu', 'avg']
]},
'request_mem': {
'options': [None, 'PHP-FPM Request Memory', 'kilobytes', 'request memory', 'phpfpm.request_mem', 'line'],
'lines': [
- ["maxReqMem", 'max request memory'],
- ["avgReqMem", 'average request memory']
+ ['minReqMem', 'min', 'absolute', 1, 1024],
+ ['maxReqMem', 'max', 'absolute', 1, 1024],
+ ['avgReqMem', 'avg', 'absolute', 1, 1024]
]}
}
@@ -64,76 +96,73 @@ CHARTS = {
class Service(UrlService):
def __init__(self, configuration=None, name=None):
UrlService.__init__(self, configuration=configuration, name=name)
- if len(self.url) == 0:
- self.url = "http://localhost/status?full&json"
+ self.url = self.configuration.get('url', 'http://localhost/status?full&json')
self.order = ORDER
self.definitions = CHARTS
- self.assignment = {"active processes": 'active',
- "max active processes": 'maxActive',
- "idle processes": 'idle',
- "accepted conn": 'requests',
- "max children reached": 'reached',
- "slow requests": 'slow'}
- self.proc_assignment = {"request duration": 'ReqDur',
- "last request cpu": 'ReqCPU',
- "last request memory": 'ReqMem'}
+ self.regex = re.compile(r'([a-z][a-z ]+): ([\d.]+)')
+ self.json = '&json' in self.url or '?json' in self.url
+ self.json_full = self.url.endswith(('?full&json', '?json&full'))
+ self.if_all_processes_running = dict([(c_name + p_name, 0) for c_name, func in CALC
+ for metric, p_name in PER_PROCESS_INFO])
def _get_data(self):
"""
Format data received from http request
:return: dict
"""
- try:
- raw = self._get_raw_data()
- except AttributeError:
+ raw = self._get_raw_data()
+ if not raw:
return None
- if '?json' in self.url or '&json' in self.url:
- try:
- raw_json = json.loads(raw)
- except ValueError:
- return None
- data = {}
- for k,v in raw_json.items():
- if k in self.assignment:
- data[self.assignment[k]] = v
-
- if '&full' in self.url or '?full' in self.url:
- c = 0
- sum_val = {}
- for proc in raw_json['processes']:
- if proc['state'] != 'Idle':
- continue
- c += 1
- for k, v in self.proc_assignment.items():
- d = proc[k]
- if v == 'ReqDur':
- d = d/1000
- if v == 'ReqMem':
- d = d/1024
- if 'max' + v not in data or data['max' + v] < d:
- data['max' + v] = d
- if 'avg' + v not in sum_val:
- sum_val['avg' + v] = 0
- data['avg' + v] = 0
- sum_val['avg' + v] += d
- if len(sum_val):
- for k, v in sum_val.items():
- data[k] = v/c
-
- if len(data) == 0:
- return None
- return data
-
- raw = raw.split('\n')
- data = {}
- for row in raw:
- tmp = row.split(":")
- if str(tmp[0]) in self.assignment:
- try:
- data[self.assignment[tmp[0]]] = int(tmp[1])
- except (IndexError, ValueError):
- pass
- if len(data) == 0:
- return None
- return data
+ raw_json = parse_raw_data_(is_json=self.json, regex=self.regex, raw_data=raw)
+
+ # Per Pool info: active connections, requests and performance charts
+ to_netdata = fetch_data_(raw_data=raw_json, metrics_list=POOL_INFO)
+
+ # Per Process Info: duration, cpu and memory charts (min, max, avg)
+ if self.json_full:
+ p_info = dict()
+ to_netdata.update(self.if_all_processes_running) # If all processes are in running state
+ # Metrics are always 0 if the process is not in Idle state because calculation is done
+ # when the request processing has terminated
+ for process in [p for p in raw_json['processes'] if p['state'] == 'Idle']:
+ p_info.update(fetch_data_(raw_data=process, metrics_list=PER_PROCESS_INFO, pid=str(process['pid'])))
+
+ if p_info:
+ for new_name in PER_PROCESS_INFO:
+ for name, function in CALC:
+ to_netdata[name + new_name[1]] = function([p_info[k] for k in p_info if new_name[1] in k])
+
+ return to_netdata or None
+
+
+def fetch_data_(raw_data, metrics_list, pid=''):
+ """
+ :param raw_data: dict
+ :param metrics_list: list
+ :param pid: str
+ :return: dict
+ """
+ result = dict()
+ for metric, new_name in metrics_list:
+ if metric in raw_data:
+ result[new_name + pid] = float(raw_data[metric])
+ return result
+
+
+def parse_raw_data_(is_json, regex, raw_data):
+ """
+ :param is_json: bool
+ :param regex: compiled regular expr
+ :param raw_data: dict
+ :return: dict
+ """
+ if is_json:
+ try:
+ return json.loads(raw_data)
+ except ValueError:
+ return dict()
+ else:
+ raw_data = ' '.join(raw_data.split())
+ return dict(regex.findall(raw_data))
+
diff --git a/python.d/postgres.chart.py b/python.d/postgres.chart.py
index 919b6f8ee..d359bb4f7 100644
--- a/python.d/postgres.chart.py
+++ b/python.d/postgres.chart.py
@@ -2,12 +2,16 @@
# Description: example netdata python.d module
# Authors: facetoe, dangtranhoang
-import re
from copy import deepcopy
-import psycopg2
-from psycopg2 import extensions
-from psycopg2.extras import DictCursor
+try:
+ import psycopg2
+ from psycopg2 import extensions
+ from psycopg2.extras import DictCursor
+ from psycopg2 import OperationalError
+ PSYCOPG2 = True
+except ImportError:
+ PSYCOPG2 = False
from base import SimpleService
@@ -16,39 +20,70 @@ update_every = 1
priority = 90000
retries = 60
-ARCHIVE = """
+METRICS = dict(
+ DATABASE=['connections',
+ 'xact_commit',
+ 'xact_rollback',
+ 'blks_read',
+ 'blks_hit',
+ 'tup_returned',
+ 'tup_fetched',
+ 'tup_inserted',
+ 'tup_updated',
+ 'tup_deleted',
+ 'conflicts',
+ 'size'],
+ BACKENDS=['backends_active',
+ 'backends_idle'],
+ INDEX_STATS=['index_count',
+ 'index_size'],
+ TABLE_STATS=['table_size',
+ 'table_count'],
+ ARCHIVE=['ready_count',
+ 'done_count',
+ 'file_count'],
+ BGWRITER=['writer_scheduled',
+ 'writer_requested'],
+ LOCKS=['ExclusiveLock',
+ 'RowShareLock',
+ 'SIReadLock',
+ 'ShareUpdateExclusiveLock',
+ 'AccessExclusiveLock',
+ 'AccessShareLock',
+ 'ShareRowExclusiveLock',
+ 'ShareLock',
+ 'RowExclusiveLock']
+)
+
+QUERIES = dict(
+ ARCHIVE="""
SELECT
CAST(COUNT(*) AS INT) AS file_count,
CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.ready$$r$ as INT)), 0) AS INT) AS ready_count,
CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.done$$r$ AS INT)), 0) AS INT) AS done_count
FROM
pg_catalog.pg_ls_dir('pg_xlog/archive_status') AS archive_files (archive_file);
-"""
-
-BACKENDS = """
+""",
+ BACKENDS="""
SELECT
count(*) - (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle') AS backends_active,
(SELECT count(*) FROM pg_stat_activity WHERE state = 'idle' ) AS backends_idle
-FROM
- pg_stat_activity;
-"""
-
-TABLE_STATS = """
+FROM pg_stat_activity;
+""",
+ TABLE_STATS="""
SELECT
- ((sum(relpages) * 8) * 1024) AS size_relations,
- count(1) AS relations
+ ((sum(relpages) * 8) * 1024) AS table_size,
+ count(1) AS table_count
FROM pg_class
WHERE relkind IN ('r', 't');
-"""
-
-INDEX_STATS = """
+""",
+ INDEX_STATS="""
SELECT
- ((sum(relpages) * 8) * 1024) AS size_indexes,
- count(1) AS indexes
+ ((sum(relpages) * 8) * 1024) AS index_size,
+ count(1) AS index_count
FROM pg_class
-WHERE relkind = 'i';"""
-
-DATABASE = """
+WHERE relkind = 'i';""",
+ DATABASE="""
SELECT
datname AS database_name,
sum(numbackends) AS connections,
@@ -61,93 +96,108 @@ SELECT
sum(tup_inserted) AS tup_inserted,
sum(tup_updated) AS tup_updated,
sum(tup_deleted) AS tup_deleted,
- sum(conflicts) AS conflicts
+ sum(conflicts) AS conflicts,
+ pg_database_size(datname) AS size
FROM pg_stat_database
WHERE NOT datname ~* '^template\d+'
GROUP BY database_name;
-"""
-
-BGWRITER = 'SELECT * FROM pg_stat_bgwriter;'
-DATABASE_LOCKS = """
+""",
+ BGWRITER="""
+SELECT
+ checkpoints_timed AS writer_scheduled,
+ checkpoints_req AS writer_requested
+FROM pg_stat_bgwriter;""",
+ LOCKS="""
SELECT
pg_database.datname as database_name,
mode,
- count(mode) AS count
+ count(mode) AS locks_count
FROM pg_locks
INNER JOIN pg_database ON pg_database.oid = pg_locks.database
GROUP BY datname, mode
ORDER BY datname, mode;
-"""
-REPLICATION = """
-SELECT
- client_hostname,
- client_addr,
- state,
- sent_offset - (
- replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag
-FROM (
- SELECT
- client_addr, client_hostname, state,
- ('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS sent_xlog,
- ('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS replay_xlog,
- ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS sent_offset,
- ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS replay_offset
- FROM pg_stat_replication
-) AS s;
-"""
-
-LOCK_TYPES = [
- 'ExclusiveLock',
- 'RowShareLock',
- 'SIReadLock',
- 'ShareUpdateExclusiveLock',
- 'AccessExclusiveLock',
- 'AccessShareLock',
- 'ShareRowExclusiveLock',
- 'ShareLock',
- 'RowExclusiveLock'
-]
-
-ORDER = ['db_stat_transactions', 'db_stat_tuple_read', 'db_stat_tuple_returned', 'db_stat_tuple_write',
+""",
+ FIND_DATABASES="""
+SELECT datname FROM pg_stat_database WHERE NOT datname ~* '^template\d+'
+""",
+ IF_SUPERUSER="""
+SELECT current_setting('is_superuser') = 'on' AS is_superuser;
+ """)
+
+# REPLICATION = """
+# SELECT
+# client_hostname,
+# client_addr,
+# state,
+# sent_offset - (
+# replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag
+# FROM (
+# SELECT
+# client_addr, client_hostname, state,
+# ('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS sent_xlog,
+# ('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS replay_xlog,
+# ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS sent_offset,
+# ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS replay_offset
+# FROM pg_stat_replication
+# ) AS s;
+# """
+
+
+QUERY_STATS = {
+ QUERIES['DATABASE']: METRICS['DATABASE'],
+ QUERIES['BACKENDS']: METRICS['BACKENDS'],
+ QUERIES['ARCHIVE']: METRICS['ARCHIVE'],
+ QUERIES['LOCKS']: METRICS['LOCKS']
+}
+
+ORDER = ['db_stat_transactions', 'db_stat_tuple_read', 'db_stat_tuple_returned', 'db_stat_tuple_write', 'database_size',
'backend_process', 'index_count', 'index_size', 'table_count', 'table_size', 'wal', 'background_writer']
CHARTS = {
'db_stat_transactions': {
- 'options': [None, 'Transactions on db', 'transactions/s', 'db statistics', 'postgres.db_stat_transactions', 'line'],
+ 'options': [None, 'Transactions on db', 'transactions/s', 'db statistics', 'postgres.db_stat_transactions',
+ 'line'],
'lines': [
- ['db_stat_xact_commit', 'committed', 'incremental'],
- ['db_stat_xact_rollback', 'rolled back', 'incremental']
+ ['xact_commit', 'committed', 'incremental'],
+ ['xact_rollback', 'rolled back', 'incremental']
]},
'db_stat_connections': {
- 'options': [None, 'Current connections to db', 'count', 'db statistics', 'postgres.db_stat_connections', 'line'],
+ 'options': [None, 'Current connections to db', 'count', 'db statistics', 'postgres.db_stat_connections',
+ 'line'],
'lines': [
- ['db_stat_connections', 'connections', 'absolute']
+ ['connections', 'connections', 'absolute']
]},
'db_stat_tuple_read': {
'options': [None, 'Tuple reads from db', 'reads/s', 'db statistics', 'postgres.db_stat_tuple_read', 'line'],
'lines': [
- ['db_stat_blks_read', 'disk', 'incremental'],
- ['db_stat_blks_hit', 'cache', 'incremental']
+ ['blks_read', 'disk', 'incremental'],
+ ['blks_hit', 'cache', 'incremental']
]},
'db_stat_tuple_returned': {
- 'options': [None, 'Tuples returned from db', 'tuples/s', 'db statistics', 'postgres.db_stat_tuple_returned', 'line'],
+ 'options': [None, 'Tuples returned from db', 'tuples/s', 'db statistics', 'postgres.db_stat_tuple_returned',
+ 'line'],
'lines': [
- ['db_stat_tup_returned', 'sequential', 'incremental'],
- ['db_stat_tup_fetched', 'bitmap', 'incremental']
+ ['tup_returned', 'sequential', 'incremental'],
+ ['tup_fetched', 'bitmap', 'incremental']
]},
'db_stat_tuple_write': {
'options': [None, 'Tuples written to db', 'writes/s', 'db statistics', 'postgres.db_stat_tuple_write', 'line'],
'lines': [
- ['db_stat_tup_inserted', 'inserted', 'incremental'],
- ['db_stat_tup_updated', 'updated', 'incremental'],
- ['db_stat_tup_deleted', 'deleted', 'incremental'],
- ['db_stat_conflicts', 'conflicts', 'incremental']
+ ['tup_inserted', 'inserted', 'incremental'],
+ ['tup_updated', 'updated', 'incremental'],
+ ['tup_deleted', 'deleted', 'incremental'],
+ ['conflicts', 'conflicts', 'incremental']
+ ]},
+ 'database_size': {
+ 'options': [None, 'Database size', 'MB', 'database size', 'postgres.db_size', 'stacked'],
+ 'lines': [
]},
'backend_process': {
- 'options': [None, 'Current Backend Processes', 'processes', 'backend processes', 'postgres.backend_process', 'line'],
+ 'options': [None, 'Current Backend Processes', 'processes', 'backend processes', 'postgres.backend_process',
+ 'line'],
'lines': [
- ['backend_process_active', 'active', 'absolute'],
- ['backend_process_idle', 'idle', 'absolute']
+ ['backends_active', 'active', 'absolute'],
+ ['backends_idle', 'idle', 'absolute']
]},
'index_count': {
'options': [None, 'Total indexes', 'index', 'indexes', 'postgres.index_count', 'line'],
@@ -172,15 +222,15 @@ CHARTS = {
'wal': {
'options': [None, 'Write-Ahead Logging Statistics', 'files/s', 'write ahead log', 'postgres.wal', 'line'],
'lines': [
- ['wal_total', 'total', 'incremental'],
- ['wal_ready', 'ready', 'incremental'],
- ['wal_done', 'done', 'incremental']
+ ['file_count', 'total', 'incremental'],
+ ['ready_count', 'ready', 'incremental'],
+ ['done_count', 'done', 'incremental']
]},
'background_writer': {
'options': [None, 'Checkpoints', 'writes/s', 'background writer', 'postgres.background_writer', 'line'],
'lines': [
- ['background_writer_scheduled', 'scheduled', 'incremental'],
- ['background_writer_requested', 'requested', 'incremental']
+ ['writer_scheduled', 'scheduled', 'incremental'],
+ ['writer_requested', 'requested', 'incremental']
]}
}
@@ -188,199 +238,169 @@ CHARTS = {
class Service(SimpleService):
def __init__(self, configuration=None, name=None):
super(self.__class__, self).__init__(configuration=configuration, name=name)
- self.order = ORDER
- self.definitions = CHARTS
- self.table_stats = configuration.pop('table_stats', True)
- self.index_stats = configuration.pop('index_stats', True)
+ self.order = ORDER[:]
+ self.definitions = deepcopy(CHARTS)
+ self.table_stats = configuration.pop('table_stats', False)
+ self.index_stats = configuration.pop('index_stats', False)
self.configuration = configuration
- self.connection = None
+ self.connection = False
self.is_superuser = False
- self.data = {}
- self.databases = set()
+ self.data = dict()
+ self.locks_zeroed = dict()
+ self.databases = list()
def _connect(self):
params = dict(user='postgres',
database=None,
password=None,
- host='localhost',
+ host=None,
port=5432)
params.update(self.configuration)
if not self.connection:
- self.connection = psycopg2.connect(**params)
- self.connection.set_isolation_level(extensions.ISOLATION_LEVEL_AUTOCOMMIT)
- self.connection.set_session(readonly=True)
+ try:
+ self.connection = psycopg2.connect(**params)
+ self.connection.set_isolation_level(extensions.ISOLATION_LEVEL_AUTOCOMMIT)
+ self.connection.set_session(readonly=True)
+ except OperationalError as error:
+ return False, str(error)
+ return True, True
def check(self):
+ if not PSYCOPG2:
+ self.error('\'python-psycopg2\' module is needed to use postgres.chart.py')
+ return False
+ result, error = self._connect()
+ if not result:
+ conf = dict([(k, (lambda k, v: v if k != 'password' else '*****')(k, v)) for k, v in self.configuration.items()])
+ self.error('Failed to connect to %s. Error: %s' % (str(conf), error))
+ return False
try:
- self._connect()
cursor = self.connection.cursor()
- self._discover_databases(cursor)
- self._check_if_superuser(cursor)
+ self.databases = discover_databases_(cursor, QUERIES['FIND_DATABASES'])
+ is_superuser = check_if_superuser_(cursor, QUERIES['IF_SUPERUSER'])
cursor.close()
- self._create_definitions()
+ self.locks_zeroed = populate_lock_types(self.databases)
+ self.add_additional_queries_(is_superuser)
+ self.create_dynamic_charts_()
return True
- except Exception as e:
- self.error(str(e))
+ except Exception as error:
+ self.error(str(error))
return False
- def _discover_databases(self, cursor):
- cursor.execute("""
- SELECT datname
- FROM pg_stat_database
- WHERE NOT datname ~* '^template\d+'
- """)
- self.databases = set(r[0] for r in cursor)
-
- def _check_if_superuser(self, cursor):
- cursor.execute("""
- SELECT current_setting('is_superuser') = 'on' AS is_superuser;
- """)
- self.is_superuser = cursor.fetchone()[0]
-
- def _create_definitions(self):
- for database_name in self.databases:
- for chart_template_name in list(CHARTS):
- if chart_template_name.startswith('db_stat'):
- self._add_database_stat_chart(chart_template_name, database_name)
- self._add_database_lock_chart(database_name)
-
- def _add_database_stat_chart(self, chart_template_name, database_name):
- chart_template = CHARTS[chart_template_name]
- chart_name = "{0}_{1}".format(database_name, chart_template_name)
- if chart_name not in self.order:
- self.order.insert(0, chart_name)
- name, title, units, family, context, chart_type = chart_template['options']
- self.definitions[chart_name] = {
- 'options': [
- name,
- title + ': ' + database_name,
- units,
- 'db ' + database_name,
- context,
- chart_type
- ]
- }
-
- self.definitions[chart_name]['lines'] = []
- for line in deepcopy(chart_template['lines']):
- line[0] = "{0}_{1}".format(database_name, line[0])
- self.definitions[chart_name]['lines'].append(line)
-
- def _add_database_lock_chart(self, database_name):
- chart_name = "{0}_locks".format(database_name)
- if chart_name not in self.order:
- self.order.insert(-1, chart_name)
- self.definitions[chart_name] = dict(
- options=
- [
- None,
- 'Locks on db: ' + database_name,
- 'locks',
- 'db ' + database_name,
- 'postgres.db_locks',
- 'line'
- ],
- lines=[]
- )
-
- for lock_type in LOCK_TYPES:
- lock_id = "{0}_{1}".format(database_name, lock_type)
- label = re.sub("([a-z])([A-Z])", "\g<1> \g<2>", lock_type)
- self.definitions[chart_name]['lines'].append([lock_id, label, 'absolute'])
-
- def _get_data(self):
- self._connect()
-
- cursor = self.connection.cursor(cursor_factory=DictCursor)
- self.add_stats(cursor)
-
- cursor.close()
- return self.data
-
- def add_stats(self, cursor):
- self.add_database_stats(cursor)
- self.add_backend_stats(cursor)
+ def add_additional_queries_(self, is_superuser):
if self.index_stats:
- self.add_index_stats(cursor)
+ QUERY_STATS[QUERIES['INDEX_STATS']] = METRICS['INDEX_STATS']
if self.table_stats:
- self.add_table_stats(cursor)
- self.add_lock_stats(cursor)
- self.add_bgwriter_stats(cursor)
+ QUERY_STATS[QUERIES['TABLE_STATS']] = METRICS['TABLE_STATS']
+ if is_superuser:
+ QUERY_STATS[QUERIES['BGWRITER']] = METRICS['BGWRITER']
- # self.add_replication_stats(cursor)
+ def create_dynamic_charts_(self):
- if self.is_superuser:
- self.add_wal_stats(cursor)
+ for database_name in self.databases[::-1]:
+ self.definitions['database_size']['lines'].append([database_name + '_size',
+ database_name, 'absolute', 1, 1024 * 1024])
+ for chart_name in [name for name in CHARTS if name.startswith('db_stat')]:
+ add_database_stat_chart_(order=self.order, definitions=self.definitions,
+ name=chart_name, database_name=database_name)
- def add_database_stats(self, cursor):
- cursor.execute(DATABASE)
- for row in cursor:
- database_name = row.get('database_name')
- self.data["{0}_{1}".format(database_name, 'db_stat_xact_commit')] = int(row.get('xact_commit', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_xact_rollback')] = int(row.get('xact_rollback', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_blks_read')] = int(row.get('blks_read', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_blks_hit')] = int(row.get('blks_hit', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_tup_returned')] = int(row.get('tup_returned', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_tup_fetched')] = int(row.get('tup_fetched', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_tup_inserted')] = int(row.get('tup_inserted', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_tup_updated')] = int(row.get('tup_updated', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_tup_deleted')] = int(row.get('tup_deleted', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_conflicts')] = int(row.get('conflicts', 0))
- self.data["{0}_{1}".format(database_name, 'db_stat_connections')] = int(row.get('connections', 0))
-
- def add_backend_stats(self, cursor):
- cursor.execute(BACKENDS)
- temp = cursor.fetchone()
-
- self.data['backend_process_active'] = int(temp.get('backends_active', 0))
- self.data['backend_process_idle'] = int(temp.get('backends_idle', 0))
-
- def add_index_stats(self, cursor):
- cursor.execute(INDEX_STATS)
- temp = cursor.fetchone()
- self.data['index_count'] = int(temp.get('indexes', 0))
- self.data['index_size'] = int(temp.get('size_indexes', 0))
-
- def add_table_stats(self, cursor):
- cursor.execute(TABLE_STATS)
- temp = cursor.fetchone()
- self.data['table_count'] = int(temp.get('relations', 0))
- self.data['table_size'] = int(temp.get('size_relations', 0))
-
- def add_lock_stats(self, cursor):
- cursor.execute(DATABASE_LOCKS)
-
- # zero out all current lock values
- for database_name in self.databases:
- for lock_type in LOCK_TYPES:
- self.data["{0}_{1}".format(database_name, lock_type)] = 0
-
- # populate those that have current locks
+ add_database_lock_chart_(order=self.order, definitions=self.definitions, database_name=database_name)
+
+ def _get_data(self):
+ result, error = self._connect()
+ if result:
+ cursor = self.connection.cursor(cursor_factory=DictCursor)
+ try:
+ self.data.update(self.locks_zeroed)
+ for query, metrics in QUERY_STATS.items():
+ self.query_stats_(cursor, query, metrics)
+
+ except OperationalError:
+ self.connection = False
+ cursor.close()
+ return None
+ else:
+ cursor.close()
+ return self.data
+ else:
+ return None
+
+ def query_stats_(self, cursor, query, metrics):
+ cursor.execute(query)
for row in cursor:
- database_name, lock_type, lock_count = row
- self.data["{0}_{1}".format(database_name, lock_type)] = lock_count
-
- def add_wal_stats(self, cursor):
- cursor.execute(ARCHIVE)
- temp = cursor.fetchone()
- self.data['wal_total'] = int(temp.get('file_count', 0))
- self.data['wal_ready'] = int(temp.get('ready_count', 0))
- self.data['wal_done'] = int(temp.get('done_count', 0))
-
- def add_bgwriter_stats(self, cursor):
- cursor.execute(BGWRITER)
- temp = cursor.fetchone()
- self.data['background_writer_scheduled'] = temp.get('checkpoints_timed', 0)
- self.data['background_writer_requested'] = temp.get('checkpoints_requests', 0)
-
-'''
- def add_replication_stats(self, cursor):
- cursor.execute(REPLICATION)
- temp = cursor.fetchall()
- for row in temp:
- self.add_gauge_value('Replication/%s' % row.get('client_addr', 'Unknown'),
- 'byte_lag',
- int(row.get('byte_lag', 0)))
-'''
+ for metric in metrics:
+ dimension_id = '_'.join([row['database_name'], metric]) if 'database_name' in row else metric
+ if metric in row:
+ self.data[dimension_id] = int(row[metric])
+ elif 'locks_count' in row:
+ self.data[dimension_id] = row['locks_count'] if metric == row['mode'] else 0
+
+
+def discover_databases_(cursor, query):
+ cursor.execute(query)
+ result = list()
+ for db in [database[0] for database in cursor]:
+ if db not in result:
+ result.append(db)
+ return result
+
+
+def check_if_superuser_(cursor, query):
+ cursor.execute(query)
+ return cursor.fetchone()[0]
+
+
+def populate_lock_types(databases):
+ result = dict()
+ for database in databases:
+ for lock_type in METRICS['LOCKS']:
+ key = '_'.join([database, lock_type])
+ result[key] = 0
+
+ return result
+
+
+def add_database_lock_chart_(order, definitions, database_name):
+ def create_lines(database):
+ result = list()
+ for lock_type in METRICS['LOCKS']:
+ dimension_id = '_'.join([database, lock_type])
+ result.append([dimension_id, lock_type, 'absolute'])
+ return result
+
+ chart_name = database_name + '_locks'
+ order.insert(-1, chart_name)
+ definitions[chart_name] = {
+ 'options':
+ [None, 'Locks on db: ' + database_name, 'locks', 'db ' + database_name, 'postgres.db_locks', 'line'],
+ 'lines': create_lines(database_name)
+ }
+
+
+def add_database_stat_chart_(order, definitions, name, database_name):
+ def create_lines(database, lines):
+ result = list()
+ for line in lines:
+ new_line = ['_'.join([database, line[0]])] + line[1:]
+ result.append(new_line)
+ return result
+
+ chart_template = CHARTS[name]
+ chart_name = '_'.join([database_name, name])
+ order.insert(0, chart_name)
+ name, title, units, family, context, chart_type = chart_template['options']
+ definitions[chart_name] = {
+ 'options': [name, title + ': ' + database_name, units, 'db ' + database_name, context, chart_type],
+ 'lines': create_lines(database_name, chart_template['lines'])}
+
+
+#
+# def add_replication_stats(self, cursor):
+# cursor.execute(REPLICATION)
+# temp = cursor.fetchall()
+# for row in temp:
+# self.add_gauge_value('Replication/%s' % row.get('client_addr', 'Unknown'),
+# 'byte_lag',
+# int(row.get('byte_lag', 0)))
diff --git a/python.d/python_modules/__init__.py b/python.d/python_modules/__init__.py
index 8d1c8b69c..8d1c8b69c 100755..100644
--- a/python.d/python_modules/__init__.py
+++ b/python.d/python_modules/__init__.py
diff --git a/python.d/python_modules/base.py b/python.d/python_modules/base.py
index 320c54bae..859300eca 100644
--- a/python.d/python_modules/base.py
+++ b/python.d/python_modules/base.py
@@ -18,19 +18,39 @@
# using ".encode()" in one thread can block other threads as well (only in python2)
import time
-# import sys
import os
import socket
import select
+import threading
+import msg
+import ssl
+from subprocess import Popen, PIPE
+from sys import exc_info
+
+try:
+ from urlparse import urlparse
+except ImportError:
+ from urllib.parse import urlparse
+
try:
import urllib.request as urllib2
except ImportError:
import urllib2
-from subprocess import Popen, PIPE
+try:
+ import MySQLdb
+ PYMYSQL = True
+except ImportError:
+ try:
+ import pymysql as MySQLdb
+ PYMYSQL = True
+ except ImportError:
+ PYMYSQL = False
-import threading
-import msg
+try:
+ PATH = os.getenv('PATH').split(':')
+except AttributeError:
+ PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'.split(':')
# class BaseService(threading.Thread):
@@ -61,6 +81,7 @@ class SimpleService(threading.Thread):
self.__first_run = True
self.order = []
self.definitions = {}
+ self._data_from_check = dict()
if configuration is None:
self.error("BaseService: no configuration parameters supplied. Cannot create Service.")
raise RuntimeError
@@ -385,7 +406,7 @@ class SimpleService(threading.Thread):
Create charts
:return: boolean
"""
- data = self._get_data()
+ data = self._data_from_check or self._get_data()
if data is None:
self.debug("failed to receive data during create().")
return False
@@ -431,101 +452,93 @@ class SimpleService(threading.Thread):
return updated
+ @staticmethod
+ def find_binary(binary):
+ try:
+ if isinstance(binary, str):
+ binary = os.path.basename(binary)
+ return next(('/'.join([p, binary]) for p in PATH
+ if os.path.isfile('/'.join([p, binary]))
+ and os.access('/'.join([p, binary]), os.X_OK)))
+ else:
+ return None
+ except StopIteration:
+ return None
+
class UrlService(SimpleService):
- # TODO add support for https connections
def __init__(self, configuration=None, name=None):
- self.url = ""
- self.user = None
- self.password = None
- self.proxies = {}
SimpleService.__init__(self, configuration=configuration, name=name)
+ self.url = self.configuration.get('url')
+ self.user = self.configuration.get('user')
+ self.password = self.configuration.get('pass')
+ self.ss_cert = self.configuration.get('ss_cert')
def __add_openers(self):
- # TODO add error handling
- self.opener = urllib2.build_opener()
-
- # Proxy handling
- # TODO currently self.proxies isn't parsed from configuration file
- # if len(self.proxies) > 0:
- # for proxy in self.proxies:
- # url = proxy['url']
- # # TODO test this:
- # if "user" in proxy and "pass" in proxy:
- # if url.lower().startswith('https://'):
- # url = 'https://' + proxy['user'] + ':' + proxy['pass'] + '@' + url[8:]
- # else:
- # url = 'http://' + proxy['user'] + ':' + proxy['pass'] + '@' + url[7:]
- # # FIXME move proxy auth to sth like this:
- # # passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
- # # passman.add_password(None, url, proxy['user'], proxy['password'])
- # # opener.add_handler(urllib2.HTTPBasicAuthHandler(passman))
- #
- # if url.lower().startswith('https://'):
- # opener.add_handler(urllib2.ProxyHandler({'https': url}))
- # else:
- # opener.add_handler(urllib2.ProxyHandler({'https': url}))
+ def self_signed_cert(ss_cert):
+ if ss_cert:
+ try:
+ ctx = ssl.create_default_context()
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
+ return urllib2.build_opener(urllib2.HTTPSHandler(context=ctx))
+ except AttributeError:
+ return None
+ else:
+ return None
+
+ self.opener = self_signed_cert(self.ss_cert) or urllib2.build_opener()
# HTTP Basic Auth
- if self.user is not None and self.password is not None:
+ if self.user and self.password:
+ url_parse = urlparse(self.url)
+ top_level_url = '://'.join([url_parse.scheme, url_parse.netloc])
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
- passman.add_password(None, self.url, self.user, self.password)
+ passman.add_password(None, top_level_url, self.user, self.password)
self.opener.add_handler(urllib2.HTTPBasicAuthHandler(passman))
self.debug("Enabling HTTP basic auth")
- #urllib2.install_opener(opener)
-
- def _get_raw_data(self):
+ def _get_raw_data(self, custom_url=None):
"""
Get raw data from http request
:return: str
"""
- raw = None
+ raw_data = None
+ f = None
try:
- f = self.opener.open(self.url, timeout=self.update_every * 2)
- # f = urllib2.urlopen(self.url, timeout=self.update_every * 2)
- except Exception as e:
- self.error(str(e))
+ f = self.opener.open(custom_url or self.url, timeout=self.update_every * 2)
+ raw_data = f.read().decode('utf-8', 'ignore')
+ except Exception as error:
+ self.error('Url: %s. Error: %s' %(custom_url or self.url, str(error)))
return None
-
- try:
- raw = f.read().decode('utf-8', 'ignore')
- except Exception as e:
- self.error(str(e))
finally:
- f.close()
- return raw
+ if f is not None: f.close()
+
+ return raw_data or None
def check(self):
"""
Format configuration data and try to connect to server
:return: boolean
"""
- if self.name is None or self.name == str(None):
- self.name = 'local'
- self.chart_name += "_" + self.name
- else:
- self.name = str(self.name)
- try:
- self.url = str(self.configuration['url'])
- except (KeyError, TypeError):
- pass
- try:
- self.user = str(self.configuration['user'])
- except (KeyError, TypeError):
- pass
- try:
- self.password = str(self.configuration['pass'])
- except (KeyError, TypeError):
- pass
+ if not (self.url and isinstance(self.url, str)):
+ self.error('URL is not defined or type is not <str>')
+ return False
self.__add_openers()
- test = self._get_data()
- if test is None or len(test) == 0:
+ try:
+ data = self._get_data()
+ except Exception as error:
+ self.error('_get_data() failed. Url: %s. Error: %s' % (self.url, error))
return False
- else:
+
+ if isinstance(data, dict) and data:
+ self._data_from_check = data
return True
+ else:
+ self.error("_get_data() returned no data or type is not <dict>")
+ return False
class SocketService(SimpleService):
@@ -829,63 +842,212 @@ class LogService(SimpleService):
class ExecutableService(SimpleService):
- bad_substrings = ('&', '|', ';', '>', '<')
def __init__(self, configuration=None, name=None):
- self.command = ""
SimpleService.__init__(self, configuration=configuration, name=name)
+ self.command = None
def _get_raw_data(self):
"""
Get raw data from executed command
- :return: str
+ :return: <list>
"""
try:
p = Popen(self.command, stdout=PIPE, stderr=PIPE)
- except Exception as e:
- self.error("Executing command", self.command, "resulted in error:", str(e))
+ except Exception as error:
+ self.error("Executing command", self.command, "resulted in error:", str(error))
return None
- data = []
+ data = list()
for line in p.stdout.readlines():
- data.append(str(line.decode()))
+ data.append(line.decode())
- if len(data) == 0:
- self.error("No data collected.")
- return None
-
- return data
+ return data or None
def check(self):
"""
Parse basic configuration, check if command is whitelisted and is returning values
- :return: boolean
+ :return: <boolean>
"""
- if self.name is not None or self.name != str(None):
- self.name = ""
+ # Preference: 1. "command" from configuration file 2. "command" from plugin (if specified)
+ if 'command' in self.configuration:
+ self.command = self.configuration['command']
+
+ # "command" must be: 1.not None 2. type <str>
+ if not (self.command and isinstance(self.command, str)):
+ self.error('Command is not defined or command type is not <str>')
+ return False
+
+ # Split "command" into: 1. command <str> 2. options <list>
+ command, opts = self.command.split()[0], self.command.split()[1:]
+
+ # Check for "bad" symbols in options. No pipes, redirects etc. TODO: what is missing?
+ bad_opts = set(''.join(opts)) & set(['&', '|', ';', '>', '<'])
+ if bad_opts:
+ self.error("Bad command argument(s): %s" % bad_opts)
+ return False
+
+ # Find absolute path ('echo' => '/bin/echo')
+ if '/' not in command:
+ command = self.find_binary(command)
+ if not command:
+ self.error('Can\'t locate "%s" binary in PATH(%s)' % (self.command, PATH))
+ return False
+ # Check if binary exist and executable
else:
- self.name = str(self.name)
+ if not (os.path.isfile(command) and os.access(command, os.X_OK)):
+ self.error('"%s" is not a file or not executable' % command)
+ return False
+
+ self.command = [command] + opts if opts else [command]
+
try:
- self.command = str(self.configuration['command'])
- except (KeyError, TypeError):
- self.info("No command specified. Using: '" + self.command + "'")
- # Splitting self.command on every space so subprocess.Popen reads it properly
- self.command = self.command.split(' ')
+ data = self._get_data()
+ except Exception as error:
+ self.error('_get_data() failed. Command: %s. Error: %s' % (self.command, error))
+ return False
- for arg in self.command[1:]:
- if any(st in arg for st in self.bad_substrings):
- self.error("Bad command argument:" + " ".join(self.command[1:]))
- return False
+ if isinstance(data, dict) and data:
+ # We need this for create() method. No reason to execute get_data() again if result is not empty dict()
+ self._data_from_check = data
+ return True
+ else:
+ self.error("Command", str(self.command), "returned no data")
+ return False
+
+
+class MySQLService(SimpleService):
+
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.__connection = None
+ self.__conn_properties = dict()
+ self.extra_conn_properties = dict()
+ self.__queries = self.configuration.get('queries', dict())
+ self.queries = dict()
+
+ def __connect(self):
+ try:
+ connection = MySQLdb.connect(connect_timeout=self.update_every, **self.__conn_properties)
+ except (MySQLdb.MySQLError, TypeError, AttributeError) as error:
+ return None, str(error)
+ else:
+ return connection, None
- # test command and search for it in /usr/sbin or /sbin when failed
- base = self.command[0].split('/')[-1]
- if self._get_raw_data() is None:
- for prefix in ['/sbin/', '/usr/sbin/']:
- self.command[0] = prefix + base
- if os.path.isfile(self.command[0]):
- break
+ def check(self):
+ def get_connection_properties(conf, extra_conf):
+ properties = dict()
+ if 'user' in conf and conf['user']:
+ properties['user'] = conf['user']
+ if 'pass' in conf and conf['pass']:
+ properties['passwd'] = conf['pass']
+ if 'socket' in conf and conf['socket']:
+ properties['unix_socket'] = conf['socket']
+ elif 'host' in conf and conf['host']:
+ properties['host'] = conf['host']
+ properties['port'] = int(conf.get('port', 3306))
+ elif 'my.cnf' in conf and conf['my.cnf']:
+ properties['read_default_file'] = conf['my.cnf']
+ if isinstance(extra_conf, dict) and extra_conf:
+ properties.update(extra_conf)
+
+ return properties or None
+
+ def is_valid_queries_dict(raw_queries, log_error):
+ """
+ :param raw_queries: dict:
+ :param log_error: function:
+ :return: dict or None
+
+ raw_queries is valid when: type <dict> and not empty after is_valid_query(for all queries)
+ """
+ def is_valid_query(query):
+ return all([isinstance(query, str),
+ query.startswith(('SELECT', 'select', 'SHOW', 'show'))])
+
+ if hasattr(raw_queries, 'keys') and raw_queries:
+ valid_queries = dict([(n, q) for n, q in raw_queries.items() if is_valid_query(q)])
+ bad_queries = set(raw_queries) - set(valid_queries)
+
+ if bad_queries:
+ log_error('Removed query(s): %s' % bad_queries)
+ return valid_queries
+ else:
+ log_error('Unsupported "queries" format. Must be not empty <dict>')
+ return None
- if self._get_data() is None or len(self._get_data()) == 0:
- self.error("Command", self.command, "returned no data")
+ if not PYMYSQL:
+ self.error('MySQLdb or PyMySQL module is needed to use mysql.chart.py plugin')
return False
- return True
+ # Preference: 1. "queries" from the configuration file 2. "queries" from the module
+ self.queries = self.__queries or self.queries
+ # Check if "self.queries" exist, not empty and all queries are in valid format
+ self.queries = is_valid_queries_dict(self.queries, self.error)
+ if not self.queries:
+ return None
+
+ # Get connection properties
+ self.__conn_properties = get_connection_properties(self.configuration, self.extra_conn_properties)
+ if not self.__conn_properties:
+ self.error('Connection properties are missing')
+ return False
+
+ # Create connection to the database
+ self.__connection, error = self.__connect()
+ if error:
+ self.error('Can\'t establish connection to MySQL: %s' % error)
+ return False
+
+ try:
+ data = self._get_data()
+ except Exception as error:
+ self.error('_get_data() failed. Error: %s' % error)
+ return False
+
+ if isinstance(data, dict) and data:
+ # We need this for create() method
+ self._data_from_check = data
+ return True
+ else:
+ self.error("_get_data() returned no data or type is not <dict>")
+ return False
+
+ def _get_raw_data(self, description=None):
+ """
+ Get raw data from MySQL server
+ :return: dict: fetchall() or (fetchall(), description)
+ """
+
+ if not self.__connection:
+ self.__connection, error = self.__connect()
+ if error:
+ return None
+
+ raw_data = dict()
+ queries = dict(self.queries)
+ try:
+ with self.__connection as cursor:
+ for name, query in queries.items():
+ try:
+ cursor.execute(query)
+ except (MySQLdb.ProgrammingError, MySQLdb.OperationalError) as error:
+ if self.__is_error_critical(err_class=exc_info()[0], err_text=str(error)):
+ raise RuntimeError
+ self.error('Removed query: %s[%s]. Error: %s'
+ % (name, query, error))
+ self.queries.pop(name)
+ continue
+ else:
+ raw_data[name] = (cursor.fetchall(), cursor.description) if description else cursor.fetchall()
+ self.__connection.commit()
+ except (MySQLdb.MySQLError, RuntimeError, TypeError, AttributeError):
+ self.__connection.close()
+ self.__connection = None
+ return None
+ else:
+ return raw_data or None
+
+ @staticmethod
+ def __is_error_critical(err_class, err_text):
+ return err_class == MySQLdb.OperationalError and all(['denied' not in err_text,
+ 'Unknown column' not in err_text])
diff --git a/python.d/smartd_log.chart.py b/python.d/smartd_log.chart.py
new file mode 100644
index 000000000..e80372379
--- /dev/null
+++ b/python.d/smartd_log.chart.py
@@ -0,0 +1,221 @@
+# -*- coding: utf-8 -*-
+# Description: smart netdata python.d module
+# Author: l2isbad, vorph1
+
+from re import compile
+from os import listdir, access, R_OK
+from os.path import isfile, join, getsize, basename, isdir
+try:
+ from queue import Queue
+except ImportError:
+ from Queue import Queue
+from threading import Thread
+from base import SimpleService
+from collections import namedtuple
+
+# default module values (can be overridden per job in `config`)
+update_every = 5
+priority = 60000
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = ['1', '4', '5', '7', '9', '12', '193', '194', '197', '198', '200']
+
+SMART_ATTR = {
+ '1': 'Read Error Rate',
+ '2': 'Throughput Performance',
+ '3': 'Spin-Up Time',
+ '4': 'Start/Stop Count',
+ '5': 'Reallocated Sectors Count',
+ '6': 'Read Channel Margin',
+ '7': 'Seek Error Rate',
+ '8': 'Seek Time Performance',
+ '9': 'Power-On Hours Count',
+ '10': 'Spin-up Retries',
+ '11': 'Calibration Retries',
+ '12': 'Power Cycle Count',
+ '13': 'Soft Read Error Rate',
+ '100': 'Erase/Program Cycles',
+ '103': 'Translation Table Rebuild',
+ '108': 'Unknown (108)',
+ '170': 'Reserved Block Count',
+ '171': 'Program Fail Count',
+ '172': 'Erase Fail Count',
+ '173': 'Wear Leveller Worst Case Erase Count',
+ '174': 'Unexpected Power Loss',
+ '175': 'Program Fail Count',
+ '176': 'Erase Fail Count',
+ '177': 'Wear Leveling Count',
+ '178': 'Used Reserved Block Count',
+ '179': 'Used Reserved Block Count',
+ '180': 'Unused Reserved Block Count',
+ '181': 'Program Fail Count',
+ '182': 'Erase Fail Count',
+ '183': 'SATA Downshifts',
+ '184': 'End-to-End error',
+ '185': 'Head Stability',
+ '186': 'Induced Op-Vibration Detection',
+ '187': 'Reported Uncorrectable Errors',
+ '188': 'Command Timeout',
+ '189': 'High Fly Writes',
+ '190': 'Temperature',
+ '191': 'G-Sense Errors',
+ '192': 'Power-Off Retract Cycles',
+ '193': 'Load/Unload Cycles',
+ '194': 'Temperature',
+ '195': 'Hardware ECC Recovered',
+ '196': 'Reallocation Events',
+ '197': 'Current Pending Sectors',
+ '198': 'Off-line Uncorrectable',
+ '199': 'UDMA CRC Error Rate',
+ '200': 'Write Error Rate',
+ '201': 'Soft Read Errors',
+ '202': 'Data Address Mark Errors',
+ '203': 'Run Out Cancel',
+ '204': 'Soft ECC Corrections',
+ '205': 'Thermal Asperity Rate',
+ '206': 'Flying Height',
+ '207': 'Spin High Current',
+ '209': 'Offline Seek Performance',
+ '220': 'Disk Shift',
+ '221': 'G-Sense Error Rate',
+ '222': 'Loaded Hours',
+ '223': 'Load/Unload Retries',
+ '224': 'Load Friction',
+ '225': 'Load/Unload Cycles',
+ '226': 'Load-in Time',
+ '227': 'Torque Amplification Count',
+ '228': 'Power-Off Retracts',
+ '230': 'GMR Head Amplitude',
+ '231': 'Temperature',
+ '232': 'Available Reserved Space',
+ '233': 'Media Wearout Indicator',
+ '240': 'Head Flying Hours',
+ '241': 'Total LBAs Written',
+ '242': 'Total LBAs Read',
+ '250': 'Read Error Retry Rate'
+}
+
+NAMED_DISKS = namedtuple('disks', ['name', 'size', 'number'])
+
+
+class Service(SimpleService):
+ def __init__(self, configuration=None, name=None):
+ SimpleService.__init__(self, configuration=configuration, name=name)
+ self.regex = compile(r'(\d+);(\d+);(\d+)')
+ self.log_path = self.configuration.get('log_path', '/var/log/smartd')
+ self.raw_values = self.configuration.get('raw_values')
+ self.attr = self.configuration.get('smart_attributes', [])
+ self.previous_data = dict()
+
+ def check(self):
+ # Can\'t start without smartd readable diks log files
+ disks = find_disks_in_log_path(self.log_path)
+ if not disks:
+ self.error('Can\'t locate any smartd log files in %s' % self.log_path)
+ return False
+
+ # List of namedtuples to track smartd log file size
+ self.disks = [NAMED_DISKS(name=disks[i], size=0, number=i) for i in range(len(disks))]
+
+ if self._get_data():
+ self.create_charts()
+ return True
+ else:
+ self.error('Can\'t collect any data. Sorry.')
+ return False
+
+ def _get_raw_data(self, queue, disk):
+ # The idea is to open a file.
+ # Jump to the end.
+ # Seek backward until '\n' symbol appears
+ # If '\n' is found or it's the beginning of the file
+ # readline()! (last or first line)
+ with open(disk, 'rb') as f:
+ f.seek(-2, 2)
+ while f.read(1) != b'\n':
+ f.seek(-2, 1)
+ if f.tell() == 0:
+ break
+ result = f.readline()
+
+ result = result.decode()
+ result = self.regex.findall(result)
+
+ queue.put([basename(disk), result])
+
+ def _get_data(self):
+ threads, result = list(), list()
+ queue = Queue()
+ to_netdata = dict()
+
+ # If the size has not changed there is no reason to poll log files.
+ disks = [disk for disk in self.disks if self.size_changed(disk)]
+ if disks:
+ for disk in disks:
+ th = Thread(target=self._get_raw_data, args=(queue, disk.name))
+ th.start()
+ threads.append(th)
+
+ for thread in threads:
+ thread.join()
+ result.append(queue.get())
+ else:
+ # Data from last real poll
+ return self.previous_data or None
+
+ for elem in result:
+ for a, n, r in elem[1]:
+ to_netdata.update({'_'.join([elem[0], a]): r if self.raw_values else n})
+
+ self.previous_data.update(to_netdata)
+
+ return to_netdata or None
+
+ def size_changed(self, disk):
+ # We are not interested in log files:
+ # 1. zero size
+ # 2. size is not changed since last poll
+ try:
+ size = getsize(disk.name)
+ if size != disk.size and size:
+ self.disks[disk.number] = disk._replace(size=size)
+ return True
+ else:
+ return False
+ except OSError:
+ # Remove unreadable/nonexisting log files from list of disks and previous_data
+ self.disks.remove(disk)
+ self.previous_data = dict([(k, v) for k, v in self.previous_data.items() if basename(disk.name) not in k])
+ return False
+
+ def create_charts(self):
+
+ def create_lines(attrid):
+ result = list()
+ for disk in self.disks:
+ name = basename(disk.name)
+ result.append(['_'.join([name, attrid]), name[:name.index('.')], 'absolute'])
+ return result
+
+ # Add additional smart attributes to the ORDER. If something goes wrong we don't care.
+ try:
+ ORDER.extend(list(set(self.attr.split()) & SMART_ATTR.keys() - set(ORDER)))
+ except Exception:
+ pass
+ self.order = [''.join(['attrid', i]) for i in ORDER]
+ self.definitions = dict()
+ units = 'raw' if self.raw_values else 'normalized'
+
+ for k, v in dict([(k, v) for k, v in SMART_ATTR.items() if k in ORDER]).items():
+ self.definitions.update({''.join(['attrid', k]): {
+ 'options': [None, v, units, v, 'smartd.attrid' + k, 'line'],
+ 'lines': create_lines(k)}})
+
+def find_disks_in_log_path(log_path):
+ # smartd log file is OK if:
+ # 1. it is a file
+ # 2. file name endswith with 'csv'
+ # 3. file is readable
+ if not isdir(log_path): return None
+ return [join(log_path, f) for f in listdir(log_path)
+ if all([isfile(join(log_path, f)), f.endswith('.csv'), access(join(log_path, f), R_OK)])]
diff --git a/python.d/tomcat.chart.py b/python.d/tomcat.chart.py
index 31f6ab248..c20f85e1e 100644
--- a/python.d/tomcat.chart.py
+++ b/python.d/tomcat.chart.py
@@ -2,11 +2,13 @@
# Description: tomcat netdata python.d module
# Author: Pawel Krupa (paulfantom)
-# Python version higher than 2.7 is needed to run this module.
-
from base import UrlService
-import xml.etree.ElementTree as ET # phone home...
-#from xml.parsers.expat import errors
+from re import compile
+
+try:
+ from urlparse import urlparse
+except ImportError:
+ from urllib.parse import urlparse
# default module values (can be overridden per job in `config`)
# update_every = 2
@@ -20,23 +22,23 @@ CHARTS = {
'accesses': {
'options': [None, "Requests", "requests/s", "statistics", "tomcat.accesses", "area"],
'lines': [
- ["accesses", None, 'incremental']
+ ["requestCount", 'accesses', 'incremental']
]},
'volume': {
'options': [None, "Volume", "KB/s", "volume", "tomcat.volume", "area"],
'lines': [
- ["volume", None, 'incremental', 1, 1024]
+ ["bytesSent", 'volume', 'incremental', 1, 1024]
]},
'threads': {
'options': [None, "Threads", "current threads", "statistics", "tomcat.threads", "line"],
'lines': [
- ["current", None, "absolute"],
- ["busy", None, "absolute"]
+ ["currentThreadCount", 'current', "absolute"],
+ ["currentThreadsBusy", 'busy', "absolute"]
]},
'jvm': {
'options': [None, "JVM Free Memory", "MB", "statistics", "tomcat.jvm", "area"],
'lines': [
- ["jvm", None, "absolute", 1, 1048576]
+ ["free", None, "absolute", 1, 1048576]
]}
}
@@ -44,68 +46,31 @@ CHARTS = {
class Service(UrlService):
def __init__(self, configuration=None, name=None):
UrlService.__init__(self, configuration=configuration, name=name)
- if len(self.url) == 0:
- self.url = "http://localhost:8080/manager/status?XML=true"
+ self.url = self.configuration.get('url', "http://127.0.0.1:8080/manager/status?XML=true")
self.order = ORDER
self.definitions = CHARTS
- self.port = 8080
def check(self):
- if UrlService.check(self):
- return True
-
- # get port from url
- self.port = 0
- for i in self.url.split('/'):
- try:
- int(i[-1])
- self.port = i.split(':')[-1]
- break
- except:
- pass
- if self.port == 0:
- self.port = 80
-
- test = self._get_data()
- if test is None or len(test) == 0:
- return False
- else:
- return True
+ netloc = urlparse(self.url).netloc.rpartition(':')
+ if netloc[1] == ':': port = netloc[2]
+ else: port = 80
+
+ self.regex_jvm = compile(r'<jvm>.*?</jvm>')
+ self.regex_connector = compile(r'[a-z-]+%s.*?/connector' % port)
+ self.regex = compile(r'([\w]+)=\\?[\'\"](\d+)\\?[\'\"]')
+
+ return UrlService.check(self)
def _get_data(self):
"""
Format data received from http request
:return: dict
"""
- try:
- raw = self._get_raw_data()
- try:
- data = ET.fromstring(raw)
- except ET.ParseError as e:
- # if e.code == errors.codes[errors.XML_ERROR_JUNK_AFTER_DOC_ELEMENT]:
- if e.code == 9:
- end = raw.find('</status>')
- end += 9
- raw = raw[:end]
- self.debug(raw)
- data = ET.fromstring(raw)
- else:
- raise Exception(e)
-
- memory = data.find('./jvm/memory')
- threads = data.find("./connector[@name='\"http-bio-" + str(self.port) + "\"']/threadInfo")
- requests = data.find("./connector[@name='\"http-bio-" + str(self.port) + "\"']/requestInfo")
+ data = self._get_raw_data()
+ if data:
+ jvm = self.regex_jvm.findall(data) or ['']
+ connector = self.regex_connector.findall(data) or ['']
+ data = dict(self.regex.findall(''.join([jvm[0], connector[0]])))
+
+ return data or None
- return {'accesses': requests.attrib['requestCount'],
- 'volume': requests.attrib['bytesSent'],
- 'current': threads.attrib['currentThreadCount'],
- 'busy': threads.attrib['currentThreadsBusy'],
- 'jvm': memory.attrib['free']}
- except (ValueError, AttributeError) as e:
- self.debug(str(e))
- return None
- except SyntaxError as e:
- self.error("Tomcat module needs python 2.7 at least. Stopping")
- self.debug(str(e))
- except Exception as e:
- self.debug(str(e))
diff --git a/python.d/varnish.chart.py b/python.d/varnish.chart.py
index 2b1512f4e..2665bb383 100644
--- a/python.d/varnish.chart.py
+++ b/python.d/varnish.chart.py
@@ -4,10 +4,8 @@
from base import SimpleService
from re import compile
-from os import access as is_executable, X_OK
from subprocess import Popen, PIPE
-
# default module values (can be overridden per job in `config`)
# update_every = 2
priority = 60000
@@ -80,17 +78,11 @@ CHARTS = {'backend_health':
'options': [None, 'Varnish uptime', 'seconds', 'Uptime', 'varnish.uptime', 'line']}
}
-DIRECTORIES = ['/bin/', '/usr/bin/', '/sbin/', '/usr/sbin/']
-
class Service(SimpleService):
def __init__(self, configuration=None, name=None):
SimpleService.__init__(self, configuration=configuration, name=name)
- try:
- self.varnish = [''.join([directory, 'varnishstat']) for directory in DIRECTORIES
- if is_executable(''.join([directory, 'varnishstat']), X_OK)][0]
- except IndexError:
- self.varnish = False
+ self.varnish = self.find_binary('varnishstat')
self.rgx_all = compile(r'([A-Z]+\.)?([\d\w_.]+)\s+(\d+)')
# Could be
# VBE.boot.super_backend.pipe_hdrbyte (new)
@@ -104,7 +96,7 @@ class Service(SimpleService):
def check(self):
# Cant start without 'varnishstat' command
if not self.varnish:
- self.error('\'varnishstat\' command was not found in %s or not executable by netdata' % DIRECTORIES)
+ self.error('Can\'t locate \'varnishstat\' binary or binary is not executable by netdata')
return False
# If command is present and we can execute it we need to make sure..
@@ -145,7 +137,7 @@ class Service(SimpleService):
if not raw_data:
return None
- return raw_data
+ return raw_data.decode()
def _get_data(self):
"""
@@ -160,10 +152,10 @@ class Service(SimpleService):
return None
# 1. ALL data from 'varnishstat -1'. t - type(MAIN, MEMPOOL etc)
- to_netdata = {k: int(v) for t, k, v in data_all}
+ to_netdata = dict([(k, int(v)) for t, k, v in data_all])
# 2. ADD backend statistics
- to_netdata.update({'_'.join([n, k]): int(v) for n, k, v in data_backend})
+ to_netdata.update(dict([('_'.join([n, k]), int(v)) for n, k, v in data_backend]))
# 3. ADD additional keys to dict
# 3.1 Cache hit/miss/hitpass OVERALL in percent
diff --git a/python.d/web_log.chart.py b/python.d/web_log.chart.py
new file mode 100644
index 000000000..cbc8cd235
--- /dev/null
+++ b/python.d/web_log.chart.py
@@ -0,0 +1,653 @@
+# -*- coding: utf-8 -*-
+# Description: web log netdata python.d module
+# Author: l2isbad
+
+from base import LogService
+import re
+import bisect
+from os import access, R_OK
+from os.path import getsize
+from collections import namedtuple
+from copy import deepcopy
+
+priority = 60000
+retries = 60
+
+ORDER = ['response_statuses', 'response_codes', 'bandwidth', 'response_time', 'requests_per_url', 'http_method',
+ 'http_version', 'requests_per_ipproto', 'clients', 'clients_all']
+CHARTS = {
+ 'response_codes': {
+ 'options': [None, 'Response Codes', 'requests/s', 'responses', 'web_log.response_codes', 'stacked'],
+ 'lines': [
+ ['2xx', '2xx', 'incremental'],
+ ['5xx', '5xx', 'incremental'],
+ ['3xx', '3xx', 'incremental'],
+ ['4xx', '4xx', 'incremental'],
+ ['1xx', '1xx', 'incremental'],
+ ['0xx', 'other', 'incremental'],
+ ['unmatched', 'unmatched', 'incremental']
+ ]},
+ 'bandwidth': {
+ 'options': [None, 'Bandwidth', 'KB/s', 'bandwidth', 'web_log.bandwidth', 'area'],
+ 'lines': [
+ ['resp_length', 'received', 'incremental', 1, 1024],
+ ['bytes_sent', 'sent', 'incremental', -1, 1024]
+ ]},
+ 'response_time': {
+ 'options': [None, 'Processing Time', 'milliseconds', 'timings', 'web_log.response_time', 'area'],
+ 'lines': [
+ ['resp_time_min', 'min', 'incremental', 1, 1000],
+ ['resp_time_max', 'max', 'incremental', 1, 1000],
+ ['resp_time_avg', 'avg', 'incremental', 1, 1000]
+ ]},
+ 'clients': {
+ 'options': [None, 'Current Poll Unique Client IPs', 'unique ips', 'clients', 'web_log.clients', 'stacked'],
+ 'lines': [
+ ['unique_cur_ipv4', 'ipv4', 'incremental', 1, 1],
+ ['unique_cur_ipv6', 'ipv6', 'incremental', 1, 1]
+ ]},
+ 'clients_all': {
+ 'options': [None, 'All Time Unique Client IPs', 'unique ips', 'clients', 'web_log.clients_all', 'stacked'],
+ 'lines': [
+ ['unique_tot_ipv4', 'ipv4', 'absolute', 1, 1],
+ ['unique_tot_ipv6', 'ipv6', 'absolute', 1, 1]
+ ]},
+ 'http_method': {
+ 'options': [None, 'Requests Per HTTP Method', 'requests/s', 'http methods', 'web_log.http_method', 'stacked'],
+ 'lines': [
+ ['GET', 'GET', 'incremental', 1, 1]
+ ]},
+ 'http_version': {
+ 'options': [None, 'Requests Per HTTP Version', 'requests/s', 'http versions',
+ 'web_log.http_version', 'stacked'],
+ 'lines': []},
+ 'requests_per_ipproto': {
+ 'options': [None, 'Requests Per IP Protocol', 'requests/s', 'ip protocols', 'web_log.requests_per_ipproto',
+ 'stacked'],
+ 'lines': [
+ ['req_ipv4', 'ipv4', 'incremental', 1, 1],
+ ['req_ipv6', 'ipv6', 'incremental', 1, 1]
+ ]},
+ 'response_statuses': {
+ 'options': [None, 'Response Statuses', 'requests/s', 'responses', 'web_log.response_statuses',
+ 'stacked'],
+ 'lines': [
+ ['successful_requests', 'success', 'incremental', 1, 1],
+ ['server_errors', 'error', 'incremental', 1, 1],
+ ['redirects', 'redirect', 'incremental', 1, 1],
+ ['bad_requests', 'bad', 'incremental', 1, 1],
+ ['other_requests', 'other', 'incremental', 1, 1]
+ ]}
+}
+
+NAMED_URL_PATTERN = namedtuple('URL_PATTERN', ['description', 'pattern'])
+
+DET_RESP_AGGR = ['', '_1xx', '_2xx', '_3xx', '_4xx', '_5xx', '_Other']
+
+
+class Service(LogService):
+ def __init__(self, configuration=None, name=None):
+ """
+ :param configuration:
+ :param name:
+ # self._get_data = None # will be assigned in 'check' method.
+ # self.order = None # will be assigned in 'create_*_method' method.
+ # self.definitions = None # will be assigned in 'create_*_method' method.
+ """
+ LogService.__init__(self, configuration=configuration, name=name)
+ # Variables from module configuration file
+ self.log_type = self.configuration.get('type', 'web_access')
+ self.log_path = self.configuration.get('path')
+ self.url_pattern = self.configuration.get('categories') # dict
+ self.custom_log_format = self.configuration.get('custom_log_format') # dict
+ # Instance variables
+ self.regex = None # will be assigned in 'find_regex' or 'find_regex_custom' method
+ self.data = {'bytes_sent': 0, 'resp_length': 0, 'resp_time_min': 0, 'resp_time_max': 0,
+ 'resp_time_avg': 0, 'unique_cur_ipv4': 0, 'unique_cur_ipv6': 0, '2xx': 0,
+ '5xx': 0, '3xx': 0, '4xx': 0, '1xx': 0, '0xx': 0, 'unmatched': 0, 'req_ipv4': 0,
+ 'req_ipv6': 0, 'unique_tot_ipv4': 0, 'unique_tot_ipv6': 0, 'successful_requests': 0,
+ 'redirects': 0, 'bad_requests': 0, 'server_errors': 0, 'other_requests': 0, 'GET': 0}
+
+ def check(self):
+ """
+ :return: bool
+
+ 1. "log_path" is specified in the module configuration file
+ 2. "log_path" must be readable by netdata user and must exist
+ 3. "log_path' must not be empty. We need at least 1 line to find appropriate pattern to parse
+ 4. other checks depends on log "type"
+ """
+ if not self.log_path:
+ self.error('log path is not specified')
+ return False
+
+ if not access(self.log_path, R_OK):
+ self.error('%s not readable or not exist' % self.log_path)
+ return False
+
+ if not getsize(self.log_path):
+ self.error('%s is empty' % self.log_path)
+ return False
+
+ # Read last line (or first if there is only one line)
+ with open(self.log_path, 'rb') as logs:
+ logs.seek(-2, 2)
+ while logs.read(1) != b'\n':
+ logs.seek(-2, 1)
+ if logs.tell() == 0:
+ break
+ last_line = logs.readline()
+
+ try:
+ last_line = last_line.decode()
+ except UnicodeDecodeError:
+ try:
+ last_line = last_line.decode(encoding='utf-8')
+ except (TypeError, UnicodeDecodeError) as error:
+ self.error(str(error))
+ return False
+
+ if self.log_type == 'web_access':
+ self.unique_all_time = list() # sorted list of unique IPs
+ self.detailed_response_codes = self.configuration.get('detailed_response_codes', True)
+ self.detailed_response_aggregate = self.configuration.get('detailed_response_aggregate', True)
+ self.all_time = self.configuration.get('all_time', True)
+
+ # Custom_log_format or predefined log format.
+ if self.custom_log_format:
+ match_dict, error = self.find_regex_custom(last_line)
+ else:
+ match_dict, error = self.find_regex(last_line)
+
+ # "match_dict" is None if there are any problems
+ if match_dict is None:
+ self.error(str(error))
+ return False
+
+ # self.url_pattern check
+ if self.url_pattern:
+ self.url_pattern = check_req_per_url_pattern('rpu', self.url_pattern)
+
+ self.create_access_charts(match_dict) # Create charts
+ self._get_data = self._get_access_data # _get_data assignment
+ else:
+ self.error('Not implemented')
+ return False
+
+ # Double check
+ if not self.regex:
+ self.error('That can not happen, but it happened. "regex" is None')
+
+ self.info('Collected data: %s' % list(match_dict.keys()))
+ return True
+
+ def find_regex_custom(self, last_line):
+ """
+ :param last_line: str: literally last line from log file
+ :return: tuple where:
+ [0]: dict or None: match_dict or None
+ [1]: str: error description
+
+ We are here only if "custom_log_format" is in logs. We need to make sure:
+ 1. "custom_log_format" is a dict
+ 2. "pattern" in "custom_log_format" and pattern is <str> instance
+ 3. if "time_multiplier" is in "custom_log_format" it must be <int> instance
+
+ If all parameters is ok we need to make sure:
+ 1. Pattern search is success
+ 2. Pattern search contains named subgroups (?P<subgroup_name>) (= "match_dict")
+
+ If pattern search is success we need to make sure:
+ 1. All mandatory keys ['address', 'code', 'bytes_sent', 'method', 'url'] are in "match_dict"
+
+ If this is True we need to make sure:
+ 1. All mandatory key values from "match_dict" have the correct format
+ ("code" is integer, "method" is uppercase word, etc)
+
+ If non mandatory keys in "match_dict" we need to make sure:
+ 1. All non mandatory key values from match_dict ['resp_length', 'resp_time'] have the correct format
+ ("resp_length" is integer or "-", "resp_time" is integer or float)
+
+ """
+ if not hasattr(self.custom_log_format, 'keys'):
+ return find_regex_return(msg='Custom log: "custom_log_format" is not a <dict>')
+
+ pattern = self.custom_log_format.get('pattern')
+ if not (pattern and isinstance(pattern, str)):
+ return find_regex_return(msg='Custom log: "pattern" option is not specified or type is not <str>')
+
+ resp_time_func = self.custom_log_format.get('time_multiplier') or 0
+
+ if not isinstance(resp_time_func, int):
+ return find_regex_return(msg='Custom log: "time_multiplier" is not an integer')
+
+ try:
+ regex = re.compile(pattern)
+ except re.error as error:
+ return find_regex_return(msg='Pattern compile error: %s' % str(error))
+
+ match = regex.search(last_line)
+ if match:
+ match_dict = match.groupdict() or None
+ else:
+ return find_regex_return(msg='Custom log: pattern search FAILED')
+
+ if match_dict is None:
+ find_regex_return(msg='Custom log: search OK but contains no named subgroups'
+ ' (you need to use ?P<subgroup_name>)')
+ else:
+ mandatory_dict = {'address': r'[\da-f.:]+',
+ 'code': r'[1-9]\d{2}',
+ 'method': r'[A-Z]+',
+ 'bytes_sent': r'\d+|-'}
+ optional_dict = {'resp_length': r'\d+',
+ 'resp_time': r'[\d.]+',
+ 'http_version': r'\d\.\d'}
+
+ mandatory_values = set(mandatory_dict) - set(match_dict)
+ if mandatory_values:
+ return find_regex_return(msg='Custom log: search OK but some mandatory keys (%s) are missing'
+ % list(mandatory_values))
+ else:
+ for key in mandatory_dict:
+ if not re.search(mandatory_dict[key], match_dict[key]):
+ return find_regex_return(msg='Custom log: can\'t parse "%s": %s'
+ % (key, match_dict[key]))
+
+ optional_values = set(optional_dict) & set(match_dict)
+ for key in optional_values:
+ if not re.search(optional_dict[key], match_dict[key]):
+ return find_regex_return(msg='Custom log: can\'t parse "%s": %s'
+ % (key, match_dict[key]))
+
+ dot_in_time = '.' in match_dict.get('resp_time', '')
+ if dot_in_time:
+ self.resp_time_func = lambda time: time * (resp_time_func or 1000000)
+ else:
+ self.resp_time_func = lambda time: time * (resp_time_func or 1)
+
+ self.regex = regex
+ return find_regex_return(match_dict=match_dict)
+
+ def find_regex(self, last_line):
+ """
+ :param last_line: str: literally last line from log file
+ :return: tuple where:
+ [0]: dict or None: match_dict or None
+ [1]: str: error description
+ We need to find appropriate pattern for current log file
+ All logic is do a regex search through the string for all predefined patterns
+ until we find something or fail.
+ """
+ # REGEX: 1.IPv4 address 2.HTTP method 3. URL 4. Response code
+ # 5. Bytes sent 6. Response length 7. Response process time
+ acs_default = re.compile(r'(?P<address>[\da-f.:]+)'
+ r' -.*?"(?P<method>[A-Z]+)'
+ r' (?P<url>[^ ]+)'
+ r' [A-Z]+/(?P<http_version>\d\.\d)"'
+ r' (?P<code>[1-9]\d{2})'
+ r' (?P<bytes_sent>\d+|-)')
+
+ acs_apache_ext_insert = re.compile(r'(?P<address>[\da-f.:]+)'
+ r' -.*?"(?P<method>[A-Z]+)'
+ r' (?P<url>[^ ]+)'
+ r' [A-Z]+/(?P<http_version>\d\.\d)"'
+ r' (?P<code>[1-9]\d{2})'
+ r' (?P<bytes_sent>\d+|-)'
+ r' (?P<resp_length>\d+)'
+ r' (?P<resp_time>\d+) ')
+
+ acs_apache_ext_append = re.compile(r'(?P<address>[\da-f.:]+)'
+ r' -.*?"(?P<method>[A-Z]+)'
+ r' (?P<url>[^ ]+)'
+ r' [A-Z]+/(?P<http_version>\d\.\d)"'
+ r' (?P<code>[1-9]\d{2})'
+ r' (?P<bytes_sent>\d+|-)'
+ r' .*?'
+ r' (?P<resp_length>\d+)'
+ r' (?P<resp_time>\d+)'
+ r'(?: |$)')
+
+ acs_nginx_ext_insert = re.compile(r'(?P<address>[\da-f.:]+)'
+ r' -.*?"(?P<method>[A-Z]+)'
+ r' (?P<url>[^ ]+)'
+ r' [A-Z]+/(?P<http_version>\d\.\d)"'
+ r' (?P<code>[1-9]\d{2})'
+ r' (?P<bytes_sent>\d+)'
+ r' (?P<resp_length>\d+)'
+ r' (?P<resp_time>\d+\.\d+) ')
+
+ acs_nginx_ext_append = re.compile(r'(?P<address>[\da-f.:]+)'
+ r' -.*?"(?P<method>[A-Z]+)'
+ r' (?P<url>[^ ]+)'
+ r' [A-Z]+/(?P<http_version>\d\.\d)"'
+ r' (?P<code>[1-9]\d{2})'
+ r' (?P<bytes_sent>\d+)'
+ r' .*?'
+ r' (?P<resp_length>\d+)'
+ r' (?P<resp_time>\d+\.\d+)')
+
+ def func_usec(time):
+ return time
+
+ def func_sec(time):
+ return time * 1000000
+
+ r_regex = [acs_apache_ext_insert, acs_apache_ext_append, acs_nginx_ext_insert,
+ acs_nginx_ext_append, acs_default]
+ r_function = [func_usec, func_usec, func_sec, func_sec, func_usec]
+ regex_function = zip(r_regex, r_function)
+
+ match_dict = dict()
+ for regex, function in regex_function:
+ match = regex.search(last_line)
+ if match:
+ self.regex = regex
+ self.resp_time_func = function
+ match_dict = match.groupdict()
+ break
+
+ return find_regex_return(match_dict=match_dict or None,
+ msg='Unknown log format. You need to use "custom_log_format" feature.')
+
+ def create_access_charts(self, match_dict):
+ """
+ :param match_dict: dict: regex.search.groupdict(). Ex. {'address': '127.0.0.1', 'code': '200', 'method': 'GET'}
+ :return:
+ Create additional charts depending on the 'match_dict' keys and configuration file options
+ 1. 'time_response' chart is removed if there is no 'resp_time' in match_dict.
+ 2. Other stuff is just remove/add chart depending on yes/no in conf
+ """
+
+ def find_job_name(override_name, name):
+ """
+ :param override_name: str: 'name' var from configuration file
+ :param name: str: 'job_name' from configuration file
+ :return: str: new job name
+ We need this for dynamic charts. Actually same logic as in python.d.plugin.
+ """
+ add_to_name = override_name or name
+ if add_to_name:
+ return '_'.join(['web_log', re.sub('\s+', '_', add_to_name)])
+ else:
+ return 'web_log'
+
+ self.order = ORDER[:]
+ self.definitions = deepcopy(CHARTS)
+
+ job_name = find_job_name(self.override_name, self.name)
+
+ self.http_method_chart = 'CHART %s.http_method' \
+ ' "" "Requests Per HTTP Method" requests/s "http methods"' \
+ ' web_log.http_method stacked 11 %s\n' \
+ 'DIMENSION GET GET incremental\n' % (job_name, self.update_every)
+ self.http_version_chart = 'CHART %s.http_version' \
+ ' "" "Requests Per HTTP Version" requests/s "http versions"' \
+ ' web_log.http_version stacked 12 %s\n' % (job_name, self.update_every)
+
+ # Remove 'request_time' chart from ORDER if resp_time not in match_dict
+ if 'resp_time' not in match_dict:
+ self.order.remove('response_time')
+ # Remove 'clients_all' chart from ORDER if specified in the configuration
+ if not self.all_time:
+ self.order.remove('clients_all')
+ # Add 'detailed_response_codes' chart if specified in the configuration
+ if self.detailed_response_codes:
+ self.detailed_chart = list()
+ for prio, add_to_dim in enumerate(DET_RESP_AGGR):
+ self.detailed_chart.append('CHART %s.detailed_response_codes%s ""'
+ ' "Detailed Response Codes %s" requests/s responses'
+ ' web_log.detailed_response_codes%s stacked %s %s\n'
+ % (job_name, add_to_dim, add_to_dim[1:], add_to_dim,
+ str(prio), self.update_every))
+
+ codes = DET_RESP_AGGR[:1] if self.detailed_response_aggregate else DET_RESP_AGGR[1:]
+ for code in codes:
+ self.order.append('detailed_response_codes%s' % code)
+ self.definitions['detailed_response_codes%s' % code] = {'options':
+ [None,
+ 'Detailed Response Codes %s' % code[1:],
+ 'requests/s',
+ 'responses',
+ 'web_log.detailed_response_codes%s' % code,
+ 'stacked'],
+ 'lines': []}
+
+ # Add 'requests_per_url' chart if specified in the configuration
+ if self.url_pattern:
+ self.definitions['requests_per_url'] = {'options': [None, 'Requests Per Url', 'requests/s',
+ 'urls', 'web_log.requests_per_url', 'stacked'],
+ 'lines': [['rpu_other', 'other', 'incremental']]}
+ for elem in self.url_pattern:
+ self.definitions['requests_per_url']['lines'].append([elem.description, elem.description[4:],
+ 'incremental'])
+ self.data.update({elem.description: 0})
+ self.data.update({'rpu_other': 0})
+ else:
+ self.order.remove('requests_per_url')
+
+ def add_new_dimension(self, dimension, line_list, chart_string, key):
+ """
+ :param dimension: str: response status code. Ex.: '202', '499'
+ :param line_list: list: Ex.: ['202', '202', 'incremental']
+ :param chart_string: Current string we need to pass to netdata to rebuild the chart
+ :param key: str: CHARTS dict key (chart name). Ex.: 'response_time'
+ :return: str: new chart string = previous + new dimensions
+ """
+ self.data.update({dimension: 0})
+ # SET method check if dim in _dimensions
+ self._dimensions.append(dimension)
+ # UPDATE method do SET only if dim in definitions
+ self.definitions[key]['lines'].append(line_list)
+ chart = chart_string
+ chart += "%s %s\n" % ('DIMENSION', ' '.join(line_list))
+ print(chart)
+ return chart
+
+ def _get_access_data(self):
+ """
+ Parse new log lines
+ :return: dict OR None
+ None if _get_raw_data method fails.
+ In all other cases - dict.
+ """
+ raw = self._get_raw_data()
+ if raw is None:
+ return None
+
+ request_time, unique_current = list(), list()
+ request_counter = {'count': 0, 'sum': 0}
+ ip_address_counter = {'unique_cur_ip': 0}
+ for line in raw:
+ match = self.regex.search(line)
+ if match:
+ match_dict = match.groupdict()
+ try:
+ code = ''.join([match_dict['code'][0], 'xx'])
+ self.data[code] += 1
+ except KeyError:
+ self.data['0xx'] += 1
+ # detailed response code
+ if self.detailed_response_codes:
+ self._get_data_detailed_response_codes(match_dict['code'])
+ # response statuses
+ self._get_data_statuses(match_dict['code'])
+ # requests per url
+ if self.url_pattern:
+ self._get_data_per_url(match_dict['url'])
+ # requests per http method
+ self._get_data_http_method(match_dict['method'])
+ # requests per http version
+ if 'http_version' in match_dict:
+ self._get_data_http_version(match_dict['http_version'])
+ # bandwidth sent
+ bytes_sent = match_dict['bytes_sent'] if '-' not in match_dict['bytes_sent'] else 0
+ self.data['bytes_sent'] += int(bytes_sent)
+ # request processing time and bandwidth received
+ if 'resp_length' in match_dict:
+ self.data['resp_length'] += int(match_dict['resp_length'])
+ if 'resp_time' in match_dict:
+ resp_time = self.resp_time_func(float(match_dict['resp_time']))
+ bisect.insort_left(request_time, resp_time)
+ request_counter['count'] += 1
+ request_counter['sum'] += resp_time
+ # requests per ip proto
+ proto = 'ipv4' if '.' in match_dict['address'] else 'ipv6'
+ self.data['req_' + proto] += 1
+ # unique clients ips
+ if address_not_in_pool(self.unique_all_time, match_dict['address'],
+ self.data['unique_tot_ipv4'] + self.data['unique_tot_ipv6']):
+ self.data['unique_tot_' + proto] += 1
+ if address_not_in_pool(unique_current, match_dict['address'], ip_address_counter['unique_cur_ip']):
+ self.data['unique_cur_' + proto] += 1
+ ip_address_counter['unique_cur_ip'] += 1
+ else:
+ self.data['unmatched'] += 1
+
+ # timings
+ if request_time:
+ self.data['resp_time_min'] += int(request_time[0])
+ self.data['resp_time_avg'] += int(round(float(request_counter['sum']) / request_counter['count']))
+ self.data['resp_time_max'] += int(request_time[-1])
+ return self.data
+
+ def _get_data_detailed_response_codes(self, code):
+ """
+ :param code: str: CODE from parsed line. Ex.: '202, '499'
+ :return:
+ Calls add_new_dimension method If the value is found for the first time
+ """
+ if code not in self.data:
+ if self.detailed_response_aggregate:
+ chart_string_copy = self.detailed_chart[0]
+ self.detailed_chart[0] = self.add_new_dimension(code, [code, code, 'incremental'],
+ chart_string_copy, 'detailed_response_codes')
+ else:
+ code_index = int(code[0]) if int(code[0]) < 6 else 6
+ chart_string_copy = self.detailed_chart[code_index]
+ chart_name = 'detailed_response_codes' + DET_RESP_AGGR[code_index]
+ self.detailed_chart[code_index] = self.add_new_dimension(code, [code, code, 'incremental'],
+ chart_string_copy, chart_name)
+ self.data[code] += 1
+
+ def _get_data_http_method(self, method):
+ """
+ :param method: str: METHOD from parsed line. Ex.: 'GET', 'POST'
+ :return:
+ Calls add_new_dimension method If the value is found for the first time
+ """
+ if method not in self.data:
+ chart_string_copy = self.http_method_chart
+ self.http_method_chart = self.add_new_dimension(method, [method, method, 'incremental'],
+ chart_string_copy, 'http_method')
+ self.data[method] += 1
+
+ def _get_data_http_version(self, http_version):
+ """
+ :param http_version: str: METHOD from parsed line. Ex.: '1.1', '1.0'
+ :return:
+ Calls add_new_dimension method If the value is found for the first time
+ """
+ http_version_dim_id = http_version.replace('.', '_')
+ if http_version_dim_id not in self.data:
+ chart_string_copy = self.http_version_chart
+ self.http_version_chart = self.add_new_dimension(http_version_dim_id,
+ [http_version_dim_id, http_version, 'incremental'],
+ chart_string_copy, 'http_version')
+ self.data[http_version_dim_id] += 1
+
+ def _get_data_per_url(self, url):
+ """
+ :param url: str: URL from parsed line
+ :return:
+ Scan through string looking for the first location where patterns produce a match for all user
+ defined patterns
+ """
+ match = None
+ for elem in self.url_pattern:
+ if elem.pattern.search(url):
+ self.data[elem.description] += 1
+ match = True
+ break
+ if not match:
+ self.data['rpu_other'] += 1
+
+ def _get_data_statuses(self, code):
+ """
+ :param code: str: response status code. Ex.: '202', '499'
+ :return:
+ """
+ code_class = code[0]
+ if code_class == '2' or code == '304' or code_class == '1':
+ self.data['successful_requests'] += 1
+ elif code_class == '3':
+ self.data['redirects'] += 1
+ elif code_class == '4':
+ self.data['bad_requests'] += 1
+ elif code_class == '5':
+ self.data['server_errors'] += 1
+ else:
+ self.data['other_requests'] += 1
+
+
+def address_not_in_pool(pool, address, pool_size):
+ """
+ :param pool: list of ip addresses
+ :param address: ip address
+ :param pool_size: current pool size
+ :return: True if address not in pool. False if address in pool.
+ """
+ index = bisect.bisect_left(pool, address)
+ if index < pool_size:
+ if pool[index] == address:
+ return False
+ else:
+ bisect.insort_left(pool, address)
+ return True
+ else:
+ bisect.insort_left(pool, address)
+ return True
+
+
+def find_regex_return(match_dict=None, msg='Generic error message'):
+ """
+ :param match_dict: dict: re.search.groupdict() or None
+ :param msg: str: error description
+ :return: tuple:
+ """
+ return match_dict, msg
+
+
+def check_req_per_url_pattern(string, url_pattern):
+ """
+ :param string: str:
+ :param url_pattern: dict: ex. {'dim1': 'pattern1>', 'dim2': '<pattern2>'}
+ :return: list of named tuples or None:
+ We need to make sure all patterns are valid regular expressions
+ """
+ if not hasattr(url_pattern, 'keys'):
+ return None
+
+ result = list()
+
+ def is_valid_pattern(pattern):
+ """
+ :param pattern: str
+ :return: re.compile(pattern) or None
+ """
+ if not isinstance(pattern, str):
+ return False
+ else:
+ try:
+ compile_pattern = re.compile(pattern)
+ except re.error:
+ return False
+ else:
+ return compile_pattern
+
+ for dimension, regex in url_pattern.items():
+ valid_pattern = is_valid_pattern(regex)
+ if isinstance(dimension, str) and valid_pattern:
+ result.append(NAMED_URL_PATTERN(description='_'.join([string, dimension]), pattern=valid_pattern))
+
+ return result or None
diff --git a/src/Makefile.am b/src/Makefile.am
index d8274d255..1c1dd3385 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,11 +12,14 @@ AM_CPPFLAGS = \
-DRUN_DIR="\"$(localstatedir)/run/netdata\"" \
-DWEB_DIR="\"$(webdir)\"" \
$(NULL)
+
AM_CFLAGS = \
$(OPTIONAL_MATH_CFLAGS) \
$(OPTIONAL_NFACCT_CLFAGS) \
$(OPTIONAL_ZLIB_CFLAGS) \
$(OPTIONAL_UUID_CFLAGS) \
+ $(OPTIONAL_LIBCAP_CFLAGS) \
+ $(OPTIONAL_IPMIMONITORING_CFLAGS)\
$(NULL)
sbin_PROGRAMS = netdata
@@ -24,66 +27,131 @@ dist_cache_DATA = .keep
dist_varlib_DATA = .keep
dist_registry_DATA = .keep
dist_log_DATA = .keep
-if !MACOS
-plugins_PROGRAMS = apps.plugin
+plugins_PROGRAMS =
+
+if ENABLE_PLUGIN_APPS
+plugins_PROGRAMS += apps.plugin
+endif
+
+if ENABLE_PLUGIN_FREEIPMI
+plugins_PROGRAMS += freeipmi.plugin
endif
netdata_SOURCES = \
- appconfig.c appconfig.h \
- adaptive_resortable_list.c adaptive_resortable_list.h \
- avl.c avl.h \
- backends.c backends.h \
- clocks.c clocks.h \
- common.c common.h \
- daemon.c daemon.h \
- dictionary.c dictionary.h \
- eval.c eval.h \
- global_statistics.c global_statistics.h \
- health.c health.h \
+ adaptive_resortable_list.c \
+ adaptive_resortable_list.h \
+ appconfig.c \
+ appconfig.h \
+ avl.c \
+ avl.h \
+ backends.c \
+ backends.h \
+ clocks.c \
+ clocks.h \
+ common.c \
+ common.h \
+ daemon.c \
+ daemon.h \
+ dictionary.c \
+ dictionary.h \
+ eval.c \
+ eval.h \
+ global_statistics.c \
+ global_statistics.h \
+ health.c \
+ health.h \
+ health_config.c \
+ health_json.c \
+ health_log.c \
inlined.h \
- log.c log.h \
- main.c main.h \
- plugin_checks.c plugin_checks.h \
- plugin_idlejitter.c plugin_idlejitter.h \
- plugin_nfacct.c plugin_nfacct.h \
- plugin_tc.c plugin_tc.h \
- plugins_d.c plugins_d.h \
- popen.c popen.h \
- socket.c socket.h \
- simple_pattern.c simple_pattern.h \
- sys_fs_cgroup.c \
- sys_devices_system_edac_mc.c \
- sys_devices_system_node.c \
- procfile.c procfile.h \
- proc_self_mountinfo.c proc_self_mountinfo.h \
- registry.c registry.h \
- registry_internals.c registry_internals.h \
- registry_url.c registry_url.h \
- registry_person.c registry_person.h \
- registry_machine.c registry_machine.h \
- registry_init.c \
+ locks.h \
+ log.c \
+ log.h \
+ main.c \
+ main.h \
+ plugin_checks.c \
+ plugin_checks.h \
+ plugin_idlejitter.c \
+ plugin_idlejitter.h \
+ plugin_nfacct.c \
+ plugin_nfacct.h \
+ plugin_tc.c \
+ plugin_tc.h \
+ plugins_d.c \
+ plugins_d.h \
+ popen.c \
+ popen.h \
+ proc_self_mountinfo.c \
+ proc_self_mountinfo.h \
+ procfile.c \
+ procfile.h \
+ registry.c \
+ registry.h \
registry_db.c \
+ registry_init.c \
+ registry_internals.c \
+ registry_internals.h \
registry_log.c \
- rrd.c rrd.h \
- rrd2json.c rrd2json.h \
- storage_number.c storage_number.h \
- unit_test.c unit_test.h \
+ registry_machine.c \
+ registry_machine.h \
+ registry_person.c \
+ registry_person.h \
+ registry_url.c \
+ registry_url.h \
+ rrd.c \
+ rrd.h \
+ rrd2json.c \
+ rrd2json.h \
+ rrd2json_api_old.c \
+ rrd2json_api_old.h \
+ rrdcalc.c \
+ rrdcalctemplate.c \
+ rrddim.c \
+ rrddimvar.c \
+ rrdfamily.c \
+ rrdhost.c \
+ rrdpush.c \
+ rrdpush.h \
+ rrdset.c \
+ rrdsetvar.c \
+ rrdvar.c \
+ simple_pattern.c \
+ simple_pattern.h \
+ socket.c \
+ socket.h \
+ storage_number.c \
+ storage_number.h \
+ sys_devices_system_edac_mc.c \
+ sys_devices_system_node.c \
+ sys_fs_cgroup.c \
+ unit_test.c \
+ unit_test.h \
url.c url.h \
- web_buffer.c web_buffer.h \
- web_buffer_svg.c web_buffer_svg.h \
- web_client.c web_client.h \
- web_server.c web_server.h \
+ web_api_old.c \
+ web_api_old.h \
+ web_api_v1.c \
+ web_api_v1.h \
+ web_buffer.c \
+ web_buffer.h \
+ web_buffer_svg.c \
+ web_buffer_svg.h \
+ web_client.c \
+ web_client.h \
+ web_server.c \
+ web_server.h \
$(NULL)
if FREEBSD
netdata_SOURCES += \
- plugin_freebsd.c plugin_freebsd.h \
+ plugin_freebsd.c \
+ plugin_freebsd.h \
freebsd_sysctl.c \
$(NULL)
else
if MACOS
netdata_SOURCES += \
- plugin_macos.c plugin_macos.h \
+ plugin_macos.c \
+ plugin_macos.h \
macos_sysctl.c \
macos_mach_smi.c \
macos_fw.c \
@@ -91,8 +159,10 @@ netdata_SOURCES += \
else
netdata_SOURCES += \
ipc.c ipc.h \
- plugin_proc.c plugin_proc.h \
- plugin_proc_diskspace.c plugin_proc_diskspace.h \
+ plugin_proc.c \
+ plugin_proc.h \
+ plugin_proc_diskspace.c \
+ plugin_proc_diskspace.h \
proc_diskstats.c \
proc_interrupts.c \
proc_softirqs.c \
@@ -135,19 +205,26 @@ apps_plugin_SOURCES = \
web_buffer.c web_buffer.h \
$(NULL)
-install-data-hook:
- if [ `id -u` == 0 ]; then \
- chown root '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- ( setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin' || \
- chmod 4755 '$(DESTDIR)$(pluginsdir)/apps.plugin' ); \
- else \
- echo; \
- echo "ATTENTION"; \
- echo; \
- echo "$(pluginsdir)/apps.plugin requires escalated capabilities:"; \
- echo "sudo chown root '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo; \
- fi
+if FREEBSD
+apps_plugin_SOURCES += \
+ plugin_freebsd.h \
+ $(NULL)
+endif
+
+apps_plugin_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_LIBCAP_LIBS) \
+ $(NULL)
+
+freeipmi_plugin_SOURCES = \
+ freeipmi_plugin.c \
+ clocks.c clocks.h \
+ common.c common.h \
+ inlined.h \
+ log.c log.h \
+ procfile.c procfile.h \
+ $(NULL)
+
+freeipmi_plugin_LDADD = \
+ $(OPTIONAL_IPMIMONITORING_LIBS) \
+ $(NULL)
diff --git a/src/Makefile.in b/src/Makefile.in
index f94646363..d7229d18a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,61 +17,6 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,23 +36,29 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = netdata$(EXEEXT)
-@MACOS_FALSE@plugins_PROGRAMS = apps.plugin$(EXEEXT)
-@FREEBSD_TRUE@am__append_1 = \
-@FREEBSD_TRUE@ plugin_freebsd.c plugin_freebsd.h \
+plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
+@ENABLE_PLUGIN_APPS_TRUE@am__append_1 = apps.plugin
+@ENABLE_PLUGIN_FREEIPMI_TRUE@am__append_2 = freeipmi.plugin
+@FREEBSD_TRUE@am__append_3 = \
+@FREEBSD_TRUE@ plugin_freebsd.c \
+@FREEBSD_TRUE@ plugin_freebsd.h \
@FREEBSD_TRUE@ freebsd_sysctl.c \
@FREEBSD_TRUE@ $(NULL)
-@FREEBSD_FALSE@@MACOS_TRUE@am__append_2 = \
-@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.c plugin_macos.h \
+@FREEBSD_FALSE@@MACOS_TRUE@am__append_4 = \
+@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.c \
+@FREEBSD_FALSE@@MACOS_TRUE@ plugin_macos.h \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_sysctl.c \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_mach_smi.c \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_fw.c \
@FREEBSD_FALSE@@MACOS_TRUE@ $(NULL)
-@FREEBSD_FALSE@@MACOS_FALSE@am__append_3 = \
+@FREEBSD_FALSE@@MACOS_FALSE@am__append_5 = \
@FREEBSD_FALSE@@MACOS_FALSE@ ipc.c ipc.h \
-@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.c plugin_proc.h \
-@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.c plugin_proc_diskspace.h \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.c \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.h \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.c \
+@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.h \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_diskstats.c \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_interrupts.c \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_softirqs.c \
@@ -129,10 +81,17 @@ sbin_PROGRAMS = netdata$(EXEEXT)
@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.c \
@FREEBSD_FALSE@@MACOS_FALSE@ $(NULL)
+@FREEBSD_TRUE@am__append_6 = \
+@FREEBSD_TRUE@ plugin_freebsd.h \
+@FREEBSD_TRUE@ $(NULL)
+
subdir = src
+DIST_COMMON = $(dist_cache_DATA) $(dist_log_DATA) \
+ $(dist_registry_DATA) $(dist_varlib_DATA) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -141,43 +100,56 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_cache_DATA) \
- $(dist_log_DATA) $(dist_registry_DATA) $(dist_varlib_DATA) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
+@ENABLE_PLUGIN_APPS_TRUE@am__EXEEXT_1 = apps.plugin$(EXEEXT)
+@ENABLE_PLUGIN_FREEIPMI_TRUE@am__EXEEXT_2 = freeipmi.plugin$(EXEEXT)
am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" \
"$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)" \
"$(DESTDIR)$(registrydir)" "$(DESTDIR)$(varlibdir)"
PROGRAMS = $(plugins_PROGRAMS) $(sbin_PROGRAMS)
+am__apps_plugin_SOURCES_DIST = apps_plugin.c avl.c avl.h clocks.c \
+ clocks.h common.c common.h inlined.h log.c log.h procfile.c \
+ procfile.h web_buffer.c web_buffer.h plugin_freebsd.h
+am__objects_1 =
am_apps_plugin_OBJECTS = apps_plugin.$(OBJEXT) avl.$(OBJEXT) \
clocks.$(OBJEXT) common.$(OBJEXT) log.$(OBJEXT) \
- procfile.$(OBJEXT) web_buffer.$(OBJEXT)
+ procfile.$(OBJEXT) web_buffer.$(OBJEXT) $(am__objects_1)
apps_plugin_OBJECTS = $(am_apps_plugin_OBJECTS)
-apps_plugin_LDADD = $(LDADD)
-am__netdata_SOURCES_DIST = appconfig.c appconfig.h \
- adaptive_resortable_list.c adaptive_resortable_list.h avl.c \
- avl.h backends.c backends.h clocks.c clocks.h common.c \
- common.h daemon.c daemon.h dictionary.c dictionary.h eval.c \
- eval.h global_statistics.c global_statistics.h health.c \
- health.h inlined.h log.c log.h main.c main.h plugin_checks.c \
- plugin_checks.h plugin_idlejitter.c plugin_idlejitter.h \
- plugin_nfacct.c plugin_nfacct.h plugin_tc.c plugin_tc.h \
- plugins_d.c plugins_d.h popen.c popen.h socket.c socket.h \
- simple_pattern.c simple_pattern.h sys_fs_cgroup.c \
- sys_devices_system_edac_mc.c sys_devices_system_node.c \
- procfile.c procfile.h proc_self_mountinfo.c \
- proc_self_mountinfo.h registry.c registry.h \
- registry_internals.c registry_internals.h registry_url.c \
- registry_url.h registry_person.c registry_person.h \
- registry_machine.c registry_machine.h registry_init.c \
- registry_db.c registry_log.c rrd.c rrd.h rrd2json.c rrd2json.h \
- storage_number.c storage_number.h unit_test.c unit_test.h \
- url.c url.h web_buffer.c web_buffer.h web_buffer_svg.c \
- web_buffer_svg.h web_client.c web_client.h web_server.c \
- web_server.h plugin_freebsd.c plugin_freebsd.h \
+am__DEPENDENCIES_1 =
+apps_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_freeipmi_plugin_OBJECTS = freeipmi_plugin.$(OBJEXT) \
+ clocks.$(OBJEXT) common.$(OBJEXT) log.$(OBJEXT) \
+ procfile.$(OBJEXT)
+freeipmi_plugin_OBJECTS = $(am_freeipmi_plugin_OBJECTS)
+freeipmi_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__netdata_SOURCES_DIST = adaptive_resortable_list.c \
+ adaptive_resortable_list.h appconfig.c appconfig.h avl.c avl.h \
+ backends.c backends.h clocks.c clocks.h common.c common.h \
+ daemon.c daemon.h dictionary.c dictionary.h eval.c eval.h \
+ global_statistics.c global_statistics.h health.c health.h \
+ health_config.c health_json.c health_log.c inlined.h locks.h \
+ log.c log.h main.c main.h plugin_checks.c plugin_checks.h \
+ plugin_idlejitter.c plugin_idlejitter.h plugin_nfacct.c \
+ plugin_nfacct.h plugin_tc.c plugin_tc.h plugins_d.c \
+ plugins_d.h popen.c popen.h proc_self_mountinfo.c \
+ proc_self_mountinfo.h procfile.c procfile.h registry.c \
+ registry.h registry_db.c registry_init.c registry_internals.c \
+ registry_internals.h registry_log.c registry_machine.c \
+ registry_machine.h registry_person.c registry_person.h \
+ registry_url.c registry_url.h rrd.c rrd.h rrd2json.c \
+ rrd2json.h rrd2json_api_old.c rrd2json_api_old.h rrdcalc.c \
+ rrdcalctemplate.c rrddim.c rrddimvar.c rrdfamily.c rrdhost.c \
+ rrdpush.c rrdpush.h rrdset.c rrdsetvar.c rrdvar.c \
+ simple_pattern.c simple_pattern.h socket.c socket.h \
+ storage_number.c storage_number.h sys_devices_system_edac_mc.c \
+ sys_devices_system_node.c sys_fs_cgroup.c unit_test.c \
+ unit_test.h url.c url.h web_api_old.c web_api_old.h \
+ web_api_v1.c web_api_v1.h web_buffer.c web_buffer.h \
+ web_buffer_svg.c web_buffer_svg.h web_client.c web_client.h \
+ web_server.c web_server.h plugin_freebsd.c plugin_freebsd.h \
freebsd_sysctl.c plugin_macos.c plugin_macos.h macos_sysctl.c \
macos_mach_smi.c macos_fw.c ipc.c ipc.h plugin_proc.c \
plugin_proc.h plugin_proc_diskspace.c plugin_proc_diskspace.h \
@@ -189,13 +161,13 @@ am__netdata_SOURCES_DIST = appconfig.c appconfig.h \
proc_net_stat_synproxy.c proc_stat.c \
proc_sys_kernel_random_entropy_avail.c proc_vmstat.c \
proc_uptime.c sys_kernel_mm_ksm.c
-@FREEBSD_TRUE@am__objects_1 = plugin_freebsd.$(OBJEXT) \
+@FREEBSD_TRUE@am__objects_2 = plugin_freebsd.$(OBJEXT) \
@FREEBSD_TRUE@ freebsd_sysctl.$(OBJEXT)
-@FREEBSD_FALSE@@MACOS_TRUE@am__objects_2 = plugin_macos.$(OBJEXT) \
+@FREEBSD_FALSE@@MACOS_TRUE@am__objects_3 = plugin_macos.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_sysctl.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_mach_smi.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_TRUE@ macos_fw.$(OBJEXT)
-@FREEBSD_FALSE@@MACOS_FALSE@am__objects_3 = ipc.$(OBJEXT) \
+@FREEBSD_FALSE@@MACOS_FALSE@am__objects_4 = ipc.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_diskstats.$(OBJEXT) \
@@ -218,65 +190,48 @@ am__netdata_SOURCES_DIST = appconfig.c appconfig.h \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_vmstat.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ proc_uptime.$(OBJEXT) \
@FREEBSD_FALSE@@MACOS_FALSE@ sys_kernel_mm_ksm.$(OBJEXT)
-am_netdata_OBJECTS = appconfig.$(OBJEXT) \
- adaptive_resortable_list.$(OBJEXT) avl.$(OBJEXT) \
- backends.$(OBJEXT) clocks.$(OBJEXT) common.$(OBJEXT) \
- daemon.$(OBJEXT) dictionary.$(OBJEXT) eval.$(OBJEXT) \
- global_statistics.$(OBJEXT) health.$(OBJEXT) log.$(OBJEXT) \
- main.$(OBJEXT) plugin_checks.$(OBJEXT) \
- plugin_idlejitter.$(OBJEXT) plugin_nfacct.$(OBJEXT) \
- plugin_tc.$(OBJEXT) plugins_d.$(OBJEXT) popen.$(OBJEXT) \
- socket.$(OBJEXT) simple_pattern.$(OBJEXT) \
- sys_fs_cgroup.$(OBJEXT) sys_devices_system_edac_mc.$(OBJEXT) \
- sys_devices_system_node.$(OBJEXT) procfile.$(OBJEXT) \
- proc_self_mountinfo.$(OBJEXT) registry.$(OBJEXT) \
- registry_internals.$(OBJEXT) registry_url.$(OBJEXT) \
- registry_person.$(OBJEXT) registry_machine.$(OBJEXT) \
- registry_init.$(OBJEXT) registry_db.$(OBJEXT) \
- registry_log.$(OBJEXT) rrd.$(OBJEXT) rrd2json.$(OBJEXT) \
- storage_number.$(OBJEXT) unit_test.$(OBJEXT) url.$(OBJEXT) \
- web_buffer.$(OBJEXT) web_buffer_svg.$(OBJEXT) \
- web_client.$(OBJEXT) web_server.$(OBJEXT) $(am__objects_1) \
- $(am__objects_2) $(am__objects_3)
+am_netdata_OBJECTS = adaptive_resortable_list.$(OBJEXT) \
+ appconfig.$(OBJEXT) avl.$(OBJEXT) backends.$(OBJEXT) \
+ clocks.$(OBJEXT) common.$(OBJEXT) daemon.$(OBJEXT) \
+ dictionary.$(OBJEXT) eval.$(OBJEXT) \
+ global_statistics.$(OBJEXT) health.$(OBJEXT) \
+ health_config.$(OBJEXT) health_json.$(OBJEXT) \
+ health_log.$(OBJEXT) log.$(OBJEXT) main.$(OBJEXT) \
+ plugin_checks.$(OBJEXT) plugin_idlejitter.$(OBJEXT) \
+ plugin_nfacct.$(OBJEXT) plugin_tc.$(OBJEXT) \
+ plugins_d.$(OBJEXT) popen.$(OBJEXT) \
+ proc_self_mountinfo.$(OBJEXT) procfile.$(OBJEXT) \
+ registry.$(OBJEXT) registry_db.$(OBJEXT) \
+ registry_init.$(OBJEXT) registry_internals.$(OBJEXT) \
+ registry_log.$(OBJEXT) registry_machine.$(OBJEXT) \
+ registry_person.$(OBJEXT) registry_url.$(OBJEXT) rrd.$(OBJEXT) \
+ rrd2json.$(OBJEXT) rrd2json_api_old.$(OBJEXT) \
+ rrdcalc.$(OBJEXT) rrdcalctemplate.$(OBJEXT) rrddim.$(OBJEXT) \
+ rrddimvar.$(OBJEXT) rrdfamily.$(OBJEXT) rrdhost.$(OBJEXT) \
+ rrdpush.$(OBJEXT) rrdset.$(OBJEXT) rrdsetvar.$(OBJEXT) \
+ rrdvar.$(OBJEXT) simple_pattern.$(OBJEXT) socket.$(OBJEXT) \
+ storage_number.$(OBJEXT) sys_devices_system_edac_mc.$(OBJEXT) \
+ sys_devices_system_node.$(OBJEXT) sys_fs_cgroup.$(OBJEXT) \
+ unit_test.$(OBJEXT) url.$(OBJEXT) web_api_old.$(OBJEXT) \
+ web_api_v1.$(OBJEXT) web_buffer.$(OBJEXT) \
+ web_buffer_svg.$(OBJEXT) web_client.$(OBJEXT) \
+ web_server.$(OBJEXT) $(am__objects_2) $(am__objects_3) \
+ $(am__objects_4)
netdata_OBJECTS = $(am_netdata_OBJECTS)
-am__DEPENDENCIES_1 =
netdata_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo " GEN " $@;
-am__v_GEN_1 =
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-AM_V_CC = $(am__v_CC_@AM_V@)
-am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
-am__v_CC_0 = @echo " CC " $@;
-am__v_CC_1 =
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_CCLD = $(am__v_CCLD_@AM_V@)
-am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
-am__v_CCLD_0 = @echo " CCLD " $@;
-am__v_CCLD_1 =
-SOURCES = $(apps_plugin_SOURCES) $(netdata_SOURCES)
-DIST_SOURCES = $(apps_plugin_SOURCES) $(am__netdata_SOURCES_DIST)
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
+SOURCES = $(apps_plugin_SOURCES) $(freeipmi_plugin_SOURCES) \
+ $(netdata_SOURCES)
+DIST_SOURCES = $(am__apps_plugin_SOURCES_DIST) \
+ $(freeipmi_plugin_SOURCES) $(am__netdata_SOURCES_DIST)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -306,30 +261,11 @@ am__uninstall_files_from_dir = { \
}
DATA = $(dist_cache_DATA) $(dist_log_DATA) $(dist_registry_DATA) \
$(dist_varlib_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates. Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
- BEGIN { nonempty = 0; } \
- { items[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique. This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
- list='$(am__tagged_files)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -353,7 +289,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -367,6 +307,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -483,33 +427,40 @@ AM_CFLAGS = \
$(OPTIONAL_NFACCT_CLFAGS) \
$(OPTIONAL_ZLIB_CFLAGS) \
$(OPTIONAL_UUID_CFLAGS) \
+ $(OPTIONAL_LIBCAP_CFLAGS) \
+ $(OPTIONAL_IPMIMONITORING_CFLAGS)\
$(NULL)
dist_cache_DATA = .keep
dist_varlib_DATA = .keep
dist_registry_DATA = .keep
dist_log_DATA = .keep
-netdata_SOURCES = appconfig.c appconfig.h adaptive_resortable_list.c \
- adaptive_resortable_list.h avl.c avl.h backends.c backends.h \
- clocks.c clocks.h common.c common.h daemon.c daemon.h \
- dictionary.c dictionary.h eval.c eval.h global_statistics.c \
- global_statistics.h health.c health.h inlined.h log.c log.h \
- main.c main.h plugin_checks.c plugin_checks.h \
+netdata_SOURCES = adaptive_resortable_list.c \
+ adaptive_resortable_list.h appconfig.c appconfig.h avl.c avl.h \
+ backends.c backends.h clocks.c clocks.h common.c common.h \
+ daemon.c daemon.h dictionary.c dictionary.h eval.c eval.h \
+ global_statistics.c global_statistics.h health.c health.h \
+ health_config.c health_json.c health_log.c inlined.h locks.h \
+ log.c log.h main.c main.h plugin_checks.c plugin_checks.h \
plugin_idlejitter.c plugin_idlejitter.h plugin_nfacct.c \
plugin_nfacct.h plugin_tc.c plugin_tc.h plugins_d.c \
- plugins_d.h popen.c popen.h socket.c socket.h simple_pattern.c \
- simple_pattern.h sys_fs_cgroup.c sys_devices_system_edac_mc.c \
- sys_devices_system_node.c procfile.c procfile.h \
- proc_self_mountinfo.c proc_self_mountinfo.h registry.c \
- registry.h registry_internals.c registry_internals.h \
- registry_url.c registry_url.h registry_person.c \
- registry_person.h registry_machine.c registry_machine.h \
- registry_init.c registry_db.c registry_log.c rrd.c rrd.h \
- rrd2json.c rrd2json.h storage_number.c storage_number.h \
- unit_test.c unit_test.h url.c url.h web_buffer.c web_buffer.h \
+ plugins_d.h popen.c popen.h proc_self_mountinfo.c \
+ proc_self_mountinfo.h procfile.c procfile.h registry.c \
+ registry.h registry_db.c registry_init.c registry_internals.c \
+ registry_internals.h registry_log.c registry_machine.c \
+ registry_machine.h registry_person.c registry_person.h \
+ registry_url.c registry_url.h rrd.c rrd.h rrd2json.c \
+ rrd2json.h rrd2json_api_old.c rrd2json_api_old.h rrdcalc.c \
+ rrdcalctemplate.c rrddim.c rrddimvar.c rrdfamily.c rrdhost.c \
+ rrdpush.c rrdpush.h rrdset.c rrdsetvar.c rrdvar.c \
+ simple_pattern.c simple_pattern.h socket.c socket.h \
+ storage_number.c storage_number.h sys_devices_system_edac_mc.c \
+ sys_devices_system_node.c sys_fs_cgroup.c unit_test.c \
+ unit_test.h url.c url.h web_api_old.c web_api_old.h \
+ web_api_v1.c web_api_v1.h web_buffer.c web_buffer.h \
web_buffer_svg.c web_buffer_svg.h web_client.c web_client.h \
- web_server.c web_server.h $(NULL) $(am__append_1) \
- $(am__append_2) $(am__append_3)
+ web_server.c web_server.h $(NULL) $(am__append_3) \
+ $(am__append_4) $(am__append_5)
netdata_LDADD = \
$(OPTIONAL_MATH_LIBS) \
$(OPTIONAL_NFACCT_LIBS) \
@@ -517,15 +468,25 @@ netdata_LDADD = \
$(OPTIONAL_UUID_LIBS) \
$(NULL)
-apps_plugin_SOURCES = \
- apps_plugin.c \
- avl.c avl.h \
+apps_plugin_SOURCES = apps_plugin.c avl.c avl.h clocks.c clocks.h \
+ common.c common.h inlined.h log.c log.h procfile.c procfile.h \
+ web_buffer.c web_buffer.h $(NULL) $(am__append_6)
+apps_plugin_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_LIBCAP_LIBS) \
+ $(NULL)
+
+freeipmi_plugin_SOURCES = \
+ freeipmi_plugin.c \
clocks.c clocks.h \
common.c common.h \
inlined.h \
log.c log.h \
procfile.c procfile.h \
- web_buffer.c web_buffer.h \
+ $(NULL)
+
+freeipmi_plugin_LDADD = \
+ $(OPTIONAL_IPMIMONITORING_LIBS) \
$(NULL)
all: all-am
@@ -544,6 +505,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -563,18 +525,14 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-pluginsPROGRAMS: $(plugins_PROGRAMS)
@$(NORMAL_INSTALL)
+ test -z "$(pluginsdir)" || $(MKDIR_P) "$(DESTDIR)$(pluginsdir)"
@list='$(plugins_PROGRAMS)'; test -n "$(pluginsdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(pluginsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(pluginsdir)" || exit 1; \
- fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
- while read p p1; do if test -f $$p \
- ; then echo "$$p"; echo "$$p"; else :; fi; \
+ while read p p1; do if test -f $$p; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
done | \
- sed -e 'p;s,.*/,,;n;h' \
- -e 's|.*|.|' \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
@@ -595,8 +553,7 @@ uninstall-pluginsPROGRAMS:
@list='$(plugins_PROGRAMS)'; test -n "$(pluginsdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
- -e 's/$$/$(EXEEXT)/' \
- `; \
+ -e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pluginsdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pluginsdir)" && rm -f $$files
@@ -605,18 +562,14 @@ clean-pluginsPROGRAMS:
-test -z "$(plugins_PROGRAMS)" || rm -f $(plugins_PROGRAMS)
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
- fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
- while read p p1; do if test -f $$p \
- ; then echo "$$p"; echo "$$p"; else :; fi; \
+ while read p p1; do if test -f $$p; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
done | \
- sed -e 'p;s,.*/,,;n;h' \
- -e 's|.*|.|' \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
@@ -637,22 +590,22 @@ uninstall-sbinPROGRAMS:
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
- -e 's/$$/$(EXEEXT)/' \
- `; \
+ -e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(sbindir)" && rm -f $$files
clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
-
apps.plugin$(EXEEXT): $(apps_plugin_OBJECTS) $(apps_plugin_DEPENDENCIES) $(EXTRA_apps_plugin_DEPENDENCIES)
@rm -f apps.plugin$(EXEEXT)
- $(AM_V_CCLD)$(LINK) $(apps_plugin_OBJECTS) $(apps_plugin_LDADD) $(LIBS)
-
+ $(LINK) $(apps_plugin_OBJECTS) $(apps_plugin_LDADD) $(LIBS)
+freeipmi.plugin$(EXEEXT): $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_DEPENDENCIES) $(EXTRA_freeipmi_plugin_DEPENDENCIES)
+ @rm -f freeipmi.plugin$(EXEEXT)
+ $(LINK) $(freeipmi_plugin_OBJECTS) $(freeipmi_plugin_LDADD) $(LIBS)
netdata$(EXEEXT): $(netdata_OBJECTS) $(netdata_DEPENDENCIES) $(EXTRA_netdata_DEPENDENCIES)
@rm -f netdata$(EXEEXT)
- $(AM_V_CCLD)$(LINK) $(netdata_OBJECTS) $(netdata_LDADD) $(LIBS)
+ $(LINK) $(netdata_OBJECTS) $(netdata_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -671,8 +624,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dictionary.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebsd_sysctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freeipmi_plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global_statistics.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health_json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/health_log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macos_fw.Po@am__quote@
@@ -720,6 +677,17 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry_url.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd2json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd2json_api_old.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdcalc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdcalctemplate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrddim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrddimvar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdfamily.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdhost.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdpush.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdset.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdsetvar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrdvar.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_pattern.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_number.Po@am__quote@
@@ -729,31 +697,30 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_kernel_mm_ksm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_api_old.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_api_v1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_buffer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_buffer_svg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_client.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_server.Po@am__quote@
.c.o:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
install-dist_cacheDATA: $(dist_cache_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(cachedir)" || $(MKDIR_P) "$(DESTDIR)$(cachedir)"
@list='$(dist_cache_DATA)'; test -n "$(cachedir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(cachedir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(cachedir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -770,11 +737,8 @@ uninstall-dist_cacheDATA:
dir='$(DESTDIR)$(cachedir)'; $(am__uninstall_files_from_dir)
install-dist_logDATA: $(dist_log_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(logdir)" || $(MKDIR_P) "$(DESTDIR)$(logdir)"
@list='$(dist_log_DATA)'; test -n "$(logdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(logdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(logdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -791,11 +755,8 @@ uninstall-dist_logDATA:
dir='$(DESTDIR)$(logdir)'; $(am__uninstall_files_from_dir)
install-dist_registryDATA: $(dist_registry_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(registrydir)" || $(MKDIR_P) "$(DESTDIR)$(registrydir)"
@list='$(dist_registry_DATA)'; test -n "$(registrydir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(registrydir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(registrydir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -812,11 +773,8 @@ uninstall-dist_registryDATA:
dir='$(DESTDIR)$(registrydir)'; $(am__uninstall_files_from_dir)
install-dist_varlibDATA: $(dist_varlib_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(varlibdir)" || $(MKDIR_P) "$(DESTDIR)$(varlibdir)"
@list='$(dist_varlib_DATA)'; test -n "$(varlibdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(varlibdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(varlibdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -832,15 +790,26 @@ uninstall-dist_varlibDATA:
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(varlibdir)'; $(am__uninstall_files_from_dir)
-ID: $(am__tagged_files)
- $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
- $(am__define_uniq_tagged_files); \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
@@ -852,11 +821,15 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$$unique; \
fi; \
fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
- $(am__define_uniq_tagged_files); \
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
@@ -865,21 +838,6 @@ GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
- list='$(am__tagged_files)'; \
- case "$(srcdir)" in \
- [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
- *) sdir=$(subdir)/$(srcdir) ;; \
- esac; \
- for i in $$list; do \
- if test -f "$$i"; then \
- echo "$(subdir)/$$i"; \
- else \
- echo "$$sdir/$$i"; \
- fi; \
- done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
@@ -978,8 +936,7 @@ info-am:
install-data-am: install-dist_cacheDATA install-dist_logDATA \
install-dist_registryDATA install-dist_varlibDATA \
install-pluginsPROGRAMS
- @$(NORMAL_INSTALL)
- $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+
install-dvi: install-dvi-am
install-dvi-am:
@@ -1027,45 +984,26 @@ uninstall-am: uninstall-dist_cacheDATA uninstall-dist_logDATA \
uninstall-dist_registryDATA uninstall-dist_varlibDATA \
uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS
-.MAKE: install-am install-data-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
- clean-pluginsPROGRAMS clean-sbinPROGRAMS cscopelist-am ctags \
- ctags-am distclean distclean-compile distclean-generic \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am \
- install-data-hook install-dist_cacheDATA install-dist_logDATA \
- install-dist_registryDATA install-dist_varlibDATA install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-pluginsPROGRAMS install-ps \
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-pluginsPROGRAMS clean-sbinPROGRAMS ctags distclean \
+ distclean-compile distclean-generic distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_cacheDATA \
+ install-dist_logDATA install-dist_registryDATA \
+ install-dist_varlibDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pluginsPROGRAMS install-ps \
install-ps-am install-sbinPROGRAMS install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
- mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am uninstall-dist_cacheDATA uninstall-dist_logDATA \
uninstall-dist_registryDATA uninstall-dist_varlibDATA \
uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS
-.PRECIOUS: Makefile
-
-
-install-data-hook:
- if [ `id -u` == 0 ]; then \
- chown root '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
- ( setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin' || \
- chmod 4755 '$(DESTDIR)$(pluginsdir)/apps.plugin' ); \
- else \
- echo; \
- echo "ATTENTION"; \
- echo; \
- echo "$(pluginsdir)/apps.plugin requires escalated capabilities:"; \
- echo "sudo chown root '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo chmod 0755 '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo "sudo setcap cap_dac_read_search,cap_sys_ptrace+ep '$(DESTDIR)$(pluginsdir)/apps.plugin'"; \
- echo; \
- fi
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/adaptive_resortable_list.c b/src/adaptive_resortable_list.c
index a37c396fa..f74c53eae 100644
--- a/src/adaptive_resortable_list.c
+++ b/src/adaptive_resortable_list.c
@@ -52,7 +52,6 @@ void arl_free(ARL_BASE *arl_base) {
}
void arl_begin(ARL_BASE *base) {
- ARL_ENTRY *e;
#ifdef NETDATA_INTERNAL_CHECKS
if(likely(base->iteration > 10)) {
@@ -66,6 +65,7 @@ void arl_begin(ARL_BASE *base) {
info("ARL '%s' has %zu fast searches and %zu slow searches. Is the source really changing so fast?"
, base->name, base->fast, base->slow);
+ /*
if(unlikely(base->iteration % 60 == 0)) {
info("ARL '%s' statistics: iteration %zu, expected %zu, wanted %zu, allocated %zu, fred %zu, relinkings %zu, found %zu, added %zu, fast %zu, slow %zu"
, base->name
@@ -83,13 +83,15 @@ void arl_begin(ARL_BASE *base) {
// for(e = base->head; e; e = e->next) fprintf(stderr, "%s ", e->name);
// fprintf(stderr, "\n");
}
+ */
}
#endif
if(unlikely(base->added || base->iteration % base->rechecks) == 1) {
base->added = 0;
base->wanted = 0;
- for(e = base->head; e ; e = e->next) {
+ ARL_ENTRY *e = base->head;
+ while(e) {
if(e->flags & ARL_ENTRY_FLAG_FOUND) {
// remove the found flag
@@ -98,25 +100,48 @@ void arl_begin(ARL_BASE *base) {
// count it in wanted
if(e->flags & ARL_ENTRY_FLAG_EXPECTED)
base->wanted++;
+
}
- else if(e->flags & ARL_ENTRY_FLAG_DYNAMIC) {
+ else if(e->flags & ARL_ENTRY_FLAG_DYNAMIC && !(base->head == e && !e->next)) { // not last entry
// we can remove this entry
// it is not found, and it was created because
// it was found in the source file
+
+ // remember the next one
+ ARL_ENTRY *t = e->next;
+
+ // remove it from the list
if(e->next) e->next->prev = e->prev;
if(e->prev) e->prev->next = e->next;
if(base->head == e) base->head = e->next;
+
+ // free it
freez(e->name);
freez(e);
+ // count it
base->fred++;
+
+ // continue
+ e = t;
+ continue;
}
+
+ e = e->next;
}
}
+ if(unlikely(!base->head)) {
+ // hm... no nodes at all in the list #1700
+ // add a fake one to prevent a crash
+ // this is better than checking for the existence of nodes all the time
+ arl_expect(base, "a-really-not-existing-source-keyword", NULL);
+ }
+
base->iteration++;
base->next_keyword = base->head;
base->found = 0;
+
}
// register an expected keyword to the ARL
@@ -153,7 +178,7 @@ int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *val
break;
#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(e == base->next_keyword))
+ if(unlikely(base->next_keyword && e == base->next_keyword))
fatal("Internal Error: e == base->last");
#endif
@@ -208,9 +233,14 @@ int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *val
if(base->head == base->next_keyword)
base->head = e;
}
- else
+ else {
e->prev = NULL;
+ if(!base->head)
+ base->head = e;
+ }
+
+ // prepare the next iteration
base->next_keyword = e->next;
if(unlikely(!base->next_keyword))
base->next_keyword = base->head;
diff --git a/src/appconfig.c b/src/appconfig.c
index 81ab01be2..71ff4b75e 100644
--- a/src/appconfig.c
+++ b/src/appconfig.c
@@ -2,8 +2,6 @@
#define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2)
-pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
-
// ----------------------------------------------------------------------------
// definitions
@@ -12,7 +10,7 @@ pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
#define CONFIG_VALUE_CHANGED 0x04 // has been changed from the loaded value
#define CONFIG_VALUE_CHECKED 0x08 // has been checked if the value is different from the default
-struct config_value {
+struct config_option {
avl avl; // the index - this has to be first!
uint8_t flags;
@@ -22,10 +20,10 @@ struct config_value {
char *name;
char *value;
- struct config_value *next; // config->mutex protects just this
+ struct config_option *next; // config->mutex protects just this
};
-struct config {
+struct section {
avl avl;
uint32_t hash; // a simple hash to speed up searching
@@ -33,111 +31,124 @@ struct config {
char *name;
- struct config *next; // gloabl config_mutex protects just this
+ struct section *next; // gloabl config_mutex protects just this
- struct config_value *values;
+ struct config_option *values;
avl_tree_lock values_index;
- pthread_mutex_t mutex; // this locks only the writers, to ensure atomic updates
+ netdata_mutex_t mutex; // this locks only the writers, to ensure atomic updates
// readers are protected using the rwlock in avl_tree_lock
-} *config_root = NULL;
+};
+
+static int appconfig_section_compare(void *a, void *b);
+
+struct config netdata_config = {
+ .sections = NULL,
+ .mutex = NETDATA_MUTEX_INITIALIZER,
+ .index = {
+ { NULL, appconfig_section_compare },
+ AVL_LOCK_INITIALIZER
+ }
+};
+struct config stream_config = {
+ .sections = NULL,
+ .mutex = NETDATA_MUTEX_INITIALIZER,
+ .index = {
+ { NULL, appconfig_section_compare },
+ AVL_LOCK_INITIALIZER
+ }
+};
// ----------------------------------------------------------------------------
// locking
-static inline void config_global_write_lock(void) {
- pthread_mutex_lock(&config_mutex);
+static inline void appconfig_wrlock(struct config *root) {
+ netdata_mutex_lock(&root->mutex);
}
-static inline void config_global_unlock(void) {
- pthread_mutex_unlock(&config_mutex);
+static inline void appconfig_unlock(struct config *root) {
+ netdata_mutex_unlock(&root->mutex);
}
-static inline void config_section_write_lock(struct config *co) {
- pthread_mutex_lock(&co->mutex);
+static inline void config_section_wrlock(struct section *co) {
+ netdata_mutex_lock(&co->mutex);
}
-static inline void config_section_unlock(struct config *co) {
- pthread_mutex_unlock(&co->mutex);
+static inline void config_section_unlock(struct section *co) {
+ netdata_mutex_unlock(&co->mutex);
}
// ----------------------------------------------------------------------------
// config name-value index
-static int config_value_compare(void* a, void* b) {
- if(((struct config_value *)a)->hash < ((struct config_value *)b)->hash) return -1;
- else if(((struct config_value *)a)->hash > ((struct config_value *)b)->hash) return 1;
- else return strcmp(((struct config_value *)a)->name, ((struct config_value *)b)->name);
+static int appconfig_option_compare(void *a, void *b) {
+ if(((struct config_option *)a)->hash < ((struct config_option *)b)->hash) return -1;
+ else if(((struct config_option *)a)->hash > ((struct config_option *)b)->hash) return 1;
+ else return strcmp(((struct config_option *)a)->name, ((struct config_option *)b)->name);
}
-#define config_value_index_add(co, cv) (struct config_value *)avl_insert_lock(&((co)->values_index), (avl *)(cv))
-#define config_value_index_del(co, cv) (struct config_value *)avl_remove_lock(&((co)->values_index), (avl *)(cv))
+#define appconfig_option_index_add(co, cv) (struct config_option *)avl_insert_lock(&((co)->values_index), (avl *)(cv))
+#define appconfig_option_index_del(co, cv) (struct config_option *)avl_remove_lock(&((co)->values_index), (avl *)(cv))
-static struct config_value *config_value_index_find(struct config *co, const char *name, uint32_t hash) {
- struct config_value tmp;
+static struct config_option *appconfig_option_index_find(struct section *co, const char *name, uint32_t hash) {
+ struct config_option tmp;
tmp.hash = (hash)?hash:simple_hash(name);
tmp.name = (char *)name;
- return (struct config_value *)avl_search_lock(&(co->values_index), (avl *) &tmp);
+ return (struct config_option *)avl_search_lock(&(co->values_index), (avl *) &tmp);
}
// ----------------------------------------------------------------------------
// config sections index
-static int config_compare(void* a, void* b) {
- if(((struct config *)a)->hash < ((struct config *)b)->hash) return -1;
- else if(((struct config *)a)->hash > ((struct config *)b)->hash) return 1;
- else return strcmp(((struct config *)a)->name, ((struct config *)b)->name);
+static int appconfig_section_compare(void *a, void *b) {
+ if(((struct section *)a)->hash < ((struct section *)b)->hash) return -1;
+ else if(((struct section *)a)->hash > ((struct section *)b)->hash) return 1;
+ else return strcmp(((struct section *)a)->name, ((struct section *)b)->name);
}
-avl_tree_lock config_root_index = {
- { NULL, config_compare },
- AVL_LOCK_INITIALIZER
-};
-
-#define config_index_add(cfg) (struct config *)avl_insert_lock(&config_root_index, (avl *)(cfg))
-#define config_index_del(cfg) (struct config *)avl_remove_lock(&config_root_index, (avl *)(cfg))
+#define appconfig_index_add(root, cfg) (struct section *)avl_insert_lock(&root->index, (avl *)(cfg))
+#define appconfig_index_del(root, cfg) (struct section *)avl_remove_lock(&root->index, (avl *)(cfg))
-static struct config *config_index_find(const char *name, uint32_t hash) {
- struct config tmp;
+static struct section *appconfig_index_find(struct config *root, const char *name, uint32_t hash) {
+ struct section tmp;
tmp.hash = (hash)?hash:simple_hash(name);
tmp.name = (char *)name;
- return (struct config *)avl_search_lock(&config_root_index, (avl *) &tmp);
+ return (struct section *)avl_search_lock(&root->index, (avl *) &tmp);
}
// ----------------------------------------------------------------------------
// config section methods
-static inline struct config *config_section_find(const char *section) {
- return config_index_find(section, 0);
+static inline struct section *appconfig_section_find(struct config *root, const char *section) {
+ return appconfig_index_find(root, section, 0);
}
-static inline struct config *config_section_create(const char *section)
-{
+static inline struct section *appconfig_section_create(struct config *root, const char *section) {
debug(D_CONFIG, "Creating section '%s'.", section);
- struct config *co = callocz(1, sizeof(struct config));
+ struct section *co = callocz(1, sizeof(struct section));
co->name = strdupz(section);
co->hash = simple_hash(co->name);
- avl_init_lock(&co->values_index, config_value_compare);
+ avl_init_lock(&co->values_index, appconfig_option_compare);
- if(unlikely(config_index_add(co) != co))
+ if(unlikely(appconfig_index_add(root, co) != co))
error("INTERNAL ERROR: indexing of section '%s', already exists.", co->name);
- config_global_write_lock();
- struct config *co2 = config_root;
+ appconfig_wrlock(root);
+ struct section *co2 = root->sections;
if(co2) {
while (co2->next) co2 = co2->next;
co2->next = co;
}
- else config_root = co;
- config_global_unlock();
+ else root->sections = co;
+ appconfig_unlock(root);
return co;
}
@@ -146,20 +157,25 @@ static inline struct config *config_section_create(const char *section)
// ----------------------------------------------------------------------------
// config name-value methods
-static inline struct config_value *config_value_create(struct config *co, const char *name, const char *value)
-{
+static inline struct config_option *appconfig_value_create(struct section *co, const char *name, const char *value) {
debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
- struct config_value *cv = callocz(1, sizeof(struct config_value));
+ struct config_option *cv = callocz(1, sizeof(struct config_option));
cv->name = strdupz(name);
cv->hash = simple_hash(cv->name);
cv->value = strdupz(value);
- if(unlikely(config_value_index_add(co, cv) != cv))
- error("INTERNAL ERROR: indexing of config '%s' in section '%s': already exists.", cv->name, co->name);
+ struct config_option *found = appconfig_option_index_add(co, cv);
+ if(found != cv) {
+ error("indexing of config '%s' in section '%s': already exists - using the existing one.", cv->name, co->name);
+ freez(cv->value);
+ freez(cv->name);
+ freez(cv);
+ return found;
+ }
- config_section_write_lock(co);
- struct config_value *cv2 = co->values;
+ config_section_wrlock(co);
+ struct config_option *cv2 = co->values;
if(cv2) {
while (cv2->next) cv2 = cv2->next;
cv2->next = cv;
@@ -170,66 +186,87 @@ static inline struct config_value *config_value_create(struct config *co, const
return cv;
}
-int config_exists(const char *section, const char *name) {
- struct config_value *cv;
+int appconfig_exists(struct config *root, const char *section, const char *name) {
+ struct config_option *cv;
debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
- struct config *co = config_section_find(section);
+ struct section *co = appconfig_section_find(root, section);
if(!co) return 0;
- cv = config_value_index_find(co, name, 0);
+ cv = appconfig_option_index_find(co, name, 0);
if(!cv) return 0;
return 1;
}
-int config_rename(const char *section, const char *old, const char *new) {
- struct config_value *cv, *cv2;
+int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) {
+ struct config_option *cv_old, *cv_new;
+ int ret = -1;
- debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
+ debug(D_CONFIG, "request to rename config in section '%s', old name '%s', to section '%s', new name '%s'", section_old, name_old, section_new, name_new);
- struct config *co = config_section_find(section);
- if(!co) return -1;
+ struct section *co_old = appconfig_section_find(root, section_old);
+ if(!co_old) return ret;
- config_section_write_lock(co);
+ struct section *co_new = appconfig_section_find(root, section_new);
+ if(!co_new) co_new = appconfig_section_create(root, section_new);
- cv = config_value_index_find(co, old, 0);
- if(!cv) goto cleanup;
+ config_section_wrlock(co_old);
+ config_section_wrlock(co_new);
- cv2 = config_value_index_find(co, new, 0);
- if(cv2) goto cleanup;
+ cv_old = appconfig_option_index_find(co_old, name_old, 0);
+ if(!cv_old) goto cleanup;
- if(unlikely(config_value_index_del(co, cv) != cv))
- error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted tge wrong config entry.", cv->name, co->name);
+ cv_new = appconfig_option_index_find(co_new, name_new, 0);
+ if(cv_new) goto cleanup;
- freez(cv->name);
- cv->name = strdupz(new);
- cv->hash = simple_hash(cv->name);
- if(unlikely(config_value_index_add(co, cv) != cv))
- error("INTERNAL ERROR: indexing of config '%s' in section '%s', already exists.", cv->name, co->name);
+ if(unlikely(appconfig_option_index_del(co_old, cv_old) != cv_old))
+ error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted tge wrong config entry.", cv_old->name, co_old->name);
- config_section_unlock(co);
+ if(co_old->values == cv_old) {
+ co_old->values = cv_old->next;
+ }
+ else {
+ struct config_option *t;
+ for(t = co_old->values; t && t->next != cv_old ;t = t->next) ;
+ if(!t || t->next != cv_old)
+ error("INTERNAL ERROR: cannot find variable '%s' in section '%s' of the config - but it should be there.", cv_old->name, co_old->name);
+ else
+ t->next = cv_old->next;
+ }
- return 0;
+ freez(cv_old->name);
+ cv_old->name = strdupz(name_new);
+ cv_old->hash = simple_hash(cv_old->name);
+
+ cv_new = cv_old;
+ cv_new->next = co_new->values;
+ co_new->values = cv_new;
+
+ if(unlikely(appconfig_option_index_add(co_new, cv_old) != cv_old))
+ error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.", cv_old->name, co_new->name);
+
+ ret = 0;
cleanup:
- config_section_unlock(co);
- return -1;
+ config_section_unlock(co_new);
+ config_section_unlock(co_old);
+ return ret;
}
-char *config_get(const char *section, const char *name, const char *default_value)
+char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value)
{
- struct config_value *cv;
+ struct config_option *cv;
debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
- struct config *co = config_section_find(section);
- if(!co) co = config_section_create(section);
+ struct section *co = appconfig_section_find(root, section);
+ if(!co) co = appconfig_section_create(root, section);
- cv = config_value_index_find(co, name, 0);
+ cv = appconfig_option_index_find(co, name, 0);
if(!cv) {
- cv = config_value_create(co, name, default_value);
+ cv = appconfig_value_create(co, name, default_value);
if(!cv) return NULL;
}
cv->flags |= CONFIG_VALUE_USED;
@@ -246,67 +283,67 @@ char *config_get(const char *section, const char *name, const char *default_valu
return(cv->value);
}
-long long config_get_number(const char *section, const char *name, long long value)
+long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value)
{
char buffer[100], *s;
sprintf(buffer, "%lld", value);
- s = config_get(section, name, buffer);
+ s = appconfig_get(root, section, name, buffer);
if(!s) return value;
return strtoll(s, NULL, 0);
}
-int config_get_boolean(const char *section, const char *name, int value)
+int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value)
{
char *s;
if(value) s = "yes";
else s = "no";
- s = config_get(section, name, s);
+ s = appconfig_get(root, section, name, s);
if(!s) return value;
if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
return 0;
}
-int config_get_boolean_ondemand(const char *section, const char *name, int value)
+int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value)
{
char *s;
- if(value == CONFIG_ONDEMAND_ONDEMAND)
+ if(value == CONFIG_BOOLEAN_AUTO)
s = "auto";
- else if(value == CONFIG_ONDEMAND_NO)
+ else if(value == CONFIG_BOOLEAN_NO)
s = "no";
else
s = "yes";
- s = config_get(section, name, s);
+ s = appconfig_get(root, section, name, s);
if(!s) return value;
if(!strcmp(s, "yes"))
- return CONFIG_ONDEMAND_YES;
+ return CONFIG_BOOLEAN_YES;
else if(!strcmp(s, "no"))
- return CONFIG_ONDEMAND_NO;
+ return CONFIG_BOOLEAN_NO;
else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
- return CONFIG_ONDEMAND_ONDEMAND;
+ return CONFIG_BOOLEAN_AUTO;
return value;
}
-const char *config_set_default(const char *section, const char *name, const char *value)
+const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value)
{
- struct config_value *cv;
+ struct config_option *cv;
debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
- struct config *co = config_section_find(section);
- if(!co) return config_set(section, name, value);
+ struct section *co = appconfig_section_find(root, section);
+ if(!co) return appconfig_set(root, section, name, value);
- cv = config_value_index_find(co, name, 0);
- if(!cv) return config_set(section, name, value);
+ cv = appconfig_option_index_find(co, name, 0);
+ if(!cv) return appconfig_set(root, section, name, value);
cv->flags |= CONFIG_VALUE_USED;
@@ -323,17 +360,17 @@ const char *config_set_default(const char *section, const char *name, const char
return cv->value;
}
-const char *config_set(const char *section, const char *name, const char *value)
+const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value)
{
- struct config_value *cv;
+ struct config_option *cv;
debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
- struct config *co = config_section_find(section);
- if(!co) co = config_section_create(section);
+ struct section *co = appconfig_section_find(root, section);
+ if(!co) co = appconfig_section_create(root, section);
- cv = config_value_index_find(co, name, 0);
- if(!cv) cv = config_value_create(co, name, value);
+ cv = appconfig_option_index_find(co, name, 0);
+ if(!cv) cv = appconfig_value_create(co, name, value);
cv->flags |= CONFIG_VALUE_USED;
if(strcmp(cv->value, value) != 0) {
@@ -346,23 +383,23 @@ const char *config_set(const char *section, const char *name, const char *value)
return value;
}
-long long config_set_number(const char *section, const char *name, long long value)
+long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value)
{
char buffer[100];
sprintf(buffer, "%lld", value);
- config_set(section, name, buffer);
+ appconfig_set(root, section, name, buffer);
return value;
}
-int config_set_boolean(const char *section, const char *name, int value)
+int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value)
{
char *s;
if(value) s = "yes";
else s = "no";
- config_set(section, name, s);
+ appconfig_set(root, section, name, s);
return value;
}
@@ -371,10 +408,10 @@ int config_set_boolean(const char *section, const char *name, int value)
// ----------------------------------------------------------------------------
// config load/save
-int load_config(char *filename, int overwrite_used)
+int appconfig_load(struct config *root, char *filename, int overwrite_used)
{
int line = 0;
- struct config *co = NULL;
+ struct section *co = NULL;
char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
@@ -404,8 +441,8 @@ int load_config(char *filename, int overwrite_used)
s[len - 1] = '\0';
s++;
- co = config_section_find(s);
- if(!co) co = config_section_create(s);
+ co = appconfig_section_find(root, s);
+ if(!co) co = appconfig_section_create(root, s);
continue;
}
@@ -437,9 +474,9 @@ int load_config(char *filename, int overwrite_used)
continue;
}
- struct config_value *cv = config_value_index_find(co, name, 0);
+ struct config_option *cv = appconfig_option_index_find(co, name, 0);
- if(!cv) cv = config_value_create(co, name, value);
+ if(!cv) cv = appconfig_value_create(co, name, value);
else {
if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
@@ -457,11 +494,11 @@ int load_config(char *filename, int overwrite_used)
return 1;
}
-void generate_config(BUFFER *wb, int only_changed)
+void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
{
int i, pri;
- struct config *co;
- struct config_value *cv;
+ struct section *co;
+ struct config_option *cv;
for(i = 0; i < 3 ;i++) {
switch(i) {
@@ -490,13 +527,16 @@ void generate_config(BUFFER *wb, int only_changed)
break;
}
- config_global_write_lock();
- for(co = config_root; co ; co = co->next) {
- if(!strcmp(co->name, "global") ||
- !strcmp(co->name, "plugins") ||
- !strcmp(co->name, "registry") ||
- !strcmp(co->name, "health") ||
- !strcmp(co->name, "backend"))
+ appconfig_wrlock(root);
+ for(co = root->sections; co ; co = co->next) {
+ if(!strcmp(co->name, CONFIG_SECTION_GLOBAL)
+ || !strcmp(co->name, CONFIG_SECTION_WEB)
+ || !strcmp(co->name, CONFIG_SECTION_PLUGINS)
+ || !strcmp(co->name, CONFIG_SECTION_REGISTRY)
+ || !strcmp(co->name, CONFIG_SECTION_HEALTH)
+ || !strcmp(co->name, CONFIG_SECTION_BACKEND)
+ || !strcmp(co->name, CONFIG_SECTION_STREAM)
+ )
pri = 0;
else if(!strncmp(co->name, "plugin:", 7)) pri = 1;
else pri = 2;
@@ -506,7 +546,7 @@ void generate_config(BUFFER *wb, int only_changed)
int changed = 0;
int count = 0;
- config_section_write_lock(co);
+ config_section_wrlock(co);
for(cv = co->values; cv ; cv = cv->next) {
used += (cv->flags & CONFIG_VALUE_USED)?1:0;
changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
@@ -523,7 +563,7 @@ void generate_config(BUFFER *wb, int only_changed)
buffer_sprintf(wb, "\n[%s]\n", co->name);
- config_section_write_lock(co);
+ config_section_wrlock(co);
for(cv = co->values; cv ; cv = cv->next) {
if(used && !(cv->flags & CONFIG_VALUE_USED)) {
@@ -534,6 +574,6 @@ void generate_config(BUFFER *wb, int only_changed)
config_section_unlock(co);
}
}
- config_global_unlock();
+ appconfig_unlock(root);
}
}
diff --git a/src/appconfig.h b/src/appconfig.h
index 08aae8348..45cc8cfd5 100644
--- a/src/appconfig.h
+++ b/src/appconfig.h
@@ -3,30 +3,67 @@
#define CONFIG_FILENAME "netdata.conf"
+#define CONFIG_SECTION_GLOBAL "global"
+#define CONFIG_SECTION_WEB "web"
+#define CONFIG_SECTION_PLUGINS "plugins"
+#define CONFIG_SECTION_REGISTRY "registry"
+#define CONFIG_SECTION_HEALTH "health"
+#define CONFIG_SECTION_BACKEND "backend"
+#define CONFIG_SECTION_STREAM "stream"
+
// these are used to limit the configuration names and values lengths
// they are not enforced by config.c functions (they will strdup() all strings, no matter of their length)
#define CONFIG_MAX_NAME 1024
#define CONFIG_MAX_VALUE 2048
-extern int load_config(char *filename, int overwrite_used);
+struct config {
+ struct section *sections;
+ netdata_mutex_t mutex;
+ avl_tree_lock index;
+};
+
+extern struct config
+ netdata_config,
+ stream_config;
+
+#define CONFIG_BOOLEAN_NO 0
+#define CONFIG_BOOLEAN_YES 1
+#define CONFIG_BOOLEAN_AUTO 2
+
+extern int appconfig_load(struct config *root, char *filename, int overwrite_used);
+
+extern char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value);
+extern long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value);
+extern int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value);
+extern int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value);
+
+extern const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value);
+extern const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value);
+extern long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value);
+extern int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value);
+
+extern int appconfig_exists(struct config *root, const char *section, const char *name);
+extern int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new);
+
+extern void appconfig_generate(struct config *root, BUFFER *wb, int only_changed);
-extern char *config_get(const char *section, const char *name, const char *default_value);
-extern long long config_get_number(const char *section, const char *name, long long value);
-extern int config_get_boolean(const char *section, const char *name, int value);
+// ----------------------------------------------------------------------------
+// shortcuts for the default netdata configuration
-#define CONFIG_ONDEMAND_NO 0
-#define CONFIG_ONDEMAND_YES 1
-#define CONFIG_ONDEMAND_ONDEMAND 2
-extern int config_get_boolean_ondemand(const char *section, const char *name, int value);
+#define config_load(filename, overwrite_used) appconfig_load(&netdata_config, filename, overwrite_used)
+#define config_get(section, name, default_value) appconfig_get(&netdata_config, section, name, default_value)
+#define config_get_number(section, name, value) appconfig_get_number(&netdata_config, section, name, value)
+#define config_get_boolean(section, name, value) appconfig_get_boolean(&netdata_config, section, name, value)
+#define config_get_boolean_ondemand(section, name, value) appconfig_get_boolean_ondemand(&netdata_config, section, name, value)
-extern const char *config_set(const char *section, const char *name, const char *value);
-extern const char *config_set_default(const char *section, const char *name, const char *value);
-extern long long config_set_number(const char *section, const char *name, long long value);
-extern int config_set_boolean(const char *section, const char *name, int value);
+#define config_set(section, name, default_value) appconfig_get(&netdata_config, section, name, default_value)
+#define config_set_default(section, name, value) appconfig_set_default(&netdata_config, section, name, value)
+#define config_set_number(section, name, value) appconfig_set_number(&netdata_config, section, name, value)
+#define config_set_boolean(section, name, value) appconfig_set_boolean(&netdata_config, section, name, value)
-extern int config_exists(const char *section, const char *name);
-extern int config_rename(const char *section, const char *old, const char *new);
+#define config_exists(section, name) appconfig_exists(&netdata_config, section, name)
+#define config_move(section_old, name_old, section_new, name_new) appconfig_move(&netdata_config, section_old, name_old, section_new, name_new)
-extern void generate_config(BUFFER *wb, int only_changed);
+#define config_generate(buffer, only_changed) appconfig_generate(&netdata_config, buffer, only_changed)
#endif /* NETDATA_CONFIG_H */
diff --git a/src/apps_plugin.c b/src/apps_plugin.c
index 0a72190aa..b1bf06bee 100644
--- a/src/apps_plugin.c
+++ b/src/apps_plugin.c
@@ -1,50 +1,141 @@
+
+/*
+ * netdata apps.plugin
+ * (C) Copyright 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
+ * Released under GPL v3+
+ */
+
#include "common.h"
+#ifdef __FreeBSD__
+#include <sys/user.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// per O/S configuration
+
+// the minimum PID of the system
+// this is also the pid of the init process
+#define INIT_PID 1
+
+// if the way apps.plugin will work, will read the entire process list,
+// including the resource utilization of each process, instantly
+// set this to 1
+// when set to 0, apps.plugin builds a sort list of processes, in order
+// to process children processes, before parent processes
+#ifdef __FreeBSD__
+#define ALL_PIDS_ARE_READ_INSTANTLY 1
+#else
+#define ALL_PIDS_ARE_READ_INSTANTLY 0
+#endif
+
+// ----------------------------------------------------------------------------
+// string lengths
+
#define MAX_COMPARE_NAME 100
#define MAX_NAME 100
#define MAX_CMDLINE 1024
-// the rates we are going to send to netdata
-// will have this detail
-// a value of:
-// 1 will send just integer parts to netdata
-// 100 will send 2 decimal points
-// 1000 will send 3 decimal points
+
+// ----------------------------------------------------------------------------
+// the rates we are going to send to netdata will have this detail a value of:
+// - 1 will send just integer parts to netdata
+// - 100 will send 2 decimal points
+// - 1000 will send 3 decimal points
// etc.
#define RATES_DETAIL 10000ULL
+
+// ----------------------------------------------------------------------------
+// to avoid reallocating too frequently, we can increase the number of spare
+// file descriptors used by processes.
+// IMPORTANT:
+// having a lot of spares, increases the CPU utilization of the plugin.
#define MAX_SPARE_FDS 1
-int debug = 0;
-int update_every = 1;
-unsigned long long global_iterations_counter = 1;
-unsigned long long file_counter = 0;
-int proc_pid_cmdline_is_needed = 0;
-int include_exited_childs = 1;
-char *config_dir = CONFIG_DIR;
+// ----------------------------------------------------------------------------
+// command line options
+
+static int
+ debug = 0,
+ update_every = 1,
+ enable_guest_charts = 0,
+#ifdef __FreeBSD__
+ enable_file_charts = 0,
+#else
+ enable_file_charts = 1,
+#endif
+ enable_users_charts = 1,
+ enable_groups_charts = 1,
+ include_exited_childs = 1;
-pid_t *all_pids_sortlist = NULL;
-// will be automatically set to 1, if guest values are collected
-int show_guest_time = 0;
-int show_guest_time_old = 0;
+// will be changed to getenv(NETDATA_CONFIG_DIR) if it exists
+static char *config_dir = CONFIG_DIR;
+
+// ----------------------------------------------------------------------------
+// internal flags
+// handled in code (automatically set)
+
+static int
+ show_guest_time = 0, // 1 when guest values are collected
+ show_guest_time_old = 0,
+ proc_pid_cmdline_is_needed = 0; // 1 when we need to read /proc/cmdline
-int enable_guest_charts = 0;
-int enable_file_charts = 1;
-int enable_users_charts = 1;
-int enable_groups_charts = 1;
// ----------------------------------------------------------------------------
+// internal counters
+
+static size_t
+ global_iterations_counter = 1,
+ calls_counter = 0,
+ file_counter = 0,
+ targets_assignment_counter = 0;
+
+
+// ----------------------------------------------------------------------------
+// Normalization
+//
+// With normalization we lower the collected metrics by a factor to make them
+// match the total utilization of the system.
+// The discrepancy exists because apps.plugin needs some time to collect all
+// the metrics. This results in utilization that exceeds the total utilization
+// of the system.
+//
+// With normalization we align the per-process utilization, to the total of
+// the system. We first consume the exited children utilization and it the
+// collected values is above the total, we proportionally scale each reported
+// metric.
+
+// the total system time, as reported by /proc/stat
+static kernel_uint_t
+ global_utime = 0,
+ global_stime = 0,
+ global_gtime = 0;
-void netdata_cleanup_and_exit(int ret) {
- exit(ret);
-}
+
+// the normalization ratios, as calculated by normalize_utilization()
+double utime_fix_ratio = 1.0,
+ stime_fix_ratio = 1.0,
+ gtime_fix_ratio = 1.0,
+ minflt_fix_ratio = 1.0,
+ majflt_fix_ratio = 1.0,
+ cutime_fix_ratio = 1.0,
+ cstime_fix_ratio = 1.0,
+ cgtime_fix_ratio = 1.0,
+ cminflt_fix_ratio = 1.0,
+ cmajflt_fix_ratio = 1.0;
// ----------------------------------------------------------------------------
// target
-// target is the structure that process data are aggregated
+//
+// target is the structure that processes are aggregated to be reported
+// to netdata.
+//
+// - Each entry in /etc/apps_groups.conf creates a target.
+// - Each user and group used by a process in the system, creates a target.
struct target {
char compare[MAX_COMPARE_NAME + 1];
@@ -59,74 +150,281 @@ struct target {
uid_t uid;
gid_t gid;
- unsigned long long minflt;
- unsigned long long cminflt;
- unsigned long long majflt;
- unsigned long long cmajflt;
- unsigned long long utime;
- unsigned long long stime;
- unsigned long long gtime;
- unsigned long long cutime;
- unsigned long long cstime;
- unsigned long long cgtime;
- unsigned long long num_threads;
- // unsigned long long rss;
-
- unsigned long long statm_size;
- unsigned long long statm_resident;
- unsigned long long statm_share;
- // unsigned long long statm_text;
- // unsigned long long statm_lib;
- // unsigned long long statm_data;
- // unsigned long long statm_dirty;
-
- unsigned long long io_logical_bytes_read;
- unsigned long long io_logical_bytes_written;
- // unsigned long long io_read_calls;
- // unsigned long long io_write_calls;
- unsigned long long io_storage_bytes_read;
- unsigned long long io_storage_bytes_written;
- // unsigned long long io_cancelled_write_bytes;
+ kernel_uint_t minflt;
+ kernel_uint_t cminflt;
+ kernel_uint_t majflt;
+ kernel_uint_t cmajflt;
+ kernel_uint_t utime;
+ kernel_uint_t stime;
+ kernel_uint_t gtime;
+ kernel_uint_t cutime;
+ kernel_uint_t cstime;
+ kernel_uint_t cgtime;
+ kernel_uint_t num_threads;
+ // kernel_uint_t rss;
+
+ kernel_uint_t statm_size;
+ kernel_uint_t statm_resident;
+ kernel_uint_t statm_share;
+ // kernel_uint_t statm_text;
+ // kernel_uint_t statm_lib;
+ // kernel_uint_t statm_data;
+ // kernel_uint_t statm_dirty;
+
+ kernel_uint_t io_logical_bytes_read;
+ kernel_uint_t io_logical_bytes_written;
+ // kernel_uint_t io_read_calls;
+ // kernel_uint_t io_write_calls;
+ kernel_uint_t io_storage_bytes_read;
+ kernel_uint_t io_storage_bytes_written;
+ // kernel_uint_t io_cancelled_write_bytes;
int *target_fds;
int target_fds_size;
- unsigned long long openfiles;
- unsigned long long openpipes;
- unsigned long long opensockets;
- unsigned long long openinotifies;
- unsigned long long openeventfds;
- unsigned long long opentimerfds;
- unsigned long long opensignalfds;
- unsigned long long openeventpolls;
- unsigned long long openother;
-
- unsigned long processes; // how many processes have been merged to this
- int exposed; // if set, we have sent this to netdata
- int hidden; // if set, we set the hidden flag on the dimension
+ kernel_uint_t openfiles;
+ kernel_uint_t openpipes;
+ kernel_uint_t opensockets;
+ kernel_uint_t openinotifies;
+ kernel_uint_t openeventfds;
+ kernel_uint_t opentimerfds;
+ kernel_uint_t opensignalfds;
+ kernel_uint_t openeventpolls;
+ kernel_uint_t openother;
+
+ unsigned int processes; // how many processes have been merged to this
+ int exposed; // if set, we have sent this to netdata
+ int hidden; // if set, we set the hidden flag on the dimension
int debug;
int ends_with;
- int starts_with; // if set, the compare string matches only the
- // beginning of the command
+ int starts_with; // if set, the compare string matches only the
+ // beginning of the command
- struct target *target; // the one that will be reported to netdata
+ struct target *target; // the one that will be reported to netdata
struct target *next;
};
+struct target
+ *apps_groups_default_target = NULL, // the default target
+ *apps_groups_root_target = NULL, // apps_groups.conf defined
+ *users_root_target = NULL, // users
+ *groups_root_target = NULL; // user groups
+
+size_t
+ apps_groups_targets_count = 0; // # of apps_groups.conf targets
+
// ----------------------------------------------------------------------------
-// apps_groups.conf
-// aggregate all processes in groups, to have a limited number of dimensions
+// pid_stat
+//
+// structure to store data for each process running
+// see: man proc for the description of the fields
+
+struct pid_stat {
+ int32_t pid;
+ char comm[MAX_COMPARE_NAME + 1];
+ char cmdline[MAX_CMDLINE + 1];
-struct target *apps_groups_root_target = NULL;
-struct target *apps_groups_default_target = NULL;
-long apps_groups_targets = 0;
+ uint32_t log_thrown;
-struct target *users_root_target = NULL;
-struct target *groups_root_target = NULL;
+ // char state;
+ int32_t ppid;
+ // int32_t pgrp;
+ // int32_t session;
+ // int32_t tty_nr;
+ // int32_t tpgid;
+ // uint64_t flags;
-static struct target *get_users_target(uid_t uid)
-{
+ // these are raw values collected
+ kernel_uint_t minflt_raw;
+ kernel_uint_t cminflt_raw;
+ kernel_uint_t majflt_raw;
+ kernel_uint_t cmajflt_raw;
+ kernel_uint_t utime_raw;
+ kernel_uint_t stime_raw;
+ kernel_uint_t gtime_raw; // guest_time
+ kernel_uint_t cutime_raw;
+ kernel_uint_t cstime_raw;
+ kernel_uint_t cgtime_raw; // cguest_time
+
+ // these are rates
+ kernel_uint_t minflt;
+ kernel_uint_t cminflt;
+ kernel_uint_t majflt;
+ kernel_uint_t cmajflt;
+ kernel_uint_t utime;
+ kernel_uint_t stime;
+ kernel_uint_t gtime;
+ kernel_uint_t cutime;
+ kernel_uint_t cstime;
+ kernel_uint_t cgtime;
+
+ // int64_t priority;
+ // int64_t nice;
+ int32_t num_threads;
+ // int64_t itrealvalue;
+ // kernel_uint_t starttime;
+ // kernel_uint_t vsize;
+ // kernel_uint_t rss;
+ // kernel_uint_t rsslim;
+ // kernel_uint_t starcode;
+ // kernel_uint_t endcode;
+ // kernel_uint_t startstack;
+ // kernel_uint_t kstkesp;
+ // kernel_uint_t kstkeip;
+ // uint64_t signal;
+ // uint64_t blocked;
+ // uint64_t sigignore;
+ // uint64_t sigcatch;
+ // uint64_t wchan;
+ // uint64_t nswap;
+ // uint64_t cnswap;
+ // int32_t exit_signal;
+ // int32_t processor;
+ // uint32_t rt_priority;
+ // uint32_t policy;
+ // kernel_uint_t delayacct_blkio_ticks;
+
+ uid_t uid;
+ gid_t gid;
+
+ kernel_uint_t statm_size;
+ kernel_uint_t statm_resident;
+ kernel_uint_t statm_share;
+ // kernel_uint_t statm_text;
+ // kernel_uint_t statm_lib;
+ // kernel_uint_t statm_data;
+ // kernel_uint_t statm_dirty;
+
+ kernel_uint_t io_logical_bytes_read_raw;
+ kernel_uint_t io_logical_bytes_written_raw;
+ // kernel_uint_t io_read_calls_raw;
+ // kernel_uint_t io_write_calls_raw;
+ kernel_uint_t io_storage_bytes_read_raw;
+ kernel_uint_t io_storage_bytes_written_raw;
+ // kernel_uint_t io_cancelled_write_bytes_raw;
+
+ kernel_uint_t io_logical_bytes_read;
+ kernel_uint_t io_logical_bytes_written;
+ // kernel_uint_t io_read_calls;
+ // kernel_uint_t io_write_calls;
+ kernel_uint_t io_storage_bytes_read;
+ kernel_uint_t io_storage_bytes_written;
+ // kernel_uint_t io_cancelled_write_bytes;
+
+ int *fds; // array of fds it uses
+ int fds_size; // the size of the fds array
+
+ int children_count; // number of processes directly referencing this
+ char keep:1; // 1 when we need to keep this process in memory even after it exited
+ int keeploops; // increases by 1 every time keep is 1 and updated 0
+ char updated:1; // 1 when the process is currently running
+ char merged:1; // 1 when it has been merged to its parent
+ char read:1; // 1 when we have already read this process for this iteration
+
+ int sortlist; // higher numbers = top on the process tree
+ // each process gets a unique number
+
+ struct target *target; // app_groups.conf targets
+ struct target *user_target; // uid based targets
+ struct target *group_target; // gid based targets
+
+ usec_t stat_collected_usec;
+ usec_t last_stat_collected_usec;
+
+ usec_t io_collected_usec;
+ usec_t last_io_collected_usec;
+
+ char *fds_dirname; // the full directory name in /proc/PID/fd
+
+ char *stat_filename;
+ char *statm_filename;
+ char *io_filename;
+ char *cmdline_filename;
+
+ struct pid_stat *parent;
+ struct pid_stat *prev;
+ struct pid_stat *next;
+};
+
+// log each problem once per process
+// log flood protection flags (log_thrown)
+#define PID_LOG_IO 0x00000001
+#define PID_LOG_STATM 0x00000002
+#define PID_LOG_CMDLINE 0x00000004
+#define PID_LOG_FDS 0x00000008
+#define PID_LOG_STAT 0x00000010
+
+static struct pid_stat
+ *root_of_pids = NULL, // global list of all processes running
+ **all_pids = NULL; // to avoid allocations, we pre-allocate the
+ // the entire pid space.
+
+static size_t
+ all_pids_count = 0; // the number of processes running
+
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
+// Another pre-allocated list of all possible pids.
+// We need it to pids and assign them a unique sortlist id, so that we
+// read parents before children. This is needed to prevent a situation where
+// a child is found running, but until we read its parent, it has exited and
+// its parent has accumulated its resources.
+static pid_t
+ *all_pids_sortlist = NULL;
+#endif
+
+// ----------------------------------------------------------------------------
+// file descriptor
+//
+// this is used to keep a global list of all open files of the system.
+// it is needed in order to calculate the unique files processes have open.
+
+#define FILE_DESCRIPTORS_INCREASE_STEP 100
+
+// types for struct file_descriptor->type
+typedef enum fd_filetype {
+ FILETYPE_OTHER,
+ FILETYPE_FILE,
+ FILETYPE_PIPE,
+ FILETYPE_SOCKET,
+ FILETYPE_INOTIFY,
+ FILETYPE_EVENTFD,
+ FILETYPE_EVENTPOLL,
+ FILETYPE_TIMERFD,
+ FILETYPE_SIGNALFD
+} FD_FILETYPE;
+
+struct file_descriptor {
+ avl avl;
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ uint32_t magic;
+#endif /* NETDATA_INTERNAL_CHECKS */
+
+ const char *name;
+ uint32_t hash;
+
+ FD_FILETYPE type;
+ int count;
+ int pos;
+} *all_files = NULL;
+
+static int
+ all_files_len = 0,
+ all_files_size = 0;
+
+// ----------------------------------------------------------------------------
+// callback required by fatal()
+
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+// ----------------------------------------------------------------------------
+// apps_groups.conf
+// aggregate all processes in groups, to have a limited number of dimensions
+
+static struct target *get_users_target(uid_t uid) {
struct target *w;
for(w = users_root_target ; w ; w = w->next)
if(w->uid == uid) return w;
@@ -221,10 +519,12 @@ static struct target *get_apps_groups_target(const char *id, struct target *targ
if(*name == '-') thidden = 1;
name++;
}
- for(target = apps_groups_root_target ; target ; target = target->next) {
+
+ for(target = apps_groups_root_target ; target != NULL ; target = target->next) {
if(!target->target && strcmp(name, target->name) == 0)
break;
}
+
if(unlikely(debug)) {
if(unlikely(target))
fprintf(stderr, "apps.plugin: REUSING TARGET NAME '%s' on ID '%s'\n", target->name, target->id);
@@ -302,10 +602,10 @@ static int read_apps_groups_conf(const char *file)
if(!ff)
return 1;
- unsigned long line, lines = procfile_lines(ff);
+ size_t line, lines = procfile_lines(ff);
for(line = 0; line < lines ;line++) {
- unsigned long word, words = procfile_linewords(ff, line);
+ size_t word, words = procfile_linewords(ff, line);
if(!words) continue;
char *name = procfile_lineword(ff, line, 0);
@@ -326,7 +626,7 @@ static int read_apps_groups_conf(const char *file)
// add this target
struct target *n = get_apps_groups_target(s, w, name);
if(!n) {
- error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
+ error("Cannot create target '%s' (line %zu, word %zu)", s, line, word);
continue;
}
@@ -351,186 +651,135 @@ static int read_apps_groups_conf(const char *file)
// ----------------------------------------------------------------------------
-// data to store for each pid
-// see: man proc
+// struct pid_stat management
-#define PID_LOG_IO 0x00000001
-#define PID_LOG_STATM 0x00000002
-#define PID_LOG_CMDLINE 0x00000004
-#define PID_LOG_FDS 0x00000008
-#define PID_LOG_STAT 0x00000010
+static inline struct pid_stat *get_pid_entry(pid_t pid) {
+ if(unlikely(all_pids[pid]))
+ return all_pids[pid];
-struct pid_stat {
- int32_t pid;
- char comm[MAX_COMPARE_NAME + 1];
- char cmdline[MAX_CMDLINE + 1];
+ struct pid_stat *p = callocz(sizeof(struct pid_stat), 1);
+ p->fds = callocz(sizeof(int), MAX_SPARE_FDS);
+ p->fds_size = MAX_SPARE_FDS;
- uint32_t log_thrown;
+ if(likely(root_of_pids))
+ root_of_pids->prev = p;
- // char state;
- int32_t ppid;
- // int32_t pgrp;
- // int32_t session;
- // int32_t tty_nr;
- // int32_t tpgid;
- // uint64_t flags;
+ p->next = root_of_pids;
+ root_of_pids = p;
- // these are raw values collected
- unsigned long long minflt_raw;
- unsigned long long cminflt_raw;
- unsigned long long majflt_raw;
- unsigned long long cmajflt_raw;
- unsigned long long utime_raw;
- unsigned long long stime_raw;
- unsigned long long gtime_raw; // guest_time
- unsigned long long cutime_raw;
- unsigned long long cstime_raw;
- unsigned long long cgtime_raw; // cguest_time
+ p->pid = pid;
- // these are rates
- unsigned long long minflt;
- unsigned long long cminflt;
- unsigned long long majflt;
- unsigned long long cmajflt;
- unsigned long long utime;
- unsigned long long stime;
- unsigned long long gtime;
- unsigned long long cutime;
- unsigned long long cstime;
- unsigned long long cgtime;
+ all_pids[pid] = p;
+ all_pids_count++;
- // int64_t priority;
- // int64_t nice;
- int32_t num_threads;
- // int64_t itrealvalue;
- // unsigned long long starttime;
- // unsigned long long vsize;
- // unsigned long long rss;
- // unsigned long long rsslim;
- // unsigned long long starcode;
- // unsigned long long endcode;
- // unsigned long long startstack;
- // unsigned long long kstkesp;
- // unsigned long long kstkeip;
- // uint64_t signal;
- // uint64_t blocked;
- // uint64_t sigignore;
- // uint64_t sigcatch;
- // uint64_t wchan;
- // uint64_t nswap;
- // uint64_t cnswap;
- // int32_t exit_signal;
- // int32_t processor;
- // uint32_t rt_priority;
- // uint32_t policy;
- // unsigned long long delayacct_blkio_ticks;
+ return p;
+}
- uid_t uid;
- gid_t gid;
+static inline void del_pid_entry(pid_t pid) {
+ struct pid_stat *p = all_pids[pid];
- unsigned long long statm_size;
- unsigned long long statm_resident;
- unsigned long long statm_share;
- // unsigned long long statm_text;
- // unsigned long long statm_lib;
- // unsigned long long statm_data;
- // unsigned long long statm_dirty;
-
- unsigned long long io_logical_bytes_read_raw;
- unsigned long long io_logical_bytes_written_raw;
- // unsigned long long io_read_calls_raw;
- // unsigned long long io_write_calls_raw;
- unsigned long long io_storage_bytes_read_raw;
- unsigned long long io_storage_bytes_written_raw;
- // unsigned long long io_cancelled_write_bytes_raw;
-
- unsigned long long io_logical_bytes_read;
- unsigned long long io_logical_bytes_written;
- // unsigned long long io_read_calls;
- // unsigned long long io_write_calls;
- unsigned long long io_storage_bytes_read;
- unsigned long long io_storage_bytes_written;
- // unsigned long long io_cancelled_write_bytes;
+ if(unlikely(!p)) {
+ error("attempted to free pid %d that is not allocated.", pid);
+ return;
+ }
- int *fds; // array of fds it uses
- int fds_size; // the size of the fds array
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, p->comm);
- int children_count; // number of processes directly referencing this
- int keep; // 1 when we need to keep this process in memory even after it exited
- int keeploops; // increases by 1 every time keep is 1 and updated 0
- int updated; // 1 when the process is currently running
- int merged; // 1 when it has been merged to its parent
- int new_entry; // 1 when this is a new process, just saw for the first time
- int read; // 1 when we have already read this process for this iteration
- int sortlist; // higher numbers = top on the process tree
- // each process gets a unique number
+ if(root_of_pids == p)
+ root_of_pids = p->next;
- struct target *target; // app_groups.conf targets
- struct target *user_target; // uid based targets
- struct target *group_target; // gid based targets
+ if(p->next) p->next->prev = p->prev;
+ if(p->prev) p->prev->next = p->next;
- unsigned long long stat_collected_usec;
- unsigned long long last_stat_collected_usec;
+ freez(p->fds);
+ freez(p->fds_dirname);
+ freez(p->stat_filename);
+ freez(p->statm_filename);
+ freez(p->io_filename);
+ freez(p->cmdline_filename);
+ freez(p);
- unsigned long long io_collected_usec;
- unsigned long long last_io_collected_usec;
+ all_pids[pid] = NULL;
+ all_pids_count--;
+}
- char *stat_filename;
- char *statm_filename;
- char *io_filename;
- char *cmdline_filename;
+// ----------------------------------------------------------------------------
- struct pid_stat *parent;
- struct pid_stat *prev;
- struct pid_stat *next;
-} *root_of_pids = NULL, **all_pids;
+static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
+ if(unlikely(!status)) {
+ // error("command failed log %u, errno %d", log, errno);
-long all_pids_count = 0;
+ if(unlikely(debug || errno != ENOENT)) {
+ if(unlikely(debug || !(p->log_thrown & log))) {
+ p->log_thrown |= log;
+ switch(log) {
+ case PID_LOG_IO:
+ error("Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
-static inline struct pid_stat *get_pid_entry(pid_t pid) {
- if(all_pids[pid]) {
- all_pids[pid]->new_entry = 0;
- return all_pids[pid];
- }
+ case PID_LOG_STATM:
+ error("Cannot process %s/proc/%d/statm (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
- all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
- all_pids[pid]->fds = callocz(sizeof(int), MAX_SPARE_FDS);
- all_pids[pid]->fds_size = MAX_SPARE_FDS;
+ case PID_LOG_CMDLINE:
+ error("Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
- if(root_of_pids) root_of_pids->prev = all_pids[pid];
- all_pids[pid]->next = root_of_pids;
- root_of_pids = all_pids[pid];
+ case PID_LOG_FDS:
+ error("Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
+ break;
- all_pids[pid]->pid = pid;
- all_pids[pid]->new_entry = 1;
+ case PID_LOG_STAT:
+ break;
- all_pids_count++;
+ default:
+ error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
+ break;
+ }
+ }
+ }
+ errno = 0;
+ }
+ else if(unlikely(p->log_thrown & log)) {
+ // error("unsetting log %u on pid %d", log, p->pid);
+ p->log_thrown &= ~log;
+ }
- return all_pids[pid];
+ return status;
}
-static inline void del_pid_entry(pid_t pid) {
- if(!all_pids[pid]) {
- error("attempted to free pid %d that is not allocated.", pid);
- return;
- }
+static inline void assign_target_to_pid(struct pid_stat *p) {
+ targets_assignment_counter++;
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
+ uint32_t hash = simple_hash(p->comm);
+ size_t pclen = strlen(p->comm);
- if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
- if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
- if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
+ struct target *w;
+ for(w = apps_groups_root_target; w ; w = w->next) {
+ // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
- if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
- if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
- if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
- if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
- if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
- freez(all_pids[pid]);
+ // find it - 4 cases:
+ // 1. the target is not a pattern
+ // 2. the target has the prefix
+ // 3. the target has the suffix
+ // 4. the target is something inside cmdline
- all_pids[pid] = NULL;
- all_pids_count--;
+ if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
+ || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
+ || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
+ || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
+ ))) {
+
+ if(w->target) p->target = w->target;
+ else p->target = w;
+
+ if(debug || (p->target && p->target->debug))
+ fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
+
+ break;
+ }
+ }
}
@@ -539,9 +788,20 @@ static inline void del_pid_entry(pid_t pid) {
static inline int read_proc_pid_cmdline(struct pid_stat *p) {
+#ifdef __FreeBSD__
+ size_t i, bytes = MAX_CMDLINE;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ARGS;
+ mib[3] = p->pid;
+ if (unlikely(sysctl(mib, 4, p->cmdline, &bytes, NULL, 0)))
+ goto cleanup;
+#else
if(unlikely(!p->cmdline_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
p->cmdline_filename = strdupz(filename);
}
@@ -552,6 +812,7 @@ static inline int read_proc_pid_cmdline(struct pid_stat *p) {
close(fd);
if(unlikely(bytes < 0)) goto cleanup;
+#endif
p->cmdline[bytes] = '\0';
for(i = 0; i < bytes ; i++)
@@ -568,7 +829,16 @@ cleanup:
return 0;
}
-static inline int read_proc_pid_ownership(struct pid_stat *p) {
+static inline int read_proc_pid_ownership(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+
+ p->uid = proc_info->ki_uid;
+ p->gid = proc_info->ki_groups[0];
+
+ return 1;
+#else
if(unlikely(!p->stat_filename)) {
error("pid %d does not have a stat_filename", p->pid);
return 0;
@@ -587,14 +857,41 @@ static inline int read_proc_pid_ownership(struct pid_stat *p) {
p->gid = st.st_gid;
return 1;
+#endif
}
-static inline int read_proc_pid_stat(struct pid_stat *p) {
+// ----------------------------------------------------------------------------
+// macro to calculate the incremental rate of a value
+// each parameter is accessed only ONCE - so it is safe to pass function calls
+// or other macros as parameters
+
+#define incremental_rate(rate_variable, last_kernel_variable, new_kernel_value, collected_usec, last_collected_usec) { \
+ kernel_uint_t _new_tmp = new_kernel_value; \
+ rate_variable = (_new_tmp - last_kernel_variable) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec); \
+ last_kernel_variable = _new_tmp; \
+ }
+
+// the same macro for struct pid members
+#define pid_incremental_rate(type, var, value) \
+ incremental_rate(var, var##_raw, value, p->type##_collected_usec, p->last_##type##_collected_usec)
+
+
+// ----------------------------------------------------------------------------
+
+static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+
+ if (unlikely(proc_info->ki_tdflags & TDF_IDLETD))
+ goto cleanup;
+#else
static procfile *ff = NULL;
if(unlikely(!p->stat_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", netdata_configured_host_prefix, p->pid);
p->stat_filename = strdupz(filename);
}
@@ -604,95 +901,104 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
if(unlikely(!ff)) goto cleanup;
// if(set_quotes) procfile_set_quotes(ff, "()");
- if(set_quotes) procfile_set_open_close(ff, "(", ")");
+ if(unlikely(set_quotes))
+ procfile_set_open_close(ff, "(", ")");
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
p->last_stat_collected_usec = p->stat_collected_usec;
- p->stat_collected_usec = now_realtime_usec();
- file_counter++;
+ p->stat_collected_usec = now_monotonic_usec();
+ calls_counter++;
+
+#ifdef __FreeBSD__
+ char *comm = proc_info->ki_comm;
+ p->ppid = proc_info->ki_ppid;
+#else
+ // p->pid = str2pid_t(procfile_lineword(ff, 0, 0));
+ char *comm = procfile_lineword(ff, 0, 1);
+ // p->state = *(procfile_lineword(ff, 0, 2));
+ p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
+ // p->pgrp = (int32_t)str2pid_t(procfile_lineword(ff, 0, 4));
+ // p->session = (int32_t)str2pid_t(procfile_lineword(ff, 0, 5));
+ // p->tty_nr = (int32_t)str2pid_t(procfile_lineword(ff, 0, 6));
+ // p->tpgid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 7));
+ // p->flags = str2uint64_t(procfile_lineword(ff, 0, 8));
+#endif
- // p->pid = str2ul(procfile_lineword(ff, 0, 0+i));
+ if(strcmp(p->comm, comm)) {
+ if(unlikely(debug)) {
+ if(p->comm[0])
+ fprintf(stderr, "apps.plugin: \tpid %d (%s) changed name to '%s'\n", p->pid, p->comm, comm);
+ else
+ fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", p->pid, comm);
+ }
- strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
+ strncpyz(p->comm, comm, MAX_COMPARE_NAME);
- // p->state = *(procfile_lineword(ff, 0, 2));
- p->ppid = (int32_t)str2ul(procfile_lineword(ff, 0, 3));
- // p->pgrp = str2ul(procfile_lineword(ff, 0, 4));
- // p->session = str2ul(procfile_lineword(ff, 0, 5));
- // p->tty_nr = str2ul(procfile_lineword(ff, 0, 6));
- // p->tpgid = str2ul(procfile_lineword(ff, 0, 7));
- // p->flags = str2ull(procfile_lineword(ff, 0, 8));
-
- unsigned long long last;
-
- last = p->minflt_raw;
- p->minflt_raw = str2ull(procfile_lineword(ff, 0, 9));
- p->minflt = (p->minflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cminflt_raw;
- p->cminflt_raw = str2ull(procfile_lineword(ff, 0, 10));
- p->cminflt = (p->cminflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->majflt_raw;
- p->majflt_raw = str2ull(procfile_lineword(ff, 0, 11));
- p->majflt = (p->majflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cmajflt_raw;
- p->cmajflt_raw = str2ull(procfile_lineword(ff, 0, 12));
- p->cmajflt = (p->cmajflt_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->utime_raw;
- p->utime_raw = str2ull(procfile_lineword(ff, 0, 13));
- p->utime = (p->utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->stime_raw;
- p->stime_raw = str2ull(procfile_lineword(ff, 0, 14));
- p->stime = (p->stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cutime_raw;
- p->cutime_raw = str2ull(procfile_lineword(ff, 0, 15));
- p->cutime = (p->cutime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- last = p->cstime_raw;
- p->cstime_raw = str2ull(procfile_lineword(ff, 0, 16));
- p->cstime = (p->cstime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
- // p->priority = str2ull(procfile_lineword(ff, 0, 17));
- // p->nice = str2ull(procfile_lineword(ff, 0, 18));
- p->num_threads = (int32_t)str2ul(procfile_lineword(ff, 0, 19));
- // p->itrealvalue = str2ull(procfile_lineword(ff, 0, 20));
- // p->starttime = str2ull(procfile_lineword(ff, 0, 21));
- // p->vsize = str2ull(procfile_lineword(ff, 0, 22));
- // p->rss = str2ull(procfile_lineword(ff, 0, 23));
- // p->rsslim = str2ull(procfile_lineword(ff, 0, 24));
- // p->starcode = str2ull(procfile_lineword(ff, 0, 25));
- // p->endcode = str2ull(procfile_lineword(ff, 0, 26));
- // p->startstack = str2ull(procfile_lineword(ff, 0, 27));
- // p->kstkesp = str2ull(procfile_lineword(ff, 0, 28));
- // p->kstkeip = str2ull(procfile_lineword(ff, 0, 29));
- // p->signal = str2ull(procfile_lineword(ff, 0, 30));
- // p->blocked = str2ull(procfile_lineword(ff, 0, 31));
- // p->sigignore = str2ull(procfile_lineword(ff, 0, 32));
- // p->sigcatch = str2ull(procfile_lineword(ff, 0, 33));
- // p->wchan = str2ull(procfile_lineword(ff, 0, 34));
- // p->nswap = str2ull(procfile_lineword(ff, 0, 35));
- // p->cnswap = str2ull(procfile_lineword(ff, 0, 36));
- // p->exit_signal = str2ul(procfile_lineword(ff, 0, 37));
- // p->processor = str2ul(procfile_lineword(ff, 0, 38));
- // p->rt_priority = str2ul(procfile_lineword(ff, 0, 39));
- // p->policy = str2ul(procfile_lineword(ff, 0, 40));
- // p->delayacct_blkio_ticks = str2ull(procfile_lineword(ff, 0, 41));
+ // /proc/<pid>/cmdline
+ if(likely(proc_pid_cmdline_is_needed))
+ managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
+
+ assign_target_to_pid(p);
+ }
+
+#ifdef __FreeBSD__
+ pid_incremental_rate(stat, p->minflt, (kernel_uint_t)proc_info->ki_rusage.ru_minflt);
+ pid_incremental_rate(stat, p->cminflt, (kernel_uint_t)proc_info->ki_rusage_ch.ru_minflt);
+ pid_incremental_rate(stat, p->majflt, (kernel_uint_t)proc_info->ki_rusage.ru_majflt);
+ pid_incremental_rate(stat, p->cmajflt, (kernel_uint_t)proc_info->ki_rusage_ch.ru_majflt);
+ pid_incremental_rate(stat, p->utime, (kernel_uint_t)proc_info->ki_rusage.ru_utime.tv_sec * 100 + proc_info->ki_rusage.ru_utime.tv_usec / 10000);
+ pid_incremental_rate(stat, p->stime, (kernel_uint_t)proc_info->ki_rusage.ru_stime.tv_sec * 100 + proc_info->ki_rusage.ru_stime.tv_usec / 10000);
+ pid_incremental_rate(stat, p->cutime, (kernel_uint_t)proc_info->ki_rusage_ch.ru_utime.tv_sec * 100 + proc_info->ki_rusage_ch.ru_utime.tv_usec / 10000);
+ pid_incremental_rate(stat, p->cstime, (kernel_uint_t)proc_info->ki_rusage_ch.ru_stime.tv_sec * 100 + proc_info->ki_rusage_ch.ru_utime.tv_usec / 10000);
+
+ p->num_threads = proc_info->ki_numthreads;
if(enable_guest_charts) {
- last = p->gtime_raw;
- p->gtime_raw = str2ull(procfile_lineword(ff, 0, 42));
- p->gtime = (p->gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ enable_guest_charts = 0;
+ info("Guest charts aren't supported by FreeBSD");
+ }
+#else
+ pid_incremental_rate(stat, p->minflt, str2kernel_uint_t(procfile_lineword(ff, 0, 9)));
+ pid_incremental_rate(stat, p->cminflt, str2kernel_uint_t(procfile_lineword(ff, 0, 10)));
+ pid_incremental_rate(stat, p->majflt, str2kernel_uint_t(procfile_lineword(ff, 0, 11)));
+ pid_incremental_rate(stat, p->cmajflt, str2kernel_uint_t(procfile_lineword(ff, 0, 12)));
+ pid_incremental_rate(stat, p->utime, str2kernel_uint_t(procfile_lineword(ff, 0, 13)));
+ pid_incremental_rate(stat, p->stime, str2kernel_uint_t(procfile_lineword(ff, 0, 14)));
+ pid_incremental_rate(stat, p->cutime, str2kernel_uint_t(procfile_lineword(ff, 0, 15)));
+ pid_incremental_rate(stat, p->cstime, str2kernel_uint_t(procfile_lineword(ff, 0, 16)));
+ // p->priority = str2kernel_uint_t(procfile_lineword(ff, 0, 17));
+ // p->nice = str2kernel_uint_t(procfile_lineword(ff, 0, 18));
+ p->num_threads = (int32_t)str2uint32_t(procfile_lineword(ff, 0, 19));
+ // p->itrealvalue = str2kernel_uint_t(procfile_lineword(ff, 0, 20));
+ // p->starttime = str2kernel_uint_t(procfile_lineword(ff, 0, 21));
+ // p->vsize = str2kernel_uint_t(procfile_lineword(ff, 0, 22));
+ // p->rss = str2kernel_uint_t(procfile_lineword(ff, 0, 23));
+ // p->rsslim = str2kernel_uint_t(procfile_lineword(ff, 0, 24));
+ // p->starcode = str2kernel_uint_t(procfile_lineword(ff, 0, 25));
+ // p->endcode = str2kernel_uint_t(procfile_lineword(ff, 0, 26));
+ // p->startstack = str2kernel_uint_t(procfile_lineword(ff, 0, 27));
+ // p->kstkesp = str2kernel_uint_t(procfile_lineword(ff, 0, 28));
+ // p->kstkeip = str2kernel_uint_t(procfile_lineword(ff, 0, 29));
+ // p->signal = str2kernel_uint_t(procfile_lineword(ff, 0, 30));
+ // p->blocked = str2kernel_uint_t(procfile_lineword(ff, 0, 31));
+ // p->sigignore = str2kernel_uint_t(procfile_lineword(ff, 0, 32));
+ // p->sigcatch = str2kernel_uint_t(procfile_lineword(ff, 0, 33));
+ // p->wchan = str2kernel_uint_t(procfile_lineword(ff, 0, 34));
+ // p->nswap = str2kernel_uint_t(procfile_lineword(ff, 0, 35));
+ // p->cnswap = str2kernel_uint_t(procfile_lineword(ff, 0, 36));
+ // p->exit_signal = str2kernel_uint_t(procfile_lineword(ff, 0, 37));
+ // p->processor = str2kernel_uint_t(procfile_lineword(ff, 0, 38));
+ // p->rt_priority = str2kernel_uint_t(procfile_lineword(ff, 0, 39));
+ // p->policy = str2kernel_uint_t(procfile_lineword(ff, 0, 40));
+ // p->delayacct_blkio_ticks = str2kernel_uint_t(procfile_lineword(ff, 0, 41));
- last = p->cgtime_raw;
- p->cgtime_raw = str2ull(procfile_lineword(ff, 0, 43));
- p->cgtime = (p->cgtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ if(enable_guest_charts) {
+
+ pid_incremental_rate(stat, p->gtime, str2kernel_uint_t(procfile_lineword(ff, 0, 42)));
+ pid_incremental_rate(stat, p->cgtime, str2kernel_uint_t(procfile_lineword(ff, 0, 43)));
if (show_guest_time || p->gtime || p->cgtime) {
p->utime -= (p->utime >= p->gtime) ? p->gtime : p->utime;
@@ -700,9 +1006,10 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
show_guest_time = 1;
}
}
+#endif
if(unlikely(debug || (p->target && p->target->debug)))
- fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", global_host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+ fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT ", threads=%d\n", netdata_configured_host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
if(unlikely(global_iterations_counter == 1)) {
p->minflt = 0;
@@ -735,12 +1042,16 @@ cleanup:
return 0;
}
-static inline int read_proc_pid_statm(struct pid_stat *p) {
+static inline int read_proc_pid_statm(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+#else
static procfile *ff = NULL;
if(unlikely(!p->statm_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", netdata_configured_host_prefix, p->pid);
p->statm_filename = strdupz(filename);
}
@@ -749,19 +1060,27 @@ static inline int read_proc_pid_statm(struct pid_stat *p) {
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
- file_counter++;
+ calls_counter++;
- p->statm_size = str2ull(procfile_lineword(ff, 0, 0));
- p->statm_resident = str2ull(procfile_lineword(ff, 0, 1));
- p->statm_share = str2ull(procfile_lineword(ff, 0, 2));
- // p->statm_text = str2ull(procfile_lineword(ff, 0, 3));
- // p->statm_lib = str2ull(procfile_lineword(ff, 0, 4));
- // p->statm_data = str2ull(procfile_lineword(ff, 0, 5));
- // p->statm_dirty = str2ull(procfile_lineword(ff, 0, 6));
+#ifdef __FreeBSD__
+ p->statm_size = proc_info->ki_size / sysconf(_SC_PAGESIZE);
+ p->statm_resident = proc_info->ki_rssize;
+ p->statm_share = 0; // do we have to use ru_ixrss here?
+#else
+ p->statm_size = str2kernel_uint_t(procfile_lineword(ff, 0, 0));
+ p->statm_resident = str2kernel_uint_t(procfile_lineword(ff, 0, 1));
+ p->statm_share = str2kernel_uint_t(procfile_lineword(ff, 0, 2));
+ // p->statm_text = str2kernel_uint_t(procfile_lineword(ff, 0, 3));
+ // p->statm_lib = str2kernel_uint_t(procfile_lineword(ff, 0, 4));
+ // p->statm_data = str2kernel_uint_t(procfile_lineword(ff, 0, 5));
+ // p->statm_dirty = str2kernel_uint_t(procfile_lineword(ff, 0, 6));
+#endif
return 1;
+#ifndef __FreeBSD__
cleanup:
p->statm_size = 0;
p->statm_resident = 0;
@@ -771,14 +1090,19 @@ cleanup:
// p->statm_data = 0;
// p->statm_dirty = 0;
return 0;
+#endif
}
-static inline int read_proc_pid_io(struct pid_stat *p) {
+static inline int read_proc_pid_io(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
+#else
static procfile *ff = NULL;
if(unlikely(!p->io_filename)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", global_host_prefix, p->pid);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", netdata_configured_host_prefix, p->pid);
p->io_filename = strdupz(filename);
}
@@ -788,41 +1112,25 @@ static inline int read_proc_pid_io(struct pid_stat *p) {
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
- file_counter++;
+ calls_counter++;
p->last_io_collected_usec = p->io_collected_usec;
- p->io_collected_usec = now_realtime_usec();
-
- unsigned long long last;
-
- last = p->io_logical_bytes_read_raw;
- p->io_logical_bytes_read_raw = str2ull(procfile_lineword(ff, 0, 1));
- p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- last = p->io_logical_bytes_written_raw;
- p->io_logical_bytes_written_raw = str2ull(procfile_lineword(ff, 1, 1));
- p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- // last = p->io_read_calls_raw;
- // p->io_read_calls_raw = str2ull(procfile_lineword(ff, 2, 1));
- // p->io_read_calls = (p->io_read_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- // last = p->io_write_calls_raw;
- // p->io_write_calls_raw = str2ull(procfile_lineword(ff, 3, 1));
- // p->io_write_calls = (p->io_write_calls_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+ p->io_collected_usec = now_monotonic_usec();
- last = p->io_storage_bytes_read_raw;
- p->io_storage_bytes_read_raw = str2ull(procfile_lineword(ff, 4, 1));
- p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- last = p->io_storage_bytes_written_raw;
- p->io_storage_bytes_written_raw = str2ull(procfile_lineword(ff, 5, 1));
- p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
-
- // last = p->io_cancelled_write_bytes_raw;
- // p->io_cancelled_write_bytes_raw = str2ull(procfile_lineword(ff, 6, 1));
- // p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+#ifdef __FreeBSD__
+ pid_incremental_rate(io, p->io_storage_bytes_read, proc_info->ki_rusage.ru_inblock);
+ pid_incremental_rate(io, p->io_storage_bytes_written, proc_info->ki_rusage.ru_oublock);
+#else
+ pid_incremental_rate(io, p->io_logical_bytes_read, str2kernel_uint_t(procfile_lineword(ff, 0, 1)));
+ pid_incremental_rate(io, p->io_logical_bytes_written, str2kernel_uint_t(procfile_lineword(ff, 1, 1)));
+ // pid_incremental_rate(io, p->io_read_calls, str2kernel_uint_t(procfile_lineword(ff, 2, 1)));
+ // pid_incremental_rate(io, p->io_write_calls, str2kernel_uint_t(procfile_lineword(ff, 3, 1)));
+ pid_incremental_rate(io, p->io_storage_bytes_read, str2kernel_uint_t(procfile_lineword(ff, 4, 1)));
+ pid_incremental_rate(io, p->io_storage_bytes_written, str2kernel_uint_t(procfile_lineword(ff, 5, 1)));
+ // pid_incremental_rate(io, p->io_cancelled_write_bytes, str2kernel_uint_t(procfile_lineword(ff, 6, 1)));
+#endif
if(unlikely(global_iterations_counter == 1)) {
p->io_logical_bytes_read = 0;
@@ -836,6 +1144,7 @@ static inline int read_proc_pid_io(struct pid_stat *p) {
return 1;
+#ifndef __FreeBSD__
cleanup:
p->io_logical_bytes_read = 0;
p->io_logical_bytes_written = 0;
@@ -845,60 +1154,77 @@ cleanup:
p->io_storage_bytes_written = 0;
// p->io_cancelled_write_bytes = 0;
return 0;
+#endif
}
-unsigned long long global_utime = 0;
-unsigned long long global_stime = 0;
-unsigned long long global_gtime = 0;
-
static inline int read_proc_stat() {
+#ifdef __FreeBSD__
+ long cp_time[CPUSTATES];
+ static kernel_uint_t utime_raw = 0, stime_raw = 0, ntime_raw = 0;
+
+ if (unlikely(CPUSTATES != 5)) {
+ error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+ goto cleanup;
+ }
+ if (unlikely(GETSYSCTL_BY_NAME("kern.cp_time", cp_time))) goto cleanup;
+#else
static char filename[FILENAME_MAX + 1] = "";
static procfile *ff = NULL;
- static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
+ static kernel_uint_t utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
+#endif
static usec_t collected_usec = 0, last_collected_usec = 0;
+#ifndef __FreeBSD__
if(unlikely(!ff)) {
- snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix);
ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) goto cleanup;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) goto cleanup;
+#endif
last_collected_usec = collected_usec;
- collected_usec = now_realtime_usec();
-
- file_counter++;
+ collected_usec = now_monotonic_usec();
- unsigned long long last;
+ calls_counter++;
- last = utime_raw;
- utime_raw = str2ull(procfile_lineword(ff, 0, 1));
- global_utime = (utime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+ // temporary - it is added global_ntime;
+ kernel_uint_t global_ntime = 0;
- // nice time, on user time
- last = ntime_raw;
- ntime_raw = str2ull(procfile_lineword(ff, 0, 2));
- global_utime += (ntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
-
- last = stime_raw;
- stime_raw = str2ull(procfile_lineword(ff, 0, 3));
- global_stime = (stime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+#ifdef __FreeBSD__
+ incremental_rate(global_utime, utime_raw, cp_time[0], collected_usec, last_collected_usec);
+ incremental_rate(global_ntime, ntime_raw, cp_time[1], collected_usec, last_collected_usec);
+ incremental_rate(global_stime, stime_raw, cp_time[2], collected_usec, last_collected_usec);
+#else
+ incremental_rate(global_utime, utime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 1)), collected_usec, last_collected_usec);
+ incremental_rate(global_ntime, ntime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 2)), collected_usec, last_collected_usec);
+ incremental_rate(global_stime, stime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 3)), collected_usec, last_collected_usec);
+ incremental_rate(global_gtime, gtime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 10)), collected_usec, last_collected_usec);
+#endif
- last = gtime_raw;
- gtime_raw = str2ull(procfile_lineword(ff, 0, 10));
- global_gtime = (gtime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+ global_utime += global_ntime;
+#ifdef __FreeBSD__
+ if(enable_guest_charts) {
+ enable_guest_charts = 0;
+ info("Guest charts aren't supported by FreeBSD");
+ }
+#else
if(enable_guest_charts) {
+ // temporary - it is added global_ntime;
+ kernel_uint_t global_gntime = 0;
+
// guest nice time, on guest time
- last = gntime_raw;
- gntime_raw = str2ull(procfile_lineword(ff, 0, 11));
- global_gtime += (gntime_raw - last) * (USEC_PER_SEC * RATES_DETAIL) / (collected_usec - last_collected_usec);
+ incremental_rate(global_gntime, gntime_raw, str2kernel_uint_t(procfile_lineword(ff, 0, 11)), collected_usec, last_collected_usec);
+
+ global_gtime += global_gntime;
// remove guest time from user time
global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime;
}
+#endif
if(unlikely(global_iterations_counter == 1)) {
global_utime = 0;
@@ -917,26 +1243,6 @@ cleanup:
// ----------------------------------------------------------------------------
-// file descriptor
-// this is used to keep a global list of all open files of the system
-// it is needed in order to calculate the unique files processes have open
-
-#define FILE_DESCRIPTORS_INCREASE_STEP 100
-
-struct file_descriptor {
- avl avl;
-#ifdef NETDATA_INTERNAL_CHECKS
- uint32_t magic;
-#endif /* NETDATA_INTERNAL_CHECKS */
- uint32_t hash;
- const char *name;
- int type;
- int count;
- int pos;
-} *all_files = NULL;
-
-int all_files_len = 0;
-int all_files_size = 0;
int file_descriptor_compare(void* a, void* b) {
#ifdef NETDATA_INTERNAL_CHECKS
@@ -977,15 +1283,7 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h
#define file_descriptor_add(fd) avl_insert(&all_files_index, (avl *)(fd))
#define file_descriptor_remove(fd) avl_remove(&all_files_index, (avl *)(fd))
-#define FILETYPE_OTHER 0
-#define FILETYPE_FILE 1
-#define FILETYPE_PIPE 2
-#define FILETYPE_SOCKET 3
-#define FILETYPE_INOTIFY 4
-#define FILETYPE_EVENTFD 5
-#define FILETYPE_EVENTPOLL 6
-#define FILETYPE_TIMERFD 7
-#define FILETYPE_SIGNALFD 8
+// ----------------------------------------------------------------------------
static inline void file_descriptor_not_used(int id)
{
@@ -1066,7 +1364,7 @@ static inline void all_files_grow() {
all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
}
-static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t hash, int type) {
+static inline int file_descriptor_set_on_empty_slot(const char *name, uint32_t hash, FD_FILETYPE type) {
// check we have enough memory to add it
if(!all_files || all_files_len == all_files_size)
all_files_grow();
@@ -1147,21 +1445,26 @@ static inline int file_descriptor_find_or_add(const char *name)
}
// not found
- int type;
- if(name[0] == '/') type = FILETYPE_FILE;
- else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
- else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
- else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
- else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
- else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
- else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
- else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
- else if(strncmp(name, "anon_inode:", 11) == 0) {
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
+ FD_FILETYPE type;
+ if(likely(name[0] == '/')) type = FILETYPE_FILE;
+ else if(likely(strncmp(name, "pipe:", 5) == 0)) type = FILETYPE_PIPE;
+ else if(likely(strncmp(name, "socket:", 7) == 0)) type = FILETYPE_SOCKET;
+ else if(likely(strncmp(name, "anon_inode:", 11) == 0)) {
+ const char *t = &name[11];
+
+ if(strcmp(t, "inotify") == 0) type = FILETYPE_INOTIFY;
+ else if(strcmp(t, "[eventfd]") == 0) type = FILETYPE_EVENTFD;
+ else if(strcmp(t, "[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
+ else if(strcmp(t, "[timerfd]") == 0) type = FILETYPE_TIMERFD;
+ else if(strcmp(t, "[signalfd]") == 0) type = FILETYPE_SIGNALFD;
+ else {
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
- type = FILETYPE_OTHER;
+ type = FILETYPE_OTHER;
+ }
}
+ else if(likely(strcmp(name, "inotify") == 0)) type = FILETYPE_INOTIFY;
else {
if(unlikely(debug))
fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
@@ -1172,81 +1475,243 @@ static inline int file_descriptor_find_or_add(const char *name)
return file_descriptor_set_on_empty_slot(name, hash, type);
}
-static inline int read_pid_file_descriptors(struct pid_stat *p) {
- char dirname[FILENAME_MAX+1];
+static inline void make_all_pid_fds_negative(struct pid_stat *p) {
+ int *fd = p->fds, *end = &p->fds[p->fds_size];
+ while(fd < end) {
+ *fd = -(*fd);
+ fd++;
+ }
+}
- snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
- DIR *fds = opendir(dirname);
- if(fds) {
- int c;
- struct dirent *de;
- char fdname[FILENAME_MAX + 1];
- char linkname[FILENAME_MAX + 1];
+static inline void cleanup_negative_pid_fds(struct pid_stat *p) {
+ int *fd = p->fds, *fdend = &p->fds[p->fds_size];
- // make the array negative
- for(c = 0 ; c < p->fds_size ; c++)
- p->fds[c] = -p->fds[c];
+ while(fd < fdend) {
+ if(unlikely(*fd < 0)) {
+ file_descriptor_not_used(-(*fd));
+ *fd++ = 0;
+ }
+ else
+ fd++;
+ }
+}
- while((de = readdir(fds))) {
- if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
- continue;
+static inline void zero_pid_fds(struct pid_stat *p, int first, int size) {
+ int *fd = &p->fds[first], *end = &p->fds[first + size];
+ while(fd < end) *fd++ = 0;
+}
- // check if the fds array is small
- int fdid = (int)str2l(de->d_name);
- if(fdid < 0) continue;
- if(fdid >= p->fds_size) {
- // it is small, extend it
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
+static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) {
+ (void)ptr;
+#ifdef __FreeBSD__
+ int mib[4];
+ size_t size;
+ struct kinfo_file *fds;
+ static char *fdsbuf;
+ char *bfdsbuf, *efdsbuf;
+ char fdsname[FILENAME_MAX + 1];
+
+ // we make all pid fds negative, so that
+ // we can detect unused file descriptors
+ // at the end, to free them
+ make_all_pid_fds_negative(p);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_FILEDESC;
+ mib[3] = p->pid;
+
+ if (unlikely(sysctl(mib, 4, NULL, &size, NULL, 0))) {
+ error("sysctl error: Can't get file descriptors data size for pid %d", p->pid);
+ return 0;
+ }
+ if (likely(size > 0))
+ fdsbuf = reallocz(fdsbuf, size);
+ if (unlikely(sysctl(mib, 4, fdsbuf, &size, NULL, 0))) {
+ error("sysctl error: Can't get file descriptors data for pid %d", p->pid);
+ return 0;
+ }
- p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+ bfdsbuf = fdsbuf;
+ efdsbuf = fdsbuf + size;
+ while (bfdsbuf < efdsbuf) {
+ fds = (struct kinfo_file *)(uintptr_t)bfdsbuf;
+ if (unlikely(fds->kf_structsize == 0))
+ break;
- // and initialize it
- for(c = p->fds_size ; c < (fdid + MAX_SPARE_FDS) ; c++) p->fds[c] = 0;
- p->fds_size = fdid + MAX_SPARE_FDS;
- }
+ // do not process file descriptors for current working directory, root directory,
+ // jail directory, ktrace vnode, text vnode and controlling terminal
+ if (unlikely(fds->kf_fd < 0)) {
+ bfdsbuf += fds->kf_structsize;
+ continue;
+ }
- if(p->fds[fdid] == 0) {
- // we don't know this fd, get it
+ // get file descriptors array index
+ int fdid = fds->kf_fd;
- sprintf(fdname, "%s/proc/%d/fd/%s", global_host_prefix, p->pid, de->d_name);
- ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
- if(l == -1) {
- if(debug || (p->target && p->target->debug)) {
- if(debug || (p->target && p->target->debug))
- error("Cannot read link %s", fdname);
- }
- continue;
- }
- linkname[l] = '\0';
- file_counter++;
+ // check if the fds array is small
+ if (unlikely(fdid >= p->fds_size)) {
+ // it is small, extend it
+
+ if (unlikely(debug))
+ fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
+
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
- // if another process already has this, we will get
- // the same id
- p->fds[fdid] = file_descriptor_find_or_add(linkname);
+ // and initialize it
+ zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+ p->fds_size = fdid + MAX_SPARE_FDS;
+ }
+
+ if (unlikely(p->fds[fdid] == 0)) {
+ // we don't know this fd, get it
+
+ switch (fds->kf_type) {
+ case KF_TYPE_FIFO:
+ case KF_TYPE_VNODE:
+ if (unlikely(!fds->kf_path[0])) {
+ sprintf(fdsname, "other: inode: %lu", fds->kf_un.kf_file.kf_file_fileid);
+ break;
+ }
+ sprintf(fdsname, "%s", fds->kf_path);
+ break;
+ case KF_TYPE_SOCKET:
+ switch (fds->kf_sock_domain) {
+ case AF_INET:
+ case AF_INET6:
+ if (fds->kf_sock_protocol == IPPROTO_TCP)
+ sprintf(fdsname, "socket: %d %lx", fds->kf_sock_protocol, fds->kf_un.kf_sock.kf_sock_inpcb);
+ else
+ sprintf(fdsname, "socket: %d %lx", fds->kf_sock_protocol, fds->kf_un.kf_sock.kf_sock_pcb);
+ break;
+ case AF_UNIX:
+ /* print address of pcb and connected pcb */
+ sprintf(fdsname, "socket: %lx %lx", fds->kf_un.kf_sock.kf_sock_pcb, fds->kf_un.kf_sock.kf_sock_unpconn);
+ break;
+ default:
+ /* print protocol number and socket address */
+ sprintf(fdsname, "socket: other: %d %s %s", fds->kf_sock_protocol, fds->kf_sa_local.__ss_pad1, fds->kf_sa_local.__ss_pad2);
+ }
+ break;
+ case KF_TYPE_PIPE:
+ sprintf(fdsname, "pipe: %lu %lu", fds->kf_un.kf_pipe.kf_pipe_addr, fds->kf_un.kf_pipe.kf_pipe_peer);
+ break;
+ case KF_TYPE_PTS:
+ sprintf(fdsname, "other: pts: %u", fds->kf_un.kf_pts.kf_pts_dev);
+ break;
+ case KF_TYPE_SHM:
+ sprintf(fdsname, "other: shm: %s size: %lu", fds->kf_path, fds->kf_un.kf_file.kf_file_size);
+ break;
+ case KF_TYPE_SEM:
+ sprintf(fdsname, "other: sem: %u", fds->kf_un.kf_sem.kf_sem_value);
+ break;
+ default:
+ sprintf(fdsname, "other: pid: %d fd: %d", fds->kf_un.kf_proc.kf_pid, fds->kf_fd);
}
+ // if another process already has this, we will get
+ // the same id
+ p->fds[fdid] = file_descriptor_find_or_add(fdsname);
+ }
+
// else make it positive again, we need it
// of course, the actual file may have changed, but we don't care so much
// FIXME: we could compare the inode as returned by readdir dirent structure
- else p->fds[fdid] = -p->fds[fdid];
+
+ else
+ p->fds[fdid] = -p->fds[fdid];
+
+ bfdsbuf += fds->kf_structsize;
+ }
+#else
+ if(unlikely(!p->fds_dirname)) {
+ char dirname[FILENAME_MAX+1];
+ snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", netdata_configured_host_prefix, p->pid);
+ p->fds_dirname = strdupz(dirname);
+ }
+
+ DIR *fds = opendir(p->fds_dirname);
+ if(unlikely(!fds)) return 0;
+
+ struct dirent *de;
+ char fdname[FILENAME_MAX + 1];
+ char linkname[FILENAME_MAX + 1];
+
+ // we make all pid fds negative, so that
+ // we can detect unused file descriptors
+ // at the end, to free them
+ make_all_pid_fds_negative(p);
+
+ while((de = readdir(fds))) {
+ // we need only files with numeric names
+
+ if(unlikely(de->d_name[0] < '0' || de->d_name[0] > '9'))
+ continue;
+
+ // get its number
+ int fdid = (int) str2l(de->d_name);
+ if(unlikely(fdid < 0)) continue;
+
+ // check if the fds array is small
+ if(unlikely(fdid >= p->fds_size)) {
+ // it is small, extend it
+
+ if(unlikely(debug))
+ fprintf(stderr
+ , "apps.plugin: extending fd memory slots for %s from %d to %d\n"
+ , p->comm
+ , p->fds_size
+ , fdid + MAX_SPARE_FDS
+ );
+
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
+
+ // and initialize it
+ zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
+ p->fds_size = fdid + MAX_SPARE_FDS;
}
- closedir(fds);
- // remove all the negative file descriptors
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
- file_descriptor_not_used(-p->fds[c]);
- p->fds[c] = 0;
+ if(unlikely(p->fds[fdid] == 0)) {
+ // we don't know this fd, get it
+
+ sprintf(fdname, "%s/proc/%d/fd/%s", netdata_configured_host_prefix, p->pid, de->d_name);
+ ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
+ if(unlikely(l == -1)) {
+ if(debug || (p->target && p->target->debug)) {
+ if(debug || (p->target && p->target->debug))
+ error("Cannot read link %s", fdname);
+ }
+ continue;
+ }
+ else
+ linkname[l] = '\0';
+
+ file_counter++;
+
+ // if another process already has this, we will get
+ // the same id
+ p->fds[fdid] = file_descriptor_find_or_add(linkname);
}
+
+ // else make it positive again, we need it
+ // of course, the actual file may have changed, but we don't care so much
+ // FIXME: we could compare the inode as returned by readdir dirent structure
+ // UPDATE: no we cannot use inodes - under /proc inodes don't change when the link is changed
+
+ else
+ p->fds[fdid] = -p->fds[fdid];
}
- else return 0;
+
+ closedir(fds);
+#endif
+ cleanup_negative_pid_fds(p);
return 1;
}
// ----------------------------------------------------------------------------
-static inline int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
+static inline int print_process_and_parents(struct pid_stat *p, usec_t time) {
char *prefix = "\\_ ";
int indent = 0;
@@ -1261,25 +1726,25 @@ static inline int print_process_and_parents(struct pid_stat *p, unsigned long lo
for(i = 0; i < indent ;i++) buffer[i] = ' ';
buffer[i] = '\0';
- fprintf(stderr, " %s %s%s (%d %s %lld"
+ fprintf(stderr, " %s %s%s (%d %s %llu"
, buffer
, prefix
, p->comm
, p->pid
, p->updated?"running":"exited"
- , (long long)p->stat_collected_usec - (long long)time
+ , p->stat_collected_usec - time
);
- if(p->utime) fprintf(stderr, " utime=%llu", p->utime);
- if(p->stime) fprintf(stderr, " stime=%llu", p->stime);
- if(p->gtime) fprintf(stderr, " gtime=%llu", p->gtime);
- if(p->cutime) fprintf(stderr, " cutime=%llu", p->cutime);
- if(p->cstime) fprintf(stderr, " cstime=%llu", p->cstime);
- if(p->cgtime) fprintf(stderr, " cgtime=%llu", p->cgtime);
- if(p->minflt) fprintf(stderr, " minflt=%llu", p->minflt);
- if(p->cminflt) fprintf(stderr, " cminflt=%llu", p->cminflt);
- if(p->majflt) fprintf(stderr, " majflt=%llu", p->majflt);
- if(p->cmajflt) fprintf(stderr, " cmajflt=%llu", p->cmajflt);
+ if(p->utime) fprintf(stderr, " utime=" KERNEL_UINT_FORMAT, p->utime);
+ if(p->stime) fprintf(stderr, " stime=" KERNEL_UINT_FORMAT, p->stime);
+ if(p->gtime) fprintf(stderr, " gtime=" KERNEL_UINT_FORMAT, p->gtime);
+ if(p->cutime) fprintf(stderr, " cutime=" KERNEL_UINT_FORMAT, p->cutime);
+ if(p->cstime) fprintf(stderr, " cstime=" KERNEL_UINT_FORMAT, p->cstime);
+ if(p->cgtime) fprintf(stderr, " cgtime=" KERNEL_UINT_FORMAT, p->cgtime);
+ if(p->minflt) fprintf(stderr, " minflt=" KERNEL_UINT_FORMAT, p->minflt);
+ if(p->cminflt) fprintf(stderr, " cminflt=" KERNEL_UINT_FORMAT, p->cminflt);
+ if(p->majflt) fprintf(stderr, " majflt=" KERNEL_UINT_FORMAT, p->majflt);
+ if(p->cmajflt) fprintf(stderr, " cmajflt=" KERNEL_UINT_FORMAT, p->cmajflt);
fprintf(stderr, ")\n");
return indent + 1;
@@ -1291,7 +1756,7 @@ static inline void print_process_tree(struct pid_stat *p, char *msg) {
print_process_and_parents(p, p->stat_collected_usec);
}
-static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) {
+static inline void find_lost_child_debug(struct pid_stat *pe, kernel_uint_t lost, int type) {
int found = 0;
struct pid_stat *p = NULL;
@@ -1301,35 +1766,35 @@ static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long
switch(type) {
case 1:
if(p->cminflt > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child minflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 2:
if(p->cmajflt > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child majflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 3:
if(p->cutime > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child utime " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 4:
if(p->cstime > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child stime " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
case 5:
if(p->cgtime > lost) {
- fprintf(stderr, " > process %d (%s) could use the lost exited child gtime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+ fprintf(stderr, " > process %d (%s) could use the lost exited child gtime " KERNEL_UINT_FORMAT " of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
found++;
}
break;
@@ -1339,30 +1804,30 @@ static inline void find_lost_child_debug(struct pid_stat *pe, unsigned long long
if(!found) {
switch(type) {
case 1:
- fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child minflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 2:
- fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child majflt " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 3:
- fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child utime " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 4:
- fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child stime " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
case 5:
- fprintf(stderr, " > cannot find any process to use the lost exited child gtime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+ fprintf(stderr, " > cannot find any process to use the lost exited child gtime " KERNEL_UINT_FORMAT " of process %d (%s)\n", lost, pe->pid, pe->comm);
break;
}
}
}
-static inline unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) {
- unsigned long long absorbed = 0;
+static inline kernel_uint_t remove_exited_child_from_parent(kernel_uint_t *field, kernel_uint_t *pfield) {
+ kernel_uint_t absorbed = 0;
if(*field > *pfield) {
absorbed += *pfield;
@@ -1385,20 +1850,18 @@ static inline void process_exited_processes() {
if(p->updated || !p->stat_collected_usec)
continue;
- struct pid_stat *pp = p->parent;
-
- unsigned long long utime = (p->utime_raw + p->cutime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long stime = (p->stime_raw + p->cstime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long gtime = (p->gtime_raw + p->cgtime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long minflt = (p->minflt_raw + p->cminflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
- unsigned long long majflt = (p->majflt_raw + p->cmajflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t utime = (p->utime_raw + p->cutime_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t stime = (p->stime_raw + p->cstime_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t gtime = (p->gtime_raw + p->cgtime_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t minflt = (p->minflt_raw + p->cminflt_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+ kernel_uint_t majflt = (p->majflt_raw + p->cmajflt_raw) * (USEC_PER_SEC * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
if(utime + stime + gtime + minflt + majflt == 0)
continue;
if(unlikely(debug)) {
log_date(stderr);
- fprintf(stderr, "Absorb %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
+ fprintf(stderr, "Absorb %s (%d %s total resources: utime=" KERNEL_UINT_FORMAT " stime=" KERNEL_UINT_FORMAT " gtime=" KERNEL_UINT_FORMAT " minflt=" KERNEL_UINT_FORMAT " majflt=" KERNEL_UINT_FORMAT ")\n"
, p->comm
, p->pid
, p->updated?"running":"exited"
@@ -1411,29 +1874,30 @@ static inline void process_exited_processes() {
print_process_tree(p, "Searching parents");
}
+ struct pid_stat *pp;
for(pp = p->parent; pp ; pp = pp->parent) {
if(!pp->updated) continue;
- unsigned long long absorbed;
+ kernel_uint_t absorbed;
absorbed = remove_exited_child_from_parent(&utime, &pp->cutime);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu utime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " utime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
absorbed = remove_exited_child_from_parent(&stime, &pp->cstime);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu stime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " stime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
absorbed = remove_exited_child_from_parent(&gtime, &pp->cgtime);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu gtime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " gtime (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu minflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " minflt (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
if(unlikely(debug && absorbed))
- fprintf(stderr, " > process %s (%d %s) absorbed %llu majflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
+ fprintf(stderr, " > process %s (%d %s) absorbed " KERNEL_UINT_FORMAT " majflt (remaining: " KERNEL_UINT_FORMAT ")\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
}
if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
@@ -1448,7 +1912,7 @@ static inline void process_exited_processes() {
p->keep = 1;
if(unlikely(debug))
- fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
+ fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=" KERNEL_UINT_FORMAT " stime=" KERNEL_UINT_FORMAT " gtime=" KERNEL_UINT_FORMAT " minflt=" KERNEL_UINT_FORMAT " majflt=" KERNEL_UINT_FORMAT ")\n"
, p->comm
, p->pid
, p->updated?"running":"exited"
@@ -1513,7 +1977,7 @@ static inline void link_all_processes_to_their_parents(void) {
pp->children_count++;
if(unlikely(debug || (p->target && p->target->debug)))
- fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, gtime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
+ fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
}
else {
p->parent = NULL;
@@ -1540,6 +2004,7 @@ static inline void link_all_processes_to_their_parents(void) {
// to avoid filling up all disk space
// if debug is enabled, all errors are printed
+#ifndef __FreeBSD__
static int compar_pid(const void *pid1, const void *pid2) {
struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
@@ -1550,53 +2015,11 @@ static int compar_pid(const void *pid1, const void *pid2) {
else
return 1;
}
+#endif
-static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
- if(unlikely(!status)) {
- // error("command failed log %u, errno %d", log, errno);
-
- if(unlikely(debug || errno != ENOENT)) {
- if(unlikely(debug || !(p->log_thrown & log))) {
- p->log_thrown |= log;
- switch(log) {
- case PID_LOG_IO:
- error("Cannot process %s/proc/%d/io (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_STATM:
- error("Cannot process %s/proc/%d/statm (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_CMDLINE:
- error("Cannot process %s/proc/%d/cmdline (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_FDS:
- error("Cannot process entries in %s/proc/%d/fd (command '%s')", global_host_prefix, p->pid, p->comm);
- break;
-
- case PID_LOG_STAT:
- break;
-
- default:
- error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
- break;
- }
- }
- }
- errno = 0;
- }
- else if(unlikely(p->log_thrown & log)) {
- // error("unsetting log %u on pid %d", log, p->pid);
- p->log_thrown &= ~log;
- }
-
- return status;
-}
-
-static inline int collect_data_for_pid(pid_t pid) {
- if(unlikely(pid <= 0 || pid > pid_max)) {
- error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
+static inline int collect_data_for_pid(pid_t pid, void *ptr) {
+ if(unlikely(pid < INIT_PID || pid > pid_max)) {
+ error("Invalid pid %d read (expected %d to %d). Ignoring process.", pid, INIT_PID, pid_max);
return 0;
}
@@ -1609,11 +2032,11 @@ static inline int collect_data_for_pid(pid_t pid) {
// --------------------------------------------------------------------
// /proc/<pid>/stat
- if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p))))
+ if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p, ptr))))
// there is no reason to proceed if we cannot get its status
return 0;
- read_proc_pid_ownership(p);
+ read_proc_pid_ownership(p, ptr);
// check its parent pid
if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
@@ -1624,61 +2047,20 @@ static inline int collect_data_for_pid(pid_t pid) {
// --------------------------------------------------------------------
// /proc/<pid>/io
- managed_log(p, PID_LOG_IO, read_proc_pid_io(p));
+ managed_log(p, PID_LOG_IO, read_proc_pid_io(p, ptr));
// --------------------------------------------------------------------
// /proc/<pid>/statm
- if(unlikely(!managed_log(p, PID_LOG_STATM, read_proc_pid_statm(p))))
+ if(unlikely(!managed_log(p, PID_LOG_STATM, read_proc_pid_statm(p, ptr))))
// there is no reason to proceed if we cannot get its memory status
return 0;
// --------------------------------------------------------------------
- // link it
-
- // check if it is target
- // we do this only once, the first time this pid is loaded
- if(unlikely(p->new_entry)) {
- // /proc/<pid>/cmdline
- if(likely(proc_pid_cmdline_is_needed))
- managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
-
- if(unlikely(debug))
- fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
-
- uint32_t hash = simple_hash(p->comm);
- size_t pclen = strlen(p->comm);
-
- struct target *w;
- for(w = apps_groups_root_target; w ; w = w->next) {
- // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
-
- // find it - 4 cases:
- // 1. the target is not a pattern
- // 2. the target has the prefix
- // 3. the target has the suffix
- // 4. the target is something inside cmdline
- if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
- || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
- || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
- || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
- ) {
- if(w->target) p->target = w->target;
- else p->target = w;
-
- if(debug || (p->target && p->target->debug))
- fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
-
- break;
- }
- }
- }
-
- // --------------------------------------------------------------------
// /proc/<pid>/fd
if(enable_file_charts)
- managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p));
+ managed_log(p, PID_LOG_FDS, read_pid_file_descriptors(p, ptr));
// --------------------------------------------------------------------
// done!
@@ -1694,71 +2076,116 @@ static inline int collect_data_for_pid(pid_t pid) {
return 1;
}
-static int collect_data_for_all_processes_from_proc(void) {
+static int collect_data_for_all_processes(void) {
struct pid_stat *p = NULL;
- if(all_pids_count) {
- // read parents before childs
- // this is needed to prevent a situation where
- // a child is found running, but until we read
- // its parent, it has exited and its parent
- // has accumulated its resources
+#ifdef __FreeBSD__
+ int i, procnum;
+ size_t procbase_size;
+ static struct kinfo_proc *procbase;
- long slc = 0;
+ int mib[3];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PROC;
+ if (unlikely(sysctl(mib, 3, NULL, &procbase_size, NULL, 0))) {
+ error("sysctl error: Can't get processes data size");
+ return 0;
+ }
+ procbase = reallocz(procbase, procbase_size);
+ if (unlikely(sysctl(mib, 3, procbase, &procbase_size, NULL, 0))) {
+ error("sysctl error: Can't get processes data");
+ return 0;
+ }
+ procnum = procbase_size / sizeof(struct kinfo_proc);
+#endif
+
+ if(all_pids_count) {
+#ifndef __FreeBSD__
+ size_t slc = 0;
+#endif
for(p = root_of_pids; p ; p = p->next) {
- p->read = 0;
+ p->read = 0; // mark it as not read, so that collect_data_for_pid() will read it
p->updated = 0;
- p->new_entry = 0;
p->merged = 0;
p->children_count = 0;
p->parent = NULL;
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
all_pids_sortlist[slc++] = p->pid;
+#endif
}
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
if(unlikely(slc != all_pids_count)) {
- error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
+ error("Internal error: I was thinking I had %zu processes in my arrays, but it seems there are more.", all_pids_count);
all_pids_count = slc;
}
if(include_exited_childs) {
+ // Read parents before childs
+ // This is needed to prevent a situation where
+ // a child is found running, but until we read
+ // its parent, it has exited and its parent
+ // has accumulated its resources.
+
qsort((void *)all_pids_sortlist, (size_t)all_pids_count, sizeof(pid_t), compar_pid);
+
+ // we forward read all running processes
+ // collect_data_for_pid() is smart enough,
+ // not to read the same pid twice per iteration
for(slc = 0; slc < all_pids_count; slc++)
- collect_data_for_pid(all_pids_sortlist[slc]);
+ collect_data_for_pid(all_pids_sortlist[slc], NULL);
}
+#endif
}
+#ifdef __FreeBSD__
+ for (i = INIT_PID; i < procnum - INIT_PID; ++i) {
+ pid_t pid = procbase[i].ki_pid;
+ collect_data_for_pid(pid, &procbase[i]);
+ }
+#else
char dirname[FILENAME_MAX + 1];
- snprintfz(dirname, FILENAME_MAX, "%s/proc", global_host_prefix);
+ snprintfz(dirname, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
DIR *dir = opendir(dirname);
if(!dir) return 0;
- struct dirent *file = NULL;
+ struct dirent *de = NULL;
+
+ while((de = readdir(dir))) {
+ char *endptr = de->d_name;
+
+ if(unlikely(de->d_type != DT_DIR || de->d_name[0] < '0' || de->d_name[0] > '9'))
+ continue;
- while((file = readdir(dir))) {
- char *endptr = file->d_name;
- pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
+ pid_t pid = (pid_t) strtoul(de->d_name, &endptr, 10);
// make sure we read a valid number
- if(unlikely(endptr == file->d_name || *endptr != '\0'))
+ if(unlikely(endptr == de->d_name || *endptr != '\0'))
continue;
- collect_data_for_pid(pid);
+ collect_data_for_pid(pid, NULL);
}
closedir(dir);
+#endif
if(!all_pids_count)
return 0;
+ // we need /proc/stat to normalize the cpu consumption of the exited childs
+ read_proc_stat();
+
+ // build the process tree
+ link_all_processes_to_their_parents();
+
// normally this is done
// however we may have processes exited while we collected values
// so let's find the exited ones
// we do this by collecting the ownership of process
// if we manage to get the ownership, the process still runs
-
- read_proc_stat();
- link_all_processes_to_their_parents();
process_exited_processes();
return 1;
@@ -1786,15 +2213,14 @@ static void cleanup_exited_pids(void) {
for(p = root_of_pids; p ;) {
if(!p->updated && (!p->keep || p->keeploops > 0)) {
-// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
-
if(unlikely(debug && (p->keep || p->keeploops)))
fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
- file_descriptor_not_used(p->fds[c]);
- p->fds[c] = 0;
- }
+ for(c = 0; c < p->fds_size; c++)
+ if(p->fds[c] > 0) {
+ file_descriptor_not_used(p->fds[c]);
+ p->fds[c] = 0;
+ }
pid_t r = p->pid;
p = p->next;
@@ -1857,7 +2283,7 @@ static void apply_apps_groups_targets_inheritance(void) {
&& p->parent
&& p->parent->children_count
&& (p->target == p->parent->target || !p->parent->target)
- && p->ppid != 1
+ && p->ppid != INIT_PID
)) {
p->parent->children_count--;
p->merged = 1;
@@ -1879,8 +2305,8 @@ static void apply_apps_groups_targets_inheritance(void) {
}
// init goes always to default target
- if(all_pids[1])
- all_pids[1]->target = apps_groups_default_target;
+ if(all_pids[INIT_PID])
+ all_pids[INIT_PID]->target = apps_groups_default_target;
// give a default target on all top level processes
if(unlikely(debug)) loops++;
@@ -1918,9 +2344,9 @@ static void apply_apps_groups_targets_inheritance(void) {
fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
}
-static long zero_all_targets(struct target *root) {
+static size_t zero_all_targets(struct target *root) {
struct target *w;
- long count = 0;
+ size_t count = 0;
for (w = root; w ; w = w->next) {
count++;
@@ -2032,7 +2458,7 @@ static inline void aggregate_fd_on_target(int fd, struct target *w) {
w->openeventpolls++;
break;
- default:
+ case FILETYPE_OTHER:
w->openother++;
break;
}
@@ -2111,7 +2537,7 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
w->num_threads += p->num_threads;
if(unlikely(debug || w->debug))
- fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+ fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
}
static void calculate_netdata_statistics(void) {
@@ -2120,7 +2546,7 @@ static void calculate_netdata_statistics(void) {
zero_all_targets(users_root_target);
zero_all_targets(groups_root_target);
- apps_groups_targets = zero_all_targets(apps_groups_root_target);
+ apps_groups_targets_count = zero_all_targets(apps_groups_root_target);
// this has to be done, before the cleanup
struct pid_stat *p = NULL;
@@ -2182,21 +2608,18 @@ static void calculate_netdata_statistics(void) {
int print_calculated_number(char *str, calculated_number value) { (void)str; (void)value; return 0; }
-static inline void send_BEGIN(const char *type, const char *id, unsigned long long usec) {
+static inline void send_BEGIN(const char *type, const char *id, usec_t usec) {
fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
}
-static inline void send_SET(const char *name, unsigned long long value) {
- fprintf(stdout, "SET %s = %llu\n", name, value);
+static inline void send_SET(const char *name, kernel_uint_t value) {
+ fprintf(stdout, "SET %s = " KERNEL_UINT_FORMAT "\n", name, value);
}
static inline void send_END(void) {
fprintf(stdout, "END\n");
}
-double utime_fix_ratio = 1.0, stime_fix_ratio = 1.0, gtime_fix_ratio = 1.0, cutime_fix_ratio = 1.0, cstime_fix_ratio = 1.0, cgtime_fix_ratio = 1.0;
-double minflt_fix_ratio = 1.0, majflt_fix_ratio = 1.0, cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0;
-
static usec_t send_resource_usage_to_netdata() {
static struct timeval last = { 0, 0 };
static struct rusage me_last;
@@ -2209,7 +2632,7 @@ static usec_t send_resource_usage_to_netdata() {
usec_t cpusyst;
if(!last.tv_sec) {
- now_realtime_timeval(&last);
+ now_monotonic_timeval(&last);
getrusage(RUSAGE_SELF, &me_last);
// the first time, give a zero to allow
@@ -2220,7 +2643,7 @@ static usec_t send_resource_usage_to_netdata() {
cpusyst = 0;
}
else {
- now_realtime_timeval(&now);
+ now_monotonic_timeval(&now);
getrusage(RUSAGE_SELF, &me);
usec = dt_usec(&now, &last);
@@ -2231,73 +2654,115 @@ static usec_t send_resource_usage_to_netdata() {
memmove(&me_last, &me, sizeof(struct rusage));
}
+ static char created_charts = 0;
+ if(unlikely(!created_charts)) {
+ created_charts = 1;
+
+ fprintf(stdout
+ , "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
+ "DIMENSION user '' incremental 1 1000\n"
+ "DIMENSION system '' incremental 1 1000\n"
+ "CHART netdata.apps_sizes '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_sizes line 140001 %1$d\n"
+ "DIMENSION calls '' incremental 1 1\n"
+ "DIMENSION files '' incremental 1 1\n"
+ "DIMENSION pids '' absolute 1 1\n"
+ "DIMENSION fds '' absolute 1 1\n"
+ "DIMENSION targets '' absolute 1 1\n"
+ "DIMENSION new_pids 'new pids' incremental 1 1\n"
+ "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
+ "DIMENSION utime '' absolute 1 %2$llu\n"
+ "DIMENSION stime '' absolute 1 %2$llu\n"
+ "DIMENSION gtime '' absolute 1 %2$llu\n"
+ "DIMENSION minflt '' absolute 1 %2$llu\n"
+ "DIMENSION majflt '' absolute 1 %2$llu\n"
+ , update_every
+ , RATES_DETAIL
+ );
+
+ if(include_exited_childs)
+ fprintf(stdout
+ , "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
+ "DIMENSION cutime '' absolute 1 %2$llu\n"
+ "DIMENSION cstime '' absolute 1 %2$llu\n"
+ "DIMENSION cgtime '' absolute 1 %2$llu\n"
+ "DIMENSION cminflt '' absolute 1 %2$llu\n"
+ "DIMENSION cmajflt '' absolute 1 %2$llu\n"
+ , update_every
+ , RATES_DETAIL
+ );
+ }
+
fprintf(stdout,
"BEGIN netdata.apps_cpu %llu\n"
"SET user = %llu\n"
"SET system = %llu\n"
"END\n"
- "BEGIN netdata.apps_files %llu\n"
- "SET files = %llu\n"
- "SET pids = %ld\n"
+ "BEGIN netdata.apps_sizes %llu\n"
+ "SET calls = %zu\n"
+ "SET files = %zu\n"
+ "SET pids = %zu\n"
"SET fds = %d\n"
- "SET targets = %ld\n"
+ "SET targets = %zu\n"
+ "SET new_pids = %zu\n"
"END\n"
"BEGIN netdata.apps_fix %llu\n"
- "SET utime = %llu\n"
- "SET stime = %llu\n"
- "SET gtime = %llu\n"
- "SET minflt = %llu\n"
- "SET majflt = %llu\n"
+ "SET utime = %u\n"
+ "SET stime = %u\n"
+ "SET gtime = %u\n"
+ "SET minflt = %u\n"
+ "SET majflt = %u\n"
"END\n"
, usec
, cpuuser
, cpusyst
, usec
+ , calls_counter
, file_counter
, all_pids_count
, all_files_len
- , apps_groups_targets
+ , apps_groups_targets_count
+ , targets_assignment_counter
, usec
- , (unsigned long long)(utime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(stime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(gtime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(minflt_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(majflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(utime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(stime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(gtime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(minflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(majflt_fix_ratio * 100 * RATES_DETAIL)
);
if(include_exited_childs)
fprintf(stdout,
"BEGIN netdata.apps_children_fix %llu\n"
- "SET cutime = %llu\n"
- "SET cstime = %llu\n"
- "SET cgtime = %llu\n"
- "SET cminflt = %llu\n"
- "SET cmajflt = %llu\n"
+ "SET cutime = %u\n"
+ "SET cstime = %u\n"
+ "SET cgtime = %u\n"
+ "SET cminflt = %u\n"
+ "SET cmajflt = %u\n"
"END\n"
, usec
- , (unsigned long long)(cutime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cstime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cgtime_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cminflt_fix_ratio * 100 * RATES_DETAIL)
- , (unsigned long long)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cutime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cstime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cgtime_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cminflt_fix_ratio * 100 * RATES_DETAIL)
+ , (unsigned int)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
);
return usec;
}
-static void normalize_data(struct target *root) {
+static void normalize_utilization(struct target *root) {
struct target *w;
// childs processing introduces spikes
// here we try to eliminate them by disabling childs processing either for specific dimensions
// or entirely. Of course, either way, we disable it just a single iteration.
- unsigned long long max = processors * hz * RATES_DETAIL;
- unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
+ kernel_uint_t max_time = processors * hz * RATES_DETAIL;
+ kernel_uint_t utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
- if(global_utime > max) global_utime = max;
- if(global_stime > max) global_stime = max;
- if(global_gtime > max) global_gtime = max;
+ if(global_utime > max_time) global_utime = max_time;
+ if(global_stime > max_time) global_stime = max_time;
+ if(global_gtime > max_time) global_gtime = max_time;
for(w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
@@ -2397,11 +2862,11 @@ static void normalize_data(struct target *root) {
if(unlikely(debug)) {
fprintf(stderr,
- "SYSTEM: u=%llu s=%llu g=%llu "
- "COLLECTED: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
- "DELTA: u=%lld s=%lld g=%lld "
+ "SYSTEM: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " "
+ "COLLECTED: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " cu=" KERNEL_UINT_FORMAT " cs=" KERNEL_UINT_FORMAT " cg=" KERNEL_UINT_FORMAT " "
+ "DELTA: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " "
"FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
- "FINALLY: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
+ "FINALLY: u=" KERNEL_UINT_FORMAT " s=" KERNEL_UINT_FORMAT " g=" KERNEL_UINT_FORMAT " cu=" KERNEL_UINT_FORMAT " cs=" KERNEL_UINT_FORMAT " cg=" KERNEL_UINT_FORMAT " "
"\n"
, global_utime
, global_stime
@@ -2412,21 +2877,21 @@ static void normalize_data(struct target *root) {
, cutime
, cstime
, cgtime
- , (long long)utime + (long long)cutime - (long long)global_utime
- , (long long)stime + (long long)cstime - (long long)global_stime
- , (long long)gtime + (long long)cgtime - (long long)global_gtime
+ , utime + cutime - global_utime
+ , stime + cstime - global_stime
+ , gtime + cgtime - global_gtime
, utime_fix_ratio
, stime_fix_ratio
, gtime_fix_ratio
, cutime_fix_ratio
, cstime_fix_ratio
, cgtime_fix_ratio
- , (unsigned long long)(utime * utime_fix_ratio)
- , (unsigned long long)(stime * stime_fix_ratio)
- , (unsigned long long)(gtime * gtime_fix_ratio)
- , (unsigned long long)(cutime * cutime_fix_ratio)
- , (unsigned long long)(cstime * cstime_fix_ratio)
- , (unsigned long long)(cgtime * cgtime_fix_ratio)
+ , (kernel_uint_t)(utime * utime_fix_ratio)
+ , (kernel_uint_t)(stime * stime_fix_ratio)
+ , (kernel_uint_t)(gtime * gtime_fix_ratio)
+ , (kernel_uint_t)(cutime * cutime_fix_ratio)
+ , (kernel_uint_t)(cstime * cstime_fix_ratio)
+ , (kernel_uint_t)(cgtime * cgtime_fix_ratio)
);
}
}
@@ -2437,21 +2902,21 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_BEGIN(type, "cpu", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (unsigned long long)(w->stime * stime_fix_ratio) + (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio) + (unsigned long long)(w->cstime * cstime_fix_ratio) + (unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->utime * utime_fix_ratio) + (kernel_uint_t)(w->stime * stime_fix_ratio) + (kernel_uint_t)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cutime * cutime_fix_ratio) + (kernel_uint_t)(w->cstime * cstime_fix_ratio) + (kernel_uint_t)(w->cgtime * cgtime_fix_ratio)):0ULL));
}
send_END();
send_BEGIN(type, "cpu_user", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->utime * utime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cutime * cutime_fix_ratio)):0ULL));
}
send_END();
send_BEGIN(type, "cpu_system", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->stime * stime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cstime * cstime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->stime * stime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cstime * cstime_fix_ratio)):0ULL));
}
send_END();
@@ -2459,7 +2924,7 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_BEGIN(type, "cpu_guest", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cgtime * cgtime_fix_ratio)):0ULL));
}
send_END();
}
@@ -2495,17 +2960,18 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_BEGIN(type, "minor_faults", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cminflt * cminflt_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cminflt * cminflt_fix_ratio)):0ULL));
}
send_END();
send_BEGIN(type, "major_faults", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
- send_SET(w->name, (unsigned long long)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
+ send_SET(w->name, (kernel_uint_t)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((kernel_uint_t)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
}
send_END();
+#ifndef __FreeBSD__
send_BEGIN(type, "lreads", usec);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
@@ -2519,6 +2985,7 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_SET(w->name, w->io_logical_bytes_written);
}
send_END();
+#endif
send_BEGIN(type, "preads", usec);
for (w = root; w ; w = w->next) {
@@ -2644,29 +3111,43 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
+#ifdef __FreeBSD__
+ fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'blocks/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed))
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+ }
+
+ fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'blocks/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed))
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+ }
+#else
+ fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
+ fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
+ fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
- fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
+ fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
}
+#endif
if(enable_file_charts) {
fprintf(stdout, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type,
@@ -2696,6 +3177,22 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
// ----------------------------------------------------------------------------
// parse command line arguments
+int check_proc_1_io() {
+ int ret = 0;
+
+ procfile *ff = procfile_open("/proc/1/io", NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+ if(!ff) goto cleanup;
+
+ ff = procfile_readall(ff);
+ if(!ff) goto cleanup;
+
+ ret = 1;
+
+cleanup:
+ procfile_close(ff);
+ return ret;
+}
+
static void parse_args(int argc, char **argv)
{
int i, freq = 0;
@@ -2710,11 +3207,20 @@ static void parse_args(int argc, char **argv)
}
}
- if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0) {
+ if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
printf("apps.plugin %s\n", VERSION);
exit(0);
}
+ if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
+ if(!check_proc_1_io()) {
+ perror("Tried to read /proc/1/io and it failed");
+ exit(1);
+ }
+ printf("OK\n");
+ exit(0);
+ }
+
if(strcmp("debug", argv[i]) == 0) {
debug = 1;
// debug_flags = 0xffffffff;
@@ -2766,12 +3272,12 @@ static void parse_args(int argc, char **argv)
"\n"
" netdata apps.plugin %s\n"
" Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
- " Released under GNU Public License v3 or later.\n"
+ " Released under GNU General Public License v3 or later.\n"
" All rights reserved.\n"
"\n"
" This program is a data collector plugin for netdata.\n"
"\n"
- " Valid command line options:\n"
+ " Available command line options:\n"
"\n"
" SECONDS set the data collection frequency\n"
"\n"
@@ -2794,7 +3300,7 @@ static void parse_args(int argc, char **argv)
" apps_groups.conf\n"
" (default NAME=groups)\n"
"\n"
- " version print program version and exit\n"
+ " version or -v or -V print program version and exit\n"
"\n"
, VERSION
);
@@ -2819,15 +3325,74 @@ static void parse_args(int argc, char **argv)
}
}
-int main(int argc, char **argv)
-{
+static int am_i_running_as_root() {
+ uid_t uid = getuid(), euid = geteuid();
+
+ if(uid == 0 || euid == 0) {
+ if(debug) info("I am running with escalated privileges, uid = %u, euid = %u.", uid, euid);
+ return 1;
+ }
+
+ if(debug) info("I am not running with escalated privileges, uid = %u, euid = %u.", uid, euid);
+ return 0;
+}
+
+#ifdef HAVE_CAPABILITY
+static int check_capabilities() {
+ cap_t caps = cap_get_proc();
+ if(!caps) {
+ error("Cannot get current capabilities.");
+ return 0;
+ }
+ else if(debug)
+ info("Received my capabilities from the system.");
+
+ int ret = 1;
+
+ cap_flag_value_t cfv = CAP_CLEAR;
+ if(cap_get_flag(caps, CAP_DAC_READ_SEARCH, CAP_EFFECTIVE, &cfv) == -1) {
+ error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
+ ret = 0;
+ }
+ else {
+ if(cfv != CAP_SET) {
+ error("apps.plugin should run with CAP_DAC_READ_SEARCH.");
+ ret = 0;
+ }
+ else if(debug)
+ info("apps.plugin runs with CAP_DAC_READ_SEARCH.");
+ }
+
+ cfv = CAP_CLEAR;
+ if(cap_get_flag(caps, CAP_SYS_PTRACE, CAP_EFFECTIVE, &cfv) == -1) {
+ error("Cannot find if CAP_SYS_PTRACE is effective.");
+ ret = 0;
+ }
+ else {
+ if(cfv != CAP_SET) {
+ error("apps.plugin should run with CAP_SYS_PTRACE.");
+ ret = 0;
+ }
+ else if(debug)
+ info("apps.plugin runs with CAP_SYS_PTRACE.");
+ }
+
+ cap_free(caps);
+
+ return ret;
+}
+#else
+static int check_capabilities() {
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv) {
// debug_flags = D_PROCFILE;
// set the name for logging
program_name = "apps.plugin";
- info("started on pid %d", getpid());
-
// disable syslog for apps.plugin
error_log_syslog = 0;
@@ -2835,12 +3400,12 @@ int main(int argc, char **argv)
error_log_errors_per_period = 100;
error_log_throttle_period = 3600;
- global_host_prefix = getenv("NETDATA_HOST_PREFIX");
- if(global_host_prefix == NULL) {
+ netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
+ if(netdata_configured_host_prefix == NULL) {
// info("NETDATA_HOST_PREFIX is not passed from netdata");
- global_host_prefix = "";
+ netdata_configured_host_prefix = "";
}
- // else info("Found NETDATA_HOST_PREFIX='%s'", global_host_prefix);
+ // else info("Found NETDATA_HOST_PREFIX='%s'", netdata_configured_host_prefix);
config_dir = getenv("NETDATA_CONFIG_DIR");
if(config_dir == NULL) {
@@ -2854,58 +3419,53 @@ int main(int argc, char **argv)
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+#ifdef HAVE_SYS_PRCTL_H
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+#endif
}
#endif /* NETDATA_INTERNAL_CHECKS */
procfile_adaptive_initial_allocation = 1;
- time_t started_t = now_realtime_sec();
+ time_t started_t = now_monotonic_sec();
get_system_HZ();
get_system_pid_max();
get_system_cpus();
parse_args(argc, argv);
- all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
- all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
-
- fprintf(stdout,
- "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
- "DIMENSION user '' incremental 1 1000\n"
- "DIMENSION system '' incremental 1 1000\n"
- "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %1$d\n"
- "DIMENSION files '' incremental 1 1\n"
- "DIMENSION pids '' absolute 1 1\n"
- "DIMENSION fds '' absolute 1 1\n"
- "DIMENSION targets '' absolute 1 1\n"
- "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
- "DIMENSION utime '' absolute 1 %2$llu\n"
- "DIMENSION stime '' absolute 1 %2$llu\n"
- "DIMENSION gtime '' absolute 1 %2$llu\n"
- "DIMENSION minflt '' absolute 1 %2$llu\n"
- "DIMENSION majflt '' absolute 1 %2$llu\n"
- , update_every
- , RATES_DETAIL
+ if(!check_capabilities() && !am_i_running_as_root() && !check_proc_1_io()) {
+ uid_t uid = getuid(), euid = geteuid();
+#ifdef HAVE_CAPABILITY
+ error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
+ "Without these, apps.plugin cannot report disk I/O utilization of other processes. "
+ "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
+ "To enable setuid to root run: sudo chown root %s; sudo chmod 4755 %s; "
+ , uid, euid, argv[0], argv[0], argv[0]
);
+#else
+ error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
+ "Without these, apps.plugin cannot report disk I/O utilization of other processes. "
+ "Your system does not support capabilities. "
+ "To enable setuid to root run: sudo chown root %s; sudo chmod 4755 %s; "
+ , uid, euid, argv[0], argv[0]
+ );
+#endif
+ }
- if(include_exited_childs)
- fprintf(stdout,
- "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
- "DIMENSION cutime '' absolute 1 %2$llu\n"
- "DIMENSION cstime '' absolute 1 %2$llu\n"
- "DIMENSION cgtime '' absolute 1 %2$llu\n"
- "DIMENSION cminflt '' absolute 1 %2$llu\n"
- "DIMENSION cmajflt '' absolute 1 %2$llu\n"
- , update_every
- , RATES_DETAIL
- );
+ info("started on pid %d", getpid());
+
+#if (ALL_PIDS_ARE_READ_INSTANTLY == 0)
+ all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
+#endif
+
+ all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
usec_t step = update_every * USEC_PER_SEC;
global_iterations_counter = 1;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;1; global_iterations_counter++) {
- usec_t now = now_realtime_usec();
- usec_t next = now - (now % step) + step;
#ifdef NETDATA_PROFILING
#warning "compiling for profiling"
@@ -2913,20 +3473,17 @@ int main(int argc, char **argv)
profiling_count++;
if(unlikely(profiling_count > 1000)) exit(0);
#else
- while(now < next) {
- sleep_usec(next - now);
- now = now_realtime_usec();
- }
+ heartbeat_next(&hb, step);
#endif
- if(!collect_data_for_all_processes_from_proc()) {
+ if(!collect_data_for_all_processes()) {
error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
printf("DISABLE\n");
exit(1);
}
calculate_netdata_statistics();
- normalize_data(apps_groups_root_target);
+ normalize_utilization(apps_groups_root_target);
usec_t dt = send_resource_usage_to_netdata();
@@ -2952,11 +3509,9 @@ int main(int argc, char **argv)
show_guest_time_old = show_guest_time;
if(unlikely(debug))
- fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);
-
- time_t current_t = now_realtime_sec();
+ fprintf(stderr, "apps.plugin: done Loop No %zu\n", global_iterations_counter);
// restart check (14400 seconds)
- if(current_t - started_t > 14400) exit(0);
+ if(now_monotonic_sec() - started_t > 14400) exit(0);
}
}
diff --git a/src/avl.c b/src/avl.c
index 1ec1b8ad2..0ea119a7c 100644
--- a/src/avl.c
+++ b/src/avl.c
@@ -315,9 +315,9 @@ int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *da
void avl_read_lock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_lock(&t->mutex);
+ netdata_mutex_lock(&t->mutex);
#else
- pthread_rwlock_rdlock(&t->rwlock);
+ netdata_rwlock_rdlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
@@ -325,9 +325,9 @@ void avl_read_lock(avl_tree_lock *t) {
void avl_write_lock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_lock(&t->mutex);
+ netdata_mutex_lock(&t->mutex);
#else
- pthread_rwlock_wrlock(&t->rwlock);
+ netdata_rwlock_wrlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
@@ -335,9 +335,9 @@ void avl_write_lock(avl_tree_lock *t) {
void avl_unlock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_unlock(&t->mutex);
+ netdata_mutex_unlock(&t->mutex);
#else
- pthread_rwlock_unlock(&t->rwlock);
+ netdata_rwlock_unlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
@@ -352,9 +352,9 @@ void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) {
int lock;
#ifdef AVL_LOCK_WITH_MUTEX
- lock = pthread_mutex_init(&t->mutex, NULL);
+ lock = netdata_mutex_init(&t->mutex, NULL);
#else
- lock = pthread_rwlock_init(&t->rwlock, NULL);
+ lock = netdata_rwlock_init(&t->rwlock);
#endif
if(lock != 0)
diff --git a/src/avl.h b/src/avl.h
index d30be0dd8..19648cd1d 100644
--- a/src/avl.h
+++ b/src/avl.h
@@ -13,9 +13,9 @@
// #define AVL_LOCK_WITH_MUTEX 1
#ifdef AVL_LOCK_WITH_MUTEX
-#define AVL_LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define AVL_LOCK_INITIALIZER NETDATA_MUTEX_INITIALIZER
#else /* AVL_LOCK_WITH_MUTEX */
-#define AVL_LOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+#define AVL_LOCK_INITIALIZER NETDATA_RWLOCK_INITIALIZER
#endif /* AVL_LOCK_WITH_MUTEX */
#else /* AVL_WITHOUT_PTHREADS */
@@ -41,9 +41,9 @@ typedef struct avl_tree_lock {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_t mutex;
+ netdata_mutex_t mutex;
#else /* AVL_LOCK_WITH_MUTEX */
- pthread_rwlock_t rwlock;
+ netdata_rwlock_t rwlock;
#endif /* AVL_LOCK_WITH_MUTEX */
#endif /* AVL_WITHOUT_PTHREADS */
} avl_tree_lock;
diff --git a/src/backends.c b/src/backends.c
index 1272d0473..3e385cab5 100644
--- a/src/backends.c
+++ b/src/backends.c
@@ -1,16 +1,51 @@
#include "common.h"
+// ----------------------------------------------------------------------------
+// How backends work in netdata:
+//
+// 1. There is an independent thread that runs at the required interval
+// (for example, once every 10 seconds)
+//
+// 2. Every time it wakes, it calls the backend formatting functions to build
+// a buffer of data. This is a very fast, memory only operation.
+//
+// 3. If the buffer already includes data, the new data are appended.
+// If the buffer becomes too big, because the data cannot be sent, a
+// log is written and the buffer is discarded.
+//
+// 4. Then it tries to send all the data. It blocks until all the data are sent
+// or the socket returns an error.
+// If the time required for this is above the interval, it starts skipping
+// intervals, but the calculated values include the entire database, without
+// gaps (it remembers the timestamps and continues from where it stopped).
+//
+// 5. repeats the above forever.
+//
+
#define BACKEND_SOURCE_DATA_AS_COLLECTED 0x00000001
#define BACKEND_SOURCE_DATA_AVERAGE 0x00000002
#define BACKEND_SOURCE_DATA_SUM 0x00000004
-static inline calculated_number backend_calculate_value_from_stored_data(RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+
+// ----------------------------------------------------------------------------
+// helper functions for backends
+
+// calculate the SUM or AVERAGE of a dimension, for any timeframe
+// may return NAN if the database does not have any value in the give timeframe
+
+static inline calculated_number backend_calculate_value_from_stored_data(
+ RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
+ // find the edges of the rrd database for this chart
time_t first_t = rrdset_first_entry_t(st);
- time_t last_t = rrdset_last_entry_t(st);
+ time_t last_t = rrdset_last_entry_t(st);
- if(unlikely(before - after < st->update_every && after != after - after % st->update_every))
- // when st->update_every is bigger than the frequency we send data to backend
- // skip the iterations that are not aligned to the database
+ if(unlikely(before < first_t || after > last_t))
+ // the chart has not been updated in the wanted timeframe
return NAN;
// align the time-frame
@@ -22,7 +57,7 @@ static inline calculated_number backend_calculate_value_from_stored_data(RRDSET
after = first_t;
if(unlikely(after > before))
- // this can happen when the st->update_every > before - after
+ // this can happen when st->update_every > before - after
before = after;
if(unlikely(before > last_t))
@@ -36,14 +71,20 @@ static inline calculated_number backend_calculate_value_from_stored_data(RRDSET
slot, stop_now = 0;
for(slot = start_at_slot; !stop_now ; slot--) {
+
if(unlikely(slot < 0)) slot = st->entries - 1;
if(unlikely(slot == stop_at_slot)) stop_now = 1;
storage_number n = rd->values[slot];
- if(unlikely(!does_storage_number_exist(n))) continue;
+
+ if(unlikely(!does_storage_number_exist(n))) {
+ // not collected
+ continue;
+ }
calculated_number value = unpack_storage_number(n);
sum += value;
+
counter++;
}
@@ -56,84 +97,295 @@ static inline calculated_number backend_calculate_value_from_stored_data(RRDSET
return sum / (calculated_number)counter;
}
-static inline int format_dimension_collected_graphite_plaintext(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+
+// discard a response received by a backend
+// after logging a simple of it to error.log
+
+static inline int discard_response(BUFFER *b, const char *backend) {
+ char sample[1024];
+ const char *s = buffer_tostring(b);
+ char *d = sample, *e = &sample[sizeof(sample) - 1];
+
+ for(; *s && d < e ;s++) {
+ char c = *s;
+ if(unlikely(!isprint(c))) c = ' ';
+ *d++ = c;
+ }
+ *d = '\0';
+
+ info("Received %zu bytes from %s backend. Ignoring them. Sample: '%s'", buffer_strlen(b), backend, sample);
+ buffer_flush(b);
+ return 0;
+}
+
+
+// ----------------------------------------------------------------------------
+// graphite backend
+
+static inline int format_dimension_collected_graphite_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
(void)after;
(void)before;
(void)options;
- buffer_sprintf(b, "%s.%s.%s.%s " COLLECTED_NUMBER_FORMAT " %u\n", prefix, hostname, st->id, rd->id, rd->last_collected_value, (uint32_t)rd->last_collected_time.tv_sec);
+
+ buffer_sprintf(
+ b
+ , "%s.%s.%s.%s " COLLECTED_NUMBER_FORMAT " %u\n"
+ , prefix
+ , hostname
+ , st->id
+ , rd->id
+ , rd->last_collected_value
+ , (uint32_t)rd->last_collected_time.tv_sec
+ );
+
return 1;
}
-static inline int format_dimension_stored_graphite_plaintext(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+static inline int format_dimension_stored_graphite_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
+
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options);
+
if(!isnan(value)) {
- buffer_sprintf(b, "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n", prefix, hostname, st->id, rd->id, value, (uint32_t) before);
+
+ buffer_sprintf(
+ b
+ , "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n"
+ , prefix
+ , hostname
+ , st->id
+ , rd->id
+ , value
+ , (uint32_t) before
+ );
+
return 1;
}
return 0;
}
-static inline int format_dimension_collected_opentsdb_telnet(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+static inline int process_graphite_response(BUFFER *b) {
+ return discard_response(b, "graphite");
+}
+
+
+// ----------------------------------------------------------------------------
+// opentsdb backend
+
+static inline int format_dimension_collected_opentsdb_telnet(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
(void)after;
(void)before;
(void)options;
- buffer_sprintf(b, "put %s.%s.%s %u " COLLECTED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t)rd->last_collected_time.tv_sec, rd->last_collected_value, hostname);
+
+ buffer_sprintf(
+ b
+ , "put %s.%s.%s %u " COLLECTED_NUMBER_FORMAT " host=%s\n"
+ , prefix
+ , st->id
+ , rd->id
+ , (uint32_t)rd->last_collected_time.tv_sec
+ , rd->last_collected_value
+ , hostname
+ );
+
return 1;
}
-static inline int format_dimension_stored_opentsdb_telnet(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) {
+static inline int format_dimension_stored_opentsdb_telnet(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
(void)host;
+
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options);
+
if(!isnan(value)) {
- buffer_sprintf(b, "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t) before, value, hostname);
+
+ buffer_sprintf(
+ b
+ , "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s\n"
+ , prefix
+ , st->id
+ , rd->id
+ , (uint32_t) before
+ , value
+ , hostname
+ );
+
return 1;
}
return 0;
}
-static inline int process_graphite_response(BUFFER *b) {
- char sample[1024];
- const char *s = buffer_tostring(b);
- char *d = sample, *e = &sample[sizeof(sample) - 1];
+static inline int process_opentsdb_response(BUFFER *b) {
+ return discard_response(b, "opentsdb");
+}
- for(; *s && d < e ;s++) {
- char c = *s;
- if(unlikely(!isprint(c))) c = ' ';
- *d++ = c;
- }
- *d = '\0';
- info("Received %zu bytes from graphite backend. Ignoring them. Sample: '%s'", buffer_strlen(b), sample);
- buffer_flush(b);
- return 0;
+// ----------------------------------------------------------------------------
+// json backend
+
+static inline int format_dimension_collected_json_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
+ (void)host;
+ (void)after;
+ (void)before;
+ (void)options;
+
+ buffer_sprintf(b, "{"
+ "\"prefix\":\"%s\","
+ "\"hostname\":\"%s\","
+
+ "\"chart_id\":\"%s\","
+ "\"chart_name\":\"%s\","
+ "\"chart_family\":\"%s\","
+ "\"chart_context\": \"%s\","
+ "\"chart_type\":\"%s\","
+ "\"units\": \"%s\","
+
+ "\"id\":\"%s\","
+ "\"name\":\"%s\","
+ "\"value\":" COLLECTED_NUMBER_FORMAT ","
+
+ "\"timestamp\": %u}\n",
+ prefix,
+ hostname,
+
+ st->id,
+ st->name,
+ st->family,
+ st->context,
+ st->type,
+ st->units,
+
+ rd->id,
+ rd->name,
+ rd->last_collected_value,
+
+ (uint32_t)rd->last_collected_time.tv_sec
+ );
+
+ return 1;
}
-static inline int process_opentsdb_response(BUFFER *b) {
- char sample[1024];
- const char *s = buffer_tostring(b);
- char *d = sample, *e = &sample[sizeof(sample) - 1];
+static inline int format_dimension_stored_json_plaintext(
+ BUFFER *b // the buffer to write data to
+ , const char *prefix // the prefix to use
+ , RRDHOST *host // the host this chart comes from
+ , const char *hostname // the hostname (to override host->hostname)
+ , RRDSET *st // the chart
+ , RRDDIM *rd // the dimension
+ , time_t after // the start timestamp
+ , time_t before // the end timestamp
+ , uint32_t options // BACKEND_SOURCE_* bitmap
+) {
+ (void)host;
- for(; *s && d < e ;s++) {
- char c = *s;
- if(unlikely(!isprint(c))) c = ' ';
- *d++ = c;
- }
- *d = '\0';
+ calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, options);
- info("Received %zu bytes from opentsdb backend. Ignoring them. Sample: '%s'", buffer_strlen(b), sample);
- buffer_flush(b);
+ if(!isnan(value)) {
+ buffer_sprintf(b, "{"
+ "\"prefix\":\"%s\","
+ "\"hostname\":\"%s\","
+
+ "\"chart_id\":\"%s\","
+ "\"chart_name\":\"%s\","
+ "\"chart_family\":\"%s\","
+ "\"chart_context\": \"%s\","
+ "\"chart_type\":\"%s\","
+ "\"units\": \"%s\","
+
+ "\"id\":\"%s\","
+ "\"name\":\"%s\","
+ "\"value\":" CALCULATED_NUMBER_FORMAT ","
+
+ "\"timestamp\": %u}\n",
+ prefix,
+ hostname,
+
+ st->id,
+ st->name,
+ st->family,
+ st->context,
+ st->type,
+ st->units,
+
+ rd->id,
+ rd->name,
+ value,
+
+ (uint32_t)before
+ );
+
+ return 1;
+ }
return 0;
}
+static inline int process_json_response(BUFFER *b) {
+ return discard_response(b, "json");
+}
+
+
+// ----------------------------------------------------------------------------
+// the backend thread
+
void *backends_main(void *ptr) {
+ int default_port = 0;
+ int sock = -1;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
BUFFER *b = buffer_create(1), *response = buffer_create(1);
- int (*backend_request_formatter)(BUFFER *b, const char *prefix, RRDHOST *host, const char *hostname, RRDSET *st, RRDDIM *rd, time_t after, time_t before, uint32_t options) = NULL;
- int (*backend_response_checker)(BUFFER *b) = NULL;
+ int (*backend_request_formatter)(BUFFER *, const char *, RRDHOST *, const char *, RRDSET *, RRDDIM *, time_t, time_t, uint32_t) = NULL;
+ int (*backend_response_checker)(BUFFER *) = NULL;
info("BACKEND thread created with task id %d", gettid());
@@ -150,22 +402,21 @@ void *backends_main(void *ptr) {
.tv_sec = 0,
.tv_usec = 0
};
- int default_port = 0;
- int sock = -1;
uint32_t options;
- int enabled = config_get_boolean("backend", "enabled", 0);
- const char *source = config_get("backend", "data source", "average");
- const char *type = config_get("backend", "type", "graphite");
- const char *destination = config_get("backend", "destination", "localhost");
- const char *prefix = config_get("backend", "prefix", "netdata");
- const char *hostname = config_get("backend", "hostname", localhost.hostname);
- int frequency = (int)config_get_number("backend", "update every", 10);
- int buffer_on_failures = (int)config_get_number("backend", "buffer on failures", 10);
- long timeoutms = config_get_number("backend", "timeout ms", frequency * 2 * 1000);
+ int enabled = config_get_boolean(CONFIG_SECTION_BACKEND, "enabled", 0);
+ const char *source = config_get(CONFIG_SECTION_BACKEND, "data source", "average");
+ const char *type = config_get(CONFIG_SECTION_BACKEND, "type", "graphite");
+ const char *destination = config_get(CONFIG_SECTION_BACKEND, "destination", "localhost");
+ const char *prefix = config_get(CONFIG_SECTION_BACKEND, "prefix", "netdata");
+ const char *hostname = config_get(CONFIG_SECTION_BACKEND, "hostname", localhost->hostname);
+ int frequency = (int)config_get_number(CONFIG_SECTION_BACKEND, "update every", 10);
+ int buffer_on_failures = (int)config_get_number(CONFIG_SECTION_BACKEND, "buffer on failures", 10);
+ long timeoutms = config_get_number(CONFIG_SECTION_BACKEND, "timeout ms", frequency * 2 * 1000);
// ------------------------------------------------------------------------
// validate configuration options
// and prepare for sending data to our backend
+
if(!enabled || frequency < 1)
goto cleanup;
@@ -183,23 +434,49 @@ void *backends_main(void *ptr) {
goto cleanup;
}
+ if(timeoutms < 1) {
+ error("BACKED invalid timeout %ld ms given. Assuming %d ms.", timeoutms, frequency * 2 * 1000);
+ timeoutms = frequency * 2 * 1000;
+ }
+ timeout.tv_sec = (timeoutms * 1000) / 1000000;
+ timeout.tv_usec = (timeoutms * 1000) % 1000000;
+
+
+ // ------------------------------------------------------------------------
+ // select the backend type
+
if(!strcmp(type, "graphite") || !strcmp(type, "graphite:plaintext")) {
+
default_port = 2003;
+ backend_response_checker = process_graphite_response;
+
if(options == BACKEND_SOURCE_DATA_AS_COLLECTED)
backend_request_formatter = format_dimension_collected_graphite_plaintext;
else
backend_request_formatter = format_dimension_stored_graphite_plaintext;
- backend_response_checker = process_graphite_response;
}
else if(!strcmp(type, "opentsdb") || !strcmp(type, "opentsdb:telnet")) {
+
default_port = 4242;
+ backend_response_checker = process_opentsdb_response;
+
if(options == BACKEND_SOURCE_DATA_AS_COLLECTED)
backend_request_formatter = format_dimension_collected_opentsdb_telnet;
else
backend_request_formatter = format_dimension_stored_opentsdb_telnet;
- backend_response_checker = process_opentsdb_response;
+ }
+ else if (!strcmp(type, "json") || !strcmp(type, "json:plaintext")) {
+
+ default_port = 5448;
+ backend_response_checker = process_json_response;
+
+ if (options == BACKEND_SOURCE_DATA_AS_COLLECTED)
+ backend_request_formatter = format_dimension_collected_json_plaintext;
+ else
+ backend_request_formatter = format_dimension_stored_json_plaintext;
+
}
else {
error("Unknown backend type '%s'", type);
@@ -211,15 +488,9 @@ void *backends_main(void *ptr) {
goto cleanup;
}
- if(timeoutms < 1) {
- error("BACKED invalid timeout %ld ms given. Assuming %d ms.", timeoutms, frequency * 2 * 1000);
- timeoutms = frequency * 2 * 1000;
- }
- timeout.tv_sec = (timeoutms * 1000) / 1000000;
- timeout.tv_usec = (timeoutms * 1000) % 1000000;
// ------------------------------------------------------------------------
- // prepare the charts for monitoring the backend
+ // prepare the charts for monitoring the backend operation
struct rusage thread;
@@ -238,32 +509,23 @@ void *backends_main(void *ptr) {
chart_backend_reconnects = 0,
chart_backend_latency = 0;
- RRDSET *chart_metrics = rrdset_find("netdata.backend_metrics");
- if(!chart_metrics) {
- chart_metrics = rrdset_create("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", 130600, frequency, RRDSET_TYPE_LINE);
- rrddim_add(chart_metrics, "buffered", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_metrics, "lost", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_metrics, "sent", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_metrics = rrdset_create_localhost("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", 130600, frequency, RRDSET_TYPE_LINE);
+ rrddim_add(chart_metrics, "buffered", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_metrics, "lost", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_metrics, "sent", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- RRDSET *chart_bytes = rrdset_find("netdata.backend_bytes");
- if(!chart_bytes) {
- chart_bytes = rrdset_create("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", 130610, frequency, RRDSET_TYPE_AREA);
- rrddim_add(chart_bytes, "buffered", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(chart_bytes, "lost", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(chart_bytes, "sent", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(chart_bytes, "received", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_bytes = rrdset_create_localhost("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", 130610, frequency, RRDSET_TYPE_AREA);
+ rrddim_add(chart_bytes, "buffered", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_bytes, "lost", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_bytes, "sent", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_bytes, "received", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
- RRDSET *chart_ops = rrdset_find("netdata.backend_ops");
- if(!chart_ops) {
- chart_ops = rrdset_create("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", 130630, frequency, RRDSET_TYPE_LINE);
- rrddim_add(chart_ops, "write", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "discard", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "reconnect", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "failure", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(chart_ops, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_ops = rrdset_create_localhost("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", 130630, frequency, RRDSET_TYPE_LINE);
+ rrddim_add(chart_ops, "write", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "discard", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "reconnect", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "failure", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(chart_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
/*
* this is misleading - we can only measure the time we need to send data
@@ -272,19 +534,14 @@ void *backends_main(void *ptr) {
*
* issue #1432 and https://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html
*
- RRDSET *chart_latency = rrdset_find("netdata.backend_latency");
- if(!chart_latency) {
- chart_latency = rrdset_create("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", 130620, frequency, RRDSET_TYPE_AREA);
- rrddim_add(chart_latency, "latency", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- }
+ RRDSET *chart_latency = rrdset_create_localhost("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", 130620, frequency, RRDSET_TYPE_AREA);
+ rrddim_add(chart_latency, "latency", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
*/
- RRDSET *chart_rusage = rrdset_find("netdata.backend_thread_cpu");
- if(!chart_rusage) {
- chart_rusage = rrdset_create("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", 130630, frequency, RRDSET_TYPE_STACKED);
- rrddim_add(chart_rusage, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(chart_rusage, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- }
+ RRDSET *chart_rusage = rrdset_create_localhost("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", 130630, frequency, RRDSET_TYPE_STACKED);
+ rrddim_add(chart_rusage, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(chart_rusage, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+
// ------------------------------------------------------------------------
// prepare the backend main loop
@@ -292,49 +549,49 @@ void *backends_main(void *ptr) {
info("BACKEND configured ('%s' on '%s' sending '%s' data, every %d seconds, as host '%s', with prefix '%s')", type, destination, source, frequency, hostname, prefix);
usec_t step_ut = frequency * USEC_PER_SEC;
- usec_t random_ut = now_realtime_usec() % (step_ut / 2);
- time_t before = (time_t)((now_realtime_usec() - step_ut) / USEC_PER_SEC);
- time_t after = before;
+ time_t after = now_realtime_sec();
int failures = 0;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;;) {
- // ------------------------------------------------------------------------
- // wait for the next iteration point
- usec_t now_ut = now_realtime_usec();
- usec_t next_ut = now_ut - (now_ut % step_ut) + step_ut;
- before = (time_t)(next_ut / USEC_PER_SEC);
-
- // add a little delay (1/4 of the step) plus some randomness
- next_ut += (step_ut / 4) + random_ut;
+ // ------------------------------------------------------------------------
+ // Wait for the next iteration point.
+ heartbeat_next(&hb, step_ut);
+ time_t before = now_realtime_sec();
- while(now_ut < next_ut) {
- sleep_usec(next_ut - now_ut);
- now_ut = now_realtime_usec();
- }
// ------------------------------------------------------------------------
// add to the buffer the data we need to send to the backend
- RRDSET *st;
int pthreadoldcancelstate;
if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
error("Cannot set pthread cancel state to DISABLE.");
- rrdhost_rdlock(&localhost);
- for(st = localhost.rrdset_root; st ;st = st->next) {
- pthread_rwlock_rdlock(&st->rwlock);
+ rrd_rdlock();
+ RRDHOST *host;
+ rrdhost_foreach_read(host) {
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE)
+ continue;
- RRDDIM *rd;
- for(rd = st->dimensions; rd ;rd = rd->next) {
- if(rd->last_collected_time.tv_sec >= after)
- chart_buffered_metrics += backend_request_formatter(b, prefix, &localhost, hostname, st, rd, after, before, options);
- }
+ rrdhost_rdlock(host);
- pthread_rwlock_unlock(&st->rwlock);
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ rrdset_rdlock(st);
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ if(rd->last_collected_time.tv_sec >= after)
+ chart_buffered_metrics += backend_request_formatter(b, prefix, host, (host == localhost)?hostname:host->hostname, st, rd, after, before, options);
+ }
+ rrdset_unlock(st);
+ }
+ rrdhost_unlock(host);
}
- rrdhost_unlock(&localhost);
+ rrd_unlock();
if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
@@ -360,6 +617,10 @@ void *backends_main(void *ptr) {
//fprintf(stderr, "\nBACKEND BEGIN:\n%s\nBACKEND END\n", buffer_tostring(b)); // FIXME
//fprintf(stderr, "after = %lu, before = %lu\n", after, before);
+ // prepare for the next iteration
+ // to add incrementally data to buffer
+ after = before;
+
// ------------------------------------------------------------------------
// if we are connected, receive a response, without blocking
@@ -399,28 +660,13 @@ void *backends_main(void *ptr) {
// if we are not connected, connect to a backend server
if(unlikely(sock == -1)) {
- usec_t start_ut = now_realtime_usec();
- const char *s = destination;
- while(*s) {
- const char *e = s;
-
- // skip separators, moving both s(tart) and e(nd)
- while(isspace(*e) || *e == ',') s = ++e;
-
- // move e(nd) to the first separator
- while(*e && !isspace(*e) && *e != ',') e++;
-
- // is there anything?
- if(!*s || s == e) break;
-
- char buf[e - s + 1];
- strncpyz(buf, s, e - s);
- chart_backend_reconnects++;
- sock = connect_to(buf, default_port, &timeout);
- if(sock != -1) break;
- s = e;
- }
- chart_backend_latency += now_realtime_usec() - start_ut;
+ usec_t start_ut = now_monotonic_usec();
+ size_t reconnects = 0;
+
+ sock = connect_to_one_of(destination, default_port, &timeout, &reconnects, NULL, 0);
+
+ chart_backend_reconnects += reconnects;
+ chart_backend_latency += now_monotonic_usec() - start_ut;
}
if(unlikely(netdata_exit)) break;
@@ -430,14 +676,14 @@ void *backends_main(void *ptr) {
if(likely(sock != -1)) {
size_t len = buffer_strlen(b);
- usec_t start_ut = now_realtime_usec();
+ usec_t start_ut = now_monotonic_usec();
int flags = 0;
#ifdef MSG_NOSIGNAL
flags += MSG_NOSIGNAL;
#endif
ssize_t written = send(sock, buffer_tostring(b), len, flags);
- chart_backend_latency += now_realtime_usec() - start_ut;
+ chart_backend_latency += now_monotonic_usec() - start_ut;
if(written != -1 && (size_t)written == len) {
// we sent the data successfully
chart_transmission_successes++;
@@ -465,12 +711,6 @@ void *backends_main(void *ptr) {
close(sock);
sock = -1;
}
-
- // either the buffer is empty
- // or is holding the data we couldn't send
- // so, make sure the next iteration will continue
- // from where we are now
- after = before;
}
else {
error("Failed to update database backend '%s'", destination);
@@ -495,7 +735,7 @@ void *backends_main(void *ptr) {
// ------------------------------------------------------------------------
// update the monitoring charts
- if(chart_ops->counter_done) rrdset_next(chart_ops);
+ if(likely(chart_ops->counter_done)) rrdset_next(chart_ops);
rrddim_set(chart_ops, "read", chart_receptions);
rrddim_set(chart_ops, "write", chart_transmission_successes);
rrddim_set(chart_ops, "discard", chart_data_lost_events);
@@ -503,13 +743,13 @@ void *backends_main(void *ptr) {
rrddim_set(chart_ops, "reconnect", chart_backend_reconnects);
rrdset_done(chart_ops);
- if(chart_metrics->counter_done) rrdset_next(chart_metrics);
+ if(likely(chart_metrics->counter_done)) rrdset_next(chart_metrics);
rrddim_set(chart_metrics, "buffered", chart_buffered_metrics);
rrddim_set(chart_metrics, "lost", chart_lost_metrics);
rrddim_set(chart_metrics, "sent", chart_sent_metrics);
rrdset_done(chart_metrics);
- if(chart_bytes->counter_done) rrdset_next(chart_bytes);
+ if(likely(chart_bytes->counter_done)) rrdset_next(chart_bytes);
rrddim_set(chart_bytes, "buffered", chart_buffered_bytes);
rrddim_set(chart_bytes, "lost", chart_lost_bytes);
rrddim_set(chart_bytes, "sent", chart_sent_bytes);
@@ -517,13 +757,13 @@ void *backends_main(void *ptr) {
rrdset_done(chart_bytes);
/*
- if(chart_latency->counter_done) rrdset_next(chart_latency);
+ if(likely(chart_latency->counter_done)) rrdset_next(chart_latency);
rrddim_set(chart_latency, "latency", chart_backend_latency);
rrdset_done(chart_latency);
*/
getrusage(RUSAGE_THREAD, &thread);
- if(chart_rusage->counter_done) rrdset_next(chart_rusage);
+ if(likely(chart_rusage->counter_done)) rrdset_next(chart_rusage);
rrddim_set(chart_rusage, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
rrddim_set(chart_rusage, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
rrdset_done(chart_rusage);
diff --git a/src/clocks.c b/src/clocks.c
index c90a07c2f..879ebf911 100644
--- a/src/clocks.c
+++ b/src/clocks.c
@@ -6,64 +6,89 @@ inline int clock_gettime(clockid_t clk_id, struct timespec *ts) {
if(unlikely(gettimeofday(&tv, NULL) == -1))
return -1;
ts->tv_sec = tv.tv_sec;
- ts->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+ ts->tv_nsec = (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC;
return 0;
}
#endif
-inline time_t now_realtime_sec(void) {
+static inline time_t now_sec(clockid_t clk_id) {
struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_REALTIME, &ts) == -1))
+ if(unlikely(clock_gettime(clk_id, &ts) == -1))
return 0;
return ts.tv_sec;
}
-inline int now_realtime_timeval(struct timeval *tv) {
+static inline usec_t now_usec(clockid_t clk_id) {
+ struct timespec ts;
+ if(unlikely(clock_gettime(clk_id, &ts) == -1))
+ return 0;
+ return (usec_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
+}
+
+static inline int now_timeval(clockid_t clk_id, struct timeval *tv) {
struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_REALTIME, &ts) == -1))
+
+ if(unlikely(clock_gettime(clk_id, &ts) == -1)) {
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
return -1;
+ }
+
tv->tv_sec = ts.tv_sec;
- tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ tv->tv_usec = (suseconds_t)((ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC);
return 0;
}
+inline time_t now_realtime_sec(void) {
+ return now_sec(CLOCK_REALTIME);
+}
+
inline usec_t now_realtime_usec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_REALTIME, &ts) == -1))
- return 0;
- return (usec_t)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
+ return now_usec(CLOCK_REALTIME);
+}
+
+inline int now_realtime_timeval(struct timeval *tv) {
+ return now_timeval(CLOCK_REALTIME, tv);
}
inline time_t now_monotonic_sec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_MONOTONIC, &ts) == -1))
- return 0;
- return ts.tv_sec;
+ return now_sec(CLOCK_MONOTONIC);
}
inline usec_t now_monotonic_usec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_MONOTONIC, &ts) == -1))
- return 0;
- return (usec_t)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
+ return now_usec(CLOCK_MONOTONIC);
+}
+
+inline int now_monotonic_timeval(struct timeval *tv) {
+ return now_timeval(CLOCK_MONOTONIC, tv);
}
inline time_t now_boottime_sec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_BOOTTIME, &ts) == -1))
- return 0;
- return ts.tv_sec;
+ return now_sec(CLOCK_BOOTTIME);
}
inline usec_t now_boottime_usec(void) {
- struct timespec ts;
- if(unlikely(clock_gettime(CLOCK_BOOTTIME, &ts) == -1))
- return 0;
- return (usec_t)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
+ return now_usec(CLOCK_BOOTTIME);
+}
+
+inline int now_boottime_timeval(struct timeval *tv) {
+ return now_timeval(CLOCK_BOOTTIME, tv);
}
inline usec_t timeval_usec(struct timeval *tv) {
- return (usec_t)tv->tv_sec * USEC_PER_SEC + tv->tv_usec;
+ return (usec_t)tv->tv_sec * USEC_PER_SEC + (tv->tv_usec % USEC_PER_SEC);
+}
+
+inline msec_t timeval_msec(struct timeval *tv) {
+ return (msec_t)tv->tv_sec * MSEC_PER_SEC + ((tv->tv_usec % USEC_PER_SEC) / MSEC_PER_SEC);
+}
+
+inline susec_t dt_usec_signed(struct timeval *now, struct timeval *old) {
+ usec_t ts1 = timeval_usec(now);
+ usec_t ts2 = timeval_usec(old);
+
+ if(likely(ts1 >= ts2)) return (susec_t)(ts1 - ts2);
+ return -((susec_t)(ts2 - ts1));
}
inline usec_t dt_usec(struct timeval *now, struct timeval *old) {
@@ -71,3 +96,38 @@ inline usec_t dt_usec(struct timeval *now, struct timeval *old) {
usec_t ts2 = timeval_usec(old);
return (ts1 > ts2) ? (ts1 - ts2) : (ts2 - ts1);
}
+
+inline void heartbeat_init(heartbeat_t *hb)
+{
+ *hb = 0ULL;
+}
+
+usec_t heartbeat_next(heartbeat_t *hb, usec_t tick)
+{
+ heartbeat_t now = now_monotonic_usec();
+ usec_t next = now - (now % tick) + tick;
+
+ while(now < next) {
+ sleep_usec(next - now);
+ now = now_monotonic_usec();
+ }
+
+ if(likely(*hb != 0ULL)) {
+ usec_t dt = now - *hb;
+ *hb = now;
+ if(unlikely(dt / tick > 1))
+ error("heartbeat missed between %llu usec and %llu usec", *hb, now);
+ return dt;
+ }
+ else {
+ *hb = now;
+ return 0ULL;
+ }
+}
+
+inline usec_t heartbeat_dt_usec(heartbeat_t *hb)
+{
+ if(!*hb)
+ return 0ULL;
+ return now_monotonic_usec() - *hb;
+}
diff --git a/src/clocks.h b/src/clocks.h
index c1b8e7017..197b5431f 100644
--- a/src/clocks.h
+++ b/src/clocks.h
@@ -12,9 +12,12 @@ struct timespec {
typedef int clockid_t;
#endif
-#ifndef HAVE_CLOCK_GETTIME
-int clock_gettime(clockid_t clk_id, struct timespec *ts);
-#endif
+typedef unsigned long long nsec_t;
+typedef unsigned long long msec_t;
+typedef unsigned long long usec_t;
+typedef long long susec_t;
+
+typedef usec_t heartbeat_t;
/* Linux value is as good as any other */
#ifndef CLOCK_REALTIME
@@ -27,20 +30,30 @@ int clock_gettime(clockid_t clk_id, struct timespec *ts);
#endif
#ifndef CLOCK_BOOTTIME
-/* fallback to CLOCK_MONOTONIC if not available */
+
+#ifdef CLOCK_UPTIME
+/* CLOCK_BOOTTIME falls back to CLOCK_UPTIME on FreeBSD */
+#define CLOCK_BOOTTIME CLOCK_UPTIME
+#else // CLOCK_UPTIME
+/* CLOCK_BOOTTIME falls back to CLOCK_MONOTONIC */
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
-#else
+#endif // CLOCK_UPTIME
+
+#else // CLOCK_BOOTTIME
+
#ifdef HAVE_CLOCK_GETTIME
#define CLOCK_BOOTTIME_IS_AVAILABLE 1 // required for /proc/uptime
-#endif
-#endif
+#endif // HAVE_CLOCK_GETTIME
-typedef unsigned long long usec_t;
+#endif // CLOCK_BOOTTIME
-#define NSEC_PER_SEC 1000000000ULL
#define NSEC_PER_MSEC 1000000ULL
+
+#define NSEC_PER_SEC 1000000000ULL
#define NSEC_PER_USEC 1000ULL
+
#define USEC_PER_SEC 1000000ULL
+#define MSEC_PER_SEC 1000ULL
#ifndef HAVE_CLOCK_GETTIME
/* Fallback function for POSIX.1-2001 clock_gettime() function.
@@ -52,41 +65,58 @@ typedef unsigned long long usec_t;
extern int clock_gettime(clockid_t clk_id, struct timespec *ts);
#endif
-/* Fills struct timeval with time since EPOCH from real-time clock (i.e. wall-clock).
- * - Hibernation/suspend time is included
- * - adjtime()/NTP adjustments affect this clock
- * Return 0 on succes, -1 else with errno set appropriately.
+/*
+ * Three clocks are available (cf. man 3 clock_gettime):
+ *
+ * REALTIME clock (i.e. wall-clock):
+ * This clock is affected by discontinuous jumps in the system time
+ * (e.g., if the system administrator manually changes the clock), and by the incremental adjustments performed by adjtime(3) and NTP.
+ *
+ * MONOTONIC clock
+ * Clock that cannot be set and represents monotonic time since some unspecified starting point.
+ * This clock is not affected by discontinuous jumps in the system time
+ * (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP.
+ * If not available on the system, this clock falls back to REALTIME clock.
+ *
+ * BOOTTIME clock
+ * Identical to CLOCK_MONOTONIC, except it also includes any time that the system is suspended.
+ * This allows applications to get a suspend-aware monotonic clock without having to deal with the complications of CLOCK_REALTIME,
+ * which may have discontinuities if the time is changed using settimeofday(2).
+ * If not available on the system, this clock falls back to MONOTONIC clock.
+ *
+ * All now_*_timeval() functions fill the `struct timeval` with the time from the appropriate clock.
+ * Those functions return 0 on success, -1 else with errno set appropriately.
+ *
+ * All now_*_sec() functions return the time in seconds from the approriate clock, or 0 on error.
+ * All now_*_usec() functions return the time in microseconds from the approriate clock, or 0 on error.
*/
extern int now_realtime_timeval(struct timeval *tv);
-
-/* Returns time since EPOCH from real-time clock (i.e. wall-clock).
- * - Hibernation/suspend time is included
- * - adjtime()/NTP adjustments affect this clock
- */
extern time_t now_realtime_sec(void);
extern usec_t now_realtime_usec(void);
-/* Returns time from monotonic clock if available, real-time clock else.
- * If monotonic clock is available:
- * - hibernation/suspend time is not included
- * - adjtime()/NTP adjusments affect this clock
- * If monotonic clock is not available, this fallbacks to now_realtime().
- */
+extern int now_monotonic_timeval(struct timeval *tv);
extern time_t now_monotonic_sec(void);
extern usec_t now_monotonic_usec(void);
-/* Returns time from boottime clock if available,
- * monotonic clock else if available, real-time clock else.
- * If boottime clock is available:
- * - hibernation/suspend time is included
- * - adjtime()/NTP adjusments affect this clock
- * If boottime clock is not available, this fallbacks to now_monotonic().
- * If monotonic clock is not available, this fallbacks to now_realtime().
- */
+extern int now_boottime_timeval(struct timeval *tv);
extern time_t now_boottime_sec(void);
extern usec_t now_boottime_usec(void);
+
extern usec_t timeval_usec(struct timeval *ts);
+extern msec_t timeval_msec(struct timeval *tv);
+
extern usec_t dt_usec(struct timeval *now, struct timeval *old);
+extern susec_t dt_usec_signed(struct timeval *now, struct timeval *old);
+
+extern void heartbeat_init(heartbeat_t *hb);
+
+/* Sleeps until next multiple of tick using monotonic clock.
+ * Returns elapsed time in microseconds since previous heartbeat
+ */
+extern usec_t heartbeat_next(heartbeat_t *hb, usec_t tick);
+
+/* Returns elapsed time in microseconds since last heartbeat */
+extern usec_t heartbeat_dt_usec(heartbeat_t *hb);
#endif /* NETDATA_CLOCKS_H */
diff --git a/src/common.c b/src/common.c
index 42f3d8d15..88fcf85bc 100644
--- a/src/common.c
+++ b/src/common.c
@@ -8,10 +8,21 @@
# define MADV_DONTFORK INHERIT_NONE
#endif /* __FreeBSD__ || __APPLE__*/
-char *global_host_prefix = "";
+char *netdata_configured_hostname = NULL;
+char *netdata_configured_config_dir = NULL;
+char *netdata_configured_log_dir = NULL;
+char *netdata_configured_plugins_dir = NULL;
+char *netdata_configured_web_dir = NULL;
+char *netdata_configured_cache_dir = NULL;
+char *netdata_configured_varlib_dir = NULL;
+char *netdata_configured_home_dir = NULL;
+char *netdata_configured_host_prefix = NULL;
+
int enable_ksm = 1;
volatile sig_atomic_t netdata_exit = 0;
+const char *os_type = NETDATA_OS_TYPE;
+const char *program_version = VERSION;
// ----------------------------------------------------------------------------
// memory allocation functions that handle failures
@@ -903,6 +914,9 @@ char *trim(char *s) {
}
void *mymmap(const char *filename, size_t size, int flags, int ksm) {
+#ifndef MADV_MERGEABLE
+ (void)ksm;
+#endif
static int log_madvise_1 = 1;
#ifdef MADV_MERGEABLE
static int log_madvise_2 = 1, log_madvise_3 = 1;
@@ -1060,17 +1074,6 @@ char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
return s;
}
-char *strncpyz(char *dst, const char *src, size_t n) {
- char *p = dst;
-
- while (*src && n--)
- *dst++ = *src++;
-
- *dst = '\0';
-
- return p;
-}
-
int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
int size = vsnprintf(dst, n, fmt, args);
@@ -1104,7 +1107,17 @@ long get_system_cpus(void) {
#ifdef __APPLE__
int32_t tmp_processors;
- if (unlikely(GETSYSCTL("hw.logicalcpu", tmp_processors))) {
+ if (unlikely(GETSYSCTL_BY_NAME("hw.logicalcpu", tmp_processors))) {
+ error("Assuming system has %d processors.", processors);
+ } else {
+ processors = tmp_processors;
+ }
+
+ return processors;
+ #elif __FreeBSD__
+ int32_t tmp_processors;
+
+ if (unlikely(GETSYSCTL_BY_NAME("hw.ncpu", tmp_processors))) {
error("Assuming system has %d processors.", processors);
} else {
processors = tmp_processors;
@@ -1114,7 +1127,7 @@ long get_system_cpus(void) {
#else
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix);
procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
if(!ff) {
@@ -1143,7 +1156,7 @@ long get_system_cpus(void) {
debug(D_SYSTEM, "System has %d processors.", processors);
return processors;
- #endif /* __APPLE__ */
+ #endif /* __APPLE__, __FreeBSD__ */
}
pid_t pid_max = 32768;
@@ -1153,35 +1166,41 @@ pid_t get_system_pid_max(void) {
// we use the number defined in bsd/sys/proc_internal.h in XNU sources
pid_max = 99999;
return pid_max;
+ #elif __FreeBSD__
+ int32_t tmp_pid_max;
+
+ if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
+ pid_max = 99999;
+ error("Assuming system's maximum pid is %d.", pid_max);
+ } else {
+ pid_max = tmp_pid_max;
+ }
+
+ return pid_max;
#else
+ static char read = 0;
+ if(unlikely(read)) return pid_max;
+ read = 1;
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", global_host_prefix);
- procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
- if(!ff) {
- error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
- return pid_max;
- }
+ snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix);
- ff = procfile_readall(ff);
- if(!ff) {
- error("Cannot read file '%s'. Assuming system supports %d pids.", filename, pid_max);
+ unsigned long long max = 0;
+ if(read_single_number_file(filename, &max) != 0) {
+ error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
return pid_max;
}
- pid_max = (pid_t)str2i(procfile_lineword(ff, 0, 0));
- if(!pid_max) {
- procfile_close(ff);
- pid_max = 32768;
+ if(!max) {
error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max);
return pid_max;
}
- procfile_close(ff);
- debug(D_SYSTEM, "System supports %d pids.", pid_max);
+ pid_max = (pid_t) max;
return pid_max;
- #endif /* __APPLE__ */
+ #endif /* __APPLE__, __FreeBSD__ */
}
unsigned int hz;
diff --git a/src/common.h b/src/common.h
index e38e95b48..b82c078fa 100644
--- a/src/common.h
+++ b/src/common.h
@@ -67,9 +67,9 @@
#include <syslog.h>
#include <sys/mman.h>
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
-#endif /* __FreeBSD__ || __APPLE__*/
+#endif
#include <sys/resource.h>
#include <sys/socket.h>
@@ -109,6 +109,10 @@
#include <zlib.h>
#endif
+#ifdef HAVE_CAPABILITY
+#include <sys/capability.h>
+#endif
+
// ----------------------------------------------------------------------------
// netdata common definitions
@@ -164,10 +168,11 @@
// ----------------------------------------------------------------------------
// netdata include files
-#include "simple_pattern.h"
-#include "avl.h"
#include "clocks.h"
#include "log.h"
+#include "locks.h"
+#include "simple_pattern.h"
+#include "avl.h"
#include "global_statistics.h"
#include "storage_number.h"
#include "web_buffer.h"
@@ -184,21 +189,26 @@
#include "plugin_nfacct.h"
#if defined(__FreeBSD__)
+#include <pthread_np.h>
#include "plugin_freebsd.h"
+#define NETDATA_OS_TYPE "freebsd"
#elif defined(__APPLE__)
#include "plugin_macos.h"
+#define NETDATA_OS_TYPE "macos"
#else
#include "plugin_proc.h"
#include "plugin_proc_diskspace.h"
+#define NETDATA_OS_TYPE "linux"
#endif /* __FreeBSD__, __APPLE__*/
-#include "plugin_tc.h"
-#include "plugins_d.h"
#include "socket.h"
#include "eval.h"
#include "health.h"
#include "rrd.h"
+#include "plugin_tc.h"
+#include "plugins_d.h"
#include "rrd2json.h"
+#include "rrd2json_api_old.h"
#include "web_client.h"
#include "web_server.h"
#include "registry.h"
@@ -209,6 +219,19 @@
#include "backends.h"
#include "inlined.h"
#include "adaptive_resortable_list.h"
+#include "rrdpush.h"
+#include "web_api_v1.h"
+#include "web_api_old.h"
+
+extern char *netdata_configured_hostname;
+extern char *netdata_configured_config_dir;
+extern char *netdata_configured_log_dir;
+extern char *netdata_configured_plugins_dir;
+extern char *netdata_configured_web_dir;
+extern char *netdata_configured_cache_dir;
+extern char *netdata_configured_varlib_dir;
+extern char *netdata_configured_home_dir;
+extern char *netdata_configured_host_prefix;
extern void netdata_fix_chart_id(char *s);
extern void netdata_fix_chart_name(char *s);
@@ -217,7 +240,6 @@ extern void strreverse(char* begin, char* end);
extern char *mystrsep(char **ptr, char *s);
extern char *trim(char *s);
-extern char *strncpyz(char *dst, const char *src, size_t n);
extern int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args);
extern int snprintfz(char *dst, size_t n, const char *fmt, ...) PRINTFLIKE(3, 4);
@@ -249,7 +271,6 @@ extern int savememory(const char *filename, void *mem, size_t size);
extern int fd_is_valid(int fd);
-extern char *global_host_prefix;
extern int enable_ksm;
extern pid_t gettid(void);
@@ -268,6 +289,10 @@ extern pid_t get_system_pid_max(void);
extern unsigned int hz;
extern void get_system_HZ(void);
+extern volatile sig_atomic_t netdata_exit;
+extern const char *os_type;
+
+extern const char *program_version;
/* fix for alpine linux */
#ifndef RUSAGE_THREAD
diff --git a/src/daemon.c b/src/daemon.c
index 4fd8ca5e5..42b04c401 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -27,7 +27,7 @@ void sig_handler_save(int signo)
if(signo) {
error_log_limit_unlimited();
info("Received signal %d to save the database...", signo);
- rrdset_save_all();
+ rrdhost_save_all();
error_log_limit_reset();
}
}
@@ -84,8 +84,8 @@ int become_user(const char *username, int pid_fd)
uid_t uid = pw->pw_uid;
gid_t gid = pw->pw_gid;
- create_needed_dir(CACHE_DIR, uid, gid);
- create_needed_dir(VARLIB_DIR, uid, gid);
+ create_needed_dir(netdata_configured_cache_dir, uid, gid);
+ create_needed_dir(netdata_configured_varlib_dir, uid, gid);
if(pidfile[0]) {
if(chown(pidfile, uid, gid) == -1)
@@ -155,13 +155,15 @@ int become_user(const char *username, int pid_fd)
return(0);
}
-void oom_score_adj(int score) {
+static void oom_score_adj(void) {
+ int score = (int)config_get_number(CONFIG_SECTION_GLOBAL, "OOM score", 1000);
+
int done = 0;
int fd = open("/proc/self/oom_score_adj", O_WRONLY);
if(fd != -1) {
char buf[10 + 1];
ssize_t len = snprintfz(buf, 10, "%d", score);
- if(write(fd, buf, len) == len) done = 1;
+ if(len > 0 && write(fd, buf, (size_t)len) == len) done = 1;
close(fd);
}
@@ -171,23 +173,130 @@ void oom_score_adj(int score) {
debug(D_SYSTEM, "Adjusted my Out-Of-Memory score to %d.", score);
}
-int sched_setscheduler_idle(void) {
+static void process_nice_level(void) {
+#ifdef HAVE_NICE
+ int nice_level = (int)config_get_number(CONFIG_SECTION_GLOBAL, "process nice level", 19);
+ if(nice(nice_level) == -1) error("Cannot set netdata CPU nice level to %d.", nice_level);
+ else debug(D_SYSTEM, "Set netdata nice level to %d.", nice_level);
+#endif // HAVE_NICE
+};
+
+#ifdef HAVE_SCHED_SETSCHEDULER
+
+#define SCHED_FLAG_NONE 0x00
+#define SCHED_FLAG_PRIORITY_CONFIGURABLE 0x01 // the priority is user configurable
+#define SCHED_FLAG_KEEP_AS_IS 0x04 // do not attempt to set policy, priority or nice()
+#define SCHED_FLAG_USE_NICE 0x08 // use nice() after setting this policy
+
+struct sched_def {
+ char *name;
+ int policy;
+ int priority;
+ uint8_t flags;
+} scheduler_defaults[] = {
+
+ // the order of array members is important!
+ // the first defined is the default used by netdata
+
+ // the available members are important too!
+ // these are all the possible scheduling policies supported by netdata
+
#ifdef SCHED_IDLE
- const struct sched_param param = {
- .sched_priority = 0
- };
+ { "idle", SCHED_IDLE, 0, SCHED_FLAG_NONE },
+#endif
- int i = sched_setscheduler(0, SCHED_IDLE, &param);
- if(i != 0)
- error("Cannot adjust my scheduling priority to IDLE.");
- else
- debug(D_SYSTEM, "Adjusted my scheduling priority to IDLE.");
+#ifdef SCHED_OTHER
+ { "nice", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE },
+ { "other", SCHED_OTHER, 0, SCHED_FLAG_USE_NICE },
+#endif
- return i;
-#else
- return -1;
+#ifdef SCHED_RR
+ { "rr", SCHED_RR, 0, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_FIFO
+ { "fifo", SCHED_FIFO, 0, SCHED_FLAG_PRIORITY_CONFIGURABLE },
+#endif
+
+#ifdef SCHED_BATCH
+ { "batch", SCHED_BATCH, 0, SCHED_FLAG_USE_NICE },
+#endif
+
+ // do not change the scheduling priority
+ { "keep", 0, 0, SCHED_FLAG_KEEP_AS_IS },
+ { "none", 0, 0, SCHED_FLAG_KEEP_AS_IS },
+
+ // array termination
+ { NULL, 0, 0, 0 }
+};
+
+static void sched_setscheduler_set(void) {
+
+ if(scheduler_defaults[0].name) {
+ const char *name = scheduler_defaults[0].name;
+ int policy = scheduler_defaults[0].policy, priority = scheduler_defaults[0].priority;
+ uint8_t flags = scheduler_defaults[0].flags;
+ int found = 0;
+
+ // read the configuration
+ name = config_get(CONFIG_SECTION_GLOBAL, "process scheduling policy", name);
+ int i;
+ for(i = 0 ; scheduler_defaults[i].name ; i++) {
+ if(!strcmp(name, scheduler_defaults[i].name)) {
+ found = 1;
+ priority = scheduler_defaults[i].priority;
+ flags = scheduler_defaults[i].flags;
+
+ if(flags & SCHED_FLAG_KEEP_AS_IS)
+ return;
+
+ if(flags & SCHED_FLAG_PRIORITY_CONFIGURABLE)
+ priority = (int)config_get_number(CONFIG_SECTION_GLOBAL, "process scheduling priority", priority);
+
+#ifdef HAVE_SCHED_GET_PRIORITY_MIN
+ if(priority < sched_get_priority_min(policy)) {
+ error("scheduler %s priority %d is below the minimum %d. Using the minimum.", name, priority, sched_get_priority_min(policy));
+ priority = sched_get_priority_min(policy);
+ }
+#endif
+#ifdef HAVE_SCHED_GET_PRIORITY_MAX
+ if(priority > sched_get_priority_max(policy)) {
+ error("scheduler %s priority %d is above the maximum %d. Using the maximum.", name, priority, sched_get_priority_max(policy));
+ priority = sched_get_priority_max(policy);
+ }
#endif
+ break;
+ }
+ }
+
+ if(!found) {
+ error("Unknown scheduling policy %s - falling back to nice()", name);
+ goto fallback;
+ }
+
+ const struct sched_param param = {
+ .sched_priority = priority
+ };
+
+ i = sched_setscheduler(0, policy, &param);
+ if(i != 0) {
+ error("Cannot adjust netdata scheduling policy to %s (%d), with priority %d. Falling back to nice", name, policy, priority);
+ }
+ else {
+ debug(D_SYSTEM, "Adjusted netdata scheduling policy to %s (%d), with priority %d.", name, policy, priority);
+ if(!(flags & SCHED_FLAG_USE_NICE))
+ return;
+ }
+ }
+
+fallback:
+ process_nice_level();
}
+#else
+static void sched_setscheduler_set(void) {
+ process_nice_level();
+}
+#endif
int become_daemon(int dont_fork, const char *user)
{
@@ -239,13 +348,10 @@ int become_daemon(int dont_fork, const char *user)
umask(0007);
// adjust my Out-Of-Memory score
- oom_score_adj(1000);
+ oom_score_adj();
// never become a problem
- if(sched_setscheduler_idle() != 0) {
- if(nice(19) == -1) error("Cannot lower my CPU priority.");
- else debug(D_SYSTEM, "Set my nice value to 19.");
- }
+ sched_setscheduler_set();
if(user && *user) {
if(become_user(user, pidfd) != 0) {
@@ -254,8 +360,8 @@ int become_daemon(int dont_fork, const char *user)
else debug(D_SYSTEM, "Successfully became user '%s'.", user);
}
else {
- create_needed_dir(CACHE_DIR, getuid(), getgid());
- create_needed_dir(VARLIB_DIR, getuid(), getgid());
+ create_needed_dir(netdata_configured_cache_dir, getuid(), getgid());
+ create_needed_dir(netdata_configured_varlib_dir, getuid(), getgid());
}
if(pidfd != -1)
diff --git a/src/dictionary.c b/src/dictionary.c
index fb9efeedb..512b4bbe6 100644
--- a/src/dictionary.c
+++ b/src/dictionary.c
@@ -31,21 +31,21 @@ static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) {
static inline void dictionary_read_lock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary READ lock");
- pthread_rwlock_rdlock(dict->rwlock);
+ netdata_rwlock_rdlock(dict->rwlock);
}
}
static inline void dictionary_write_lock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary WRITE lock");
- pthread_rwlock_wrlock(dict->rwlock);
+ netdata_rwlock_wrlock(dict->rwlock);
}
}
static inline void dictionary_unlock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary UNLOCK lock");
- pthread_rwlock_unlock(dict->rwlock);
+ netdata_rwlock_unlock(dict->rwlock);
}
}
@@ -135,8 +135,8 @@ DICTIONARY *dictionary_create(uint8_t flags) {
dict->stats = callocz(1, sizeof(struct dictionary_stats));
if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
- dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
- pthread_rwlock_init(dict->rwlock, NULL);
+ dict->rwlock = callocz(1, sizeof(netdata_rwlock_t));
+ netdata_rwlock_init(dict->rwlock);
}
avl_init(&dict->values_index, name_value_compare);
@@ -158,8 +158,10 @@ void dictionary_destroy(DICTIONARY *dict) {
if(dict->stats)
freez(dict->stats);
- if(dict->rwlock)
+ if(dict->rwlock) {
+ netdata_rwlock_destroy(dict->rwlock);
freez(dict->rwlock);
+ }
freez(dict);
}
diff --git a/src/dictionary.h b/src/dictionary.h
index 6bebbfa85..f028dbb30 100644
--- a/src/dictionary.h
+++ b/src/dictionary.h
@@ -24,7 +24,7 @@ typedef struct dictionary {
uint8_t flags;
struct dictionary_stats *stats;
- pthread_rwlock_t *rwlock;
+ netdata_rwlock_t *rwlock;
} DICTIONARY;
#define DICTIONARY_FLAG_DEFAULT 0x00000000
diff --git a/src/freebsd_sysctl.c b/src/freebsd_sysctl.c
index 9400089db..965c1cbbf 100644
--- a/src/freebsd_sysctl.c
+++ b/src/freebsd_sysctl.c
@@ -1,1116 +1,1309 @@
#include "common.h"
-// NEEDED BY: struct vmtotal, struct vmmeter
#include <sys/vmmeter.h>
-// NEEDED BY: struct devstat
#include <sys/devicestat.h>
-// NEEDED BY: struct xswdev
+#include <sys/mount.h>
#include <vm/vm_param.h>
-// NEEDED BY: struct semid_kernel, struct shmid_kernel, struct msqid_kernel
+
#define _KERNEL
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#undef _KERNEL
-// NEEDED BY: struct sysctl_netisr_workstream, struct sysctl_netisr_work
+
#include <net/netisr.h>
-// NEEDED BY: struct ifaddrs, getifaddrs()
#include <net/if.h>
#include <ifaddrs.h>
-// NEEDED BY do_tcp...
-#include <netinet/tcp_var.h>
-#include <netinet/tcp_fsm.h>
-// NEEDED BY do_udp..., do_ip...
-#include <netinet/ip_var.h>
-// NEEDED BY do_udp...
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-// NEEDED BY do_icmp...
+
#include <netinet/ip.h>
+#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
-// NEEDED BY do_ip6...
#include <netinet6/ip6_var.h>
-// NEEDED BY do_icmp6...
#include <netinet/icmp6.h>
-// NEEDED BY do_space, do_inodes
-#include <sys/mount.h>
-// NEEDED BY do_uptime
-#include <time.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+// --------------------------------------------------------------------------------------------------------------------
+// common definitions and variables
#define KILO_FACTOR 1024
#define MEGA_FACTOR 1048576 // 1024 * 1024
#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024
-// NEEDED BY: do_disk_io
-#define RRD_TYPE_DISK "disk"
+#define MAX_INT_DIGITS 10 // maximum number of digits for int
-// FreeBSD calculates load averages once every 5 seconds
-#define MIN_LOADAVG_UPDATE_EVERY 5
+int system_pagesize = PAGE_SIZE;
+int number_of_cpus = 1;
-// NEEDED BY: do_bandwidth
-#define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+// --------------------------------------------------------------------------------------------------------------------
+// FreeBSD plugin initialization
-int do_freebsd_sysctl(int update_every, usec_t dt) {
- (void)dt;
-
- static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
- do_loadavg = -1, do_all_processes = -1, do_disk_io = -1, do_swap = -1, do_ram = -1, do_swapio = -1,
- do_pgfaults = -1, do_committed = -1, do_ipc_semaphores = -1, do_ipc_shared_mem = -1, do_ipc_msg_queues = -1,
- do_dev_intr = -1, do_soft_intr = -1, do_netisr = -1, do_netisr_per_core = -1, do_bandwidth = -1,
- do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
- do_ecn = -1, do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1,
- do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1,
- do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
- do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1,
- do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
- do_icmp6_neighbor = -1, do_icmp6_types = -1, do_space = -1, do_inodes = -1, do_uptime = -1;
-
- if (unlikely(do_cpu == -1)) {
- do_cpu = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
- do_cpu_cores = config_get_boolean("plugin:freebsd:sysctl", "per cpu core utilization", 1);
- do_interrupts = config_get_boolean("plugin:freebsd:sysctl", "cpu interrupts", 1);
- do_dev_intr = config_get_boolean("plugin:freebsd:sysctl", "device interrupts", 1);
- do_soft_intr = config_get_boolean("plugin:freebsd:sysctl", "software interrupts", 1);
- do_context = config_get_boolean("plugin:freebsd:sysctl", "context switches", 1);
- do_forks = config_get_boolean("plugin:freebsd:sysctl", "processes started", 1);
- do_processes = config_get_boolean("plugin:freebsd:sysctl", "processes running", 1);
- do_loadavg = config_get_boolean("plugin:freebsd:sysctl", "enable load average", 1);
- do_all_processes = config_get_boolean("plugin:freebsd:sysctl", "enable total processes", 1);
- do_disk_io = config_get_boolean("plugin:freebsd:sysctl", "stats for all disks", 1);
- do_swap = config_get_boolean("plugin:freebsd:sysctl", "system swap", 1);
- do_ram = config_get_boolean("plugin:freebsd:sysctl", "system ram", 1);
- do_swapio = config_get_boolean("plugin:freebsd:sysctl", "swap i/o", 1);
- do_pgfaults = config_get_boolean("plugin:freebsd:sysctl", "memory page faults", 1);
- do_committed = config_get_boolean("plugin:freebsd:sysctl", "committed memory", 1);
- do_ipc_semaphores = config_get_boolean("plugin:freebsd:sysctl", "ipc semaphores", 1);
- do_ipc_shared_mem = config_get_boolean("plugin:freebsd:sysctl", "ipc shared memory", 1);
- do_ipc_msg_queues = config_get_boolean("plugin:freebsd:sysctl", "ipc message queues", 1);
- do_netisr = config_get_boolean("plugin:freebsd:sysctl", "netisr", 1);
- do_netisr_per_core = config_get_boolean("plugin:freebsd:sysctl", "netisr per core", 1);
- do_bandwidth = config_get_boolean("plugin:freebsd:sysctl", "bandwidth", 1);
- do_tcp_sockets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP connections", 1);
- do_tcp_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP packets", 1);
- do_tcp_errors = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP errors", 1);
- do_tcp_handshake = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP handshake issues", 1);
- do_ecn = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
- do_udp_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP packets", 1);
- do_udp_errors = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP errors", 1);
- do_icmp_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP packets", 1);
- do_icmpmsg = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP messages", 1);
- do_ip_packets = config_get_boolean("plugin:freebsd:sysctl", "ipv4 packets", 1);
- do_ip_fragsout = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments sent", 1);
- do_ip_fragsin = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments assembly", 1);
- do_ip_errors = config_get_boolean("plugin:freebsd:sysctl", "ipv4 errors", 1);
- do_ip6_packets = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsout = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsin = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_errors = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6 = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_redir = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_errors = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_echos = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_router = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_neighbor = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_types = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
- do_space = config_get_boolean("plugin:freebsd:sysctl", "space usage for all disks", 1);
- do_inodes = config_get_boolean("plugin:freebsd:sysctl", "inodes usage for all disks", 1);
- do_uptime = config_get_boolean("plugin:macos:sysctl", "system uptime", 1);
+int freebsd_plugin_init()
+{
+ system_pagesize = getpagesize();
+ if (system_pagesize <= 0) {
+ error("FREEBSD: can't get system page size");
+ return 1;
}
- RRDSET *st;
- RRDDIM *rd;
-
- int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
- int i, n;
- void *p;
- int common_error = 0;
- size_t size;
- char title[4096 + 1];
-
- // NEEDED BY: do_loadavg
- static usec_t last_loadavg_usec = 0;
- struct loadavg sysload;
-
- // NEEDED BY: do_cpu, do_cpu_cores
- long cp_time[CPUSTATES];
-
- // NEEDED BY: du_cpu_cores, do_netisr, do_netisr_per_core
- int ncpus;
-
- // NEEDED BY: do_cpu_cores
- static long *pcpu_cp_time = NULL;
- char cpuid[8]; // no more than 4 digits expected
-
- // NEEDED BY: do_all_processes, do_processes
- struct vmtotal vmtotal_data;
-
- // NEEDED BY: do_context, do_forks
- u_int u_int_data;
-
- // NEEDED BY: do_interrupts
- size_t intrcnt_size;
- unsigned long nintr = 0;
- static unsigned long *intrcnt = NULL;
- static char *intrnames = NULL;
- unsigned long long totalintr = 0;
-
- // NEEDED BY: do_disk_io
- #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
- int numdevs;
- static void *devstat_data = NULL;
- struct devstat *dstat;
- char disk[DEVSTAT_NAME_LEN + 10 + 1]; // 10 - maximum number of digits for int
- struct cur_dstat {
- collected_number duration_read_ms;
- collected_number duration_write_ms;
- collected_number busy_time_ms;
- } cur_dstat;
- struct prev_dstat {
- collected_number bytes_read;
- collected_number bytes_write;
- collected_number operations_read;
- collected_number operations_write;
- collected_number duration_read_ms;
- collected_number duration_write_ms;
- collected_number busy_time_ms;
- } prev_dstat;
-
- // NEEDED BY: do_swap
- size_t mibsize;
- int mib[3]; // CTL_MAXNAME = 24 maximum mib components (sysctl.h)
- struct xswdev xsw;
- struct total_xsw {
- collected_number bytes_used;
- collected_number bytes_total;
- } total_xsw = {0, 0};
-
- // NEEDED BY: do_swapio, do_ram
- struct vmmeter vmmeter_data;
-
- // NEEDED BY: do_ram
- int vfs_bufspace_count;
-
- // NEEDED BY: do_ipc_semaphores
- struct ipc_sem {
- int semmni;
- collected_number sets;
- collected_number semaphores;
- } ipc_sem = {0, 0, 0};
- static struct semid_kernel *ipc_sem_data = NULL;
-
- // NEEDED BY: do_ipc_shared_mem
- struct ipc_shm {
- u_long shmmni;
- collected_number segs;
- collected_number segsize;
- } ipc_shm = {0, 0, 0};
- static struct shmid_kernel *ipc_shm_data = NULL;
-
- // NEEDED BY: do_ipc_msg_queues
- struct ipc_msq {
- int msgmni;
- collected_number queues;
- collected_number messages;
- collected_number usedsize;
- collected_number allocsize;
- } ipc_msq = {0, 0, 0, 0, 0};
- static struct msqid_kernel *ipc_msq_data = NULL;
+ if (unlikely(GETSYSCTL_BY_NAME("kern.smp.cpus", number_of_cpus))) {
+ error("FREEBSD: can't get number of cpus");
+ return 1;
+ }
- // NEEDED BY: do_netisr, do_netisr_per_core
- size_t netisr_workstream_size;
- size_t netisr_work_size;
- unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
- static struct sysctl_netisr_workstream *netisr_workstream = NULL;
- static struct sysctl_netisr_work *netisr_work = NULL;
- static struct netisr_stats {
- collected_number dispatched;
- collected_number hybrid_dispatched;
- collected_number qdrops;
- collected_number queued;
- } *netisr_stats = NULL;
- char netstat_cpuid[21]; // no more than 4 digits expected
+ if (unlikely(!number_of_cpus)) {
+ error("FREEBSD: wrong number of cpus");
+ return 1;
+ }
- // NEEDED BY: do_bandwidth
- struct ifaddrs *ifa, *ifap;
- struct iftot {
- u_long ift_ibytes;
- u_long ift_obytes;
- } iftot = {0, 0};
+ return 0;
+}
- // NEEDED BY: do_tcp...
- struct tcpstat tcpstat;
- uint64_t tcps_states[TCP_NSTATES];
+// --------------------------------------------------------------------------------------------------------------------
+// vm.loadavg
- // NEEDED BY: do_udp...
- struct udpstat udpstat;
+// FreeBSD calculates load averages once every 5 seconds
+#define MIN_LOADAVG_UPDATE_EVERY 5
- // NEEDED BY: do_icmp...
- struct icmpstat icmpstat;
- struct icmp_total {
- u_long msgs_in;
- u_long msgs_out;
- } icmp_total = {0, 0};
+int do_vm_loadavg(int update_every, usec_t dt){
+ static usec_t next_loadavg_dt = 0;
- // NEEDED BY: do_ip...
- struct ipstat ipstat;
+ if (next_loadavg_dt <= dt) {
+ static int mib[2] = {0, 0};
+ struct loadavg sysload;
- // NEEDED BY: do_ip6...
- struct ip6stat ip6stat;
+ if (unlikely(GETSYSCTL_SIMPLE("vm.loadavg", mib, sysload))) {
+ error("DISABLED: system.load chart");
+ error("DISABLED: vm.loadavg module");
+ return 1;
+ } else {
- // NEEDED BY: do_icmp6...
- struct icmp6stat icmp6stat;
- struct icmp6_total {
- u_long msgs_in;
- u_long msgs_out;
- } icmp6_total = {0, 0};
+ // --------------------------------------------------------------------
- // NEEDED BY: do_space, do_inodes
- struct statfs *mntbuf;
- int mntsize;
- char mntonname[MNAMELEN + 1];
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_load1 = NULL, *rd_load2 = NULL, *rd_load3 = NULL;
- // NEEDED BY: do_uptime
- struct timespec boot_time, cur_time;
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "load",
+ NULL,
+ "load",
+ NULL,
+ "System Load Average",
+ "load",
+ 100,
+ (update_every < MIN_LOADAVG_UPDATE_EVERY) ?
+ MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE
+ );
+ rd_load1 = rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rd_load2 = rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rd_load3 = rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_load1, (collected_number) ((double) sysload.ldavg[0] / sysload.fscale * 1000));
+ rrddim_set_by_pointer(st, rd_load2, (collected_number) ((double) sysload.ldavg[1] / sysload.fscale * 1000));
+ rrddim_set_by_pointer(st, rd_load3, (collected_number) ((double) sysload.ldavg[2] / sysload.fscale * 1000));
+ rrdset_done(st);
- // --------------------------------------------------------------------
+ next_loadavg_dt = st->update_every * USEC_PER_SEC;
+ }
+ }
+ else
+ next_loadavg_dt -= dt;
- if (last_loadavg_usec <= dt) {
- if (likely(do_loadavg)) {
- if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
- do_loadavg = 0;
- error("DISABLED: system.load");
- } else {
+ return 0;
+}
- st = rrdset_find_bytype("system", "load");
- if (unlikely(!st)) {
- st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.vmtotal
- rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
- rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
- rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
- rrdset_done(st);
- }
- }
+int do_vm_vmtotal(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_all_processes = -1, do_processes = -1, do_committed = -1;
- last_loadavg_usec = st->update_every * USEC_PER_SEC;
+ if (unlikely(do_all_processes == -1)) {
+ do_all_processes = config_get_boolean("plugin:freebsd:vm.vmtotal", "enable total processes", 1);
+ do_processes = config_get_boolean("plugin:freebsd:vm.vmtotal", "processes running", 1);
+ do_committed = config_get_boolean("plugin:freebsd:vm.vmtotal", "committed memory", 1);
}
- else last_loadavg_usec -= dt;
-
- // --------------------------------------------------------------------
if (likely(do_all_processes | do_processes | do_committed)) {
- if (unlikely(GETSYSCTL("vm.vmtotal", vmtotal_data))) {
+ static int mib[2] = {0, 0};
+ struct vmtotal vmtotal_data;
+
+ if (unlikely(GETSYSCTL_SIMPLE("vm.vmtotal", mib, vmtotal_data))) {
do_all_processes = 0;
- error("DISABLED: system.active_processes");
+ error("DISABLED: system.active_processes chart");
do_processes = 0;
- error("DISABLED: system.processes");
+ error("DISABLED: system.processes chart");
do_committed = 0;
- error("DISABLED: mem.committed");
+ error("DISABLED: mem.committed chart");
+ error("DISABLED: vm.vmtotal module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_all_processes)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- st = rrdset_find_bytype("system", "active_processes");
if (unlikely(!st)) {
- st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system",
+ "active_processes",
+ NULL,
+ "processes",
+ NULL,
+ "System Active Processes",
+ "processes",
+ 750,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+ rd = rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "active", (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
+ rrddim_set_by_pointer(st, rd, (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_processes)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_running = NULL, *rd_blocked = NULL;
- st = rrdset_find_bytype("system", "processes");
if (unlikely(!st)) {
- st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system",
+ "processes",
+ NULL,
+ "processes",
+ NULL,
+ "System Processes",
+ "processes",
+ 600,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_running = rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rd_blocked = rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "running", vmtotal_data.t_rq);
- rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
+ rrddim_set_by_pointer(st, rd_running, vmtotal_data.t_rq);
+ rrddim_set_by_pointer(st, rd_blocked, (vmtotal_data.t_dw + vmtotal_data.t_pw));
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_committed)) {
- st = rrdset_find("mem.committed");
- if (unlikely(!st)) {
- st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("mem",
+ "committed",
+ NULL,
+ "system",
+ NULL,
+ "Committed (Allocated) Memory",
+ "MB",
+ 5000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd = rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
- rrddim_set(st, "Committed_AS", vmtotal_data.t_rm);
+ rrddim_set_by_pointer(st, rd, vmtotal_data.t_rm);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: vm.vmtotal module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.cp_time
+
+int do_kern_cp_time(int update_every, usec_t dt) {
+ (void)dt;
- if (likely(do_cpu)) {
- if (unlikely(CPUSTATES != 5)) {
- error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
- do_cpu = 0;
- error("DISABLED: system.cpu");
+ if (unlikely(CPUSTATES != 5)) {
+ error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+ error("DISABLED: system.cpu chart");
+ error("DISABLED: kern.cp_time module");
+ return 1;
+ } else {
+ static int mib[2] = {0, 0};
+ long cp_time[CPUSTATES];
+
+ if (unlikely(GETSYSCTL_SIMPLE("kern.cp_time", mib, cp_time))) {
+ error("DISABLED: system.cpu chart");
+ error("DISABLED: kern.cp_time module");
+ return 1;
} else {
- if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
- do_cpu = 0;
- error("DISABLED: system.cpu");
- } else {
- st = rrdset_find_bytype("system", "cpu");
- if (unlikely(!st)) {
- st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_hide(st, "idle");
- }
- else rrdset_next(st);
+ // --------------------------------------------------------------------
- rrddim_set(st, "user", cp_time[0]);
- rrddim_set(st, "nice", cp_time[1]);
- rrddim_set(st, "system", cp_time[2]);
- rrddim_set(st, "interrupt", cp_time[3]);
- rrddim_set(st, "idle", cp_time[4]);
- rrdset_done(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_nice = NULL, *rd_system = NULL, *rd_user = NULL, *rd_interrupt = NULL, *rd_idle = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "cpu",
+ NULL,
+ "cpu",
+ "system.cpu",
+ "Total CPU utilization",
+ "percentage",
+ 100, update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ rd_nice = rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_system = rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_user = rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_interrupt = rrddim_add(st, "interrupt", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rd_idle = rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_hide(st, "idle");
}
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_nice, cp_time[1]);
+ rrddim_set_by_pointer(st, rd_system, cp_time[2]);
+ rrddim_set_by_pointer(st, rd_user, cp_time[0]);
+ rrddim_set_by_pointer(st, rd_interrupt, cp_time[3]);
+ rrddim_set_by_pointer(st, rd_idle, cp_time[4]);
+ rrdset_done(st);
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.cp_times
+
+int do_kern_cp_times(int update_every, usec_t dt) {
+ (void)dt;
- if (likely(do_cpu_cores)) {
- if (unlikely(CPUSTATES != 5)) {
- error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
+ if (unlikely(CPUSTATES != 5)) {
+ error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+ error("DISABLED: cpu.cpuXX charts");
+ error("DISABLED: kern.cp_times module");
+ return 1;
+ } else {
+ static int mib[2] = {0, 0};
+ long cp_time[CPUSTATES];
+ static long *pcpu_cp_time = NULL;
+
+ pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * number_of_cpus);
+ if (unlikely(GETSYSCTL_WSIZE("kern.cp_times", mib, pcpu_cp_time, sizeof(cp_time) * number_of_cpus))) {
+ error("DISABLED: cpu.cpuXX charts");
+ error("DISABLED: kern.cp_times module");
+ return 1;
} else {
- if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
- } else {
- pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
- for (i = 0; i < ncpus; i++) {
- if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
- break;
- }
- if (unlikely(ncpus > 9999)) {
- error("FREEBSD: There are more than 4 digits in cpu cores number");
- do_cpu_cores = 0;
- error("DISABLED: cpu.cpuXX");
- break;
- }
- snprintfz(cpuid, 8, "cpu%d", i);
+ // --------------------------------------------------------------------
- st = rrdset_find_bytype("cpu", cpuid);
- if (unlikely(!st)) {
- st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_hide(st, "idle");
- }
- else rrdset_next(st);
+ int i;
+ static struct cpu_chart {
+ char cpuid[MAX_INT_DIGITS + 4];
+ RRDSET *st;
+ RRDDIM *rd_user;
+ RRDDIM *rd_nice;
+ RRDDIM *rd_system;
+ RRDDIM *rd_interrupt;
+ RRDDIM *rd_idle;
+ } *all_cpu_charts = NULL;
+ static int old_number_of_cpus = 0;
+
+ if(unlikely(number_of_cpus > old_number_of_cpus)) {
+ all_cpu_charts = reallocz(all_cpu_charts, sizeof(struct cpu_chart) * number_of_cpus);
+ memset(&all_cpu_charts[old_number_of_cpus], 0, sizeof(struct cpu_chart) * (number_of_cpus - old_number_of_cpus));
+ old_number_of_cpus = number_of_cpus;
+ }
- rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
- rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
- rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
- rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
- rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
- rrdset_done(st);
- }
+ for (i = 0; i < number_of_cpus; i++) {
+ if (unlikely(!all_cpu_charts[i].st)) {
+ snprintfz(all_cpu_charts[i].cpuid, MAX_INT_DIGITS, "cpu%d", i);
+ all_cpu_charts[i].st = rrdset_create_localhost("cpu",
+ all_cpu_charts[i].cpuid,
+ NULL,
+ "utilization",
+ "cpu.cpu",
+ "Core utilization",
+ "percentage",
+ 1000,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ all_cpu_charts[i].rd_nice = rrddim_add(all_cpu_charts[i].st, "nice", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_system = rrddim_add(all_cpu_charts[i].st, "system", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_user = rrddim_add(all_cpu_charts[i].st, "user", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_interrupt = rrddim_add(all_cpu_charts[i].st, "interrupt", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ all_cpu_charts[i].rd_idle = rrddim_add(all_cpu_charts[i].st, "idle", NULL, 1, 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_hide(all_cpu_charts[i].st, "idle");
+ } else rrdset_next(all_cpu_charts[i].st);
+
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_nice, pcpu_cp_time[i * 5 + 1]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_system, pcpu_cp_time[i * 5 + 2]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_user, pcpu_cp_time[i * 5 + 0]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_interrupt, pcpu_cp_time[i * 5 + 3]);
+ rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_idle, pcpu_cp_time[i * 5 + 4]);
+ rrdset_done(all_cpu_charts[i].st);
}
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
- if (likely(do_interrupts)) {
- if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(hw.intrcnt...) failed: %s", strerror(errno));
- do_interrupts = 0;
- error("DISABLED: system.intr");
+// --------------------------------------------------------------------------------------------------------------------
+// hw.intrcnt
+
+int do_hw_intcnt(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_hw_intrcnt[2] = {0, 0};
+ size_t intrcnt_size = sizeof(mib_hw_intrcnt);
+ unsigned long i;
+
+ if (unlikely(GETSYSCTL_SIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt_size))) {
+ error("DISABLED: system.intr chart");
+ error("DISABLED: system.interrupts chart");
+ error("DISABLED: hw.intrcnt module");
+ return 1;
+ } else {
+ unsigned long nintr = 0;
+ static unsigned long *intrcnt = NULL;
+ unsigned long long totalintr = 0;
+
+ nintr = intrcnt_size / sizeof(u_long);
+ intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
+ if (unlikely(GETSYSCTL_WSIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt, nintr * sizeof(u_long)))) {
+ error("DISABLED: system.intr chart");
+ error("DISABLED: system.interrupts chart");
+ error("DISABLED: hw.intrcnt module");
+ return 1;
} else {
- nintr = intrcnt_size / sizeof(u_long);
- intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
- if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
- do_interrupts = 0;
- error("DISABLED: system.intr");
- } else {
- for (i = 0; i < nintr; i++)
- totalintr += intrcnt[i];
+ for (i = 0; i < nintr; i++)
+ totalintr += intrcnt[i];
- st = rrdset_find_bytype("system", "intr");
- if (unlikely(!st)) {
- st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Hardware Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ // --------------------------------------------------------------------
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ static RRDSET *st_intr = NULL;
+ static RRDDIM *rd_intr = NULL;
+
+ if (unlikely(!st_intr)) {
+ st_intr = rrdset_create_localhost("system",
+ "intr",
+ NULL,
+ "interrupts",
+ NULL,
+ "Total Hardware Interrupts",
+ "interrupts/s",
+ 900,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL);
+
+ rd_intr = rrddim_add(st_intr, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st_intr);
+
+ rrddim_set_by_pointer(st_intr, rd_intr, totalintr);
+ rrdset_done(st_intr);
- rrddim_set(st, "interrupts", totalintr);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ size_t size;
+ static int mib_hw_intrnames[2] = {0, 0};
+ static char *intrnames = NULL;
+
+ size = nintr * (MAXCOMLEN + 1);
+ intrnames = reallocz(intrnames, size);
+ if (unlikely(GETSYSCTL_WSIZE("hw.intrnames", mib_hw_intrnames, intrnames, size))) {
+ error("DISABLED: system.intr chart");
+ error("DISABLED: system.interrupts chart");
+ error("DISABLED: hw.intrcnt module");
+ return 1;
+ } else {
- size = nintr * (MAXCOMLEN +1);
- intrnames = reallocz(intrnames, size);
- if (unlikely(getsysctl("hw.intrnames", intrnames, size))) {
- do_interrupts = 0;
- error("DISABLED: system.intr");
- } else {
- st = rrdset_find_bytype("system", "interrupts");
- if (unlikely(!st))
- st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s",
- 1000, update_every, RRDSET_TYPE_STACKED);
- else
- rrdset_next(st);
+ // --------------------------------------------------------------------
- for (i = 0; i < nintr; i++) {
- p = intrnames + i * (MAXCOMLEN + 1);
- if (unlikely((intrcnt[i] != 0) && (*(char*)p != 0))) {
- rd = rrddim_find(st, p);
- if (unlikely(!rd))
- rd = rrddim_add(st, p, NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_set_by_pointer(st, rd, intrcnt[i]);
- }
+ static RRDSET *st_interrupts = NULL;
+ RRDDIM *rd_interrupts = NULL;
+ void *p;
+
+ if (unlikely(!st_interrupts))
+ st_interrupts = rrdset_create_localhost("system",
+ "interrupts",
+ NULL,
+ "interrupts",
+ NULL,
+ "System interrupts",
+ "interrupts/s",
+ 1000,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+ else
+ rrdset_next(st_interrupts);
+
+ for (i = 0; i < nintr; i++) {
+ p = intrnames + i * (MAXCOMLEN + 1);
+ if (unlikely((intrcnt[i] != 0) && (*(char *) p != 0))) {
+ rd_interrupts = rrddim_find(st_interrupts, p);
+ if (unlikely(!rd_interrupts))
+ rd_interrupts = rrddim_add(st_interrupts, p, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_set_by_pointer(st_interrupts, rd_interrupts, intrcnt[i]);
}
- rrdset_done(st);
}
+ rrdset_done(st_interrupts);
}
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
- if (likely(do_dev_intr)) {
- if (unlikely(GETSYSCTL("vm.stats.sys.v_intr", u_int_data))) {
- do_dev_intr = 0;
- error("DISABLED: system.dev_intr");
- } else {
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_intr
- st = rrdset_find_bytype("system", "dev_intr");
- if (unlikely(!st)) {
- st = rrdset_create("system", "dev_intr", NULL, "interrupts", NULL, "Device Interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_LINE);
+int do_vm_stats_sys_v_intr(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int int_number;
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_intr", mib, int_number))) {
+ error("DISABLED: system.dev_intr chart");
+ error("DISABLED: vm.stats.sys.v_intr module");
+ return 1;
+ } else {
- rrddim_set(st, "interrupts", u_int_data);
- rrdset_done(st);
- }
- }
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- if (likely(do_soft_intr)) {
- if (unlikely(GETSYSCTL("vm.stats.sys.v_soft", u_int_data))) {
- do_soft_intr = 0;
- error("DISABLED: system.dev_intr");
- } else {
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "dev_intr",
+ NULL,
+ "interrupts",
+ NULL,
+ "Device Interrupts",
+ "interrupts/s",
+ 1000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- st = rrdset_find_bytype("system", "soft_intr");
- if (unlikely(!st)) {
- st = rrdset_create("system", "soft_intr", NULL, "interrupts", NULL, "Software Interrupts", "interrupts/s", 1100, update_every, RRDSET_TYPE_LINE);
+ rrddim_set_by_pointer(st, rd, int_number);
+ rrdset_done(st);
+ }
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ return 0;
+}
- rrddim_set(st, "interrupts", u_int_data);
- rrdset_done(st);
- }
- }
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_soft
- // --------------------------------------------------------------------
+int do_vm_stats_sys_v_soft(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int soft_intr_number;
- if (likely(do_context)) {
- if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", u_int_data))) {
- do_context = 0;
- error("DISABLED: system.ctxt");
- } else {
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_soft", mib, soft_intr_number))) {
+ error("DISABLED: system.dev_intr chart");
+ error("DISABLED: vm.stats.sys.v_soft module");
+ return 1;
+ } else {
- st = rrdset_find_bytype("system", "ctxt");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+ // --------------------------------------------------------------------
- rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- rrddim_set(st, "switches", u_int_data);
- rrdset_done(st);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "soft_intr",
+ NULL,
+ "interrupts",
+ NULL,
+ "Software Interrupts",
+ "interrupts/s",
+ 1100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd, soft_intr_number);
+ rrdset_done(st);
}
- // --------------------------------------------------------------------
+ return 0;
+}
- if (likely(do_forks)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", u_int_data))) {
- do_forks = 0;
- error("DISABLED: system.forks");
- } else {
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_swtch
- st = rrdset_find_bytype("system", "forks");
- if (unlikely(!st)) {
- st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+int do_vm_stats_sys_v_swtch(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int ctxt_number;
- rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_swtch", mib, ctxt_number))) {
+ error("DISABLED: system.ctxt chart");
+ error("DISABLED: vm.stats.sys.v_swtch module");
+ return 1;
+ } else {
- rrddim_set(st, "started", u_int_data);
- rrdset_done(st);
- }
- }
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- if (likely(do_disk_io)) {
- if (unlikely(GETSYSCTL("kern.devstat.numdevs", numdevs))) {
- do_disk_io = 0;
- error("DISABLED: disk.io");
- } else {
- devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
- if (unlikely(getsysctl("kern.devstat.all", devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs))) {
- do_disk_io = 0;
- error("DISABLED: disk.io");
- } else {
- dstat = devstat_data + sizeof(long); // skip generation number
- collected_number total_disk_kbytes_read = 0;
- collected_number total_disk_kbytes_write = 0;
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ctxt",
+ NULL,
+ "processes",
+ NULL,
+ "CPU Context Switches",
+ "context switches/s",
+ 800,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- for (i = 0; i < numdevs; i++) {
- if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
- sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
+ rrddim_set_by_pointer(st, rd, ctxt_number);
+ rrdset_done(st);
+ }
- // --------------------------------------------------------------------
+ return 0;
+}
- st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
- if (unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_DISK, disk, NULL, disk, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_forks
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+int do_vm_stats_sys_v_forks(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ u_int forks_number;
- total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ]/KILO_FACTOR;
- total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE]/KILO_FACTOR;
- prev_dstat.bytes_read = rrddim_set(st, "reads", dstat[i].bytes[DEVSTAT_READ]);
- prev_dstat.bytes_write = rrddim_set(st, "writes", dstat[i].bytes[DEVSTAT_WRITE]);
- rrdset_done(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_forks", mib, forks_number))) {
+ error("DISABLED: system.forks chart");
+ error("DISABLED: vm.stats.sys.v_swtch module");
+ return 1;
+ } else {
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_ops", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_ops", disk, NULL, disk, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "forks",
+ NULL,
+ "processes",
+ NULL,
+ "Started Processes",
+ "processes/s",
+ 700,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd = rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- prev_dstat.operations_read = rrddim_set(st, "reads", dstat[i].operations[DEVSTAT_READ]);
- prev_dstat.operations_write = rrddim_set(st, "writes", dstat[i].operations[DEVSTAT_WRITE]);
- rrdset_done(st);
+ rrddim_set_by_pointer(st, rd, forks_number);
+ rrdset_done(st);
+ }
- // --------------------------------------------------------------------
+ return 0;
+}
- st = rrdset_find_bytype("disk_qops", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_qops", disk, NULL, disk, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+// --------------------------------------------------------------------------------------------------------------------
+// vm.swap_info
- rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+int do_vm_swap_info(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[3] = {0, 0, 0};
+
+ if (unlikely(getsysctl_mib("vm.swap_info", mib, 2))) {
+ error("DISABLED: system.swap chart");
+ error("DISABLED: vm.swap_info module");
+ return 1;
+ } else {
+ int i;
+ struct xswdev xsw;
+ struct total_xsw {
+ collected_number bytes_used;
+ collected_number bytes_total;
+ } total_xsw = {0, 0};
+
+ for (i = 0; ; i++) {
+ size_t size;
+
+ mib[2] = i;
+ size = sizeof(xsw);
+ if (unlikely(sysctl(mib, 3, &xsw, &size, NULL, 0) == -1 )) {
+ if (unlikely(errno != ENOENT)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
+ error("DISABLED: system.swap chart");
+ error("DISABLED: vm.swap_info module");
+ return 1;
+ } else {
+ if (unlikely(size != sizeof(xsw))) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
+ error("DISABLED: system.swap chart");
+ error("DISABLED: vm.swap_info module");
+ return 1;
+ } else break;
+ }
+ }
+ total_xsw.bytes_used += xsw.xsw_used;
+ total_xsw.bytes_total += xsw.xsw_nblks;
+ }
- rrddim_set(st, "operations", dstat[i].start_count - dstat[i].end_count);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_free = NULL, *rd_used = NULL;
- st = rrdset_find_bytype("disk_util", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_util", disk, NULL, disk, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "swap",
+ NULL,
+ "swap",
+ NULL,
+ "System Swap",
+ "MB",
+ 201,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_free = rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_used = rrddim_add(st, "used", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
- rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ rrddim_set_by_pointer(st, rd_free, total_xsw.bytes_total - total_xsw.bytes_used);
+ rrddim_set_by_pointer(st, rd_used, total_xsw.bytes_used);
+ rrdset_done(st);
+ }
- cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
- prev_dstat.busy_time_ms = rrddim_set(st, "utilization", cur_dstat.busy_time_ms);
- rrdset_done(st);
+ return 0;
+}
- // --------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
+// system.ram
- st = rrdset_find_bytype("disk_iotime", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_iotime", disk, NULL, disk, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+int do_system_ram(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_active_count[4] = {0, 0, 0, 0}, mib_inactive_count[4] = {0, 0, 0, 0}, mib_wire_count[4] = {0, 0, 0, 0},
+ mib_cache_count[4] = {0, 0, 0, 0}, mib_vfs_bufspace[2] = {0, 0}, mib_free_count[4] = {0, 0, 0, 0};
+ struct vmmeter vmmeter_data;
+ int vfs_bufspace_count;
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_active_count", mib_active_count, vmmeter_data.v_active_count) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_inactive_count", mib_inactive_count, vmmeter_data.v_inactive_count) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_wire_count", mib_wire_count, vmmeter_data.v_wire_count) ||
+#if __FreeBSD_version < 1200016
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_cache_count", mib_cache_count, vmmeter_data.v_cache_count) ||
+#endif
+ GETSYSCTL_SIMPLE("vfs.bufspace", mib_vfs_bufspace, vfs_bufspace_count) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_free_count", mib_free_count, vmmeter_data.v_free_count))) {
+ error("DISABLED: system.ram chart");
+ error("DISABLED: System.ram module");
+ return 1;
+ } else {
- cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
- cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
- prev_dstat.duration_read_ms = rrddim_set(st, "reads", cur_dstat.duration_read_ms);
- prev_dstat.duration_write_ms = rrddim_set(st, "writes", cur_dstat.duration_write_ms);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- // calculate differential charts
- // only if this is not the first time we run
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL,
+ *rd_wired = NULL, *rd_cache = NULL, *rd_buffers = NULL;
- if (likely(dt)) {
+ st = rrdset_find_localhost("system.ram");
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ram",
+ NULL,
+ "ram",
+ NULL,
+ "System RAM",
+ "MB",
+ 200,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ rd_free = rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_active = rrddim_add(st, "active", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_inactive = rrddim_add(st, "inactive", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rd_wired = rrddim_add(st, "wired", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+#if __FreeBSD_version < 1200016
+ rd_cache = rrddim_add(st, "cache", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+#endif
+ rd_buffers = rrddim_add(st, "buffers", NULL, 1, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st, rd_free, vmmeter_data.v_free_count);
+ rrddim_set_by_pointer(st, rd_active, vmmeter_data.v_active_count);
+ rrddim_set_by_pointer(st, rd_inactive, vmmeter_data.v_inactive_count);
+ rrddim_set_by_pointer(st, rd_wired, vmmeter_data.v_wire_count);
+#if __FreeBSD_version < 1200016
+ rrddim_set_by_pointer(st, rd_cache, vmmeter_data.v_cache_count);
+#endif
+ rrddim_set_by_pointer(st, rd_buffers, vfs_bufspace_count);
+ rrdset_done(st);
+ }
- st = rrdset_find_bytype("disk_await", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_await", disk, NULL, disk, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ return 0;
+}
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_swappgs
- rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
- (cur_dstat.duration_read_ms - prev_dstat.duration_read_ms) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
- rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
- (cur_dstat.duration_write_ms - prev_dstat.duration_write_ms) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
- rrdset_done(st);
+int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_swappgsin[4] = {0, 0, 0, 0}, mib_swappgsout[4] = {0, 0, 0, 0};
+ struct vmmeter vmmeter_data;
- // --------------------------------------------------------------------
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsin", mib_swappgsin, vmmeter_data.v_swappgsin) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsout", mib_swappgsout, vmmeter_data.v_swappgsout))) {
+ error("DISABLED: system.swapio chart");
+ error("DISABLED: vm.stats.vm.v_swappgs module");
+ return 1;
+ } else {
- st = rrdset_find_bytype("disk_avgsz", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_avgsz", disk, NULL, disk, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ // --------------------------------------------------------------------
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
- (dstat[i].bytes[DEVSTAT_READ] - prev_dstat.bytes_read) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
- rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
- (dstat[i].bytes[DEVSTAT_WRITE] - prev_dstat.bytes_write) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
- rrdset_done(st);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "swapio",
+ NULL,
+ "swap",
+ NULL,
+ "Swap I/O",
+ "kilobytes/s",
+ 250,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "in", NULL, system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "out", NULL, -system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else rrdset_next(st);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st, rd_in, vmmeter_data.v_swappgsin);
+ rrddim_set_by_pointer(st, rd_out, vmmeter_data.v_swappgsout);
+ rrdset_done(st);
+ }
- st = rrdset_find_bytype("disk_svctm", disk);
- if (unlikely(!st)) {
- st = rrdset_create("disk_svctm", disk, NULL, disk, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ return 0;
+}
- rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_pgfaults
- rrddim_set(st, "svctm", ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) ?
- (cur_dstat.busy_time_ms - prev_dstat.busy_time_ms) / ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) : 0);
- rrdset_done(st);
- }
- }
- }
+int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_vm_faults[4] = {0, 0, 0, 0}, mib_io_faults[4] = {0, 0, 0, 0}, mib_cow_faults[4] = {0, 0, 0, 0},
+ mib_cow_optim[4] = {0, 0, 0, 0}, mib_intrans[4] = {0, 0, 0, 0};
+ struct vmmeter vmmeter_data;
- // --------------------------------------------------------------------
+ if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_vm_faults", mib_vm_faults, vmmeter_data.v_vm_faults) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_io_faults", mib_io_faults, vmmeter_data.v_io_faults) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_faults", mib_cow_faults, vmmeter_data.v_cow_faults) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_optim", mib_cow_optim, vmmeter_data.v_cow_optim) ||
+ GETSYSCTL_SIMPLE("vm.stats.vm.v_intrans", mib_intrans, vmmeter_data.v_intrans))) {
+ error("DISABLED: mem.pgfaults chart");
+ error("DISABLED: vm.stats.vm.v_pgfaults module");
+ return 1;
+ } else {
- st = rrdset_find_bytype("system", "io");
- if (unlikely(!st)) {
- st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "in", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ // --------------------------------------------------------------------
- rrddim_set(st, "in", total_disk_kbytes_read);
- rrddim_set(st, "out", total_disk_kbytes_write);
- rrdset_done(st);
- }
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_memory = NULL, *rd_io_requiring = NULL, *rd_cow = NULL,
+ *rd_cow_optimized = NULL, *rd_in_transit = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("mem",
+ "pgfaults",
+ NULL,
+ "system",
+ NULL,
+ "Memory Page Faults",
+ "page faults/s",
+ 500,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_memory = rrddim_add(st, "memory", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_io_requiring = rrddim_add(st, "io_requiring", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_cow = rrddim_add(st, "cow", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_cow_optimized = rrddim_add(st, "cow_optimized", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_transit = rrddim_add(st, "in_transit", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_memory, vmmeter_data.v_vm_faults);
+ rrddim_set_by_pointer(st, rd_io_requiring, vmmeter_data.v_io_faults);
+ rrddim_set_by_pointer(st, rd_cow, vmmeter_data.v_cow_faults);
+ rrddim_set_by_pointer(st, rd_cow_optimized, vmmeter_data.v_cow_optim);
+ rrddim_set_by_pointer(st, rd_in_transit, vmmeter_data.v_intrans);
+ rrdset_done(st);
}
- // --------------------------------------------------------------------
+ return 0;
+}
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.sem
- if (likely(do_swap)) {
- mibsize = sizeof mib / sizeof mib[0];
- if (unlikely(sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)) {
- error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
- do_swap = 0;
- error("DISABLED: system.swap");
- } else {
- for (i = 0; ; i++) {
- mib[mibsize] = i;
- size = sizeof(xsw);
- if (unlikely(sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1 )) {
- if (unlikely(errno != ENOENT)) {
- error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
- do_swap = 0;
- error("DISABLED: system.swap");
- } else {
- if (unlikely(size != sizeof(xsw))) {
- error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
- do_swap = 0;
- error("DISABLED: system.swap");
- } else break;
- }
- }
- total_xsw.bytes_used += xsw.xsw_used;
- total_xsw.bytes_total += xsw.xsw_nblks;
- }
+int do_kern_ipc_sem(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_semmni[3] = {0, 0, 0}, mib_sema[3] = {0, 0, 0};
+ struct ipc_sem {
+ int semmni;
+ collected_number sets;
+ collected_number semaphores;
+ } ipc_sem = {0, 0, 0};
- if (likely(do_swap)) {
- st = rrdset_find("system.swap");
- if (unlikely(!st)) {
- st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.semmni", mib_semmni, ipc_sem.semmni))) {
+ error("DISABLED: system.ipc_semaphores chart");
+ error("DISABLED: system.ipc_semaphore_arrays chart");
+ error("DISABLED: kern.ipc.sem module");
+ return 1;
+ } else {
+ static struct semid_kernel *ipc_sem_data = NULL;
+
+ ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
+ if (unlikely(GETSYSCTL_WSIZE("kern.ipc.sema", mib_sema, ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
+ error("DISABLED: system.ipc_semaphores chart");
+ error("DISABLED: system.ipc_semaphore_arrays chart");
+ error("DISABLED: kern.ipc.sem module");
+ return 1;
+ } else {
+ int i;
- rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+ for (i = 0; i < ipc_sem.semmni; i++) {
+ if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
+ ipc_sem.sets += 1;
+ ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
}
- else rrdset_next(st);
-
- rrddim_set(st, "used", total_xsw.bytes_used);
- rrddim_set(st, "free", total_xsw.bytes_total - total_xsw.bytes_used);
- rrdset_done(st);
}
- }
- }
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- if (likely(do_ram)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_active_count", vmmeter_data.v_active_count) ||
- GETSYSCTL("vm.stats.vm.v_inactive_count", vmmeter_data.v_inactive_count) ||
- GETSYSCTL("vm.stats.vm.v_wire_count", vmmeter_data.v_wire_count) ||
- GETSYSCTL("vm.stats.vm.v_cache_count", vmmeter_data.v_cache_count) ||
- GETSYSCTL("vfs.bufspace", vfs_bufspace_count) ||
- GETSYSCTL("vm.stats.vm.v_free_count", vmmeter_data.v_free_count))) {
- do_ram = 0;
- error("DISABLED: system.ram");
- } else {
- st = rrdset_find("system.ram");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "active", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "inactive", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "wired", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "cache", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "buffers", NULL, 1, MEGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+ static RRDSET *st_semaphores = NULL, *st_semaphore_arrays = NULL;
+ static RRDDIM *rd_semaphores = NULL, *rd_semaphore_arrays = NULL;
+
+ if (unlikely(!st_semaphores)) {
+ st_semaphores = rrdset_create_localhost("system",
+ "ipc_semaphores",
+ NULL,
+ "ipc semaphores",
+ NULL,
+ "IPC Semaphores",
+ "semaphores",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
-
- rrddim_set(st, "active", vmmeter_data.v_active_count);
- rrddim_set(st, "inactive", vmmeter_data.v_inactive_count);
- rrddim_set(st, "wired", vmmeter_data.v_wire_count);
- rrddim_set(st, "cache", vmmeter_data.v_cache_count);
- rrddim_set(st, "buffers", vfs_bufspace_count);
- rrddim_set(st, "free", vmmeter_data.v_free_count);
- rrdset_done(st);
- }
- }
+ else rrdset_next(st_semaphores);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st_semaphores, rd_semaphores, ipc_sem.semaphores);
+ rrdset_done(st_semaphores);
- if (likely(do_swapio)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_swappgsin", vmmeter_data.v_swappgsin) || GETSYSCTL("vm.stats.vm.v_swappgsout", vmmeter_data.v_swappgsout))) {
- do_swapio = 0;
- error("DISABLED: system.swapio");
- } else {
- st = rrdset_find("system.swapio");
- if (unlikely(!st)) {
- st = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+ // --------------------------------------------------------------------
- rrddim_add(st, "in", NULL, system_pagesize, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRDDIM_INCREMENTAL);
+ if (unlikely(!st_semaphore_arrays)) {
+ st_semaphore_arrays = rrdset_create_localhost("system",
+ "ipc_semaphore_arrays",
+ NULL,
+ "ipc semaphores",
+ NULL,
+ "IPC Semaphore Arrays",
+ "arrays",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_semaphore_arrays = rrddim_add(st_semaphore_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(st_semaphore_arrays);
- rrddim_set(st, "in", vmmeter_data.v_swappgsin);
- rrddim_set(st, "out", vmmeter_data.v_swappgsout);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_semaphore_arrays, rd_semaphore_arrays, ipc_sem.sets);
+ rrdset_done(st_semaphore_arrays);
}
}
- // --------------------------------------------------------------------
-
- if (likely(do_pgfaults)) {
- if (unlikely(GETSYSCTL("vm.stats.vm.v_vm_faults", vmmeter_data.v_vm_faults) ||
- GETSYSCTL("vm.stats.vm.v_io_faults", vmmeter_data.v_io_faults) ||
- GETSYSCTL("vm.stats.vm.v_cow_faults", vmmeter_data.v_cow_faults) ||
- GETSYSCTL("vm.stats.vm.v_cow_optim", vmmeter_data.v_cow_optim) ||
- GETSYSCTL("vm.stats.vm.v_intrans", vmmeter_data.v_intrans))) {
- do_pgfaults = 0;
- error("DISABLED: mem.pgfaults");
- } else {
- st = rrdset_find("mem.pgfaults");
- if (unlikely(!st)) {
- st = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "memory", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "io_requiring", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "cow", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "cow_optimized", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "in_transit", NULL, 1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ return 0;
+}
- rrddim_set(st, "memory", vmmeter_data.v_vm_faults);
- rrddim_set(st, "io_requiring", vmmeter_data.v_io_faults);
- rrddim_set(st, "cow", vmmeter_data.v_cow_faults);
- rrddim_set(st, "cow_optimized", vmmeter_data.v_cow_optim);
- rrddim_set(st, "in_transit", vmmeter_data.v_intrans);
- rrdset_done(st);
- }
- }
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.shm
- // --------------------------------------------------------------------
+int do_kern_ipc_shm(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_shmmni[3] = {0, 0, 0}, mib_shmsegs[3] = {0, 0, 0};
+ struct ipc_shm {
+ u_long shmmni;
+ collected_number segs;
+ collected_number segsize;
+ } ipc_shm = {0, 0, 0};
- if (likely(do_ipc_semaphores)) {
- if (unlikely(GETSYSCTL("kern.ipc.semmni", ipc_sem.semmni))) {
- do_ipc_semaphores = 0;
- error("DISABLED: system.ipc_semaphores");
- error("DISABLED: system.ipc_semaphore_arrays");
+ if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.shmmni", mib_shmmni, ipc_shm.shmmni))) {
+ error("DISABLED: system.ipc_shared_mem_segs chart");
+ error("DISABLED: system.ipc_shared_mem_size chart");
+ error("DISABLED: kern.ipc.shmmodule");
+ return 1;
+ } else {
+ static struct shmid_kernel *ipc_shm_data = NULL;
+
+ ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
+ if (unlikely(
+ GETSYSCTL_WSIZE("kern.ipc.shmsegs", mib_shmsegs, ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
+ error("DISABLED: system.ipc_shared_mem_segs chart");
+ error("DISABLED: system.ipc_shared_mem_size chart");
+ error("DISABLED: kern.ipc.shmmodule");
+ return 1;
} else {
- ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
- if (unlikely(getsysctl("kern.ipc.sema", ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
- do_ipc_semaphores = 0;
- error("DISABLED: system.ipc_semaphores");
- error("DISABLED: system.ipc_semaphore_arrays");
- } else {
- for (i = 0; i < ipc_sem.semmni; i++) {
- if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
- ipc_sem.sets += 1;
- ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
- }
- }
-
- // --------------------------------------------------------------------
+ unsigned long i;
- st = rrdset_find("system.ipc_semaphores");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ for (i = 0; i < ipc_shm.shmmni; i++) {
+ if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
+ ipc_shm.segs += 1;
+ ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
}
- else rrdset_next(st);
+ }
- rrddim_set(st, "semaphores", ipc_sem.semaphores);
- rrdset_done(st);
+ // --------------------------------------------------------------------
- // --------------------------------------------------------------------
+ static RRDSET *st_segs = NULL, *st_size = NULL;
+ static RRDDIM *rd_segments = NULL, *rd_allocated = NULL;
+
+ if (unlikely(!st_segs)) {
+ st_segs = rrdset_create_localhost("system",
+ "ipc_shared_mem_segs",
+ NULL,
+ "ipc shared memory",
+ NULL,
+ "IPC Shared Memory Segments",
+ "segments",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_segments = rrddim_add(st_segs, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_segs);
- st = rrdset_find("system.ipc_semaphore_arrays");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ rrddim_set_by_pointer(st_segs, rd_segments, ipc_shm.segs);
+ rrdset_done(st_segs);
- rrddim_set(st, "arrays", ipc_sem.sets);
- rrdset_done(st);
+ // --------------------------------------------------------------------
+
+ if (unlikely(!st_size)) {
+ st_size = rrdset_create_localhost("system",
+ "ipc_shared_mem_size",
+ NULL,
+ "ipc shared memory",
+ NULL,
+ "IPC Shared Memory Segments Size",
+ "kilobytes",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, KILO_FACTOR, RRD_ALGORITHM_ABSOLUTE);
}
+ else rrdset_next(st_size);
+
+ rrddim_set_by_pointer(st_size, rd_allocated, ipc_shm.segsize);
+ rrdset_done(st_size);
}
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.msq
+
+int do_kern_ipc_msq(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib_msgmni[3] = {0, 0, 0}, mib_msqids[3] = {0, 0, 0};
+ struct ipc_msq {
+ int msgmni;
+ collected_number queues;
+ collected_number messages;
+ collected_number usedsize;
+ collected_number allocsize;
+ } ipc_msq = {0, 0, 0, 0, 0};
- if (likely(do_ipc_shared_mem)) {
- if (unlikely(GETSYSCTL("kern.ipc.shmmni", ipc_shm.shmmni))) {
- do_ipc_shared_mem = 0;
- error("DISABLED: system.ipc_shared_mem_segs");
- error("DISABLED: system.ipc_shared_mem_size");
+ if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.msgmni", mib_msgmni, ipc_msq.msgmni))) {
+ error("DISABLED: system.ipc_msq_queues chart");
+ error("DISABLED: system.ipc_msq_messages chart");
+ error("DISABLED: system.ipc_msq_size chart");
+ error("DISABLED: kern.ipc.msg module");
+ return 1;
+ } else {
+ static struct msqid_kernel *ipc_msq_data = NULL;
+
+ ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
+ if (unlikely(
+ GETSYSCTL_WSIZE("kern.ipc.msqids", mib_msqids, ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
+ error("DISABLED: system.ipc_msq_queues chart");
+ error("DISABLED: system.ipc_msq_messages chart");
+ error("DISABLED: system.ipc_msq_size chart");
+ error("DISABLED: kern.ipc.msg module");
+ return 1;
} else {
- ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
- if (unlikely(getsysctl("kern.ipc.shmsegs", ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
- do_ipc_shared_mem = 0;
- error("DISABLED: system.ipc_shared_mem_segs");
- error("DISABLED: system.ipc_shared_mem_size");
- } else {
- for (i = 0; i < ipc_shm.shmmni; i++) {
- if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
- ipc_shm.segs += 1;
- ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
- }
+ int i;
+
+ for (i = 0; i < ipc_msq.msgmni; i++) {
+ if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
+ ipc_msq.queues += 1;
+ ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
+ ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
+ ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
}
+ }
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find("system.ipc_shared_mem_segs");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_shared_mem_segs", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments", "segments", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "segments", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ static RRDSET *st_queues = NULL, *st_messages = NULL, *st_size = NULL;
+ static RRDDIM *rd_queues = NULL, *rd_messages = NULL, *rd_allocated = NULL, *rd_used = NULL;
+
+ if (unlikely(!st_queues)) {
+ st_queues = rrdset_create_localhost("system",
+ "ipc_msq_queues",
+ NULL,
+ "ipc message queues",
+ NULL,
+ "Number of IPC Message Queues",
+ "queues",
+ 990,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_queues = rrddim_add(st_queues, "queues", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_queues);
- rrddim_set(st, "segments", ipc_shm.segs);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_queues, rd_queues, ipc_msq.queues);
+ rrdset_done(st_queues);
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find("system.ipc_shared_mem_size");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_shared_mem_size", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments Size", "kilobytes", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "allocated", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ if (unlikely(!st_messages)) {
+ st_messages = rrdset_create_localhost("system",
+ "ipc_msq_messages",
+ NULL,
+ "ipc message queues",
+ NULL,
+ "Number of Messages in IPC Message Queues",
+ "messages",
+ 1000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_messages = rrddim_add(st_messages, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st_messages);
- rrddim_set(st, "allocated", ipc_shm.segsize);
- rrdset_done(st);
+ rrddim_set_by_pointer(st_messages, rd_messages, ipc_msq.messages);
+ rrdset_done(st_messages);
+
+ // --------------------------------------------------------------------
+
+ if (unlikely(!st_size)) {
+ st_size = rrdset_create_localhost("system",
+ "ipc_msq_size",
+ NULL,
+ "ipc message queues",
+ NULL,
+ "Size of IPC Message Queues",
+ "bytes",
+ 1100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rd_used = rrddim_add(st_size, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
+ else rrdset_next(st_size);
+
+ rrddim_set_by_pointer(st_size, rd_allocated, ipc_msq.allocsize);
+ rrddim_set_by_pointer(st_size, rd_used, ipc_msq.usedsize);
+ rrdset_done(st_size);
}
}
- // --------------------------------------------------------------------
-
- if (likely(do_ipc_msg_queues)) {
- if (unlikely(GETSYSCTL("kern.ipc.msgmni", ipc_msq.msgmni))) {
- do_ipc_msg_queues = 0;
- error("DISABLED: system.ipc_msq_queues");
- error("DISABLED: system.ipc_msq_messages");
- error("DISABLED: system.ipc_msq_size");
- } else {
- ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
- if (unlikely(getsysctl("kern.ipc.msqids", ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
- do_ipc_msg_queues = 0;
- error("DISABLED: system.ipc_msq_queues");
- error("DISABLED: system.ipc_msq_messages");
- error("DISABLED: system.ipc_msq_size");
- } else {
- for (i = 0; i < ipc_msq.msgmni; i++) {
- if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
- ipc_msq.queues += 1;
- ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
- ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
- ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
- }
- }
+ return 0;
+}
- // --------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
+// uptime
- st = rrdset_find("system.ipc_msq_queues");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_msq_queues", NULL, "ipc message queues", NULL, "Number of IPC Message Queues", "queues", 990, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "queues", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+int do_uptime(int update_every, usec_t dt) {
+ (void)dt;
+ struct timespec up_time;
- rrddim_set(st, "queues", ipc_msq.queues);
- rrdset_done(st);
+ clock_gettime(CLOCK_UPTIME, &up_time);
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
- st = rrdset_find("system.ipc_msq_messages");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_msq_messages", NULL, "ipc message queues", NULL, "Number of Messages in IPC Message Queues", "messages", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "messages", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "uptime",
+ NULL,
+ "uptime",
+ NULL,
+ "System Uptime",
+ "seconds",
+ 1000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+ else rrdset_next(st);
- rrddim_set(st, "messages", ipc_msq.messages);
- rrdset_done(st);
+ rrddim_set_by_pointer(st, rd, up_time.tv_sec);
+ rrdset_done(st);
- // --------------------------------------------------------------------
+ return 0;
+}
- st = rrdset_find("system.ipc_msq_size");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipc_msq_size", NULL, "ipc message queues", NULL, "Size of IPC Message Queues", "bytes", 1100, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "allocated", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- }
- else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.isr
- rrddim_set(st, "allocated", ipc_msq.allocsize);
- rrddim_set(st, "used", ipc_msq.usedsize);
- rrdset_done(st);
+int do_net_isr(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_netisr = -1, do_netisr_per_core = -1;
- }
- }
+ if (unlikely(do_netisr == -1)) {
+ do_netisr = config_get_boolean("plugin:freebsd:net.isr", "netisr", 1);
+ do_netisr_per_core = config_get_boolean("plugin:freebsd:net.isr", "netisr per core", 1);
}
- // --------------------------------------------------------------------
+ static int mib_workstream[3] = {0, 0, 0}, mib_work[3] = {0, 0, 0};
+ int common_error = 0;
+ size_t netisr_workstream_size = sizeof(mib_workstream), netisr_work_size = sizeof(mib_work);
+ unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
+ static struct sysctl_netisr_workstream *netisr_workstream = NULL;
+ static struct sysctl_netisr_work *netisr_work = NULL;
+ static struct netisr_stats {
+ collected_number dispatched;
+ collected_number hybrid_dispatched;
+ collected_number qdrops;
+ collected_number queued;
+ } *netisr_stats = NULL;
if (likely(do_netisr || do_netisr_per_core)) {
- if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
- common_error = 1;
- } else if (unlikely(ncpus > 9999)) {
- error("FREEBSD: There are more than 4 digits in cpu cores number");
- common_error = 1;
- } else if (unlikely(sysctlbyname("net.isr.workstream", NULL, &netisr_workstream_size, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(net.isr.workstream...) failed: %s", strerror(errno));
+ if (unlikely(GETSYSCTL_SIZE("net.isr.workstream", mib_workstream, netisr_workstream_size))) {
common_error = 1;
- } else if (unlikely(sysctlbyname("net.isr.work", NULL, &netisr_work_size, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(net.isr.work...) failed: %s", strerror(errno));
+ } else if (unlikely(GETSYSCTL_SIZE("net.isr.work", mib_work, netisr_work_size))) {
common_error = 1;
} else {
num_netisr_workstreams = netisr_workstream_size / sizeof(struct sysctl_netisr_workstream);
netisr_workstream = reallocz(netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream));
- if (unlikely(getsysctl("net.isr.workstream", netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
+ if (unlikely(GETSYSCTL_WSIZE("net.isr.workstream", mib_workstream, netisr_workstream,
+ num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
common_error = 1;
} else {
num_netisr_works = netisr_work_size / sizeof(struct sysctl_netisr_work);
netisr_work = reallocz(netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work));
- if (unlikely(getsysctl("net.isr.work", netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work)))){
+ if (unlikely(GETSYSCTL_WSIZE("net.isr.work", mib_work, netisr_work,
+ num_netisr_works * sizeof(struct sysctl_netisr_work)))){
common_error = 1;
}
}
}
if (unlikely(common_error)) {
do_netisr = 0;
- error("DISABLED: system.softnet_stat");
+ error("DISABLED: system.softnet_stat chart");
do_netisr_per_core = 0;
- error("DISABLED: system.cpuX_softnet_stat");
+ error("DISABLED: system.cpuX_softnet_stat chart");
common_error = 0;
+ error("DISABLED: net.isr module");
+ return 1;
} else {
- netisr_stats = reallocz(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
- bzero(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
+ unsigned long i, n;
+ int j;
+
+ netisr_stats = reallocz(netisr_stats, (number_of_cpus + 1) * sizeof(struct netisr_stats));
+ memset(netisr_stats, 0, (number_of_cpus + 1) * sizeof(struct netisr_stats));
for (i = 0; i < num_netisr_workstreams; i++) {
for (n = 0; n < num_netisr_works; n++) {
if (netisr_workstream[i].snws_wsid == netisr_work[n].snw_wsid) {
@@ -1121,467 +1314,584 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
}
}
}
- for (i = 0; i < ncpus; i++) {
- netisr_stats[ncpus].dispatched += netisr_stats[i].dispatched;
- netisr_stats[ncpus].hybrid_dispatched += netisr_stats[i].hybrid_dispatched;
- netisr_stats[ncpus].qdrops += netisr_stats[i].qdrops;
- netisr_stats[ncpus].queued += netisr_stats[i].queued;
+ for (j = 0; j < number_of_cpus; j++) {
+ netisr_stats[number_of_cpus].dispatched += netisr_stats[j].dispatched;
+ netisr_stats[number_of_cpus].hybrid_dispatched += netisr_stats[j].hybrid_dispatched;
+ netisr_stats[number_of_cpus].qdrops += netisr_stats[j].qdrops;
+ netisr_stats[number_of_cpus].queued += netisr_stats[j].queued;
}
}
+ } else {
+ error("DISABLED: net.isr module");
+ return 1;
}
// --------------------------------------------------------------------
if (likely(do_netisr)) {
- st = rrdset_find_bytype("system", "softnet_stat");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_dispatched = NULL, *rd_hybrid_dispatched = NULL, *rd_qdrops = NULL, *rd_queued = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat", "events/s", 955, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "qdrops", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "queued", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("system",
+ "softnet_stat",
+ NULL,
+ "softnet_stat",
+ NULL,
+ "System softnet_stat",
+ "events/s",
+ 955,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_dispatched = rrddim_add(st, "dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_hybrid_dispatched = rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_qdrops = rrddim_add(st, "qdrops", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_queued = rrddim_add(st, "queued", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "dispatched", netisr_stats[ncpus].dispatched);
- rrddim_set(st, "hybrid_dispatched", netisr_stats[ncpus].hybrid_dispatched);
- rrddim_set(st, "qdrops", netisr_stats[ncpus].qdrops);
- rrddim_set(st, "queued", netisr_stats[ncpus].queued);
+ rrddim_set_by_pointer(st, rd_dispatched, netisr_stats[number_of_cpus].dispatched);
+ rrddim_set_by_pointer(st, rd_hybrid_dispatched, netisr_stats[number_of_cpus].hybrid_dispatched);
+ rrddim_set_by_pointer(st, rd_qdrops, netisr_stats[number_of_cpus].qdrops);
+ rrddim_set_by_pointer(st, rd_queued, netisr_stats[number_of_cpus].queued);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_netisr_per_core)) {
- for (i = 0; i < ncpus ;i++) {
- snprintfz(netstat_cpuid, 21, "cpu%d_softnet_stat", i);
+ static struct softnet_chart {
+ char netisr_cpuid[MAX_INT_DIGITS + 17];
+ RRDSET *st;
+ RRDDIM *rd_dispatched;
+ RRDDIM *rd_hybrid_dispatched;
+ RRDDIM *rd_qdrops;
+ RRDDIM *rd_queued;
+ } *all_softnet_charts = NULL;
+ static int old_number_of_cpus = 0;
+ int i;
+
+ if(unlikely(number_of_cpus > old_number_of_cpus)) {
+ all_softnet_charts = reallocz(all_softnet_charts, sizeof(struct softnet_chart) * number_of_cpus);
+ memset(&all_softnet_charts[old_number_of_cpus], 0, sizeof(struct softnet_chart) * (number_of_cpus - old_number_of_cpus));
+ old_number_of_cpus = number_of_cpus;
+ }
- st = rrdset_find_bytype("cpu", netstat_cpuid);
- if (unlikely(!st)) {
- st = rrdset_create("cpu", netstat_cpuid, NULL, "softnet_stat", NULL, "Per CPU netisr statistics", "events/s", 1101 + i, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "qdrops", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "queued", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ for (i = 0; i < number_of_cpus ;i++) {
+ snprintfz(all_softnet_charts[i].netisr_cpuid, MAX_INT_DIGITS + 17, "cpu%d_softnet_stat", i);
+
+ if (unlikely(!all_softnet_charts[i].st)) {
+ all_softnet_charts[i].st = rrdset_create_localhost("cpu",
+ all_softnet_charts[i].netisr_cpuid,
+ NULL,
+ "softnet_stat",
+ NULL,
+ "Per CPU netisr statistics",
+ "events/s",
+ 1101 + i,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ all_softnet_charts[i].rd_dispatched = rrddim_add(all_softnet_charts[i].st, "dispatched",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ all_softnet_charts[i].rd_hybrid_dispatched = rrddim_add(all_softnet_charts[i].st, "hybrid_dispatched",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ all_softnet_charts[i].rd_qdrops = rrddim_add(all_softnet_charts[i].st, "qdrops",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ all_softnet_charts[i].rd_queued = rrddim_add(all_softnet_charts[i].st, "queued",
+ NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
-
- rrddim_set(st, "dispatched", netisr_stats[i].dispatched);
- rrddim_set(st, "hybrid_dispatched", netisr_stats[i].hybrid_dispatched);
- rrddim_set(st, "qdrops", netisr_stats[i].qdrops);
- rrddim_set(st, "queued", netisr_stats[i].queued);
- rrdset_done(st);
+ else rrdset_next(all_softnet_charts[i].st);
+
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_dispatched,
+ netisr_stats[i].dispatched);
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_hybrid_dispatched,
+ netisr_stats[i].hybrid_dispatched);
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_qdrops,
+ netisr_stats[i].qdrops);
+ rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_queued,
+ netisr_stats[i].queued);
+ rrdset_done(all_softnet_charts[i].st);
}
}
- // --------------------------------------------------------------------
-
- if (likely(do_bandwidth)) {
- if (unlikely(getifaddrs(&ifap))) {
- error("FREEBSD: getifaddrs()");
- do_bandwidth = 0;
- error("DISABLED: system.ipv4");
- } else {
- iftot.ift_ibytes = iftot.ift_obytes = 0;
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family != AF_INET)
- continue;
- iftot.ift_ibytes += IFA_DATA(ibytes);
- iftot.ift_obytes += IFA_DATA(obytes);
- }
-
- st = rrdset_find("system.ipv4");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "InOctets", iftot.ift_ibytes);
- rrddim_set(st, "OutOctets", iftot.ift_obytes);
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- iftot.ift_ibytes = iftot.ift_obytes = 0;
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- iftot.ift_ibytes += IFA_DATA(ibytes);
- iftot.ift_obytes += IFA_DATA(obytes);
- }
-
- st = rrdset_find("system.ipv6");
- if (unlikely(!st)) {
- st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "sent", iftot.ift_obytes);
- rrddim_set(st, "received", iftot.ift_ibytes);
- rrdset_done(st);
-
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family != AF_LINK)
- continue;
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "received", IFA_DATA(ibytes));
- rrddim_set(st, "sent", IFA_DATA(obytes));
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net_packets", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "received", IFA_DATA(ipackets));
- rrddim_set(st, "sent", IFA_DATA(opackets));
- rrddim_set(st, "multicast_received", IFA_DATA(imcasts));
- rrddim_set(st, "multicast_sent", IFA_DATA(omcasts));
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net_errors", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
-
- rrddim_set(st, "inbound", IFA_DATA(ierrors));
- rrddim_set(st, "outbound", IFA_DATA(oerrors));
- rrdset_done(st);
-
- // --------------------------------------------------------------------
-
- st = rrdset_find_bytype("net_drops", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-#if __FreeBSD__ >= 11
- rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
-#endif
- }
- else rrdset_next(st);
+ return 0;
+}
- rrddim_set(st, "inbound", IFA_DATA(iqdrops));
-#if __FreeBSD__ >= 11
- rrddim_set(st, "outbound", IFA_DATA(oqdrops));
-#endif
- rrdset_done(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.tcp.states
- // --------------------------------------------------------------------
+int do_net_inet_tcp_states(int update_every, usec_t dt) {
+ (void)dt;
+ static int mib[4] = {0, 0, 0, 0};
+ uint64_t tcps_states[TCP_NSTATES];
- st = rrdset_find_bytype("net_events", ifa->ifa_name);
- if (unlikely(!st)) {
- st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.states", mib, tcps_states))) {
+ error("DISABLED: ipv4.tcpsock chart");
+ error("DISABLED: net.inet.tcp.states module");
+ return 1;
+ } else {
- rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+ // --------------------------------------------------------------------
- rrddim_set(st, "collisions", IFA_DATA(collisions));
- rrdset_done(st);
- }
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
- freeifaddrs(ifap);
- }
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpsock",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Connections",
+ "active connections",
+ 2500,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd, tcps_states[TCPS_ESTABLISHED]);
+ rrdset_done(st);
}
- // --------------------------------------------------------------------
-
- // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
- if (likely(do_tcp_sockets)) {
- if (unlikely(GETSYSCTL("net.inet.tcp.states", tcps_states))) {
- do_tcp_sockets = 0;
- error("DISABLED: ipv4.tcpsock");
- } else {
- if (likely(do_tcp_sockets)) {
- st = rrdset_find("ipv4.tcpsock");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections",
- "active connections", 2500, update_every, RRDSET_TYPE_LINE);
+ return 0;
+}
- rrddim_add(st, "CurrEstab", "connections", 1, 1, RRDDIM_ABSOLUTE);
- } else
- rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.tcp.stats
- rrddim_set(st, "CurrEstab", tcps_states[TCPS_ESTABLISHED]);
- rrdset_done(st);
- }
- }
+int do_net_inet_tcp_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcpext_connaborts = -1, do_tcpext_ofo = -1, do_tcpext_syncookies = -1, do_ecn = -1;
+
+ if (unlikely(do_tcp_packets == -1)) {
+ do_tcp_packets = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP packets", 1);
+ do_tcp_errors = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP errors", 1);
+ do_tcp_handshake = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP handshake issues", 1);
+ do_tcpext_connaborts = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP connection aborts",
+ CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP out-of-order queue",
+ CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syncookies = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP SYN cookies",
+ CONFIG_BOOLEAN_AUTO);
+ do_ecn = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "ECN packets",
+ CONFIG_BOOLEAN_AUTO);
}
- // --------------------------------------------------------------------
-
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
- if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
- if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
+ if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syncookies || do_ecn)) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct tcpstat tcpstat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.stats", mib, tcpstat))) {
do_tcp_packets = 0;
- error("DISABLED: ipv4.tcppackets");
+ error("DISABLED: ipv4.tcppackets chart");
do_tcp_errors = 0;
- error("DISABLED: ipv4.tcperrors");
+ error("DISABLED: ipv4.tcperrors chart");
do_tcp_handshake = 0;
- error("DISABLED: ipv4.tcphandshake");
+ error("DISABLED: ipv4.tcphandshake chart");
do_tcpext_connaborts = 0;
- error("DISABLED: ipv4.tcpconnaborts");
+ error("DISABLED: ipv4.tcpconnaborts chart");
do_tcpext_ofo = 0;
- error("DISABLED: ipv4.tcpofo");
- do_tcpext_syscookies = 0;
- error("DISABLED: ipv4.tcpsyncookies");
+ error("DISABLED: ipv4.tcpofo chart");
+ do_tcpext_syncookies = 0;
+ error("DISABLED: ipv4.tcpsyncookies chart");
do_ecn = 0;
- error("DISABLED: ipv4.ecnpkts");
+ error("DISABLED: ipv4.ecnpkts chart");
+ error("DISABLED: net.inet.tcp.stats module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_tcp_packets)) {
- st = rrdset_find("ipv4.tcppackets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
- "packets/s",
- 2600, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_segs = NULL, *rd_out_segs = NULL;
- rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcppackets",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Packets",
+ "packets/s",
+ 2600,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_segs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_segs = rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InSegs", tcpstat.tcps_rcvtotal);
- rrddim_set(st, "OutSegs", tcpstat.tcps_sndtotal);
+ rrddim_set_by_pointer(st, rd_in_segs, tcpstat.tcps_rcvtotal);
+ rrddim_set_by_pointer(st, rd_out_segs, tcpstat.tcps_sndtotal);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_tcp_errors)) {
- st = rrdset_find("ipv4.tcperrors");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_errs = NULL, *rd_in_csum_errs = NULL, *rd_retrans_segs = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
- "packets/s",
- 2700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "tcperrors",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Errors",
+ "packets/s",
+ 2700,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_errs = rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum_errs = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_retrans_segs = rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
#if __FreeBSD__ >= 11
- rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull + tcpstat.tcps_rcvshort);
+ rrddim_set_by_pointer(st, rd_in_errs, tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull +
+ tcpstat.tcps_rcvshort);
#else
- rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
+ rrddim_set_by_pointer(st, rd_in_errs, tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
#endif
- rrddim_set(st, "InCsumErrors", tcpstat.tcps_rcvbadsum);
- rrddim_set(st, "RetransSegs", tcpstat.tcps_sndrexmitpack);
+ rrddim_set_by_pointer(st, rd_in_csum_errs, tcpstat.tcps_rcvbadsum);
+ rrddim_set_by_pointer(st, rd_retrans_segs, tcpstat.tcps_sndrexmitpack);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_tcp_handshake)) {
- st = rrdset_find("ipv4.tcphandshake");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_estab_resets = NULL, *rd_active_opens = NULL, *rd_passive_opens = NULL,
+ *rd_attempt_fails = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
- "IPv4 TCP Handshake Issues",
- "events/s", 2900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "tcphandshake",
+ NULL,
+ "tcp",
+ NULL,
+ "IPv4 TCP Handshake Issues",
+ "events/s",
+ 2900,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_estab_resets = rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_active_opens = rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_passive_opens = rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_attempt_fails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "EstabResets", tcpstat.tcps_drops);
- rrddim_set(st, "ActiveOpens", tcpstat.tcps_connattempt);
- rrddim_set(st, "PassiveOpens", tcpstat.tcps_accepts);
- rrddim_set(st, "AttemptFails", tcpstat.tcps_conndrops);
+ rrddim_set_by_pointer(st, rd_estab_resets, tcpstat.tcps_drops);
+ rrddim_set_by_pointer(st, rd_active_opens, tcpstat.tcps_connattempt);
+ rrddim_set_by_pointer(st, rd_passive_opens, tcpstat.tcps_accepts);
+ rrddim_set_by_pointer(st, rd_attempt_fails, tcpstat.tcps_conndrops);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
- do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpconnaborts");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
+ if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
+ do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_on_data = NULL, *rd_on_close = NULL, *rd_on_memory = NULL,
+ *rd_on_timeout = NULL, *rd_on_linger = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpconnaborts",
+ NULL,
+ "tcp",
+ NULL,
+ "TCP Connection Aborts",
+ "connections/s",
+ 3010,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_on_data = rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_close = rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_memory = rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_timeout = rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_on_linger = rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "TCPAbortOnData", tcpstat.tcps_rcvpackafterwin);
- rrddim_set(st, "TCPAbortOnClose", tcpstat.tcps_rcvafterclose);
- rrddim_set(st, "TCPAbortOnMemory", tcpstat.tcps_rcvmemdrop);
- rrddim_set(st, "TCPAbortOnTimeout", tcpstat.tcps_persistdrop);
- rrddim_set(st, "TCPAbortOnLinger", tcpstat.tcps_finwait2_drops);
+ rrddim_set_by_pointer(st, rd_on_data, tcpstat.tcps_rcvpackafterwin);
+ rrddim_set_by_pointer(st, rd_on_close, tcpstat.tcps_rcvafterclose);
+ rrddim_set_by_pointer(st, rd_on_memory, tcpstat.tcps_rcvmemdrop);
+ rrddim_set_by_pointer(st, rd_on_timeout, tcpstat.tcps_persistdrop);
+ rrddim_set_by_pointer(st, rd_on_linger, tcpstat.tcps_finwait2_drops);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
- do_tcpext_ofo = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpofo");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+ if (do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
+ do_tcpext_ofo = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ofo_queue = NULL;
- rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpofo",
+ NULL,
+ "tcp",
+ NULL,
+ "TCP Out-Of-Order Queue",
+ "packets/s",
+ 3050,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_ofo_queue = rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "TCPOFOQueue", tcpstat.tcps_rcvoopack);
+ rrddim_set_by_pointer(st, rd_ofo_queue, tcpstat.tcps_rcvoopack);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
- do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
+ if (do_tcpext_syncookies == CONFIG_BOOLEAN_YES || (do_tcpext_syncookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
+ do_tcpext_syncookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find("ipv4.tcpsyncookies");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_recv = NULL, *rd_send = NULL, *rd_failed = NULL;
- rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "tcpsyncookies",
+ NULL,
+ "tcp",
+ NULL,
+ "TCP SYN Cookies",
+ "packets/s",
+ 3100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_recv = rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_send = rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "SyncookiesRecv", tcpstat.tcps_sc_recvcookie);
- rrddim_set(st, "SyncookiesSent", tcpstat.tcps_sc_sendcookie);
- rrddim_set(st, "SyncookiesFailed", tcpstat.tcps_sc_zonefail);
+ rrddim_set_by_pointer(st, rd_recv, tcpstat.tcps_sc_recvcookie);
+ rrddim_set_by_pointer(st, rd_send, tcpstat.tcps_sc_sendcookie);
+ rrddim_set_by_pointer(st, rd_failed, tcpstat.tcps_sc_zonefail);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_ce || tcpstat.tcps_ecn_ect0 || tcpstat.tcps_ecn_ect1))) {
- do_ecn = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.ecnpkts");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_ce || tcpstat.tcps_ecn_ect0 || tcpstat.tcps_ecn_ect1))) {
+ do_ecn = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ce = NULL, *rd_no_ect = NULL, *rd_ect0 = NULL, *rd_ect1 = NULL;
- rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "ecnpkts",
+ NULL,
+ "ecn",
+ NULL,
+ "IPv4 ECN Statistics",
+ "packets/s",
+ 8700,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ce = rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_no_ect = rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ect0 = rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ect1 = rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
- rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_ce);
- rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 + tcpstat.tcps_ecn_ect1));
- rrddim_set(st, "InECT0Pkts", tcpstat.tcps_ecn_ect0);
- rrddim_set(st, "InECT1Pkts", tcpstat.tcps_ecn_ect1);
+ rrddim_set_by_pointer(st, rd_ce, tcpstat.tcps_ecn_ce);
+ rrddim_set_by_pointer(st, rd_no_ect, tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 +
+ tcpstat.tcps_ecn_ect1));
+ rrddim_set_by_pointer(st, rd_ect0, tcpstat.tcps_ecn_ect0);
+ rrddim_set_by_pointer(st, rd_ect1, tcpstat.tcps_ecn_ect1);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.tcp.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.udp.stats
+
+int do_net_inet_udp_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_udp_packets = -1, do_udp_errors = -1;
+
+ if (unlikely(do_udp_packets == -1)) {
+ do_udp_packets = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP packets", 1);
+ do_udp_errors = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP errors", 1);
+ }
// see http://net-snmp.sourceforge.net/docs/mibs/udp.html
if (likely(do_udp_packets || do_udp_errors)) {
- if (unlikely(GETSYSCTL("net.inet.udp.stats", udpstat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct udpstat udpstat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.udp.stats", mib, udpstat))) {
do_udp_packets = 0;
- error("DISABLED: ipv4.udppackets");
+ error("DISABLED: ipv4.udppackets chart");
do_udp_errors = 0;
- error("DISABLED: ipv4.udperrors");
+ error("DISABLED: ipv4.udperrors chart");
+ error("DISABLED: net.inet.udp.stats module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_udp_packets)) {
- st = rrdset_find("ipv4.udppackets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
- "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "udppackets",
+ NULL,
+ "udp",
+ NULL,
+ "IPv4 UDP Packets",
+ "packets/s",
+ 2601,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InDatagrams", udpstat.udps_ipackets);
- rrddim_set(st, "OutDatagrams", udpstat.udps_opackets);
+ rrddim_set_by_pointer(st, rd_in, udpstat.udps_ipackets);
+ rrddim_set_by_pointer(st, rd_out, udpstat.udps_opackets);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_udp_errors)) {
- st = rrdset_find("ipv4.udperrors");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_errors = NULL, *rd_no_ports = NULL, *rd_recv_buf_errors = NULL,
+ *rd_in_csum_errors = NULL, *rd_ignored_multi = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
- 2701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "udperrors",
+ NULL,
+ "udp",
+ NULL,
+ "IPv4 UDP Errors",
+ "events/s",
+ 2701,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_errors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_no_ports = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_recv_buf_errors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum_errors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ignored_multi = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InErrors", udpstat.udps_hdrops + udpstat.udps_badlen);
- rrddim_set(st, "NoPorts", udpstat.udps_noport);
- rrddim_set(st, "RcvbufErrors", udpstat.udps_fullsock);
- rrddim_set(st, "InCsumErrors", udpstat.udps_badsum + udpstat.udps_nosum);
- rrddim_set(st, "IgnoredMulti", udpstat.udps_filtermcast);
+ rrddim_set_by_pointer(st, rd_in_errors, udpstat.udps_hdrops + udpstat.udps_badlen);
+ rrddim_set_by_pointer(st, rd_no_ports, udpstat.udps_noport);
+ rrddim_set_by_pointer(st, rd_recv_buf_errors, udpstat.udps_fullsock);
+ rrddim_set_by_pointer(st, rd_in_csum_errors, udpstat.udps_badsum + udpstat.udps_nosum);
+ rrddim_set_by_pointer(st, rd_ignored_multi, udpstat.udps_filtermcast);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.udp.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.icmp.stats
+
+int do_net_inet_icmp_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_icmp_packets = -1, do_icmp_errors = -1, do_icmpmsg = -1;
+
+ if (unlikely(do_icmp_packets == -1)) {
+ do_icmp_packets = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP packets", 1);
+ do_icmp_errors = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP errors", 1);
+ do_icmpmsg = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP messages", 1);
+ }
- if (likely(do_icmp_packets || do_icmpmsg)) {
- if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+ if (likely(do_icmp_packets || do_icmp_errors || do_icmpmsg)) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct icmpstat icmpstat;
+ int i;
+ struct icmp_total {
+ u_long msgs_in;
+ u_long msgs_out;
+ } icmp_total = {0, 0};
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.icmp.stats", mib, icmpstat))) {
do_icmp_packets = 0;
- error("DISABLED: ipv4.icmp");
- error("DISABLED: ipv4.icmp_errors");
+ error("DISABLED: ipv4.icmp chart");
+ do_icmp_errors = 0;
+ error("DISABLED: ipv4.icmp_errors chart");
do_icmpmsg = 0;
- error("DISABLED: ipv4.icmpmsg");
+ error("DISABLED: ipv4.icmpmsg chart");
+ error("DISABLED: net.inet.icmp.stats module");
+ return 1;
} else {
for (i = 0; i <= ICMP_MAXTYPE; i++) {
icmp_total.msgs_in += icmpstat.icps_inhist[i];
@@ -1592,39 +1902,54 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp_packets)) {
- st = rrdset_find("ipv4.icmp");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
- 2602,
- update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
- rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "icmp",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv4 ICMP Packets",
+ "packets/s",
+ 2602,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InMsgs", icmp_total.msgs_in);
- rrddim_set(st, "OutMsgs", icmp_total.msgs_out);
+ rrddim_set_by_pointer(st, rd_in, icmp_total.msgs_in);
+ rrddim_set_by_pointer(st, rd_out, icmp_total.msgs_out);
rrdset_done(st);
+ }
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
+
+ if (likely(do_icmp_errors)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_csum = NULL;
- st = rrdset_find("ipv4.icmp_errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
- "packets/s",
- 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
+ "packets/s",
+ 2603, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rd_in = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InErrors", icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort);
- rrddim_set(st, "OutErrors", icmpstat.icps_error);
- rrddim_set(st, "InCsumErrors", icmpstat.icps_checksum);
+ rrddim_set_by_pointer(st, rd_in, icmpstat.icps_badcode + icmpstat.icps_badlen +
+ icmpstat.icps_checksum + icmpstat.icps_tooshort);
+ rrddim_set_by_pointer(st, rd_out, icmpstat.icps_error);
+ rrddim_set_by_pointer(st, rd_in_csum, icmpstat.icps_checksum);
rrdset_done(st);
}
@@ -1632,226 +1957,370 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmpmsg)) {
- st = rrdset_find("ipv4.icmpmsg");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_reps = NULL, *rd_out_reps = NULL, *rd_in = NULL, *rd_out = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
- "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
+ "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchoReps", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rd_in_reps = rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_reps = rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InEchoReps", icmpstat.icps_inhist[ICMP_ECHOREPLY]);
- rrddim_set(st, "OutEchoReps", icmpstat.icps_outhist[ICMP_ECHOREPLY]);
- rrddim_set(st, "InEchos", icmpstat.icps_inhist[ICMP_ECHO]);
- rrddim_set(st, "OutEchos", icmpstat.icps_outhist[ICMP_ECHO]);
+ rrddim_set_by_pointer(st, rd_in_reps, icmpstat.icps_inhist[ICMP_ECHOREPLY]);
+ rrddim_set_by_pointer(st, rd_out_reps, icmpstat.icps_outhist[ICMP_ECHOREPLY]);
+ rrddim_set_by_pointer(st, rd_in, icmpstat.icps_inhist[ICMP_ECHO]);
+ rrddim_set_by_pointer(st, rd_out, icmpstat.icps_outhist[ICMP_ECHO]);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.icmp.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.ip.stats
+
+int do_net_inet_ip_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1;
+
+ if (unlikely(do_ip_packets == -1)) {
+ do_ip_packets = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 packets", 1);
+ do_ip_fragsout = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments sent", 1);
+ do_ip_fragsin = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments assembly", 1);
+ do_ip_errors = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 errors", 1);
+ }
// see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
if (likely(do_ip_packets || do_ip_fragsout || do_ip_fragsin || do_ip_errors)) {
- if (unlikely(GETSYSCTL("net.inet.ip.stats", ipstat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct ipstat ipstat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet.ip.stats", mib, ipstat))) {
do_ip_packets = 0;
- error("DISABLED: ipv4.packets");
+ error("DISABLED: ipv4.packets chart");
do_ip_fragsout = 0;
- error("DISABLED: ipv4.fragsout");
+ error("DISABLED: ipv4.fragsout chart");
do_ip_fragsin = 0;
- error("DISABLED: ipv4.fragsin");
+ error("DISABLED: ipv4.fragsin chart");
do_ip_errors = 0;
- error("DISABLED: ipv4.errors");
+ error("DISABLED: ipv4.errors chart");
+ error("DISABLED: net.inet.ip.stats module");
+ return 1;
} else {
+
+ // --------------------------------------------------------------------
+
if (likely(do_ip_packets)) {
- st = rrdset_find("ipv4.packets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s",
- 3000, update_every, RRDSET_TYPE_LINE);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_receives = NULL, *rd_out_requests = NULL, *rd_forward_datagrams = NULL,
+ *rd_in_delivers = NULL;
- rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "packets",
+ NULL,
+ "packets",
+ NULL,
+ "IPv4 Packets",
+ "packets/s",
+ 3000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_receives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_requests = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_forward_datagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_delivers = rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "OutRequests", ipstat.ips_localout);
- rrddim_set(st, "InReceives", ipstat.ips_total);
- rrddim_set(st, "ForwDatagrams", ipstat.ips_forward);
- rrddim_set(st, "InDelivers", ipstat.ips_delivered);
+ rrddim_set_by_pointer(st, rd_in_receives, ipstat.ips_total);
+ rrddim_set_by_pointer(st, rd_out_requests, ipstat.ips_localout);
+ rrddim_set_by_pointer(st, rd_forward_datagrams, ipstat.ips_forward);
+ rrddim_set_by_pointer(st, rd_in_delivers, ipstat.ips_delivered);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_ip_fragsout)) {
- st = rrdset_find("ipv4.fragsout");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_fails = NULL, *rd_created = NULL;
- rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "fragsout",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv4 Fragments Sent",
+ "packets/s",
+ 3010,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_fails = rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_created = rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "FragOKs", ipstat.ips_fragmented);
- rrddim_set(st, "FragFails", ipstat.ips_cantfrag);
- rrddim_set(st, "FragCreates", ipstat.ips_ofragments);
+ rrddim_set_by_pointer(st, rd_ok, ipstat.ips_fragmented);
+ rrddim_set_by_pointer(st, rd_fails, ipstat.ips_cantfrag);
+ rrddim_set_by_pointer(st, rd_created, ipstat.ips_ofragments);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_ip_fragsin)) {
- st = rrdset_find("ipv4.fragsin");
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsin", NULL, "fragments", NULL,
- "IPv4 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4",
+ "fragsin",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv4 Fragments Reassembly",
+ "packets/s",
+ 3011,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_all = rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "ReasmOKs", ipstat.ips_fragments);
- rrddim_set(st, "ReasmFails", ipstat.ips_fragdropped);
- rrddim_set(st, "ReasmReqds", ipstat.ips_reassembled);
+ rrddim_set_by_pointer(st, rd_ok, ipstat.ips_fragments);
+ rrddim_set_by_pointer(st, rd_failed, ipstat.ips_fragdropped);
+ rrddim_set_by_pointer(st, rd_all, ipstat.ips_reassembled);
rrdset_done(st);
}
// --------------------------------------------------------------------
if (likely(do_ip_errors)) {
- st = rrdset_find("ipv4.errors");
- if (unlikely(!st)) {
- st = rrdset_create("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s",
- 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
+ *rd_in_hdr_errors = NULL, *rd_out_no_routes = NULL,
+ *rd_in_addr_errors = NULL, *rd_in_unknown_protos = NULL;
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv4",
+ "errors",
+ NULL,
+ "errors",
+ NULL,
+ "IPv4 Errors",
+ "packets/s",
+ 3002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_discards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_discards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_hdr_errors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_no_routes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_addr_errors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_unknown_protos = rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InDiscards", ipstat.ips_badsum + ipstat.ips_tooshort + ipstat.ips_toosmall + ipstat.ips_toolong);
- rrddim_set(st, "OutDiscards", ipstat.ips_odropped);
- rrddim_set(st, "InHdrErrors", ipstat.ips_badhlen + ipstat.ips_badlen + ipstat.ips_badoptions + ipstat.ips_badvers);
- rrddim_set(st, "InAddrErrors", ipstat.ips_badaddr);
- rrddim_set(st, "InUnknownProtos", ipstat.ips_noproto);
- rrddim_set(st, "OutNoRoutes", ipstat.ips_noroute);
+ rrddim_set_by_pointer(st, rd_in_discards, ipstat.ips_badsum + ipstat.ips_tooshort +
+ ipstat.ips_toosmall + ipstat.ips_toolong);
+ rrddim_set_by_pointer(st, rd_out_discards, ipstat.ips_odropped);
+ rrddim_set_by_pointer(st, rd_in_hdr_errors, ipstat.ips_badhlen + ipstat.ips_badlen +
+ ipstat.ips_badoptions + ipstat.ips_badvers);
+ rrddim_set_by_pointer(st, rd_out_no_routes, ipstat.ips_noroute);
+ rrddim_set_by_pointer(st, rd_in_addr_errors, ipstat.ips_badaddr);
+ rrddim_set_by_pointer(st, rd_in_unknown_protos, ipstat.ips_noproto);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet.ip.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet6.ip6.stats
+
+int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1;
+
+ if (unlikely(do_ip6_packets == -1)) {
+ do_ip6_packets = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 packets",
+ CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsout = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments sent",
+ CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsin = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments assembly",
+ CONFIG_BOOLEAN_AUTO);
+ do_ip6_errors = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 errors",
+ CONFIG_BOOLEAN_AUTO);
+ }
if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
- if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct ip6stat ip6stat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet6.ip6.stats", mib, ip6stat))) {
do_ip6_packets = 0;
- error("DISABLED: ipv6.packets");
+ error("DISABLED: ipv6.packets chart");
do_ip6_fragsout = 0;
- error("DISABLED: ipv6.fragsout");
+ error("DISABLED: ipv6.fragsout chart");
do_ip6_fragsin = 0;
- error("DISABLED: ipv6.fragsin");
+ error("DISABLED: ipv6.fragsin chart");
do_ip6_errors = 0;
- error("DISABLED: ipv6.errors");
+ error("DISABLED: ipv6.errors chart");
+ error("DISABLED: net.inet6.ip6.stats module");
+ return 1;
} else {
- if (do_ip6_packets == CONFIG_ONDEMAND_YES || (do_ip6_packets == CONFIG_ONDEMAND_ONDEMAND &&
- (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
- ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
- do_ip6_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.packets");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000,
- update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ // --------------------------------------------------------------------
+
+ if (do_ip6_packets == CONFIG_BOOLEAN_YES || (do_ip6_packets == CONFIG_BOOLEAN_AUTO &&
+ (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
+ ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
+ do_ip6_packets = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_forwarded = NULL, *rd_delivers = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "packets",
+ NULL,
+ "packets",
+ NULL,
+ "IPv6 Packets",
+ "packets/s",
+ 3000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_forwarded = rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_delivers = rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "sent", ip6stat.ip6s_localout);
- rrddim_set(st, "received", ip6stat.ip6s_total);
- rrddim_set(st, "forwarded", ip6stat.ip6s_forward);
- rrddim_set(st, "delivers", ip6stat.ip6s_delivered);
+ rrddim_set_by_pointer(st, rd_sent, ip6stat.ip6s_localout);
+ rrddim_set_by_pointer(st, rd_received, ip6stat.ip6s_total);
+ rrddim_set_by_pointer(st, rd_forwarded, ip6stat.ip6s_forward);
+ rrddim_set_by_pointer(st, rd_delivers, ip6stat.ip6s_delivered);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ip6_fragsout == CONFIG_ONDEMAND_YES || (do_ip6_fragsout == CONFIG_ONDEMAND_ONDEMAND &&
- (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
- ip6stat.ip6s_ofragments))) {
- do_ip6_fragsout = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsout");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ if (do_ip6_fragsout == CONFIG_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO &&
+ (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
+ ip6stat.ip6s_ofragments))) {
+ do_ip6_fragsout = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "fragsout",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv6 Fragments Sent",
+ "packets/s",
+ 3010,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_all = rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "ok", ip6stat.ip6s_fragmented);
- rrddim_set(st, "failed", ip6stat.ip6s_cantfrag);
- rrddim_set(st, "all", ip6stat.ip6s_ofragments);
+ rrddim_set_by_pointer(st, rd_ok, ip6stat.ip6s_fragmented);
+ rrddim_set_by_pointer(st, rd_failed, ip6stat.ip6s_cantfrag);
+ rrddim_set_by_pointer(st, rd_all, ip6stat.ip6s_ofragments);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ip6_fragsin == CONFIG_ONDEMAND_YES || (do_ip6_fragsin == CONFIG_ONDEMAND_ONDEMAND &&
- (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
- ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
- do_ip6_fragsin = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsin");
+ if (do_ip6_fragsin == CONFIG_BOOLEAN_YES || (do_ip6_fragsin == CONFIG_BOOLEAN_AUTO &&
+ (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
+ ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
+ do_ip6_fragsin = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_timeout = NULL, *rd_all = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6",
+ "fragsin",
+ NULL,
+ "fragments",
+ NULL,
+ "IPv6 Fragments Reassembly",
+ "packets/s",
+ 3011,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_ok = rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_failed = rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_timeout = rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_all = rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "ok", ip6stat.ip6s_reassembled);
- rrddim_set(st, "failed", ip6stat.ip6s_fragdropped);
- rrddim_set(st, "timeout", ip6stat.ip6s_fragtimeout);
- rrddim_set(st, "all", ip6stat.ip6s_fragments);
+ rrddim_set_by_pointer(st, rd_ok, ip6stat.ip6s_reassembled);
+ rrddim_set_by_pointer(st, rd_failed, ip6stat.ip6s_fragdropped);
+ rrddim_set_by_pointer(st, rd_timeout, ip6stat.ip6s_fragtimeout);
+ rrddim_set_by_pointer(st, rd_all, ip6stat.ip6s_fragments);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_ip6_errors == CONFIG_ONDEMAND_YES || (do_ip6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_ip6_errors == CONFIG_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && (
ip6stat.ip6s_toosmall ||
ip6stat.ip6s_odropped ||
ip6stat.ip6s_badoptions ||
@@ -1861,346 +2330,1634 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
ip6stat.ip6s_tooshort ||
ip6stat.ip6s_cantforward ||
ip6stat.ip6s_noroute))) {
- do_ip6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.errors");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ do_ip6_errors = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
+ *rd_in_hdr_errors = NULL, *rd_in_addr_errors = NULL, *rd_in_truncated_pkts = NULL,
+ *rd_in_no_routes = NULL, *rd_out_no_routes = NULL;
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "errors",
+ NULL,
+ "errors",
+ NULL,
+ "IPv6 Errors",
+ "packets/s",
+ 3002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rd_in_discards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_discards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_hdr_errors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_addr_errors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_truncated_pkts = rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_no_routes = rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_no_routes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InDiscards", ip6stat.ip6s_toosmall);
- rrddim_set(st, "OutDiscards", ip6stat.ip6s_odropped);
-
- rrddim_set(st, "InHdrErrors",
- ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers + ip6stat.ip6s_exthdrtoolong);
- rrddim_set(st, "InAddrErrors", ip6stat.ip6s_sources_none);
- rrddim_set(st, "InTruncatedPkts", ip6stat.ip6s_tooshort);
- rrddim_set(st, "InNoRoutes", ip6stat.ip6s_cantforward);
-
- rrddim_set(st, "OutNoRoutes", ip6stat.ip6s_noroute);
+ rrddim_set_by_pointer(st, rd_in_discards, ip6stat.ip6s_toosmall);
+ rrddim_set_by_pointer(st, rd_out_discards, ip6stat.ip6s_odropped);
+ rrddim_set_by_pointer(st, rd_in_hdr_errors, ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers +
+ ip6stat.ip6s_exthdrtoolong);
+ rrddim_set_by_pointer(st, rd_in_addr_errors, ip6stat.ip6s_sources_none);
+ rrddim_set_by_pointer(st, rd_in_truncated_pkts, ip6stat.ip6s_tooshort);
+ rrddim_set_by_pointer(st, rd_in_no_routes, ip6stat.ip6s_cantforward);
+ rrddim_set_by_pointer(st, rd_out_no_routes, ip6stat.ip6s_noroute);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet6.ip6.stats module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet6.icmp6.stats
+
+int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
+ (void)dt;
+ static int do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
+ do_icmp6_neighbor = -1, do_icmp6_types = -1;
+
+ if (unlikely(do_icmp6 == -1)) {
+ do_icmp6 = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_redir = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp redirects",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_errors = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp errors",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_echos = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp echos",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_router = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp router",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_neighbor = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp neighbor",
+ CONFIG_BOOLEAN_AUTO);
+ do_icmp6_types = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp types",
+ CONFIG_BOOLEAN_AUTO);
+ }
if (likely(do_icmp6 || do_icmp6_redir || do_icmp6_errors || do_icmp6_echos || do_icmp6_router || do_icmp6_neighbor || do_icmp6_types)) {
- if (unlikely(GETSYSCTL("net.inet6.icmp6.stats", icmp6stat))) {
+ static int mib[4] = {0, 0, 0, 0};
+ struct icmp6stat icmp6stat;
+
+ if (unlikely(GETSYSCTL_SIMPLE("net.inet6.icmp6.stats", mib, icmp6stat))) {
do_icmp6 = 0;
- error("DISABLED: ipv6.icmp");
+ error("DISABLED: ipv6.icmp chart");
+ do_icmp6_redir = 0;
+ error("DISABLED: ipv6.icmpredir chart");
+ do_icmp6_errors = 0;
+ error("DISABLED: ipv6.icmperrors chart");
+ do_icmp6_echos = 0;
+ error("DISABLED: ipv6.icmpechos chart");
+ do_icmp6_router = 0;
+ error("DISABLED: ipv6.icmprouter chart");
+ do_icmp6_neighbor = 0;
+ error("DISABLED: ipv6.icmpneighbor chart");
+ do_icmp6_types = 0;
+ error("DISABLED: ipv6.icmptypes chart");
+ error("DISABLED: net.inet6.icmp6.stats module");
+ return 1;
} else {
+ int i;
+ struct icmp6_total {
+ u_long msgs_in;
+ u_long msgs_out;
+ } icmp6_total = {0, 0};
+
for (i = 0; i <= ICMP6_MAXTYPE; i++) {
icmp6_total.msgs_in += icmp6stat.icp6s_inhist[i];
icmp6_total.msgs_out += icmp6stat.icp6s_outhist[i];
}
icmp6_total.msgs_in += icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort;
- if (do_icmp6 == CONFIG_ONDEMAND_YES || (do_icmp6 == CONFIG_ONDEMAND_ONDEMAND && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
- do_icmp6 = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmp");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages",
- "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ // --------------------------------------------------------------------
+
+ if (do_icmp6 == CONFIG_BOOLEAN_YES || (do_icmp6 == CONFIG_BOOLEAN_AUTO && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
+ do_icmp6 = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmp",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Messages",
+ "messages/s",
+ 10000,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "sent", icmp6_total.msgs_in);
- rrddim_set(st, "received", icmp6_total.msgs_out);
+ rrddim_set_by_pointer(st, rd_received, icmp6_total.msgs_out);
+ rrddim_set_by_pointer(st, rd_sent, icmp6_total.msgs_in);
+
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_redir == CONFIG_ONDEMAND_YES || (do_icmp6_redir == CONFIG_ONDEMAND_ONDEMAND && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
- do_icmp6_redir = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpredir");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects",
- "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_redir == CONFIG_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
+ do_icmp6_redir = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmpredir",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Redirects",
+ "redirects/s",
+ 10050,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "sent", icmp6stat.icp6s_inhist[ND_REDIRECT]);
- rrddim_set(st, "received", icmp6stat.icp6s_outhist[ND_REDIRECT]);
+ rrddim_set_by_pointer(st, rd_received, icmp6stat.icp6s_outhist[ND_REDIRECT]);
+ rrddim_set_by_pointer(st, rd_sent, icmp6stat.icp6s_inhist[ND_REDIRECT]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_errors == CONFIG_ONDEMAND_YES || (do_icmp6_errors == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_badcode ||
- icmp6stat.icp6s_badlen ||
- icmp6stat.icp6s_checksum ||
- icmp6stat.icp6s_tooshort ||
- icmp6stat.icp6s_error ||
- icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH] ||
- icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED] ||
- icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB] ||
- icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
- icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
- icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
- do_icmp6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmperrors");
+ if (do_icmp6_errors == CONFIG_BOOLEAN_YES || (do_icmp6_errors == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_badcode ||
+ icmp6stat.icp6s_badlen ||
+ icmp6stat.icp6s_checksum ||
+ icmp6stat.icp6s_tooshort ||
+ icmp6stat.icp6s_error ||
+ icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH] ||
+ icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED] ||
+ icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB] ||
+ icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
+ icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
+ icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
+ do_icmp6_errors = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_errors = NULL, *rd_out_errors = NULL, *rd_in_csum_errors = NULL,
+ *rd_in_dest_unreachs = NULL, *rd_in_pkt_too_bigs = NULL, *rd_in_time_excds = NULL,
+ *rd_in_parm_problems = NULL, *rd_out_dest_unreachs = NULL, *rd_out_time_excds = NULL,
+ *rd_out_parm_problems = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6",
+ "icmperrors",
+ NULL, "icmp",
+ NULL,
+ "IPv6 ICMP Errors",
+ "errors/s",
+ 10100,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_errors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_errors = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_csum_errors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_dest_unreachs = rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_pkt_too_bigs = rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_time_excds = rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_parm_problems = rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_dest_unreachs = rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_time_excds = rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_parm_problems = rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InErrors", icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
- rrddim_set(st, "OutErrors", icmp6stat.icp6s_error);
- rrddim_set(st, "InCsumErrors", icmp6stat.icp6s_checksum);
- rrddim_set(st, "InDestUnreachs", icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
- rrddim_set(st, "InPktTooBigs", icmp6stat.icp6s_badlen);
- rrddim_set(st, "InTimeExcds", icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
- rrddim_set(st, "InParmProblems", icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
- rrddim_set(st, "OutDestUnreachs", icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
- rrddim_set(st, "OutTimeExcds", icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
- rrddim_set(st, "OutParmProblems", icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
+ rrddim_set_by_pointer(st, rd_in_errors, icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen +
+ icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
+ rrddim_set_by_pointer(st, rd_out_errors, icmp6stat.icp6s_error);
+ rrddim_set_by_pointer(st, rd_in_csum_errors, icmp6stat.icp6s_checksum);
+ rrddim_set_by_pointer(st, rd_in_dest_unreachs, icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
+ rrddim_set_by_pointer(st, rd_in_pkt_too_bigs, icmp6stat.icp6s_badlen);
+ rrddim_set_by_pointer(st, rd_in_time_excds, icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
+ rrddim_set_by_pointer(st, rd_in_parm_problems, icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
+ rrddim_set_by_pointer(st, rd_out_dest_unreachs, icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
+ rrddim_set_by_pointer(st, rd_out_time_excds, icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
+ rrddim_set_by_pointer(st, rd_out_parm_problems, icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_echos == CONFIG_ONDEMAND_YES || (do_icmp6_echos == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
- icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
- icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
- icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
- do_icmp6_echos = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpechos");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_echos == CONFIG_BOOLEAN_YES || (do_icmp6_echos == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
+ icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
+ icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
+ icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
+ do_icmp6_echos = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_replies = NULL, *rd_out_replies = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmpechos",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Echo",
+ "messages/s",
+ 10200,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_replies = rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_replies = rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InEchos", icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
- rrddim_set(st, "OutEchos", icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
- rrddim_set(st, "InEchoReplies", icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
- rrddim_set(st, "OutEchoReplies", icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
+ rrddim_set_by_pointer(st, rd_in, icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
+ rrddim_set_by_pointer(st, rd_out, icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
+ rrddim_set_by_pointer(st, rd_in_replies, icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
+ rrddim_set_by_pointer(st, rd_out_replies, icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_router == CONFIG_ONDEMAND_YES || (do_icmp6_router == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
- icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
- icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
- icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
- do_icmp6_router = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmprouter");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_router == CONFIG_BOOLEAN_YES || (do_icmp6_router == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
+ icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
+ icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
+ icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
+ do_icmp6_router = CONFIG_BOOLEAN_YES;
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
+ *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmprouter",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 Router Messages",
+ "messages/s",
+ 10400,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_solicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_solicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_advertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InSolicits", icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
- rrddim_set(st, "OutSolicits", icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
- rrddim_set(st, "InAdvertisements", icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
- rrddim_set(st, "OutAdvertisements", icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
+ rrddim_set_by_pointer(st, rd_in_solicits, icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_out_solicits, icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_in_advertisements, icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
+ rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_neighbor == CONFIG_ONDEMAND_YES || (do_icmp6_neighbor == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
- icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
- icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
- icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
- do_icmp6_neighbor = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpneighbor");
- if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
+ if (do_icmp6_neighbor == CONFIG_BOOLEAN_YES || (do_icmp6_neighbor == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
+ icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
+ icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
+ icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
+ do_icmp6_neighbor = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
+ *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("ipv6",
+ "icmpneighbor",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 Neighbor Messages",
+ "messages/s",
+ 10500,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_solicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_solicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_advertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InSolicits", icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
- rrddim_set(st, "OutSolicits", icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
- rrddim_set(st, "InAdvertisements", icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
- rrddim_set(st, "OutAdvertisements", icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
+ rrddim_set_by_pointer(st, rd_in_solicits, icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_out_solicits, icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
+ rrddim_set_by_pointer(st, rd_in_advertisements, icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
+ rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if (do_icmp6_types == CONFIG_ONDEMAND_YES || (do_icmp6_types == CONFIG_ONDEMAND_ONDEMAND && (
- icmp6stat.icp6s_inhist[1] ||
- icmp6stat.icp6s_inhist[128] ||
- icmp6stat.icp6s_inhist[129] ||
- icmp6stat.icp6s_inhist[136] ||
- icmp6stat.icp6s_outhist[1] ||
- icmp6stat.icp6s_outhist[128] ||
- icmp6stat.icp6s_outhist[129] ||
- icmp6stat.icp6s_outhist[133] ||
- icmp6stat.icp6s_outhist[135] ||
- icmp6stat.icp6s_outhist[136]))) {
- do_icmp6_types = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmptypes");
+ if (do_icmp6_types == CONFIG_BOOLEAN_YES || (do_icmp6_types == CONFIG_BOOLEAN_AUTO && (
+ icmp6stat.icp6s_inhist[1] ||
+ icmp6stat.icp6s_inhist[128] ||
+ icmp6stat.icp6s_inhist[129] ||
+ icmp6stat.icp6s_inhist[136] ||
+ icmp6stat.icp6s_outhist[1] ||
+ icmp6stat.icp6s_outhist[128] ||
+ icmp6stat.icp6s_outhist[129] ||
+ icmp6stat.icp6s_outhist[133] ||
+ icmp6stat.icp6s_outhist[135] ||
+ icmp6stat.icp6s_outhist[136]))) {
+ do_icmp6_types = CONFIG_BOOLEAN_YES;
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in_1 = NULL, *rd_in_128 = NULL, *rd_in_129 = NULL, *rd_in_136 = NULL,
+ *rd_out_1 = NULL, *rd_out_128 = NULL, *rd_out_129 = NULL, *rd_out_133 = NULL,
+ *rd_out_135 = NULL, *rd_out_143 = NULL;
+
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types",
- "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6",
+ "icmptypes",
+ NULL,
+ "icmp",
+ NULL,
+ "IPv6 ICMP Types",
+ "messages/s",
+ 10700,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rd_in_1 = rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_128 = rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_129 = rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_in_136 = rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_1 = rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_128 = rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_129 = rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_133 = rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_135 = rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out_143 = rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
- rrddim_set(st, "InType1", icmp6stat.icp6s_inhist[1]);
- rrddim_set(st, "InType128", icmp6stat.icp6s_inhist[128]);
- rrddim_set(st, "InType129", icmp6stat.icp6s_inhist[129]);
- rrddim_set(st, "InType136", icmp6stat.icp6s_inhist[136]);
- rrddim_set(st, "OutType1", icmp6stat.icp6s_outhist[1]);
- rrddim_set(st, "OutType128", icmp6stat.icp6s_outhist[128]);
- rrddim_set(st, "OutType129", icmp6stat.icp6s_outhist[129]);
- rrddim_set(st, "OutType133", icmp6stat.icp6s_outhist[133]);
- rrddim_set(st, "OutType135", icmp6stat.icp6s_outhist[135]);
- rrddim_set(st, "OutType143", icmp6stat.icp6s_outhist[143]);
+ rrddim_set_by_pointer(st, rd_in_1, icmp6stat.icp6s_inhist[1]);
+ rrddim_set_by_pointer(st, rd_in_128, icmp6stat.icp6s_inhist[128]);
+ rrddim_set_by_pointer(st, rd_in_129, icmp6stat.icp6s_inhist[129]);
+ rrddim_set_by_pointer(st, rd_in_136, icmp6stat.icp6s_inhist[136]);
+ rrddim_set_by_pointer(st, rd_out_1, icmp6stat.icp6s_outhist[1]);
+ rrddim_set_by_pointer(st, rd_out_128, icmp6stat.icp6s_outhist[128]);
+ rrddim_set_by_pointer(st, rd_out_129, icmp6stat.icp6s_outhist[129]);
+ rrddim_set_by_pointer(st, rd_out_133, icmp6stat.icp6s_outhist[133]);
+ rrddim_set_by_pointer(st, rd_out_135, icmp6stat.icp6s_outhist[135]);
+ rrddim_set_by_pointer(st, rd_out_143, icmp6stat.icp6s_outhist[143]);
rrdset_done(st);
}
}
+ } else {
+ error("DISABLED: net.inet6.icmp6.stats module");
+ return 1;
}
- // --------------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// getmntinfo
+
+int do_getmntinfo(int update_every, usec_t dt) {
+ (void)dt;
+
+#define DELAULT_EXLUDED_PATHS "/proc/*"
+// taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
+#define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
+#define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
+
+ static int do_space = -1, do_inodes = -1;
+
+ if (unlikely(do_space == -1)) {
+ do_space = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
+ do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
+ }
if (likely(do_space || do_inodes)) {
+ struct statfs *mntbuf;
+ int mntsize;
+
// there is no mount info in sysctl MIBs
if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
error("FREEBSD: getmntinfo() failed");
do_space = 0;
- error("DISABLED: disk_space.X");
+ error("DISABLED: disk_space.* charts");
do_inodes = 0;
- error("DISABLED: disk_inodes.X");
+ error("DISABLED: disk_inodes.* charts");
+ error("DISABLED: getmntinfo module");
+ return 1;
} else {
+ // Data to be stored in DICTIONARY mount_points.
+ // This DICTIONARY is used to lookup the settings of the mount point on each iteration.
+ struct mount_point_metadata {
+ int do_space;
+ int do_inodes;
+
+ size_t collected; // the number of times this has been collected
+
+ // charts and dimensions
+
+ RRDSET *st_space;
+ RRDDIM *rd_space_used;
+ RRDDIM *rd_space_avail;
+ RRDDIM *rd_space_reserved;
+
+ RRDSET *st_inodes;
+ RRDDIM *rd_inodes_used;
+ RRDDIM *rd_inodes_avail;
+ };
+ static DICTIONARY *mount_points = NULL;
+ static SIMPLE_PATTERN *excluded_mountpoints = NULL;
+ static SIMPLE_PATTERN *excluded_filesystems = NULL;
+ int i;
+
+ if(unlikely(!mount_points)) {
+
+ excluded_mountpoints = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
+ DELAULT_EXLUDED_PATHS),
+ SIMPLE_PATTERN_EXACT
+ );
+
+ excluded_filesystems = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
+ DEFAULT_EXCLUDED_FILESYSTEMS),
+ SIMPLE_PATTERN_EXACT
+ );
+
+ mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+ }
+
for (i = 0; i < mntsize; i++) {
- if (mntbuf[i].f_flags == MNT_RDONLY ||
- mntbuf[i].f_blocks == 0 ||
- // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
- strcmp(mntbuf[i].f_fstypename, "autofs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "procfs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "subfs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "devfs") == 0 ||
- strcmp(mntbuf[i].f_fstypename, "none") == 0)
+
+ char title[4096 + 1];
+ int def_space, def_inodes, iter_space, iter_inodes;
+
+ struct mount_point_metadata *m = dictionary_get(mount_points, mntbuf[i].f_mntonname);
+ if(unlikely(!m)) {
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname);
+
+ def_space = do_space;
+ def_inodes = do_space;
+
+ if(unlikely(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname))) {
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
+ }
+
+ if(unlikely(simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename))) {
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
+ }
+
+ iter_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
+ iter_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
+
+ struct mount_point_metadata mp = {
+ .do_space = iter_space,
+ .do_inodes = iter_inodes,
+
+ .collected = 0,
+
+ .st_space = NULL,
+ .rd_space_avail = NULL,
+ .rd_space_used = NULL,
+ .rd_space_reserved = NULL,
+
+ .st_inodes = NULL,
+ .rd_inodes_avail = NULL,
+ .rd_inodes_used = NULL,
+ };
+
+ m = dictionary_set(mount_points, mntbuf[i].f_mntonname, &mp, sizeof(struct mount_point_metadata));
+ }
+
+ if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
+ continue;
+
+ if(unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected))
continue;
// --------------------------------------------------------------------------
- if (likely(do_space)) {
- st = rrdset_find_bytype("disk_space", mntbuf[i].f_mntonname);
- if (unlikely(!st)) {
- snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023,
- update_every,
- RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
- RRDDIM_ABSOLUTE);
+ int rendered = 0;
+
+ if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_blocks > 2))) {
+ if (unlikely(!m->st_space)) {
+ snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
+ mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+ m->st_space = rrdset_create_localhost("disk_space",
+ mntbuf[i].f_mntonname,
+ NULL,
+ mntbuf[i].f_mntonname,
+ "disk.space",
+ title,
+ "GB",
+ 2023,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL,
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_used = rrddim_add(m->st_space, "used", NULL,
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
} else
- rrdset_next(st);
+ rrdset_next(m->st_space);
- rrddim_set(st, "avail", (collected_number) mntbuf[i].f_bavail);
- rrddim_set(st, "used", (collected_number) (mntbuf[i].f_blocks - mntbuf[i].f_bfree));
- rrddim_set(st, "reserved_for_root", (collected_number) (mntbuf[i].f_bfree - mntbuf[i].f_bavail));
- rrdset_done(st);
+ rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number) mntbuf[i].f_bavail);
+ rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number) (mntbuf[i].f_blocks -
+ mntbuf[i].f_bfree));
+ rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
+ mntbuf[i].f_bavail));
+ rrdset_done(m->st_space);
+
+ rendered++;
}
// --------------------------------------------------------------------------
- if (likely(do_inodes)) {
- st = rrdset_find_bytype("disk_inodes", mntbuf[i].f_mntonname);
- if (unlikely(!st)) {
- snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024,
- update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+ if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_files > 1))) {
+ if (unlikely(!m->st_inodes)) {
+ snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
+ mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+ m->st_inodes = rrdset_create_localhost("disk_inodes",
+ mntbuf[i].f_mntonname,
+ NULL,
+ mntbuf[i].f_mntonname,
+ "disk.inodes",
+ title,
+ "Inodes",
+ 2024,
+ update_every,
+ RRDSET_TYPE_STACKED
+ );
+
+ m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
} else
- rrdset_next(st);
+ rrdset_next(m->st_inodes);
- rrddim_set(st, "avail", (collected_number) mntbuf[i].f_ffree);
- rrddim_set(st, "used", (collected_number) (mntbuf[i].f_files - mntbuf[i].f_ffree));
- rrdset_done(st);
+ rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
+ rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number) (mntbuf[i].f_files -
+ mntbuf[i].f_ffree));
+ rrdset_done(m->st_inodes);
+
+ rendered++;
}
+
+ if(likely(rendered))
+ m->collected++;
}
}
+ } else {
+ error("DISABLED: getmntinfo module");
+ return 1;
}
- // --------------------------------------------------------------------
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// getifaddrs
- if (likely(do_uptime)) {
- if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
- do_uptime = 0;
- error("DISABLED: system.uptime");
+int do_getifaddrs(int update_every, usec_t dt) {
+ (void)dt;
+
+#define DELAULT_EXLUDED_INTERFACES "lo*"
+#define CONFIG_SECTION_GETIFADDRS "plugin:freebsd:getifaddrs"
+
+ static int do_bandwidth_ipv4 = -1, do_bandwidth_ipv6 = -1, do_bandwidth = -1, do_packets = -1,
+ do_errors = -1, do_drops = -1, do_events = -1;
+
+ if (unlikely(do_bandwidth_ipv4 == -1)) {
+ do_bandwidth_ipv4 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv4 interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_bandwidth_ipv6 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv6 interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_bandwidth = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "bandwidth for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_packets = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "packets for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_errors = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "errors for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_drops = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "drops for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ do_events = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "collisions for all interfaces",
+ CONFIG_BOOLEAN_AUTO);
+ }
+
+ if (likely(do_bandwidth_ipv4 || do_bandwidth_ipv6 || do_bandwidth || do_packets || do_errors ||
+ do_drops || do_events)) {
+ struct ifaddrs *ifap;
+
+ if (unlikely(getifaddrs(&ifap))) {
+ error("FREEBSD: getifaddrs() failed");
+ do_bandwidth_ipv4 = 0;
+ error("DISABLED: system.ipv4 chart");
+ do_bandwidth_ipv6 = 0;
+ error("DISABLED: system.ipv6 chart");
+ do_bandwidth = 0;
+ error("DISABLED: net.* charts");
+ do_packets = 0;
+ error("DISABLED: net_packets.* charts");
+ do_errors = 0;
+ error("DISABLED: net_errors.* charts");
+ do_drops = 0;
+ error("DISABLED: net_drops.* charts");
+ do_events = 0;
+ error("DISABLED: net_events.* charts");
+ error("DISABLED: getifaddrs module");
+ return 1;
} else {
- clock_gettime(CLOCK_REALTIME, &cur_time);
- st = rrdset_find("system.uptime");
+ #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+ struct ifaddrs *ifa;
+ struct iftot {
+ u_long ift_ibytes;
+ u_long ift_obytes;
+ } iftot = {0, 0};
- if(unlikely(!st)) {
- st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ // --------------------------------------------------------------------
+
+ if (likely(do_bandwidth_ipv4)) {
+ iftot.ift_ibytes = iftot.ift_obytes = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ iftot.ift_ibytes += IFA_DATA(ibytes);
+ iftot.ift_obytes += IFA_DATA(obytes);
+ }
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ipv4",
+ NULL,
+ "network",
+ NULL,
+ "IPv4 Bandwidth",
+ "kilobits/s",
+ 500,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "InOctets", "received", 8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "OutOctets", "sent", -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes);
+ rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+ rrdset_done(st);
}
- else rrdset_next(st);
- rrddim_set(st, "uptime", cur_time.tv_sec - boot_time.tv_sec);
- rrdset_done(st);
+ // --------------------------------------------------------------------
+
+ if (likely(do_bandwidth_ipv6)) {
+ iftot.ift_ibytes = iftot.ift_obytes = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ iftot.ift_ibytes += IFA_DATA(ibytes);
+ iftot.ift_obytes += IFA_DATA(obytes);
+ }
+
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "ipv6",
+ NULL,
+ "network",
+ NULL,
+ "IPv6 Bandwidth",
+ "kilobits/s",
+ 500,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "received", NULL, 8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "sent", NULL, -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, iftot.ift_ibytes);
+ rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+ rrdset_done(st);
+ }
+
+ // --------------------------------------------------------------------
+
+ // Data to be stored in DICTIONARY interfaces.
+ // This DICTIONARY is used to lookup the settings of the interfaces on each iteration.
+ struct interfaces_metadata {
+ int do_bandwidth;
+ int do_packets;
+ int do_errors;
+ int do_drops;
+ int do_events;
+
+ // charts and dimensions
+
+ RRDSET *st_bandwidth;
+ RRDDIM *rd_bandwidth_in;
+ RRDDIM *rd_bandwidth_out;
+
+ RRDSET *st_packets;
+ RRDDIM *rd_packets_in;
+ RRDDIM *rd_packets_out;
+ RRDDIM *rd_packets_m_in;
+ RRDDIM *rd_packets_m_out;
+
+ RRDSET *st_errors;
+ RRDDIM *rd_errors_in;
+ RRDDIM *rd_errors_out;
+
+ RRDSET *st_drops;
+ RRDDIM *rd_drops_in;
+ RRDDIM *rd_drops_out;
+
+ RRDSET *st_events;
+ RRDDIM *rd_events_coll;
+ };
+ static DICTIONARY *interfaces = NULL;
+ static SIMPLE_PATTERN *excluded_interfaces = NULL;
+
+ if(unlikely(!interfaces)) {
+
+ excluded_interfaces = simple_pattern_create(
+ config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching",
+ DELAULT_EXLUDED_INTERFACES)
+ , SIMPLE_PATTERN_EXACT
+ );
+
+ interfaces = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ int def_bandwidth, def_packets, def_errors, def_drops, def_events,
+ iter_bandwidth, iter_packets, iter_errors, iter_drops, iter_events;
+
+ struct interfaces_metadata *ifm = dictionary_get(interfaces, ifa->ifa_name);
+ if(unlikely(!ifm)) {
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETIFADDRS, ifa->ifa_name);
+
+ def_bandwidth = do_bandwidth;
+ def_packets = do_packets;
+ def_errors = do_errors;
+ def_drops = do_drops;
+ def_events = do_events;
+
+ if(unlikely(simple_pattern_matches(excluded_interfaces, ifa->ifa_name))) {
+ def_bandwidth = CONFIG_BOOLEAN_NO;
+ def_packets = CONFIG_BOOLEAN_NO;
+ def_errors = CONFIG_BOOLEAN_NO;
+ def_drops = CONFIG_BOOLEAN_NO;
+ def_events = CONFIG_BOOLEAN_NO;
+ }
+
+ iter_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", def_bandwidth);
+ iter_packets = config_get_boolean_ondemand(var_name, "packets", def_packets);
+ iter_errors = config_get_boolean_ondemand(var_name, "errors", def_errors);
+ iter_drops = config_get_boolean_ondemand(var_name, "drops", def_drops);
+ iter_events = config_get_boolean_ondemand(var_name, "events", def_events);
+
+ struct interfaces_metadata ifmp = {
+ .do_bandwidth = iter_bandwidth,
+ .do_packets = iter_packets,
+ .do_errors = iter_errors,
+ .do_drops = iter_drops,
+ .do_events = iter_events,
+
+ .st_bandwidth = NULL,
+ .rd_bandwidth_in = NULL,
+ .rd_bandwidth_out = NULL,
+
+ .st_packets = NULL,
+ .rd_packets_in = NULL,
+ .rd_packets_out = NULL,
+ .rd_packets_m_in = NULL,
+ .rd_packets_m_out = NULL,
+
+ .st_errors = NULL,
+ .rd_errors_in = NULL,
+ .rd_errors_out = NULL,
+
+ .st_drops = NULL,
+ .rd_drops_in = NULL,
+ .rd_drops_out = NULL,
+
+ .st_events = NULL,
+ .rd_events_coll = NULL,
+ };
+
+ ifm = dictionary_set(interfaces, ifa->ifa_name, &ifmp, sizeof(struct interfaces_metadata));
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_bandwidth == CONFIG_BOOLEAN_YES || (ifm->do_bandwidth == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(ibytes) || IFA_DATA(obytes)))) {
+ if (unlikely(!ifm->st_bandwidth)) {
+ ifm->st_bandwidth = rrdset_create_localhost("net",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.net",
+ "Bandwidth",
+ "kilobits/s",
+ 7000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ ifm->rd_bandwidth_in = rrddim_add(ifm->st_bandwidth, "received", NULL, 8, KILO_FACTOR,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_bandwidth_out = rrddim_add(ifm->st_bandwidth, "sent", NULL, -8, KILO_FACTOR,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_bandwidth);
+
+ rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_in, IFA_DATA(ibytes));
+ rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_out, IFA_DATA(obytes));
+ rrdset_done(ifm->st_bandwidth);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_packets == CONFIG_BOOLEAN_YES || (ifm->do_packets == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(ipackets) || IFA_DATA(opackets) || IFA_DATA(imcasts) || IFA_DATA(omcasts)))) {
+ if (unlikely(!ifm->st_packets)) {
+ ifm->st_packets = rrdset_create_localhost("net_packets",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.packets",
+ "Packets",
+ "packets/s",
+ 7001,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_packets, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_packets_in = rrddim_add(ifm->st_packets, "received", NULL, 1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_packets_out = rrddim_add(ifm->st_packets, "sent", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_packets_m_in = rrddim_add(ifm->st_packets, "multicast_received", NULL, 1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_packets_m_out = rrddim_add(ifm->st_packets, "multicast_sent", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_packets);
+
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_in, IFA_DATA(ipackets));
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_out, IFA_DATA(opackets));
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_in, IFA_DATA(imcasts));
+ rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_out, IFA_DATA(omcasts));
+ rrdset_done(ifm->st_packets);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_errors == CONFIG_BOOLEAN_YES || (ifm->do_errors == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(ierrors) || IFA_DATA(oerrors)))) {
+ if (unlikely(!ifm->st_errors)) {
+ ifm->st_errors = rrdset_create_localhost("net_errors",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.errors",
+ "Interface Errors",
+ "errors/s",
+ 7002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_errors, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_errors_in = rrddim_add(ifm->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ ifm->rd_errors_out = rrddim_add(ifm->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_errors);
+
+ rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_in, IFA_DATA(ierrors));
+ rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_out, IFA_DATA(oerrors));
+ rrdset_done(ifm->st_errors);
+ }
+ // --------------------------------------------------------------------
+
+ if (ifm->do_drops == CONFIG_BOOLEAN_YES || (ifm->do_drops == CONFIG_BOOLEAN_AUTO &&
+ (IFA_DATA(iqdrops) || IFA_DATA(oqdrops)))) {
+ if (unlikely(!ifm->st_drops)) {
+ ifm->st_drops = rrdset_create_localhost("net_drops",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.drops",
+ "Interface Drops",
+ "drops/s",
+ 7003,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_drops, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_drops_in = rrddim_add(ifm->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+#if __FreeBSD__ >= 11
+ ifm->rd_drops_out = rrddim_add(ifm->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+#endif
+ } else
+ rrdset_next(ifm->st_drops);
+
+ rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_in, IFA_DATA(iqdrops));
+#if __FreeBSD__ >= 11
+ rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_out, IFA_DATA(oqdrops));
+#endif
+ rrdset_done(ifm->st_drops);
+ }
+
+ // --------------------------------------------------------------------
+
+ if (ifm->do_events == CONFIG_BOOLEAN_YES || (ifm->do_events == CONFIG_BOOLEAN_AUTO &&
+ IFA_DATA(collisions))) {
+ if (unlikely(!ifm->st_events)) {
+ ifm->st_events = rrdset_create_localhost("net_events",
+ ifa->ifa_name,
+ NULL,
+ ifa->ifa_name,
+ "net.events",
+ "Network Interface Events",
+ "events/s",
+ 7006,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(ifm->st_events, RRDSET_FLAG_DETAIL);
+
+ ifm->rd_events_coll = rrddim_add(ifm->st_events, "collisions", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(ifm->st_events);
+
+ rrddim_set_by_pointer(ifm->st_events, ifm->rd_events_coll, IFA_DATA(collisions));
+ rrdset_done(ifm->st_events);
+ }
+ }
+
+ freeifaddrs(ifap);
+ }
+ } else {
+ error("DISABLED: getifaddrs module");
+ return 1;
+ }
+
+ return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.devstat
+
+int do_kern_devstat(int update_every, usec_t dt) {
+
+#define DELAULT_EXLUDED_DISKS ""
+#define CONFIG_SECTION_KERN_DEVSTAT "plugin:freebsd:kern.devstat"
+#define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
+
+ static int enable_pass_devices = -1, do_system_io = -1, do_io = -1, do_ops = -1, do_qops = -1, do_util = -1,
+ do_iotime = -1, do_await = -1, do_avagsz = -1, do_svctm = -1;
+
+ if (unlikely(enable_pass_devices == -1)) {
+ enable_pass_devices = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT,
+ "performance metrics for pass devices", CONFIG_BOOLEAN_AUTO);
+
+ do_system_io = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "total bandwidth for all disks",
+ CONFIG_BOOLEAN_YES);
+
+ do_io = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "bandwidth for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_ops = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "operations for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_qops = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "queued operations for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_util = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "utilization percentage for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "i/o time for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_await = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o time for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_avagsz = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o bandwidth for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ do_svctm = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average service time for all disks",
+ CONFIG_BOOLEAN_AUTO);
+ }
+
+ if (likely(do_system_io || do_io || do_ops || do_qops || do_util || do_iotime || do_await || do_avagsz || do_svctm)) {
+ static int mib_numdevs[3] = {0, 0, 0};
+ int numdevs;
+ int common_error = 0;
+
+ if (unlikely(GETSYSCTL_SIMPLE("kern.devstat.numdevs", mib_numdevs, numdevs))) {
+ common_error = 1;
+ } else {
+ static int mib_devstat[3] = {0, 0, 0};
+ static void *devstat_data = NULL;
+
+ devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
+ if (unlikely(GETSYSCTL_WSIZE("kern.devstat.all", mib_devstat, devstat_data,
+ sizeof(long) + sizeof(struct devstat) * numdevs))) {
+ common_error = 1;
+ } else {
+ struct devstat *dstat;
+ int i;
+ collected_number total_disk_kbytes_read = 0;
+ collected_number total_disk_kbytes_write = 0;
+
+ // Data to be stored in DICTIONARY disks.
+ // This DICTIONARY is used to lookup the settings of the disks on each iteration.
+ struct disks_metadata {
+ int do_io;
+ int do_ops;
+ int do_qops;
+ int do_util;
+ int do_iotime;
+ int do_await;
+ int do_avagsz;
+ int do_svctm;
+
+
+ // data for differential charts
+
+ struct prev_dstat {
+ collected_number bytes_read;
+ collected_number bytes_write;
+ collected_number operations_read;
+ collected_number operations_write;
+ collected_number duration_read_ms;
+ collected_number duration_write_ms;
+ collected_number busy_time_ms;
+ } prev_dstat;
+
+ // charts and dimensions
+
+ RRDSET *st_io;
+ RRDDIM *rd_io_in;
+ RRDDIM *rd_io_out;
+
+ RRDSET *st_ops;
+ RRDDIM *rd_ops_in;
+ RRDDIM *rd_ops_out;
+
+ RRDSET *st_qops;
+ RRDDIM *rd_qops;
+
+ RRDSET *st_util;
+ RRDDIM *rd_util;
+
+ RRDSET *st_iotime;
+ RRDDIM *rd_iotime_in;
+ RRDDIM *rd_iotime_out;
+
+ RRDSET *st_await;
+ RRDDIM *rd_await_in;
+ RRDDIM *rd_await_out;
+
+ RRDSET *st_avagsz;
+ RRDDIM *rd_avagsz_in;
+ RRDDIM *rd_avagsz_out;
+
+ RRDSET *st_svctm;
+ RRDDIM *rd_svctm;
+
+ };
+ static DICTIONARY *disks = NULL;
+ static SIMPLE_PATTERN *excluded_disks = NULL;
+
+ if(unlikely(!disks)) {
+
+ excluded_disks = simple_pattern_create(
+ config_get(CONFIG_SECTION_KERN_DEVSTAT, "disable by default disks matching",
+ DELAULT_EXLUDED_DISKS)
+ , SIMPLE_PATTERN_EXACT
+ );
+
+ disks = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+ }
+
+ dstat = devstat_data + sizeof(long); // skip generation number
+
+ for (i = 0; i < numdevs; i++) {
+ if (likely(do_system_io)) {
+ if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+ total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ] / KILO_FACTOR;
+ total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE] / KILO_FACTOR;
+ }
+ }
+
+ if (unlikely(!enable_pass_devices))
+ if ((dstat[i].device_type & DEVSTAT_TYPE_PASS) == DEVSTAT_TYPE_PASS)
+ continue;
+
+ if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+ char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
+ int def_io, def_ops, def_qops, def_util, def_iotime, def_await, def_avagsz, def_svctm,
+ iter_io, iter_ops, iter_qops, iter_util, iter_iotime, iter_await, iter_avagsz, iter_svctm;
+ struct cur_dstat {
+ collected_number duration_read_ms;
+ collected_number duration_write_ms;
+ collected_number busy_time_ms;
+ } cur_dstat;
+
+ sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
+
+ struct disks_metadata *dm = dictionary_get(disks, disk);
+ if(unlikely(!dm)) {
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_KERN_DEVSTAT, disk);
+
+ def_io = do_io;
+ def_ops = do_ops;
+ def_qops = do_qops;
+ def_util = do_util;
+ def_iotime = do_iotime;
+ def_await = do_await;
+ def_avagsz = do_avagsz;
+ def_svctm = do_svctm;
+
+ if(unlikely(simple_pattern_matches(excluded_disks, disk))) {
+ def_io = CONFIG_BOOLEAN_NO;
+ def_ops = CONFIG_BOOLEAN_NO;
+ def_qops = CONFIG_BOOLEAN_NO;
+ def_util = CONFIG_BOOLEAN_NO;
+ def_iotime = CONFIG_BOOLEAN_NO;
+ def_await = CONFIG_BOOLEAN_NO;
+ def_avagsz = CONFIG_BOOLEAN_NO;
+ def_svctm = CONFIG_BOOLEAN_NO;
+ }
+
+ iter_io = config_get_boolean_ondemand(var_name, "bandwidth", def_io);
+ iter_ops = config_get_boolean_ondemand(var_name, "operations", def_ops);
+ iter_qops = config_get_boolean_ondemand(var_name, "queued operations", def_qops);
+ iter_util = config_get_boolean_ondemand(var_name, "utilization percentage", def_util);
+ iter_iotime = config_get_boolean_ondemand(var_name, "i/o time", def_iotime);
+ iter_await = config_get_boolean_ondemand(var_name, "average completed i/o time", def_await);
+ iter_avagsz = config_get_boolean_ondemand(var_name, "average completed i/o bandwidth",
+ def_avagsz);
+ iter_svctm = config_get_boolean_ondemand(var_name, "average service time", def_svctm);
+
+ struct disks_metadata dmp = {
+ .do_io = iter_io,
+ .do_ops = iter_ops,
+ .do_qops = iter_qops,
+ .do_util = iter_util,
+ .do_iotime = iter_iotime,
+ .do_await = iter_await,
+ .do_avagsz = iter_avagsz,
+ .do_svctm = iter_svctm,
+
+ .st_io = NULL,
+ .rd_io_in = NULL,
+ .rd_io_out = NULL,
+
+ .st_ops = NULL,
+ .rd_ops_in = NULL,
+ .rd_ops_out = NULL,
+
+ .st_qops = NULL,
+ .rd_qops = NULL,
+
+ .st_util = NULL,
+ .rd_util = NULL,
+
+ .st_iotime = NULL,
+ .rd_iotime_in = NULL,
+ .rd_iotime_out = NULL,
+
+ .st_await = NULL,
+ .rd_await_in = NULL,
+ .rd_await_out = NULL,
+
+ .st_avagsz = NULL,
+ .rd_avagsz_in = NULL,
+ .rd_avagsz_out = NULL,
+
+ .st_svctm = NULL,
+ .rd_svctm = NULL,
+ };
+
+ // initialise data for differential charts
+
+ dmp.prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
+ dmp.prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
+ dmp.prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
+ dmp.prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
+ dmp.prev_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ dmp.prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ dmp.prev_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000
+ + dstat[i].busy_time.frac * BINTIME_SCALE;
+
+ dm = dictionary_set(disks, disk, &dmp, sizeof(struct disks_metadata));
+ }
+
+ cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
+ + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+ cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_io == CONFIG_BOOLEAN_YES || (dm->do_io == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].bytes[DEVSTAT_READ] || dstat[i].bytes[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_io)) {
+ dm->st_io = rrdset_create_localhost("disk",
+ disk,
+ NULL,
+ disk,
+ "disk.io",
+ "Disk I/O Bandwidth",
+ "kilobytes/s",
+ 2000,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ dm->rd_io_in = rrddim_add(dm->st_io, "reads", NULL, 1, KILO_FACTOR,
+ RRD_ALGORITHM_INCREMENTAL);
+ dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_io);
+
+ rrddim_set_by_pointer(dm->st_io, dm->rd_io_in, dstat[i].bytes[DEVSTAT_READ]);
+ rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]);
+ rrdset_done(dm->st_io);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_ops == CONFIG_BOOLEAN_YES || (dm->do_ops == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_ops)) {
+ dm->st_ops = rrdset_create_localhost("disk_ops",
+ disk,
+ NULL,
+ disk,
+ "disk.ops",
+ "Disk Completed I/O Operations",
+ "operations/s",
+ 2001,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_ops, RRDSET_FLAG_DETAIL);
+
+ dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_ops);
+
+ rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]);
+ rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]);
+ rrdset_done(dm->st_ops);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_qops == CONFIG_BOOLEAN_YES || (dm->do_qops == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].start_count || dstat[i].end_count))) {
+ if (unlikely(!dm->st_qops)) {
+ dm->st_qops = rrdset_create_localhost("disk_qops",
+ disk,
+ NULL,
+ disk,
+ "disk.qops",
+ "Disk Current I/O Operations",
+ "operations",
+ 2002,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_qops, RRDSET_FLAG_DETAIL);
+
+ dm->rd_qops = rrddim_add(dm->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_qops);
+
+ rrddim_set_by_pointer(dm->st_qops, dm->rd_qops, dstat[i].start_count - dstat[i].end_count);
+ rrdset_done(dm->st_qops);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_util == CONFIG_BOOLEAN_YES || (dm->do_util == CONFIG_BOOLEAN_AUTO &&
+ cur_dstat.busy_time_ms)) {
+ if (unlikely(!dm->st_util)) {
+ dm->st_util = rrdset_create_localhost("disk_util",
+ disk,
+ NULL,
+ disk,
+ "disk.util",
+ "Disk Utilization Time",
+ "% of time working",
+ 2004,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(dm->st_util, RRDSET_FLAG_DETAIL);
+
+ dm->rd_util = rrddim_add(dm->st_util, "utilization", NULL, 1, 10,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_util);
+
+ rrddim_set_by_pointer(dm->st_util, dm->rd_util, cur_dstat.busy_time_ms);
+ rrdset_done(dm->st_util);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_iotime == CONFIG_BOOLEAN_YES || (dm->do_iotime == CONFIG_BOOLEAN_AUTO &&
+ (cur_dstat.duration_read_ms || cur_dstat.duration_write_ms))) {
+ if (unlikely(!dm->st_iotime)) {
+ dm->st_iotime = rrdset_create_localhost("disk_iotime",
+ disk,
+ NULL,
+ disk,
+ "disk.iotime",
+ "Disk Total I/O Time",
+ "milliseconds/s",
+ 2022,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_iotime, RRDSET_FLAG_DETAIL);
+
+ dm->rd_iotime_in = rrddim_add(dm->st_iotime, "reads", NULL, 1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1,
+ RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(dm->st_iotime);
+
+ rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in, cur_dstat.duration_read_ms);
+ rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms);
+ rrdset_done(dm->st_iotime);
+ }
+
+ // --------------------------------------------------------------------
+ // calculate differential charts
+ // only if this is not the first time we run
+
+ if (likely(dt)) {
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_await == CONFIG_BOOLEAN_YES || (dm->do_await == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_await)) {
+ dm->st_await = rrdset_create_localhost("disk_await",
+ disk,
+ NULL,
+ disk,
+ "disk.await",
+ "Average Completed I/O Operation Time",
+ "ms per operation",
+ 2005,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_await, RRDSET_FLAG_DETAIL);
+
+ dm->rd_await_in = rrddim_add(dm->st_await, "reads", NULL, 1, 1,
+ RRD_ALGORITHM_ABSOLUTE);
+ dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1,
+ RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_await);
+
+ rrddim_set_by_pointer(dm->st_await, dm->rd_await_in,
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) ?
+ (cur_dstat.duration_read_ms - dm->prev_dstat.duration_read_ms) /
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) :
+ 0);
+ rrddim_set_by_pointer(dm->st_await, dm->rd_await_out,
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) ?
+ (cur_dstat.duration_write_ms - dm->prev_dstat.duration_write_ms) /
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) :
+ 0);
+ rrdset_done(dm->st_await);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_avagsz == CONFIG_BOOLEAN_YES || (dm->do_avagsz == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_avagsz)) {
+ dm->st_avagsz = rrdset_create_localhost("disk_avgsz",
+ disk,
+ NULL,
+ disk,
+ "disk.avgsz",
+ "Average Completed I/O Operation Bandwidth",
+ "kilobytes per operation",
+ 2006,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(dm->st_avagsz, RRDSET_FLAG_DETAIL);
+
+ dm->rd_avagsz_in = rrddim_add(dm->st_avagsz, "reads", NULL, 1, KILO_FACTOR,
+ RRD_ALGORITHM_ABSOLUTE);
+ dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR,
+ RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_avagsz);
+
+ rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_in,
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) ?
+ (dstat[i].bytes[DEVSTAT_READ] - dm->prev_dstat.bytes_read) /
+ (dstat[i].operations[DEVSTAT_READ] -
+ dm->prev_dstat.operations_read) :
+ 0);
+ rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_out,
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) ?
+ (dstat[i].bytes[DEVSTAT_WRITE] - dm->prev_dstat.bytes_write) /
+ (dstat[i].operations[DEVSTAT_WRITE] -
+ dm->prev_dstat.operations_write) :
+ 0);
+ rrdset_done(dm->st_avagsz);
+ }
+
+ // --------------------------------------------------------------------
+
+ if(dm->do_svctm == CONFIG_BOOLEAN_YES || (dm->do_svctm == CONFIG_BOOLEAN_AUTO &&
+ (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+ if (unlikely(!dm->st_svctm)) {
+ dm->st_svctm = rrdset_create_localhost("disk_svctm",
+ disk,
+ NULL,
+ disk,
+ "disk.svctm",
+ "Average Service Time",
+ "ms per operation",
+ 2007,
+ update_every,
+ RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(dm->st_svctm, RRDSET_FLAG_DETAIL);
+
+ dm->rd_svctm = rrddim_add(dm->st_svctm, "svctm", NULL, 1, 1,
+ RRD_ALGORITHM_ABSOLUTE);
+ } else
+ rrdset_next(dm->st_svctm);
+
+ rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm,
+ ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
+ (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) ?
+ (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) /
+ ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
+ (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) :
+ 0);
+ rrdset_done(dm->st_svctm);
+ }
+
+ // --------------------------------------------------------------------
+
+ dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
+ dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
+ dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
+ dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
+ dm->prev_dstat.duration_read_ms = cur_dstat.duration_read_ms;
+ dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms;
+ dm->prev_dstat.busy_time_ms = cur_dstat.busy_time_ms;
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ if (likely(do_system_io)) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost("system",
+ "io",
+ NULL,
+ "disk",
+ NULL,
+ "Disk I/O",
+ "kilobytes/s",
+ 150,
+ update_every,
+ RRDSET_TYPE_AREA
+ );
+
+ rd_in = rrddim_add(st, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_out = rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ } else
+ rrdset_next(st);
+
+ rrddim_set_by_pointer(st, rd_in, total_disk_kbytes_read);
+ rrddim_set_by_pointer(st, rd_out, total_disk_kbytes_write);
+ rrdset_done(st);
+ }
+ }
+ }
+ if (unlikely(common_error)) {
+ do_system_io = 0;
+ error("DISABLED: system.io chart");
+ do_io = 0;
+ error("DISABLED: disk.* charts");
+ do_ops = 0;
+ error("DISABLED: disk_ops.* charts");
+ do_qops = 0;
+ error("DISABLED: disk_qops.* charts");
+ do_util = 0;
+ error("DISABLED: disk_util.* charts");
+ do_iotime = 0;
+ error("DISABLED: disk_iotime.* charts");
+ do_await = 0;
+ error("DISABLED: disk_await.* charts");
+ do_avagsz = 0;
+ error("DISABLED: disk_avgsz.* charts");
+ do_svctm = 0;
+ error("DISABLED: disk_svctm.* charts");
+ error("DISABLED: kern.devstat module");
+ return 1;
}
+ } else {
+ error("DISABLED: kern.devstat module");
+ return 1;
}
return 0;
diff --git a/src/freeipmi_plugin.c b/src/freeipmi_plugin.c
new file mode 100644
index 000000000..4459de7ca
--- /dev/null
+++ b/src/freeipmi_plugin.c
@@ -0,0 +1,1621 @@
+/*
+ * netdata freeipmi.plugin
+ * Copyright (C) 2017 Costa Tsaousis
+ * GPL v3+
+ *
+ * Based on:
+ * ipmimonitoring-sensors.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
+ * ipmimonitoring-sel.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
+ *
+ * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
+ * Copyright (C) 2006-2007 The Regents of the University of California.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * Written by Albert Chu <chu11@llnl.gov>
+ * UCRL-CODE-222073
+ */
+
+#include "common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef HAVE_FREEIPMI
+
+#include <ipmi_monitoring.h>
+#include <ipmi_monitoring_bitmasks.h>
+
+/* Communication Configuration - Initialize accordingly */
+
+/* Hostname, NULL for In-band communication, non-null for a hostname */
+char *hostname = NULL;
+
+/* In-band Communication Configuration */
+int driver_type = -1; // IPMI_MONITORING_DRIVER_TYPE_KCS; /* or -1 for default */
+int disable_auto_probe = 0; /* probe for in-band device */
+unsigned int driver_address = 0; /* not used if probing */
+unsigned int register_spacing = 0; /* not used if probing */
+char *driver_device = NULL; /* not used if probing */
+
+/* Out-of-band Communication Configuration */
+int protocol_version = -1; //IPMI_MONITORING_PROTOCOL_VERSION_1_5; /* or -1 for default */
+char *username = "foousername";
+char *password = "foopassword";
+unsigned char *k_g = NULL;
+unsigned int k_g_len = 0;
+int privilege_level = -1; // IPMI_MONITORING_PRIVILEGE_LEVEL_USER; /* or -1 for default */
+int authentication_type = -1; // IPMI_MONITORING_AUTHENTICATION_TYPE_MD5; /* or -1 for default */
+int cipher_suite_id = 0; /* or -1 for default */
+int session_timeout = 0; /* 0 for default */
+int retransmission_timeout = 0; /* 0 for default */
+
+/* Workarounds - specify workaround flags if necessary */
+unsigned int workaround_flags = 0;
+
+/* Initialize w/ record id numbers to only monitor specific record ids */
+unsigned int record_ids[] = {0};
+unsigned int record_ids_length = 0;
+
+/* Initialize w/ sensor types to only monitor specific sensor types
+ * see ipmi_monitoring.h sensor types list.
+ */
+unsigned int sensor_types[] = {0};
+unsigned int sensor_types_length = 0;
+
+/* Set to an appropriate alternate if desired */
+char *sdr_cache_directory = "/tmp";
+char *sensor_config_file = NULL;
+
+/* Set to 1 or 0 to enable these sensor reading flags
+ * - See ipmi_monitoring.h for descriptions of these flags.
+ */
+int reread_sdr_cache = 0;
+int ignore_non_interpretable_sensors = 1;
+int bridge_sensors = 0;
+int interpret_oem_data = 0;
+int shared_sensors = 0;
+int discrete_reading = 0;
+int ignore_scanning_disabled = 0;
+int assume_bmc_owner = 0;
+int entity_sensor_names = 0;
+
+/* Initialization flags
+ *
+ * Most commonly bitwise OR IPMI_MONITORING_FLAGS_DEBUG and/or
+ * IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS for extra debugging
+ * information.
+ */
+unsigned int ipmimonitoring_init_flags = 0;
+
+int errnum;
+
+// ----------------------------------------------------------------------------
+// SEL only variables
+
+/* Initialize w/ date range to only monitoring specific date range */
+char *date_begin = NULL; /* use MM/DD/YYYY format */
+char *date_end = NULL; /* use MM/DD/YYYY format */
+
+int assume_system_event_record = 0;
+
+char *sel_config_file = NULL;
+
+
+// ----------------------------------------------------------------------------
+// functions common to sensors and SEL
+
+static void
+_init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
+{
+ assert (ipmi_config);
+
+ ipmi_config->driver_type = driver_type;
+ ipmi_config->disable_auto_probe = disable_auto_probe;
+ ipmi_config->driver_address = driver_address;
+ ipmi_config->register_spacing = register_spacing;
+ ipmi_config->driver_device = driver_device;
+
+ ipmi_config->protocol_version = protocol_version;
+ ipmi_config->username = username;
+ ipmi_config->password = password;
+ ipmi_config->k_g = k_g;
+ ipmi_config->k_g_len = k_g_len;
+ ipmi_config->privilege_level = privilege_level;
+ ipmi_config->authentication_type = authentication_type;
+ ipmi_config->cipher_suite_id = cipher_suite_id;
+ ipmi_config->session_timeout_len = session_timeout;
+ ipmi_config->retransmission_timeout_len = retransmission_timeout;
+
+ ipmi_config->workaround_flags = workaround_flags;
+}
+
+#ifdef NETDATA_COMMENTED
+static const char *
+_get_sensor_type_string (int sensor_type)
+{
+ switch (sensor_type)
+ {
+ case IPMI_MONITORING_SENSOR_TYPE_RESERVED:
+ return ("Reserved");
+ case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
+ return ("Temperature");
+ case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
+ return ("Voltage");
+ case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
+ return ("Current");
+ case IPMI_MONITORING_SENSOR_TYPE_FAN:
+ return ("Fan");
+ case IPMI_MONITORING_SENSOR_TYPE_PHYSICAL_SECURITY:
+ return ("Physical Security");
+ case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_SECURITY_VIOLATION_ATTEMPT:
+ return ("Platform Security Violation Attempt");
+ case IPMI_MONITORING_SENSOR_TYPE_PROCESSOR:
+ return ("Processor");
+ case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
+ return ("Power Supply");
+ case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
+ return ("Power Unit");
+ case IPMI_MONITORING_SENSOR_TYPE_COOLING_DEVICE:
+ return ("Cooling Device");
+ case IPMI_MONITORING_SENSOR_TYPE_OTHER_UNITS_BASED_SENSOR:
+ return ("Other Units Based Sensor");
+ case IPMI_MONITORING_SENSOR_TYPE_MEMORY:
+ return ("Memory");
+ case IPMI_MONITORING_SENSOR_TYPE_DRIVE_SLOT:
+ return ("Drive Slot");
+ case IPMI_MONITORING_SENSOR_TYPE_POST_MEMORY_RESIZE:
+ return ("POST Memory Resize");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS:
+ return ("System Firmware Progress");
+ case IPMI_MONITORING_SENSOR_TYPE_EVENT_LOGGING_DISABLED:
+ return ("Event Logging Disabled");
+ case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG1:
+ return ("Watchdog 1");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_EVENT:
+ return ("System Event");
+ case IPMI_MONITORING_SENSOR_TYPE_CRITICAL_INTERRUPT:
+ return ("Critical Interrupt");
+ case IPMI_MONITORING_SENSOR_TYPE_BUTTON_SWITCH:
+ return ("Button/Switch");
+ case IPMI_MONITORING_SENSOR_TYPE_MODULE_BOARD:
+ return ("Module/Board");
+ case IPMI_MONITORING_SENSOR_TYPE_MICROCONTROLLER_COPROCESSOR:
+ return ("Microcontroller/Coprocessor");
+ case IPMI_MONITORING_SENSOR_TYPE_ADD_IN_CARD:
+ return ("Add In Card");
+ case IPMI_MONITORING_SENSOR_TYPE_CHASSIS:
+ return ("Chassis");
+ case IPMI_MONITORING_SENSOR_TYPE_CHIP_SET:
+ return ("Chip Set");
+ case IPMI_MONITORING_SENSOR_TYPE_OTHER_FRU:
+ return ("Other Fru");
+ case IPMI_MONITORING_SENSOR_TYPE_CABLE_INTERCONNECT:
+ return ("Cable/Interconnect");
+ case IPMI_MONITORING_SENSOR_TYPE_TERMINATOR:
+ return ("Terminator");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_BOOT_INITIATED:
+ return ("System Boot Initiated");
+ case IPMI_MONITORING_SENSOR_TYPE_BOOT_ERROR:
+ return ("Boot Error");
+ case IPMI_MONITORING_SENSOR_TYPE_OS_BOOT:
+ return ("OS Boot");
+ case IPMI_MONITORING_SENSOR_TYPE_OS_CRITICAL_STOP:
+ return ("OS Critical Stop");
+ case IPMI_MONITORING_SENSOR_TYPE_SLOT_CONNECTOR:
+ return ("Slot/Connector");
+ case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
+ return ("System ACPI Power State");
+ case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG2:
+ return ("Watchdog 2");
+ case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_ALERT:
+ return ("Platform Alert");
+ case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
+ return ("Entity Presence");
+ case IPMI_MONITORING_SENSOR_TYPE_MONITOR_ASIC_IC:
+ return ("Monitor ASIC/IC");
+ case IPMI_MONITORING_SENSOR_TYPE_LAN:
+ return ("LAN");
+ case IPMI_MONITORING_SENSOR_TYPE_MANAGEMENT_SUBSYSTEM_HEALTH:
+ return ("Management Subsystem Health");
+ case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
+ return ("Battery");
+ case IPMI_MONITORING_SENSOR_TYPE_SESSION_AUDIT:
+ return ("Session Audit");
+ case IPMI_MONITORING_SENSOR_TYPE_VERSION_CHANGE:
+ return ("Version Change");
+ case IPMI_MONITORING_SENSOR_TYPE_FRU_STATE:
+ return ("FRU State");
+ }
+
+ return ("Unrecognized");
+}
+#endif // NETDATA_COMMENTED
+
+
+// ----------------------------------------------------------------------------
+// BEGIN NETDATA CODE
+
+static int debug = 0;
+
+static int netdata_update_every = 5;
+static int netdata_priority = 90000;
+static int netdata_do_sel = 1;
+
+static size_t netdata_sensors_updated = 0;
+static size_t netdata_sensors_collected = 0;
+static size_t netdata_sel_events = 0;
+static size_t netdata_sensors_states_nominal = 0;
+static size_t netdata_sensors_states_warning = 0;
+static size_t netdata_sensors_states_critical = 0;
+
+struct sensor {
+ int record_id;
+ int sensor_number;
+ int sensor_type;
+ int sensor_state;
+ int sensor_units;
+ char *sensor_name;
+
+ int sensor_reading_type;
+ union {
+ uint8_t bool_value;
+ uint32_t uint32_value;
+ double double_value;
+ } sensor_reading;
+
+ int sent;
+ int ignore;
+ int exposed;
+ int updated;
+ struct sensor *next;
+} *sensors_root = NULL;
+
+static void netdata_mark_as_not_updated() {
+ struct sensor *sn;
+ for(sn = sensors_root; sn ;sn = sn->next)
+ sn->updated = sn->sent = 0;
+
+ netdata_sensors_updated = 0;
+ netdata_sensors_collected = 0;
+ netdata_sel_events = 0;
+
+ netdata_sensors_states_nominal = 0;
+ netdata_sensors_states_warning = 0;
+ netdata_sensors_states_critical = 0;
+}
+
+static void send_chart_to_netdata_for_units(int units) {
+ struct sensor *sn;
+
+ switch(units) {
+ case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
+ printf("CHART ipmi.temperatures_c '' 'System Celcius Temperatures read by IPMI' 'Celcius' 'temperatures' 'ipmi.temperatures_c' 'line' %d %d\n"
+ , netdata_priority + 10
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
+ printf("CHART ipmi.temperatures_f '' 'System Fahrenheit Temperatures read by IPMI' 'Fahrenheit' 'temperatures' 'ipmi.temperatures_f' 'line' %d %d\n"
+ , netdata_priority + 11
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
+ printf("CHART ipmi.volts '' 'System Voltages read by IPMI' 'Volts' 'voltages' 'ipmi.voltages' 'line' %d %d\n"
+ , netdata_priority + 12
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_AMPS:
+ printf("CHART ipmi.amps '' 'System Current read by IPMI' 'Amps' 'current' 'ipmi.amps' 'line' %d %d\n"
+ , netdata_priority + 13
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_RPM:
+ printf("CHART ipmi.rpm '' 'System Fans read by IPMI' 'RPM' 'fans' 'ipmi.rpm' 'line' %d %d\n"
+ , netdata_priority + 14
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_WATTS:
+ printf("CHART ipmi.watts '' 'System Power read by IPMI' 'Watts' 'power' 'ipmi.watts' 'line' %d %d\n"
+ , netdata_priority + 5
+ , netdata_update_every
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
+ printf("CHART ipmi.percent '' 'System Metrics read by IPMI' '%%' 'other' 'ipmi.percent' 'line' %d %d\n"
+ , netdata_priority + 15
+ , netdata_update_every
+ );
+ break;
+
+ default:
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->sensor_units == units)
+ sn->ignore = 1;
+ return;
+ }
+
+ for(sn = sensors_root; sn; sn = sn->next) {
+ if(sn->sensor_units == units && sn->updated && !sn->ignore) {
+ sn->exposed = 1;
+
+ switch(sn->sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 1\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_name
+ , sn->sensor_number
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 1000\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_name
+ , sn->sensor_number
+ );
+ break;
+
+ default:
+ sn->ignore = 1;
+ break;
+ }
+ }
+ }
+}
+
+static void send_metrics_to_netdata_for_units(int units) {
+ struct sensor *sn;
+
+ switch(units) {
+ case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
+ printf("BEGIN ipmi.temperatures_c\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
+ printf("BEGIN ipmi.temperatures_f\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
+ printf("BEGIN ipmi.volts\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_AMPS:
+ printf("BEGIN ipmi.amps\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_RPM:
+ printf("BEGIN ipmi.rpm\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_WATTS:
+ printf("BEGIN ipmi.watts\n");
+ break;
+
+ case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
+ printf("BEGIN ipmi.percent\n");
+ break;
+
+ default:
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->sensor_units == units)
+ sn->ignore = 1;
+ return;
+ }
+
+ for(sn = sensors_root; sn; sn = sn->next) {
+ if(sn->sensor_units == units && sn->updated && !sn->sent && !sn->ignore) {
+ netdata_sensors_updated++;
+
+ sn->sent = 1;
+
+ switch(sn->sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ printf("SET i%d_n%d_r%d = %u\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_reading.bool_value
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ printf("SET i%d_n%d_r%d = %u\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , sn->sensor_reading.uint32_value
+ );
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ printf("SET i%d_n%d_r%d = %lld\n"
+ , sn->sensor_number
+ , sn->record_id
+ , sn->sensor_reading_type
+ , (long long int)(sn->sensor_reading.double_value * 1000)
+ );
+ break;
+
+ default:
+ sn->ignore = 1;
+ break;
+ }
+ }
+ }
+
+ printf("END\n");
+}
+
+static void send_metrics_to_netdata() {
+ static int sel_chart_generated = 0, sensors_states_chart_generated = 0;
+ struct sensor *sn;
+
+ if(netdata_do_sel && !sel_chart_generated) {
+ sel_chart_generated = 1;
+ printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' ipmi.sel area %d %d\n"
+ , netdata_priority + 2
+ , netdata_update_every
+ );
+ printf("DIMENSION events '' absolute 1 1\n");
+ }
+
+ if(!sensors_states_chart_generated) {
+ sensors_states_chart_generated = 1;
+ printf("CHART ipmi.sensors_states '' 'IPMI Sensors State' 'sensors' 'states' ipmi.sensors_states line %d %d\n"
+ , netdata_priority + 1
+ , netdata_update_every
+ );
+ printf("DIMENSION nominal '' absolute 1 1\n");
+ printf("DIMENSION critical '' absolute 1 1\n");
+ printf("DIMENSION warning '' absolute 1 1\n");
+ }
+
+ // generate the CHART/DIMENSION lines, if we have to
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->updated && !sn->exposed && !sn->ignore)
+ send_chart_to_netdata_for_units(sn->sensor_units);
+
+ if(netdata_do_sel) {
+ printf(
+ "BEGIN ipmi.events\n"
+ "SET events = %zu\n"
+ "END\n"
+ , netdata_sel_events
+ );
+ }
+
+ printf(
+ "BEGIN ipmi.sensors_states\n"
+ "SET nominal = %zu\n"
+ "SET warning = %zu\n"
+ "SET critical = %zu\n"
+ "END\n"
+ , netdata_sensors_states_nominal
+ , netdata_sensors_states_warning
+ , netdata_sensors_states_critical
+ );
+
+ // send metrics to netdata
+ for(sn = sensors_root; sn; sn = sn->next)
+ if(sn->updated && sn->exposed && !sn->sent && !sn->ignore)
+ send_metrics_to_netdata_for_units(sn->sensor_units);
+
+}
+
+static void netdata_get_sensor(
+ int record_id
+ , int sensor_number
+ , int sensor_type
+ , int sensor_state
+ , int sensor_units
+ , int sensor_reading_type
+ , char *sensor_name
+ , void *sensor_reading
+) {
+ // find the sensor record
+ struct sensor *sn;
+ for(sn = sensors_root; sn ;sn = sn->next)
+ if( sn->record_id == record_id &&
+ sn->sensor_number == sensor_number &&
+ sn->sensor_reading_type == sensor_reading_type &&
+ sn->sensor_units == sensor_units &&
+ !strcmp(sn->sensor_name, sensor_name)
+ )
+ break;
+
+ if(!sn) {
+ // not found, create it
+
+ sn = calloc(1, sizeof(struct sensor));
+ if(!sn) {
+ fatal("cannot allocate %zu bytes of memory.", sizeof(struct sensor));
+ }
+
+ sn->record_id = record_id;
+ sn->sensor_number = sensor_number;
+ sn->sensor_type = sensor_type;
+ sn->sensor_state = sensor_state;
+ sn->sensor_units = sensor_units;
+ sn->sensor_reading_type = sensor_reading_type;
+ sn->sensor_name = strdup(sensor_name);
+ if(!sn->sensor_name) {
+ fatal("cannot allocate %zu bytes of memory.", strlen(sensor_name));
+ }
+
+ sn->next = sensors_root;
+ sensors_root = sn;
+ }
+
+ switch(sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ sn->sensor_reading.bool_value = *((uint8_t *)sensor_reading);
+ sn->updated = 1;
+ netdata_sensors_collected++;
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ sn->sensor_reading.uint32_value = *((uint32_t *)sensor_reading);
+ sn->updated = 1;
+ netdata_sensors_collected++;
+ break;
+
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ sn->sensor_reading.double_value = *((double *)sensor_reading);
+ sn->updated = 1;
+ netdata_sensors_collected++;
+ break;
+
+ default:
+ sn->ignore = 1;
+ break;
+ }
+
+ switch(sensor_state) {
+ case IPMI_MONITORING_STATE_NOMINAL:
+ netdata_sensors_states_nominal++;
+ break;
+
+ case IPMI_MONITORING_STATE_WARNING:
+ netdata_sensors_states_warning++;
+ break;
+
+ case IPMI_MONITORING_STATE_CRITICAL:
+ netdata_sensors_states_critical++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void netdata_get_sel(
+ int record_id
+ , int record_type_class
+ , int sel_state
+) {
+ (void)record_id;
+ (void)record_type_class;
+ (void)sel_state;
+
+ netdata_sel_events++;
+}
+
+
+void netdata_cleanup_and_exit(int ret) {
+ exit(ret);
+}
+
+// END NETDATA CODE
+// ----------------------------------------------------------------------------
+
+
+static int
+_ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
+{
+ ipmi_monitoring_ctx_t ctx = NULL;
+ unsigned int sensor_reading_flags = 0;
+ int i;
+ int sensor_count;
+ int rv = -1;
+
+ if (!(ctx = ipmi_monitoring_ctx_create ())) {
+ error("ipmi_monitoring_ctx_create()");
+ goto cleanup;
+ }
+
+ if (sdr_cache_directory)
+ {
+ if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
+ sdr_cache_directory) < 0)
+ {
+ error("ipmi_monitoring_ctx_sdr_cache_directory(): %s\n",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ /* Must call otherwise only default interpretations ever used */
+ if (sensor_config_file)
+ {
+ if (ipmi_monitoring_ctx_sensor_config_file (ctx,
+ sensor_config_file) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if (ipmi_monitoring_ctx_sensor_config_file (ctx, NULL) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ if (reread_sdr_cache)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
+
+ if (ignore_non_interpretable_sensors)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
+
+ if (bridge_sensors)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_BRIDGE_SENSORS;
+
+ if (interpret_oem_data)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_INTERPRET_OEM_DATA;
+
+ if (shared_sensors)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_SHARED_SENSORS;
+
+ if (discrete_reading)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING;
+
+ if (ignore_scanning_disabled)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_SCANNING_DISABLED;
+
+ if (assume_bmc_owner)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ASSUME_BMC_OWNER;
+
+#ifdef IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
+ if (entity_sensor_names)
+ sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES;
+#endif // IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
+
+ if (!record_ids_length && !sensor_types_length)
+ {
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sensor_reading_flags,
+ NULL,
+ 0,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else if (record_ids_length)
+ {
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sensor_reading_flags,
+ record_ids,
+ record_ids_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_sensor_type (ctx,
+ hostname,
+ ipmi_config,
+ sensor_reading_flags,
+ sensor_types,
+ sensor_types_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_readings_by_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+#ifdef NETDATA_COMMENTED
+ printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
+ "Record ID",
+ "Sensor Name",
+ "Sensor Number",
+ "Sensor Type",
+ "Sensor State",
+ "Sensor Reading",
+ "Sensor Units",
+ "Sensor Event/Reading Type Code",
+ "Sensor Event Bitmask",
+ "Sensor Event String");
+#endif // NETDATA_COMMENTED
+
+ for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (ctx))
+ {
+ int record_id, sensor_number, sensor_type, sensor_state, sensor_units,
+ sensor_reading_type;
+
+#ifdef NETDATA_COMMENTED
+ int sensor_bitmask_type, sensor_bitmask, event_reading_type_code;
+ char **sensor_bitmask_strings = NULL;
+ const char *sensor_type_str;
+ const char *sensor_state_str;
+#endif // NETDATA_COMMENTED
+
+ char *sensor_name = NULL;
+ void *sensor_reading;
+
+ if ((record_id = ipmi_monitoring_sensor_read_record_id (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_number = ipmi_monitoring_sensor_read_sensor_number (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_number(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!(sensor_name = ipmi_monitoring_sensor_read_sensor_name (ctx)))
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_name(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_state(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_units = ipmi_monitoring_sensor_read_sensor_units (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_units(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+#ifdef NETDATA_COMMENTED
+ if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_bitmask_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ if ((sensor_bitmask = ipmi_monitoring_sensor_read_sensor_bitmask (ctx)) < 0)
+ {
+ error(
+ "ipmi_monitoring_sensor_read_sensor_bitmask(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!(sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (ctx)))
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_bitmask_strings(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+#endif // NETDATA_COMMENTED
+
+ if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_sensor_reading_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (ctx);
+
+#ifdef NETDATA_COMMENTED
+ if ((event_reading_type_code = ipmi_monitoring_sensor_read_event_reading_type_code (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sensor_read_event_reading_type_code(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+#endif // NETDATA_COMMENTED
+
+ netdata_get_sensor(
+ record_id
+ , sensor_number
+ , sensor_type
+ , sensor_state
+ , sensor_units
+ , sensor_reading_type
+ , sensor_name
+ , sensor_reading
+ );
+
+#ifdef NETDATA_COMMENTED
+ if (!strlen (sensor_name))
+ sensor_name = "N/A";
+
+ sensor_type_str = _get_sensor_type_string (sensor_type);
+
+ printf ("%d, %s, %d, %s",
+ record_id,
+ sensor_name,
+ sensor_number,
+ sensor_type_str);
+
+ if (sensor_state == IPMI_MONITORING_STATE_NOMINAL)
+ sensor_state_str = "Nominal";
+ else if (sensor_state == IPMI_MONITORING_STATE_WARNING)
+ sensor_state_str = "Warning";
+ else if (sensor_state == IPMI_MONITORING_STATE_CRITICAL)
+ sensor_state_str = "Critical";
+ else
+ sensor_state_str = "N/A";
+
+ printf (", %s", sensor_state_str);
+
+ if (sensor_reading)
+ {
+ const char *sensor_units_str;
+
+ if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL)
+ printf (", %s",
+ (*((uint8_t *)sensor_reading) ? "true" : "false"));
+ else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32)
+ printf (", %u",
+ *((uint32_t *)sensor_reading));
+ else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE)
+ printf (", %.2f",
+ *((double *)sensor_reading));
+ else
+ printf (", N/A");
+
+ if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_CELSIUS)
+ sensor_units_str = "C";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT)
+ sensor_units_str = "F";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_VOLTS)
+ sensor_units_str = "V";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_AMPS)
+ sensor_units_str = "A";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_RPM)
+ sensor_units_str = "RPM";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_WATTS)
+ sensor_units_str = "W";
+ else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_PERCENT)
+ sensor_units_str = "%";
+ else
+ sensor_units_str = "N/A";
+
+ printf (", %s", sensor_units_str);
+ }
+ else
+ printf (", N/A, N/A");
+
+ printf (", %Xh", event_reading_type_code);
+
+ /* It is possible you may want to monitor specific event
+ * conditions that may occur. If that is the case, you may want
+ * to check out what specific bitmask type and bitmask events
+ * occurred. See ipmi_monitoring_bitmasks.h for a list of
+ * bitmasks and types.
+ */
+
+ if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
+ printf (", %Xh", sensor_bitmask);
+ else
+ printf (", N/A");
+
+ if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
+ {
+ unsigned int i = 0;
+
+ printf (",");
+
+ while (sensor_bitmask_strings[i])
+ {
+ printf (" ");
+
+ printf ("'%s'",
+ sensor_bitmask_strings[i]);
+
+ i++;
+ }
+ }
+ else
+ printf (", N/A");
+
+ printf ("\n");
+#endif // NETDATA_COMMENTED
+ }
+
+ rv = 0;
+ cleanup:
+ if (ctx)
+ ipmi_monitoring_ctx_destroy (ctx);
+ return (rv);
+}
+
+
+static int
+_ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
+{
+ ipmi_monitoring_ctx_t ctx = NULL;
+ unsigned int sel_flags = 0;
+ int i;
+ int sel_count;
+ int rv = -1;
+
+ if (!(ctx = ipmi_monitoring_ctx_create ()))
+ {
+ error("ipmi_monitoring_ctx_create()");
+ goto cleanup;
+ }
+
+ if (sdr_cache_directory)
+ {
+ if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
+ sdr_cache_directory) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sdr_cache_directory(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ /* Must call otherwise only default interpretations ever used */
+ if (sel_config_file)
+ {
+ if (ipmi_monitoring_ctx_sel_config_file (ctx,
+ sel_config_file) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sel_config_file(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if (ipmi_monitoring_ctx_sel_config_file (ctx, NULL) < 0)
+ {
+ error( "ipmi_monitoring_ctx_sel_config_file(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+ if (reread_sdr_cache)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
+
+ if (interpret_oem_data)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_INTERPRET_OEM_DATA;
+
+ if (assume_system_event_record)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_ASSUME_SYSTEM_EVENT_RECORD;
+
+#ifdef IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
+ if (entity_sensor_names)
+ sel_flags |= IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES;
+#endif // IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
+
+ if (record_ids_length)
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ record_ids,
+ record_ids_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else if (sensor_types_length)
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_sensor_type (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ sensor_types,
+ sensor_types_length,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else if (date_begin
+ || date_end)
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_date_range (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ date_begin,
+ date_end,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
+ hostname,
+ ipmi_config,
+ sel_flags,
+ NULL,
+ 0,
+ NULL,
+ NULL)) < 0)
+ {
+ error( "ipmi_monitoring_sel_by_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+ }
+
+#ifdef NETDATA_COMMENTED
+ printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
+ "Record ID",
+ "Record Type",
+ "SEL State",
+ "Timestamp",
+ "Sensor Name",
+ "Sensor Type",
+ "Event Direction",
+ "Event Type Code",
+ "Event Data",
+ "Event Offset",
+ "Event Offset String");
+#endif // NETDATA_COMMENTED
+
+ for (i = 0; i < sel_count; i++, ipmi_monitoring_sel_iterator_next (ctx))
+ {
+ int record_id, record_type, sel_state, record_type_class;
+#ifdef NETDATA_COMMENTED
+ int sensor_type, sensor_number, event_direction,
+ event_offset_type, event_offset, event_type_code, manufacturer_id;
+ unsigned int timestamp, event_data1, event_data2, event_data3;
+ char *event_offset_string = NULL;
+ const char *sensor_type_str;
+ const char *event_direction_str;
+ const char *sel_state_str;
+ char *sensor_name = NULL;
+ unsigned char oem_data[64];
+ int oem_data_len;
+ unsigned int j;
+#endif // NETDATA_COMMENTED
+
+ if ((record_id = ipmi_monitoring_sel_read_record_id (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_record_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((record_type = ipmi_monitoring_sel_read_record_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_record_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((record_type_class = ipmi_monitoring_sel_read_record_type_class (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_record_type_class(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sel_state = ipmi_monitoring_sel_read_sel_state (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_sel_state(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ netdata_get_sel(
+ record_id
+ , record_type_class
+ , sel_state
+ );
+
+#ifdef NETDATA_COMMENTED
+ if (sel_state == IPMI_MONITORING_STATE_NOMINAL)
+ sel_state_str = "Nominal";
+ else if (sel_state == IPMI_MONITORING_STATE_WARNING)
+ sel_state_str = "Warning";
+ else if (sel_state == IPMI_MONITORING_STATE_CRITICAL)
+ sel_state_str = "Critical";
+ else
+ sel_state_str = "N/A";
+
+ printf ("%d, %d, %s",
+ record_id,
+ record_type,
+ sel_state_str);
+
+ if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD
+ || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
+ {
+
+ if (ipmi_monitoring_sel_read_timestamp (ctx, &timestamp) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_timestamp(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ /* XXX: This should be converted to a nice date output using
+ * your favorite timestamp -> string conversion functions.
+ */
+ printf (", %u", timestamp);
+ }
+ else
+ printf (", N/A");
+
+ if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD)
+ {
+ /* If you are integrating ipmimonitoring SEL into a monitoring application,
+ * you may wish to count the number of times a specific error occurred
+ * and report that to the monitoring application.
+ *
+ * In this particular case, you'll probably want to check out
+ * what sensor type each SEL event is reporting, the
+ * event offset type, and the specific event offset that occurred.
+ *
+ * See ipmi_monitoring_offsets.h for a list of event offsets
+ * and types.
+ */
+
+ if (!(sensor_name = ipmi_monitoring_sel_read_sensor_name (ctx)))
+ {
+ error( "ipmi_monitoring_sel_read_sensor_name(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_type = ipmi_monitoring_sel_read_sensor_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_sensor_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((sensor_number = ipmi_monitoring_sel_read_sensor_number (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_sensor_number(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_direction = ipmi_monitoring_sel_read_event_direction (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_direction(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_type_code = ipmi_monitoring_sel_read_event_type_code (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_type_code(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (ipmi_monitoring_sel_read_event_data (ctx,
+ &event_data1,
+ &event_data2,
+ &event_data3) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_data(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_offset_type = ipmi_monitoring_sel_read_event_offset_type (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_offset_type(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if ((event_offset = ipmi_monitoring_sel_read_event_offset (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_event_offset(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!(event_offset_string = ipmi_monitoring_sel_read_event_offset_string (ctx)))
+ {
+ error( "ipmi_monitoring_sel_read_event_offset_string(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ if (!strlen (sensor_name))
+ sensor_name = "N/A";
+
+ sensor_type_str = _get_sensor_type_string (sensor_type);
+
+ if (event_direction == IPMI_MONITORING_SEL_EVENT_DIRECTION_ASSERTION)
+ event_direction_str = "Assertion";
+ else
+ event_direction_str = "Deassertion";
+
+ printf (", %s, %s, %d, %s, %Xh, %Xh-%Xh-%Xh",
+ sensor_name,
+ sensor_type_str,
+ sensor_number,
+ event_direction_str,
+ event_type_code,
+ event_data1,
+ event_data2,
+ event_data3);
+
+ if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
+ printf (", %Xh", event_offset);
+ else
+ printf (", N/A");
+
+ if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
+ printf (", %s", event_offset_string);
+ else
+ printf (", N/A");
+ }
+ else if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD
+ || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_NON_TIMESTAMPED_OEM_RECORD)
+ {
+ if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
+ {
+ if ((manufacturer_id = ipmi_monitoring_sel_read_manufacturer_id (ctx)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_manufacturer_id(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ printf (", Manufacturer ID = %Xh", manufacturer_id);
+ }
+
+ if ((oem_data_len = ipmi_monitoring_sel_read_oem_data (ctx, oem_data, 1024)) < 0)
+ {
+ error( "ipmi_monitoring_sel_read_oem_data(): %s",
+ ipmi_monitoring_ctx_errormsg (ctx));
+ goto cleanup;
+ }
+
+ printf (", OEM Data = ");
+
+ for (j = 0; j < oem_data_len; j++)
+ printf ("%02Xh ", oem_data[j]);
+ }
+ else
+ printf (", N/A, N/A, N/A, N/A, N/A, N/A, N/A");
+
+ printf ("\n");
+#endif // NETDATA_COMMENTED
+ }
+
+ rv = 0;
+ cleanup:
+ if (ctx)
+ ipmi_monitoring_ctx_destroy (ctx);
+ return (rv);
+}
+
+// ----------------------------------------------------------------------------
+// MAIN PROGRAM FOR NETDATA PLUGIN
+
+int ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config) {
+ errno = 0;
+
+ if (_ipmimonitoring_sensors(ipmi_config) < 0) return -1;
+
+ if(netdata_do_sel) {
+ if(_ipmimonitoring_sel(ipmi_config) < 0) return -2;
+ }
+
+ return 0;
+}
+
+int ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config) {
+ int i, checks = 10;
+ unsigned long long total = 0;
+
+ for(i = 0 ; i < checks ; i++) {
+ if(debug) fprintf(stderr, "freeipmi.plugin: checking data collection speed iteration %d of %d\n", i+1, checks);
+
+ // measure the time a data collection needs
+ unsigned long long start = now_realtime_usec();
+ if(ipmi_collect_data(ipmi_config) < 0)
+ fatal("freeipmi.plugin: data collection failed.");
+
+ unsigned long long end = now_realtime_usec();
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: data collection speed was %llu usec\n", end - start);
+
+ // add it to our total
+ total += end - start;
+
+ // wait the same time
+ // to avoid flooding the IPMI processor with requests
+ sleep_usec(end - start);
+ }
+
+ // so, we assume it needed 2x the time
+ // we find the average in microseconds
+ // and we round-up to the closest second
+
+ return (( total * 2 / checks / 1000000 ) + 1);
+}
+
+int main (int argc, char **argv) {
+
+ // ------------------------------------------------------------------------
+ // initialization of netdata plugin
+
+ program_name = "freeipmi.plugin";
+
+ // disable syslog
+ error_log_syslog = 0;
+
+ // set errors flood protection to 100 logs per hour
+ error_log_errors_per_period = 100;
+ error_log_throttle_period = 3600;
+
+
+ // ------------------------------------------------------------------------
+ // parse command line parameters
+
+ int i, freq = 0;
+ for(i = 1; i < argc ; i++) {
+ if(!freq) {
+ int n = atoi(argv[i]);
+ if(n > 0) {
+ freq = n;
+ continue;
+ }
+ }
+
+ if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
+ printf("freeipmi.plugin %s\n", VERSION);
+ exit(0);
+ }
+ else if(strcmp("debug", argv[i]) == 0) {
+ debug = 1;
+ continue;
+ }
+ else if(strcmp("sel", argv[i]) == 0) {
+ netdata_do_sel = 1;
+ continue;
+ }
+ else if(strcmp("no-sel", argv[i]) == 0) {
+ netdata_do_sel = 0;
+ continue;
+ }
+ else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
+ fprintf(stderr,
+ "\n"
+ " netdata freeipmi.plugin %s\n"
+ " Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
+ " Released under GNU General Public License v3 or later.\n"
+ " All rights reserved.\n"
+ "\n"
+ " This program is a data collector plugin for netdata.\n"
+ "\n"
+ " Available command line options:\n"
+ "\n"
+ " SECONDS data collection frequency\n"
+ " minimum: %d\n"
+ "\n"
+ " debug enable verbose output\n"
+ " default: disabled\n"
+ "\n"
+ " sel\n"
+ " no-sel enable/disable SEL collection\n"
+ " default: %s\n"
+ "\n"
+ " hostname HOST\n"
+ " username USER\n"
+ " password PASS connect to remote IPMI host\n"
+ " default: local IPMI processor\n"
+ "\n"
+ " sdr-cache-dir PATH directory for SDR cache files\n"
+ " default: %s\n"
+ "\n"
+ " sensor-config-file FILE filename to read sensor configuration\n"
+ " default: %s\n"
+ "\n"
+ " -v\n"
+ " -V\n"
+ " version print version and exit\n"
+ "\n"
+ " Linux kernel module for IPMI is CPU hungry.\n"
+ " On Linux run this to lower kipmiN CPU utilization:\n"
+ " # echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us\n"
+ "\n"
+ " or create: /etc/modprobe.d/ipmi.conf with these contents:\n"
+ " options ipmi_si kipmid_max_busy_us=10\n"
+ "\n"
+ " For more information:\n"
+ " https://github.com/firehol/netdata/wiki/monitoring-IPMI\n"
+ "\n"
+ , VERSION
+ , netdata_update_every
+ , netdata_do_sel?"enabled":"disabled"
+ , sdr_cache_directory?sdr_cache_directory:"system default"
+ , sensor_config_file?sensor_config_file:"system default"
+ );
+ exit(1);
+ }
+ else if(i < argc && strcmp("hostname", argv[i]) == 0) {
+ hostname = strdupz(argv[++i]);
+ char *s = argv[i];
+ // mask it be hidden from the process tree
+ while(*s) *s++ = 'x';
+ if(debug) fprintf(stderr, "freeipmi.plugin: hostname set to '%s'\n", hostname);
+ continue;
+ }
+ else if(i < argc && strcmp("username", argv[i]) == 0) {
+ username = strdupz(argv[++i]);
+ char *s = argv[i];
+ // mask it be hidden from the process tree
+ while(*s) *s++ = 'x';
+ if(debug) fprintf(stderr, "freeipmi.plugin: username set to '%s'\n", username);
+ continue;
+ }
+ else if(i < argc && strcmp("password", argv[i]) == 0) {
+ password = strdupz(argv[++i]);
+ char *s = argv[i];
+ // mask it be hidden from the process tree
+ while(*s) *s++ = 'x';
+ if(debug) fprintf(stderr, "freeipmi.plugin: password set to '%s'\n", password);
+ continue;
+ }
+ else if(i < argc && strcmp("sdr-cache-dir", argv[i]) == 0) {
+ sdr_cache_directory = argv[++i];
+ if(debug) fprintf(stderr, "freeipmi.plugin: SDR cache directory set to '%s'\n", sdr_cache_directory);
+ continue;
+ }
+ else if(i < argc && strcmp("sensor-config-file", argv[i]) == 0) {
+ sensor_config_file = argv[++i];
+ if(debug) fprintf(stderr, "freeipmi.plugin: sensor config file set to '%s'\n", sensor_config_file);
+ continue;
+ }
+
+ error("freeipmi.plugin: ignoring parameter '%s'", argv[i]);
+ }
+
+ if(freq > netdata_update_every)
+ netdata_update_every = freq;
+
+ else if(freq)
+ error("update frequency %d seconds is too small for IPMI. Using %d.", freq, netdata_update_every);
+
+
+ // ------------------------------------------------------------------------
+ // initialize IPMI
+
+ struct ipmi_monitoring_ipmi_config ipmi_config;
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling _init_ipmi_config()\n");
+
+ _init_ipmi_config(&ipmi_config);
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_monitoring_init()\n");
+
+ if(ipmi_monitoring_init(ipmimonitoring_init_flags, &errnum) < 0)
+ fatal("ipmi_monitoring_init: %s", ipmi_monitoring_ctx_strerror(errnum));
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: detecting IPMI minimum update frequency...\n");
+ freq = ipmi_detect_speed_secs(&ipmi_config);
+ if(debug) fprintf(stderr, "freeipmi.plugin: IPMI minimum update frequency was calculated to %d seconds.\n", freq);
+
+ if(netdata_update_every < freq) {
+ info("enforcing minimum data collection frequency, calculated to %d seconds.", freq);
+ netdata_update_every = freq;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // the main loop
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: starting data collection\n");
+
+ time_t started_t = now_monotonic_sec();
+
+ size_t iteration = 0;
+ usec_t step = netdata_update_every * USEC_PER_SEC;
+
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+ for(iteration = 0; 1 ; iteration++) {
+ usec_t dt = heartbeat_next(&hb, step);
+
+ if(debug && iteration)
+ fprintf(stderr, "freeipmi.plugin: iteration %zu, dt %llu usec, sensors collected %zu, sensors sent to netdata %zu \n"
+ , iteration
+ , dt
+ , netdata_sensors_collected
+ , netdata_sensors_updated
+ );
+
+ netdata_mark_as_not_updated();
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_collect_data()\n");
+ if(ipmi_collect_data(&ipmi_config) < 0)
+ fatal("data collection failed.");
+
+ if(debug) fprintf(stderr, "freeipmi.plugin: calling send_metrics_to_netdata()\n");
+ send_metrics_to_netdata();
+ fflush(stdout);
+
+ // restart check (14400 seconds)
+ if(now_monotonic_sec() - started_t > 14400) exit(0);
+ }
+}
+
+#else // !HAVE_FREEIPMI
+
+int main(int argc, char **argv) {
+ fatal("freeipmi.plugin is not compiled.");
+}
+
+#endif // !HAVE_FREEIPMI
diff --git a/src/global_statistics.c b/src/global_statistics.c
index a698615f4..8575061ac 100644
--- a/src/global_statistics.c
+++ b/src/global_statistics.c
@@ -10,14 +10,14 @@ volatile struct global_statistics global_statistics = {
.compressed_content_size = 0
};
-pthread_mutex_t global_statistics_mutex = PTHREAD_MUTEX_INITIALIZER;
+netdata_mutex_t global_statistics_mutex = NETDATA_MUTEX_INITIALIZER;
inline void global_statistics_lock(void) {
- pthread_mutex_lock(&global_statistics_mutex);
+ netdata_mutex_lock(&global_statistics_mutex);
}
inline void global_statistics_unlock(void) {
- pthread_mutex_unlock(&global_statistics_mutex);
+ netdata_mutex_unlock(&global_statistics_mutex);
}
void finished_web_request_statistics(uint64_t dt,
@@ -129,14 +129,22 @@ void global_statistics_charts(void) {
getrusage(RUSAGE_THREAD, &thread);
getrusage(RUSAGE_SELF, &me);
- if (!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_proc_cpu");
+#ifdef __FreeBSD__
+ if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_freebsd_cpu");
if (!stcpu_thread) {
- stcpu_thread = rrdset_create("netdata", "plugin_proc_cpu", NULL, "proc", NULL,
- "NetData Proc Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every,
- RRDSET_TYPE_STACKED);
+ stcpu_thread = rrdset_create_localhost("netdata", "plugin_freebsd_cpu", NULL, "freebsd", NULL
+ , "NetData FreeBSD Plugin CPU usage", "milliseconds/s", 132000
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+#else
+ if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_proc_cpu");
+ if (!stcpu_thread) {
+ stcpu_thread = rrdset_create_localhost("netdata", "plugin_proc_cpu", NULL, "proc", NULL
+ , "NetData Proc Plugin CPU usage", "milliseconds/s", 132000
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+#endif
- rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stcpu_thread);
rrddim_set(stcpu_thread, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
@@ -145,13 +153,13 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stcpu) stcpu = rrdset_find("netdata.server_cpu");
+ if (!stcpu) stcpu = rrdset_find_localhost("netdata.server_cpu");
if (!stcpu) {
- stcpu = rrdset_create("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage", "milliseconds/s",
- 130000, rrd_update_every, RRDSET_TYPE_STACKED);
+ stcpu = rrdset_create_localhost("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage"
+ , "milliseconds/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
- rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stcpu);
rrddim_set(stcpu, "user", me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec);
@@ -160,12 +168,12 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stclients) stclients = rrdset_find("netdata.clients");
+ if (!stclients) stclients = rrdset_find_localhost("netdata.clients");
if (!stclients) {
- stclients = rrdset_create("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients",
- "connected clients", 130200, rrd_update_every, RRDSET_TYPE_LINE);
+ stclients = rrdset_create_localhost("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients"
+ , "connected clients", 130200, localhost->rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(stclients, "clients", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(stclients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
} else rrdset_next(stclients);
rrddim_set(stclients, "clients", gs.connected_clients);
@@ -173,12 +181,12 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!streqs) streqs = rrdset_find("netdata.requests");
+ if (!streqs) streqs = rrdset_find_localhost("netdata.requests");
if (!streqs) {
- streqs = rrdset_create("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests", "requests/s",
- 130300, rrd_update_every, RRDSET_TYPE_LINE);
+ streqs = rrdset_create_localhost("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests"
+ , "requests/s", 130300, localhost->rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(streqs, "requests", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(streqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(streqs);
rrddim_set(streqs, "requests", (collected_number) gs.web_requests);
@@ -186,13 +194,13 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stbytes) stbytes = rrdset_find("netdata.net");
+ if (!stbytes) stbytes = rrdset_find_localhost("netdata.net");
if (!stbytes) {
- stbytes = rrdset_create("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic", "kilobits/s",
- 130000, rrd_update_every, RRDSET_TYPE_AREA);
+ stbytes = rrdset_create_localhost("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic"
+ , "kilobits/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(stbytes, "in", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(stbytes, "out", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(stbytes, "in", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stbytes, "out", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
} else rrdset_next(stbytes);
rrddim_set(stbytes, "in", (collected_number) gs.bytes_received);
@@ -201,13 +209,14 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stduration) stduration = rrdset_find("netdata.response_time");
+ if (!stduration) stduration = rrdset_find_localhost("netdata.response_time");
if (!stduration) {
- stduration = rrdset_create("netdata", "response_time", NULL, "netdata", NULL, "NetData API Response Time",
- "ms/request", 130400, rrd_update_every, RRDSET_TYPE_LINE);
+ stduration = rrdset_create_localhost("netdata", "response_time", NULL, "netdata", NULL
+ , "NetData API Response Time", "ms/request", 130400, localhost->rrd_update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(stduration, "average", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(stduration, "max", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ rrddim_add(stduration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stduration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
} else rrdset_next(stduration);
uint64_t gweb_usec = gs.web_usec;
@@ -232,13 +241,13 @@ void global_statistics_charts(void) {
// ----------------------------------------------------------------
- if (!stcompression) stcompression = rrdset_find("netdata.compression_ratio");
+ if (!stcompression) stcompression = rrdset_find_localhost("netdata.compression_ratio");
if (!stcompression) {
- stcompression = rrdset_create("netdata", "compression_ratio", NULL, "netdata", NULL,
- "NetData API Responses Compression Savings Ratio", "percentage", 130500,
- rrd_update_every, RRDSET_TYPE_LINE);
+ stcompression = rrdset_create_localhost("netdata", "compression_ratio", NULL, "netdata", NULL
+ , "NetData API Responses Compression Savings Ratio", "percentage"
+ , 130500, localhost->rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(stcompression, "savings", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ rrddim_add(stcompression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
} else rrdset_next(stcompression);
// since we don't lock here to read the global statistics
diff --git a/src/health.c b/src/health.c
index 193312eec..46b27db6f 100755..100644
--- a/src/health.c
+++ b/src/health.c
@@ -1,2588 +1,84 @@
+#define NETDATA_HEALTH_INTERNALS
#include "common.h"
-#define RRDVAR_MAX_LENGTH 1024
-
-struct health_options {
- const char *health_default_exec;
- const char *health_default_recipient;
- const char *log_filename;
- size_t log_entries_written;
- FILE *log_fp;
-};
-
-static struct health_options health = {
- .health_default_exec = PLUGINS_DIR "/alarm-notify.sh",
- .health_default_recipient = "root",
- .log_filename = VARLIB_DIR "/health/alarm_log.db",
- .log_entries_written = 0,
- .log_fp = NULL
-};
-
-int health_enabled = 1;
-
-// ----------------------------------------------------------------------------
-// health alarm log load/save
-// no need for locking - only one thread is reading / writing the alarms log
-
-static inline int health_alarm_log_open(void) {
- if(health.log_fp)
- fclose(health.log_fp);
-
- health.log_fp = fopen(health.log_filename, "a");
-
- if(health.log_fp) {
- if (setvbuf(health.log_fp, NULL, _IOLBF, 0) != 0)
- error("Health: cannot set line buffering on health log file.");
- return 0;
- }
-
- error("Health: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", health.log_filename);
- return -1;
-}
-
-static inline void health_alarm_log_close(void) {
- if(health.log_fp) {
- fclose(health.log_fp);
- health.log_fp = NULL;
- }
-}
-
-static inline void health_log_rotate(void) {
- static size_t rotate_every = 0;
-
- if(unlikely(rotate_every == 0)) {
- rotate_every = (size_t)config_get_number("health", "rotate log every lines", 2000);
- if(rotate_every < 100) rotate_every = 100;
- }
-
- if(unlikely(health.log_entries_written > rotate_every)) {
- health_alarm_log_close();
-
- char old_filename[FILENAME_MAX + 1];
- snprintfz(old_filename, FILENAME_MAX, "%s.old", health.log_filename);
-
- if(unlink(old_filename) == -1 && errno != ENOENT)
- error("Health: cannot remove old alarms log file '%s'", old_filename);
-
- if(link(health.log_filename, old_filename) == -1 && errno != ENOENT)
- error("Health: cannot move file '%s' to '%s'.", health.log_filename, old_filename);
-
- if(unlink(health.log_filename) == -1 && errno != ENOENT)
- error("Health: cannot remove old alarms log file '%s'", health.log_filename);
-
- // open it with truncate
- health.log_fp = fopen(health.log_filename, "w");
-
- if(health.log_fp)
- fclose(health.log_fp);
- else
- error("Health: cannot truncate health log '%s'", health.log_filename);
-
- health.log_fp = NULL;
-
- health.log_entries_written = 0;
- health_alarm_log_open();
- }
-}
-
-static inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
- health_log_rotate();
-
- if(likely(health.log_fp)) {
- if(unlikely(fprintf(health.log_fp
- , "%c\t%s"
- "\t%08x\t%08x\t%08x\t%08x\t%08x"
- "\t%08x\t%08x\t%08x"
- "\t%08x\t%08x\t%08x"
- "\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s"
- "\t%d\t%d\t%d\t%d"
- "\t%Lf\t%Lf"
- "\n"
- , (ae->flags & HEALTH_ENTRY_FLAG_SAVED)?'U':'A'
- , host->hostname
-
- , ae->unique_id
- , ae->alarm_id
- , ae->alarm_event_id
- , ae->updated_by_id
- , ae->updates_id
-
- , (uint32_t)ae->when
- , (uint32_t)ae->duration
- , (uint32_t)ae->non_clear_duration
- , (uint32_t)ae->flags
- , (uint32_t)ae->exec_run_timestamp
- , (uint32_t)ae->delay_up_to_timestamp
-
- , (ae->name)?ae->name:""
- , (ae->chart)?ae->chart:""
- , (ae->family)?ae->family:""
- , (ae->exec)?ae->exec:""
- , (ae->recipient)?ae->recipient:""
- , (ae->source)?ae->source:""
- , (ae->units)?ae->units:""
- , (ae->info)?ae->info:""
-
- , ae->exec_code
- , ae->new_status
- , ae->old_status
- , ae->delay
-
- , (long double)ae->new_value
- , (long double)ae->old_value
- ) < 0))
- error("Health: failed to save alarm log entry. Health data may be lost in case of abnormal restart.");
- else {
- ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
- health.log_entries_written++;
- }
- }
-}
-
-static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename) {
- static uint32_t max_unique_id = 0, max_alarm_id = 0;
-
- errno = 0;
-
- char *s, *buf = mallocz(65536 + 1);
- size_t line = 0, len = 0;
- ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
-
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
-
- while((s = fgets_trim_len(buf, 65536, fp, &len))) {
- health.log_entries_written++;
- line++;
-
- int max_entries = 30, entries = 0;
- char *pointers[max_entries];
-
- pointers[entries++] = s++;
- while(*s) {
- if(unlikely(*s == '\t')) {
- *s = '\0';
- pointers[entries++] = ++s;
- if(entries >= max_entries) {
- error("Health: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", line, filename, max_entries);
- break;
- }
- }
- else s++;
- }
-
- if(likely(*pointers[0] == 'U' || *pointers[0] == 'A')) {
- ALARM_ENTRY *ae = NULL;
-
- if(entries < 26) {
- error("Health: line %zu of file '%s' should have at least 26 entries, but it has %d. Ignoring it.", line, filename, entries);
- errored++;
- continue;
- }
-
- // check that we have valid ids
- uint32_t unique_id = (uint32_t)strtoul(pointers[2], NULL, 16);
- if(!unique_id) {
- error("Health: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", line, filename, unique_id, pointers[2]);
- errored++;
- continue;
- }
-
- uint32_t alarm_id = (uint32_t)strtoul(pointers[3], NULL, 16);
- if(!alarm_id) {
- error("Health: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", line, filename, alarm_id, pointers[3]);
- errored++;
- continue;
- }
-
- if(unlikely(*pointers[0] == 'A')) {
- // make sure it is properly numbered
- if(unlikely(host->health_log.alarms && unique_id < host->health_log.alarms->unique_id)) {
- error("Health: line %zu of file '%s' has alarm log entry with %u in wrong order. Ignoring it.", line, filename, unique_id);
- errored++;
- continue;
- }
-
- ae = callocz(1, sizeof(ALARM_ENTRY));
- }
- else if(unlikely(*pointers[0] == 'U')) {
- // find the original
- for(ae = host->health_log.alarms; ae; ae = ae->next) {
- if(unlikely(unique_id == ae->unique_id)) {
- if(unlikely(*pointers[0] == 'A')) {
- error("Health: line %zu of file '%s' adds duplicate alarm log entry with unique id %u. Using the later."
- , line, filename, unique_id);
- *pointers[0] = 'U';
- duplicate++;
- }
- break;
- }
- else if(unlikely(unique_id > ae->unique_id)) {
- // no need to continue
- // the linked list is sorted
- ae = NULL;
- break;
- }
- }
-
- // if not found, skip this line
- if(!ae) {
- // error("Health: line %zu of file '%s' updates alarm log entry with unique id %u, but it is not found.", line, filename, unique_id);
- continue;
- }
- }
-
- // check for a possible host missmatch
- //if(strcmp(pointers[1], host->hostname))
- // error("Health: line %zu of file '%s' provides an alarm for host '%s' but this is named '%s'.", line, filename, pointers[1], host->hostname);
-
- ae->unique_id = unique_id;
- ae->alarm_id = alarm_id;
- ae->alarm_event_id = (uint32_t)strtoul(pointers[4], NULL, 16);
- ae->updated_by_id = (uint32_t)strtoul(pointers[5], NULL, 16);
- ae->updates_id = (uint32_t)strtoul(pointers[6], NULL, 16);
-
- ae->when = (uint32_t)strtoul(pointers[7], NULL, 16);
- ae->duration = (uint32_t)strtoul(pointers[8], NULL, 16);
- ae->non_clear_duration = (uint32_t)strtoul(pointers[9], NULL, 16);
-
- ae->flags = (uint32_t)strtoul(pointers[10], NULL, 16);
- ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
-
- ae->exec_run_timestamp = (uint32_t)strtoul(pointers[11], NULL, 16);
- ae->delay_up_to_timestamp = (uint32_t)strtoul(pointers[12], NULL, 16);
-
- if(unlikely(ae->name)) freez(ae->name);
- ae->name = strdupz(pointers[13]);
- ae->hash_name = simple_hash(ae->name);
-
- if(unlikely(ae->chart)) freez(ae->chart);
- ae->chart = strdupz(pointers[14]);
- ae->hash_chart = simple_hash(ae->chart);
-
- if(unlikely(ae->family)) freez(ae->family);
- ae->family = strdupz(pointers[15]);
-
- if(unlikely(ae->exec)) freez(ae->exec);
- ae->exec = strdupz(pointers[16]);
- if(!*ae->exec) { freez(ae->exec); ae->exec = NULL; }
-
- if(unlikely(ae->recipient)) freez(ae->recipient);
- ae->recipient = strdupz(pointers[17]);
- if(!*ae->recipient) { freez(ae->recipient); ae->recipient = NULL; }
-
- if(unlikely(ae->source)) freez(ae->source);
- ae->source = strdupz(pointers[18]);
- if(!*ae->source) { freez(ae->source); ae->source = NULL; }
-
- if(unlikely(ae->units)) freez(ae->units);
- ae->units = strdupz(pointers[19]);
- if(!*ae->units) { freez(ae->units); ae->units = NULL; }
-
- if(unlikely(ae->info)) freez(ae->info);
- ae->info = strdupz(pointers[20]);
- if(!*ae->info) { freez(ae->info); ae->info = NULL; }
-
- ae->exec_code = str2i(pointers[21]);
- ae->new_status = str2i(pointers[22]);
- ae->old_status = str2i(pointers[23]);
- ae->delay = str2i(pointers[24]);
-
- ae->new_value = str2l(pointers[25]);
- ae->old_value = str2l(pointers[26]);
-
- // add it to host if not already there
- if(unlikely(*pointers[0] == 'A')) {
- ae->next = host->health_log.alarms;
- host->health_log.alarms = ae;
- loaded++;
- }
- else updated++;
-
- if(unlikely(ae->unique_id > max_unique_id))
- max_unique_id = ae->unique_id;
-
- if(unlikely(ae->alarm_id >= max_alarm_id))
- max_alarm_id = ae->alarm_id;
- }
- else {
- error("Health: line %zu of file '%s' is invalid (unrecognized entry type '%s').", line, filename, pointers[0]);
- errored++;
- }
- }
-
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-
- freez(buf);
-
- if(!max_unique_id) max_unique_id = (uint32_t)now_realtime_sec();
- if(!max_alarm_id) max_alarm_id = (uint32_t)now_realtime_sec();
-
- host->health_log.next_log_id = max_unique_id + 1;
- host->health_log.next_alarm_id = max_alarm_id + 1;
-
- debug(D_HEALTH, "Health: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", filename, loaded, updated, errored, duplicate);
- return loaded;
-}
-
-static inline void health_alarm_log_load(RRDHOST *host) {
- health_alarm_log_close();
-
- char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s.old", health.log_filename);
- FILE *fp = fopen(filename, "r");
- if(!fp)
- error("Health: cannot open health file: %s", filename);
- else {
- health_alarm_log_read(host, fp, filename);
- fclose(fp);
- }
-
- health.log_entries_written = 0;
- fp = fopen(health.log_filename, "r");
- if(!fp)
- error("Health: cannot open health file: %s", health.log_filename);
- else {
- health_alarm_log_read(host, fp, health.log_filename);
- fclose(fp);
- }
-
- health_alarm_log_open();
-}
-
-
-// ----------------------------------------------------------------------------
-// health alarm log management
-
-static inline void health_alarm_log(RRDHOST *host,
- uint32_t alarm_id, uint32_t alarm_event_id,
- time_t when,
- const char *name, const char *chart, const char *family,
- const char *exec, const char *recipient, time_t duration,
- calculated_number old_value, calculated_number new_value,
- int old_status, int new_status,
- const char *source,
- const char *units,
- const char *info,
- int delay
-) {
- debug(D_HEALTH, "Health adding alarm log entry with id: %u", host->health_log.next_log_id);
-
- ALARM_ENTRY *ae = callocz(1, sizeof(ALARM_ENTRY));
- ae->name = strdupz(name);
- ae->hash_name = simple_hash(ae->name);
-
- if(chart) {
- ae->chart = strdupz(chart);
- ae->hash_chart = simple_hash(ae->chart);
- }
-
- if(family)
- ae->family = strdupz(family);
-
- if(exec) ae->exec = strdupz(exec);
- if(recipient) ae->recipient = strdupz(recipient);
- if(source) ae->source = strdupz(source);
- if(units) ae->units = strdupz(units);
- if(info) ae->info = strdupz(info);
-
- ae->unique_id = host->health_log.next_log_id++;
- ae->alarm_id = alarm_id;
- ae->alarm_event_id = alarm_event_id;
- ae->when = when;
- ae->old_value = old_value;
- ae->new_value = new_value;
- ae->old_status = old_status;
- ae->new_status = new_status;
- ae->duration = duration;
- ae->delay = delay;
- ae->delay_up_to_timestamp = when + delay;
-
- if(ae->old_status == RRDCALC_STATUS_WARNING || ae->old_status == RRDCALC_STATUS_CRITICAL)
- ae->non_clear_duration += ae->duration;
-
- // link it
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
- ae->next = host->health_log.alarms;
- host->health_log.alarms = ae;
- host->health_log.count++;
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-
- // match previous alarms
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
- ALARM_ENTRY *t;
- for(t = host->health_log.alarms ; t ; t = t->next) {
- if(t != ae && t->alarm_id == ae->alarm_id) {
- if(!(t->flags & HEALTH_ENTRY_FLAG_UPDATED) && !t->updated_by_id) {
- t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
- t->updated_by_id = ae->unique_id;
- ae->updates_id = t->unique_id;
-
- if((t->new_status == RRDCALC_STATUS_WARNING || t->new_status == RRDCALC_STATUS_CRITICAL) &&
- (t->old_status == RRDCALC_STATUS_WARNING || t->old_status == RRDCALC_STATUS_CRITICAL))
- ae->non_clear_duration += t->non_clear_duration;
-
- health_alarm_log_save(host, t);
- }
-
- // no need to continue
- break;
- }
- }
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-
- health_alarm_log_save(host, ae);
-}
-
-// ----------------------------------------------------------------------------
-// RRDVAR management
-
-static inline int rrdvar_fix_name(char *variable) {
- int fixed = 0;
- while(*variable) {
- if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
- *variable++ = '_';
- fixed++;
- }
- else
- variable++;
- }
-
- return fixed;
-}
-
-int rrdvar_compare(void* a, void* b) {
- if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
- else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
- else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
-}
-
-static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
- RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
- if(ret != rv)
- debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
-
- return ret;
-}
-
-static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
- RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
- if(!ret)
- error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
-
- return ret;
-}
-
-static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
- RRDVAR tmp;
- tmp.name = (char *)name;
- tmp.hash = (hash)?hash:simple_hash(tmp.name);
-
- return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
-}
-
-static inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
- (void)host;
-
- if(!rv) return;
-
- if(tree) {
- debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
- if(unlikely(!rrdvar_index_del(tree, rv)))
- error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
- }
-
- freez(rv->name);
- freez(rv);
-}
-
-static inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) {
- char *variable = strdupz(name);
- rrdvar_fix_name(variable);
- uint32_t hash = simple_hash(variable);
-
- RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
- if(unlikely(!rv)) {
- debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
-
- rv = callocz(1, sizeof(RRDVAR));
- rv->name = variable;
- rv->hash = hash;
- rv->type = type;
- rv->value = value;
-
- RRDVAR *ret = rrdvar_index_add(tree, rv);
- if(unlikely(ret != rv)) {
- debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
- rrdvar_free(NULL, NULL, rv);
- rv = NULL;
- }
- else
- debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
- }
- else {
- debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
-
- // already exists
- freez(variable);
-
- // this is important
- // it must return NULL - not the existing variable - or double-free will happen
- rv = NULL;
- }
-
- return rv;
-}
-
-// ----------------------------------------------------------------------------
-// CUSTOM VARIABLES
-
-RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
- calculated_number *v = callocz(1, sizeof(calculated_number));
- *v = NAN;
- RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v);
- if(unlikely(!rv)) {
- free(v);
- error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name);
-
- char *variable = strdupz(name);
- rrdvar_fix_name(variable);
- uint32_t hash = simple_hash(variable);
-
- rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
- }
-
- return rv;
-}
-
-void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) {
- char *variable = strdupz(name);
- rrdvar_fix_name(variable);
- uint32_t hash = simple_hash(variable);
-
- RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
- freez(variable);
-
- if(!rv) {
- error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname);
- return;
- }
-
- if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) {
- error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname);
- return;
- }
-
- if(!rrdvar_index_del(&host->variables_root_index, rv)) {
- error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname);
- return;
- }
-
- freez(rv->name);
- freez(rv->value);
- freez(rv);
-}
-
-void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) {
- if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED)
- error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value);
- else {
- calculated_number *v = rv->value;
- *v = value;
- }
-}
-
-// ----------------------------------------------------------------------------
-// RRDVAR lookup
-
-static calculated_number rrdvar2number(RRDVAR *rv) {
- switch(rv->type) {
- case RRDVAR_TYPE_CALCULATED_ALLOCATED:
- case RRDVAR_TYPE_CALCULATED: {
- calculated_number *n = (calculated_number *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_TIME_T: {
- time_t *n = (time_t *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_COLLECTED: {
- collected_number *n = (collected_number *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_TOTAL: {
- total_number *n = (total_number *)rv->value;
- return *n;
- }
-
- case RRDVAR_TYPE_INT: {
- int *n = (int *)rv->value;
- return *n;
- }
-
- default:
- error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type);
- return NAN;
- }
-}
-
-int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
- RRDSET *st = rc->rrdset;
- RRDVAR *rv;
-
- if(!st) return 0;
-
- rv = rrdvar_index_find(&st->variables_root_index, variable, hash);
- if(rv) {
- *result = rrdvar2number(rv);
- return 1;
- }
-
- rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash);
- if(rv) {
- *result = rrdvar2number(rv);
- return 1;
- }
-
- rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash);
- if(rv) {
- *result = rrdvar2number(rv);
- return 1;
- }
-
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-// RRDVAR to JSON
-
-struct variable2json_helper {
- BUFFER *buf;
- size_t counter;
-};
-
-static int single_variable2json(void *entry, void *data) {
- struct variable2json_helper *helper = (struct variable2json_helper *)data;
- RRDVAR *rv = (RRDVAR *)entry;
- calculated_number value = rrdvar2number(rv);
-
- if(unlikely(isnan(value) || isinf(value)))
- buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
- else
- buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
-
- helper->counter++;
-
- return 0;
-}
-
-void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
- struct variable2json_helper helper = {
- .buf = buf,
- .counter = 0
- };
-
- buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", st->id, st->name, st->context);
- avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
- buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
- helper.counter = 0;
- avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
- buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
- helper.counter = 0;
- avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
- buffer_strcat(buf, "\n\t}\n}\n");
-}
-
-
-// ----------------------------------------------------------------------------
-// RRDDIMVAR management
-// DIMENSION VARIABLES
-
-#define RRDDIMVAR_ID_MAX 1024
-
-static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
- RRDDIM *rd = rs->rrddim;
- RRDSET *st = rd->rrdset;
-
- // CHART VARIABLES FOR THIS DIMENSION
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id);
- rs->var_local_id = NULL;
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name);
- rs->var_local_name = NULL;
-
- // FAMILY VARIABLES FOR THIS DIMENSION
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id);
- rs->var_family_id = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
- rs->var_family_name = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid);
- rs->var_family_contextid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname);
- rs->var_family_contextname = NULL;
-
- // HOST VARIABLES FOR THIS DIMENSION
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid);
- rs->var_host_chartidid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname);
- rs->var_host_chartidname = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid);
- rs->var_host_chartnameid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename);
- rs->var_host_chartnamename = NULL;
-
- // KEYS
-
- freez(rs->key_id);
- rs->key_id = NULL;
-
- freez(rs->key_name);
- rs->key_name = NULL;
-
- freez(rs->key_fullidid);
- rs->key_fullidid = NULL;
-
- freez(rs->key_fullidname);
- rs->key_fullidname = NULL;
-
- freez(rs->key_contextid);
- rs->key_contextid = NULL;
-
- freez(rs->key_contextname);
- rs->key_contextname = NULL;
-
- freez(rs->key_fullnameid);
- rs->key_fullnameid = NULL;
-
- freez(rs->key_fullnamename);
- rs->key_fullnamename = NULL;
-}
-
-static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
- rrddimvar_free_variables(rs);
-
- RRDDIM *rd = rs->rrddim;
- RRDSET *st = rd->rrdset;
-
- char buffer[RRDDIMVAR_ID_MAX + 1];
-
- // KEYS
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
- rs->key_id = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
- rs->key_name = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
- rs->key_fullidid = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
- rs->key_fullidname = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
- rs->key_contextid = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
- rs->key_contextname = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
- rs->key_fullnameid = strdupz(buffer);
-
- snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
- rs->key_fullnamename = strdupz(buffer);
-
- // CHART VARIABLES FOR THIS DIMENSION
- // -----------------------------------
- //
- // dimensions are available as:
- // - $id
- // - $name
-
- rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value);
- rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value);
-
- // FAMILY VARIABLES FOR THIS DIMENSION
- // -----------------------------------
- //
- // dimensions are available as:
- // - $id (only the first, when multiple overlap)
- // - $name (only the first, when multiple overlap)
- // - $chart-context.id
- // - $chart-context.name
-
- rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value);
- rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value);
- rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value);
- rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value);
-
- // HOST VARIABLES FOR THIS DIMENSION
- // -----------------------------------
- //
- // dimensions are available as:
- // - $chart-id.id
- // - $chart-id.name
- // - $chart-name.id
- // - $chart-name.name
-
- rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value);
- rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value);
- rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value);
- rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value);
-}
-
-RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
- RRDSET *st = rd->rrdset;
-
- debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", st->id, st->name, rd->id, (prefix)?prefix:"", rd->name, (suffix)?suffix:"");
-
- if(!prefix) prefix = "";
- if(!suffix) suffix = "";
-
- RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
-
- rs->prefix = strdupz(prefix);
- rs->suffix = strdupz(suffix);
-
- rs->type = type;
- rs->value = value;
- rs->options = options;
- rs->rrddim = rd;
-
- rs->next = rd->variables;
- rd->variables = rs;
-
- rrddimvar_create_variables(rs);
-
- return rs;
-}
-
-void rrddimvar_rename_all(RRDDIM *rd) {
- RRDSET *st = rd->rrdset;
- debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
-
- RRDDIMVAR *rs, *next = rd->variables;
- while((rs = next)) {
- next = rs->next;
- rrddimvar_create_variables(rs);
- }
-}
-
-void rrddimvar_free(RRDDIMVAR *rs) {
- RRDDIM *rd = rs->rrddim;
- RRDSET *st = rd->rrdset;
- debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", st->id, st->name, rd->id, rd->name, rs->prefix, rs->suffix);
-
- rrddimvar_free_variables(rs);
-
- if(rd->variables == rs) {
- debug(D_VARIABLES, "RRDDIMSET removing first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
- rd->variables = rs->next;
- }
- else {
- debug(D_VARIABLES, "RRDDIMSET removing non-first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
- RRDDIMVAR *t;
- for (t = rd->variables; t && t->next != rs; t = t->next) ;
- if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
- else t->next = rs->next;
- }
-
- freez(rs->prefix);
- freez(rs->suffix);
- freez(rs);
-}
-
-// ----------------------------------------------------------------------------
-// RRDSETVAR management
-// CHART VARIABLES
-
-static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
- RRDSET *st = rs->rrdset;
-
- // CHART
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local);
- rs->var_local = NULL;
-
- // FAMILY
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family);
- rs->var_family = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host);
- rs->var_host = NULL;
-
- // HOST
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
- rs->var_family_name = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name);
- rs->var_host_name = NULL;
-
- // KEYS
-
- freez(rs->key_fullid);
- rs->key_fullid = NULL;
-
- freez(rs->key_fullname);
- rs->key_fullname = NULL;
-}
-
-static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
- rrdsetvar_free_variables(rs);
-
- RRDSET *st = rs->rrdset;
-
- // KEYS
-
- char buffer[RRDVAR_MAX_LENGTH + 1];
- snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
- rs->key_fullid = strdupz(buffer);
-
- snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
- rs->key_fullname = strdupz(buffer);
-
- // CHART
-
- rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
-
- // FAMILY
-
- rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value);
- rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value);
-
- // HOST
-
- rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value);
- rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value);
-
-}
-
-RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
- debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
- RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
-
- rs->variable = strdupz(variable);
- rs->type = type;
- rs->value = value;
- rs->options = options;
- rs->rrdset = st;
-
- rs->next = st->variables;
- st->variables = rs;
-
- rrdsetvar_create_variables(rs);
-
- return rs;
-}
-
-void rrdsetvar_rename_all(RRDSET *st) {
- debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
-
- RRDSETVAR *rs, *next = st->variables;
- while((rs = next)) {
- next = rs->next;
- rrdsetvar_create_variables(rs);
- }
-
- rrdsetcalc_link_matching(st);
-}
-
-void rrdsetvar_free(RRDSETVAR *rs) {
- RRDSET *st = rs->rrdset;
- debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
-
- if(st->variables == rs) {
- st->variables = rs->next;
- }
- else {
- RRDSETVAR *t;
- for (t = st->variables; t && t->next != rs; t = t->next);
- if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
- else t->next = rs->next;
- }
-
- rrdsetvar_free_variables(rs);
-
- freez(rs->variable);
- freez(rs);
-}
-
-// ----------------------------------------------------------------------------
-// RRDCALC management
-
-inline const char *rrdcalc_status2string(int status) {
- switch(status) {
- case RRDCALC_STATUS_REMOVED:
- return "REMOVED";
-
- case RRDCALC_STATUS_UNDEFINED:
- return "UNDEFINED";
-
- case RRDCALC_STATUS_UNINITIALIZED:
- return "UNINITIALIZED";
-
- case RRDCALC_STATUS_CLEAR:
- return "CLEAR";
-
- case RRDCALC_STATUS_RAISED:
- return "RAISED";
-
- case RRDCALC_STATUS_WARNING:
- return "WARNING";
-
- case RRDCALC_STATUS_CRITICAL:
- return "CRITICAL";
-
- default:
- error("Unknown alarm status %d", status);
- return "UNKNOWN";
- }
-}
-
-static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
- debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
-
- rc->last_status_change = now_realtime_sec();
- rc->rrdset = st;
-
- rc->rrdset_next = st->alarms;
- rc->rrdset_prev = NULL;
-
- if(rc->rrdset_next)
- rc->rrdset_next->rrdset_prev = rc;
-
- st->alarms = rc;
-
- if(rc->update_every < rc->rrdset->update_every) {
- error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
- rc->update_every = rc->rrdset->update_every;
- }
-
- if(!isnan(rc->green) && isnan(st->green)) {
- debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
- st->green = rc->green;
- }
-
- if(!isnan(rc->red) && isnan(st->red)) {
- debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
- st->red = rc->red;
- }
-
- rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
- rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
-
- char fullname[RRDVAR_MAX_LENGTH + 1];
- snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
- rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
-
- snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
- rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
-
- if(!rc->units) rc->units = strdupz(st->units);
-
- {
- time_t now = now_realtime_sec();
- health_alarm_log(st->rrdhost, rc->id, rc->next_event_id++, now, rc->name, rc->rrdset->id, rc->rrdset->family, rc->exec, rc->recipient, now - rc->last_status_change, rc->old_value, rc->value, rc->status, RRDCALC_STATUS_UNINITIALIZED, rc->source, rc->units, rc->info, 0);
- }
-}
-
-static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
- if( (rc->hash_chart == st->hash && !strcmp(rc->chart, st->id)) ||
- (rc->hash_chart == st->hash_name && !strcmp(rc->chart, st->name)))
- return 1;
-
- return 0;
-}
-
-// this has to be called while the RRDHOST is locked
-inline void rrdsetcalc_link_matching(RRDSET *st) {
- // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
-
- RRDCALC *rc;
- for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
- if(unlikely(rc->rrdset))
- continue;
-
- if(unlikely(rrdcalc_is_matching_this_rrdset(rc, st)))
- rrdsetcalc_link(st, rc);
- }
-}
-
-// this has to be called while the RRDHOST is locked
-inline void rrdsetcalc_unlink(RRDCALC *rc) {
- RRDSET *st = rc->rrdset;
-
- if(!st) {
- debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
- error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
- return;
- }
-
- {
- time_t now = now_realtime_sec();
- health_alarm_log(st->rrdhost, rc->id, rc->next_event_id++, now, rc->name, rc->rrdset->id, rc->rrdset->family, rc->exec, rc->recipient, now - rc->last_status_change, rc->old_value, rc->value, rc->status, RRDCALC_STATUS_REMOVED, rc->source, rc->units, rc->info, 0);
- }
-
- RRDHOST *host = st->rrdhost;
-
- debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
-
- // unlink it
- if(rc->rrdset_prev)
- rc->rrdset_prev->rrdset_next = rc->rrdset_next;
-
- if(rc->rrdset_next)
- rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
-
- if(st->alarms == rc)
- st->alarms = rc->rrdset_next;
-
- rc->rrdset_prev = rc->rrdset_next = NULL;
-
- rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
- rc->local = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family);
- rc->family = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
- rc->hostid = NULL;
-
- rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
- rc->hostname = NULL;
-
- rc->rrdset = NULL;
-
- // RRDCALC will remain in RRDHOST
- // so that if the matching chart is found in the future
- // it will be applied automatically
-}
-
-RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
- RRDCALC *rc;
- uint32_t hash = simple_hash(name);
-
- for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
- if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
- return rc;
- }
-
- return NULL;
-}
-
-static inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
- RRDCALC *rc;
-
- if(unlikely(!chart)) {
- error("attempt to find RRDCALC '%s' without giving a chart name", name);
- return 1;
- }
-
- if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
- if(unlikely(!hash_name)) hash_name = simple_hash(name);
-
- // make sure it does not already exist
- for(rc = host->alarms; rc ; rc = rc->next) {
- if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
- debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
- error("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
- return 1;
- }
- }
-
- return 0;
-}
-
-static inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
- if(chart && name) {
- uint32_t hash_chart = simple_hash(chart);
- uint32_t hash_name = simple_hash(name);
-
- // re-use old IDs, by looking them up in the alarm log
- ALARM_ENTRY *ae;
- for(ae = host->health_log.alarms; ae ;ae = ae->next) {
- if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
- if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
- return ae->alarm_id;
- }
- }
- }
-
- return host->health_log.next_alarm_id++;
-}
-
-static inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
- rrdhost_check_rdlock(host);
-
- if(rc->calculation) {
- rc->calculation->status = &rc->status;
- rc->calculation->this = &rc->value;
- rc->calculation->after = &rc->db_after;
- rc->calculation->before = &rc->db_before;
- rc->calculation->rrdcalc = rc;
- }
-
- if(rc->warning) {
- rc->warning->status = &rc->status;
- rc->warning->this = &rc->value;
- rc->warning->after = &rc->db_after;
- rc->warning->before = &rc->db_before;
- rc->warning->rrdcalc = rc;
- }
-
- if(rc->critical) {
- rc->critical->status = &rc->status;
- rc->critical->this = &rc->value;
- rc->critical->after = &rc->db_after;
- rc->critical->before = &rc->db_before;
- rc->critical->rrdcalc = rc;
- }
-
- // link it to the host
- if(likely(host->alarms)) {
- // append it
- RRDCALC *t;
- for(t = host->alarms; t && t->next ; t = t->next) ;
- t->next = rc;
- }
- else {
- host->alarms = rc;
- }
-
- // link it to its chart
- RRDSET *st;
- for(st = host->rrdset_root; st ; st = st->next) {
- if(rrdcalc_is_matching_this_rrdset(rc, st)) {
- rrdsetcalc_link(st, rc);
- break;
- }
- }
-}
-
-static inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
-
- debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
-
- if(rrdcalc_exists(host, chart, rt->name, 0, 0))
- return NULL;
-
- RRDCALC *rc = callocz(1, sizeof(RRDCALC));
- rc->next_event_id = 1;
- rc->id = rrdcalc_get_unique_id(host, chart, rt->name, &rc->next_event_id);
- rc->name = strdupz(rt->name);
- rc->hash = simple_hash(rc->name);
- rc->chart = strdupz(chart);
- rc->hash_chart = simple_hash(rc->chart);
-
- if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
-
- rc->green = rt->green;
- rc->red = rt->red;
- rc->value = NAN;
- rc->old_value = NAN;
-
- rc->delay_up_duration = rt->delay_up_duration;
- rc->delay_down_duration = rt->delay_down_duration;
- rc->delay_max_duration = rt->delay_max_duration;
- rc->delay_multiplier = rt->delay_multiplier;
-
- rc->group = rt->group;
- rc->after = rt->after;
- rc->before = rt->before;
- rc->update_every = rt->update_every;
- rc->options = rt->options;
-
- if(rt->exec) rc->exec = strdupz(rt->exec);
- if(rt->recipient) rc->recipient = strdupz(rt->recipient);
- if(rt->source) rc->source = strdupz(rt->source);
- if(rt->units) rc->units = strdupz(rt->units);
- if(rt->info) rc->info = strdupz(rt->info);
-
- if(rt->calculation) {
- rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
- if(!rc->calculation)
- error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
- }
- if(rt->warning) {
- rc->warning = expression_parse(rt->warning->source, NULL, NULL);
- if(!rc->warning)
- error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
- }
- if(rt->critical) {
- rc->critical = expression_parse(rt->critical->source, NULL, NULL);
- if(!rc->critical)
- error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
- }
-
- debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
- (rc->chart)?rc->chart:"NOCHART",
- rc->name,
- (rc->exec)?rc->exec:"DEFAULT",
- (rc->recipient)?rc->recipient:"DEFAULT",
- rc->green,
- rc->red,
- rc->group,
- rc->after,
- rc->before,
- rc->options,
- (rc->dimensions)?rc->dimensions:"NONE",
- rc->update_every,
- (rc->calculation)?rc->calculation->parsed_as:"NONE",
- (rc->warning)?rc->warning->parsed_as:"NONE",
- (rc->critical)?rc->critical->parsed_as:"NONE",
- rc->source,
- rc->delay_up_duration,
- rc->delay_down_duration,
- rc->delay_max_duration,
- rc->delay_multiplier
- );
-
- rrdcalc_create_part2(host, rc);
- return rc;
-}
-
-void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
- if(!rc) return;
-
- debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
-
- // unlink it from RRDSET
- if(rc->rrdset) rrdsetcalc_unlink(rc);
-
- // unlink it from RRDHOST
- if(unlikely(rc == host->alarms))
- host->alarms = rc->next;
-
- else if(likely(host->alarms)) {
- RRDCALC *t, *last = host->alarms;
- for(t = last->next; t && t != rc; last = t, t = t->next) ;
- if(last->next == rc)
- last->next = rc->next;
- else
- error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
- }
- else
- error("Cannot unlink unlink '%s.%s' from host '%s': This host does not have any calculations", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
-
- expression_free(rc->calculation);
- expression_free(rc->warning);
- expression_free(rc->critical);
-
- freez(rc->name);
- freez(rc->chart);
- freez(rc->family);
- freez(rc->dimensions);
- freez(rc->exec);
- freez(rc->recipient);
- freez(rc->source);
- freez(rc->units);
- freez(rc->info);
- freez(rc);
-}
+int default_health_enabled = 1;
// ----------------------------------------------------------------------------
-// RRDCALCTEMPLATE management
-
-void rrdcalctemplate_link_matching(RRDSET *st) {
- RRDCALCTEMPLATE *rt;
-
- for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
- if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)
- && (!rt->family_pattern || simple_pattern_matches(rt->family_pattern, st->family))) {
- RRDCALC *rc = rrdcalc_create(st->rrdhost, rt, st->id);
- if(unlikely(!rc))
- error("Health tried to create alarm from template '%s', but it failed", rt->name);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- else if(rc->rrdset != st)
- error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
-#endif
- }
- }
-}
-
-static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
- debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
-
- if(host->templates) {
- if(host->templates == rt) {
- host->templates = rt->next;
- }
- else {
- RRDCALCTEMPLATE *t, *last = host->templates;
- for (t = last->next; t && t != rt; last = t, t = t->next ) ;
- if(last && last->next == rt) {
- last->next = rt->next;
- rt->next = NULL;
- }
- else
- error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
- }
- }
-
- expression_free(rt->calculation);
- expression_free(rt->warning);
- expression_free(rt->critical);
-
- freez(rt->family_match);
- simple_pattern_free(rt->family_pattern);
-
- freez(rt->name);
- freez(rt->exec);
- freez(rt->recipient);
- freez(rt->context);
- freez(rt->source);
- freez(rt->units);
- freez(rt->info);
- freez(rt->dimensions);
- freez(rt);
-}
-
-// ----------------------------------------------------------------------------
-// load health configuration
-
-#define HEALTH_CONF_MAX_LINE 4096
-
-#define HEALTH_ALARM_KEY "alarm"
-#define HEALTH_TEMPLATE_KEY "template"
-#define HEALTH_ON_KEY "on"
-#define HEALTH_FAMILIES_KEY "families"
-#define HEALTH_LOOKUP_KEY "lookup"
-#define HEALTH_CALC_KEY "calc"
-#define HEALTH_EVERY_KEY "every"
-#define HEALTH_GREEN_KEY "green"
-#define HEALTH_RED_KEY "red"
-#define HEALTH_WARN_KEY "warn"
-#define HEALTH_CRIT_KEY "crit"
-#define HEALTH_EXEC_KEY "exec"
-#define HEALTH_RECIPIENT_KEY "to"
-#define HEALTH_UNITS_KEY "units"
-#define HEALTH_INFO_KEY "info"
-#define HEALTH_DELAY_KEY "delay"
-
-static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
- if(!rc->chart) {
- error("Health configuration for alarm '%s' does not have a chart", rc->name);
- return 0;
- }
+// health initialization
- if(!rc->update_every) {
- error("Health configuration for alarm '%s.%s' has no frequency (parameter 'every'). Ignoring it.", rc->chart?rc->chart:"NOCHART", rc->name);
- return 0;
- }
-
- if(!RRDCALC_HAS_DB_LOOKUP(rc) && !rc->warning && !rc->critical) {
- error("Health configuration for alarm '%s.%s' is useless (no calculation, no warning and no critical evaluation)", rc->chart?rc->chart:"NOCHART", rc->name);
- return 0;
- }
-
- if (rrdcalc_exists(host, rc->chart, rc->name, rc->hash_chart, rc->hash))
- return 0;
-
- rc->id = rrdcalc_get_unique_id(&localhost, rc->chart, rc->name, &rc->next_event_id);
-
- debug(D_HEALTH, "Health configuration adding alarm '%s.%s' (%u): exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
- rc->chart?rc->chart:"NOCHART",
- rc->name,
- rc->id,
- (rc->exec)?rc->exec:"DEFAULT",
- (rc->recipient)?rc->recipient:"DEFAULT",
- rc->green,
- rc->red,
- rc->group,
- rc->after,
- rc->before,
- rc->options,
- (rc->dimensions)?rc->dimensions:"NONE",
- rc->update_every,
- (rc->calculation)?rc->calculation->parsed_as:"NONE",
- (rc->warning)?rc->warning->parsed_as:"NONE",
- (rc->critical)?rc->critical->parsed_as:"NONE",
- rc->source,
- rc->delay_up_duration,
- rc->delay_down_duration,
- rc->delay_max_duration,
- rc->delay_multiplier
- );
-
- rrdcalc_create_part2(host, rc);
- return 1;
-}
-
-static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCALCTEMPLATE *rt) {
- if(unlikely(!rt->context)) {
- error("Health configuration for template '%s' does not have a context", rt->name);
- return 0;
- }
-
- if(unlikely(!rt->update_every)) {
- error("Health configuration for template '%s' has no frequency (parameter 'every'). Ignoring it.", rt->name);
- return 0;
- }
-
- if(unlikely(!RRDCALCTEMPLATE_HAS_CALCULATION(rt) && !rt->warning && !rt->critical)) {
- error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
- return 0;
- }
-
- RRDCALCTEMPLATE *t, *last = NULL;
- for (t = host->templates; t ; last = t, t = t->next) {
- if(unlikely(t->hash_name == rt->hash_name && !strcmp(t->name, rt->name))) {
- error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
- return 0;
- }
- }
-
- debug(D_HEALTH, "Health configuration adding template '%s': context '%s', exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
- rt->name,
- (rt->context)?rt->context:"NONE",
- (rt->exec)?rt->exec:"DEFAULT",
- (rt->recipient)?rt->recipient:"DEFAULT",
- rt->green,
- rt->red,
- rt->group,
- rt->after,
- rt->before,
- rt->options,
- (rt->dimensions)?rt->dimensions:"NONE",
- rt->update_every,
- (rt->calculation)?rt->calculation->parsed_as:"NONE",
- (rt->warning)?rt->warning->parsed_as:"NONE",
- (rt->critical)?rt->critical->parsed_as:"NONE",
- rt->source,
- rt->delay_up_duration,
- rt->delay_down_duration,
- rt->delay_max_duration,
- rt->delay_multiplier
- );
-
- if(likely(last)) {
- last->next = rt;
- }
- else {
- rt->next = host->templates;
- host->templates = rt;
- }
-
- return 1;
-}
-
-static inline int health_parse_duration(char *string, int *result) {
- // make sure it is a number
- if(!*string || !(isdigit(*string) || *string == '+' || *string == '-')) {
- *result = 0;
- return 0;
- }
-
- char *e = NULL;
- calculated_number n = strtold(string, &e);
- if(e && *e) {
- switch (*e) {
- case 'Y':
- *result = (int) (n * 86400 * 365);
- break;
- case 'M':
- *result = (int) (n * 86400 * 30);
- break;
- case 'w':
- *result = (int) (n * 86400 * 7);
- break;
- case 'd':
- *result = (int) (n * 86400);
- break;
- case 'h':
- *result = (int) (n * 3600);
- break;
- case 'm':
- *result = (int) (n * 60);
- break;
-
- default:
- case 's':
- *result = (int) (n);
- break;
- }
- }
- else
- *result = (int)(n);
-
- return 1;
-}
-
-static inline int health_parse_delay(
- size_t line, const char *path, const char *file, char *string,
- int *delay_up_duration,
- int *delay_down_duration,
- int *delay_max_duration,
- float *delay_multiplier) {
-
- char given_up = 0;
- char given_down = 0;
- char given_max = 0;
- char given_multiplier = 0;
-
- char *s = string;
- while(*s) {
- char *key = s;
-
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if(!*key) break;
-
- char *value = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if(!strcasecmp(key, "up")) {
- if (!health_parse_duration(value, delay_up_duration)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_up = 1;
- }
- else if(!strcasecmp(key, "down")) {
- if (!health_parse_duration(value, delay_down_duration)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_down = 1;
- }
- else if(!strcasecmp(key, "multiplier")) {
- *delay_multiplier = strtof(value, NULL);
- if(isnan(*delay_multiplier) || isinf(*delay_multiplier) || islessequal(*delay_multiplier, 0)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_multiplier = 1;
- }
- else if(!strcasecmp(key, "max")) {
- if (!health_parse_duration(value, delay_max_duration)) {
- error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- else given_max = 1;
- }
- else {
- error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
- line, path, file, key);
- }
- }
-
- if(!given_up)
- *delay_up_duration = 0;
-
- if(!given_down)
- *delay_down_duration = 0;
-
- if(!given_multiplier)
- *delay_multiplier = 1.0;
-
- if(!given_max) {
- if((*delay_max_duration) < (*delay_up_duration) * (*delay_multiplier))
- *delay_max_duration = (*delay_up_duration) * (*delay_multiplier);
-
- if((*delay_max_duration) < (*delay_down_duration) * (*delay_multiplier))
- *delay_max_duration = (*delay_down_duration) * (*delay_multiplier);
- }
-
- return 1;
-}
-
-static inline int health_parse_db_lookup(
- size_t line, const char *path, const char *file, char *string,
- int *group_method, int *after, int *before, int *every,
- uint32_t *options, char **dimensions
-) {
- debug(D_HEALTH, "Health configuration parsing database lookup %zu@%s/%s: %s", line, path, file, string);
-
- if(*dimensions) freez(*dimensions);
- *dimensions = NULL;
- *after = 0;
- *before = 0;
- *every = 0;
- *options = 0;
-
- char *s = string, *key;
-
- // first is the group method
- key = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
- if(!*s) {
- error("Health configuration invalid chart calculation at line %zu of file '%s/%s': expected group method followed by the 'after' time, but got '%s'",
- line, path, file, key);
- return 0;
- }
-
- if((*group_method = web_client_api_request_v1_data_group(key, -1)) == -1) {
- error("Health configuration at line %zu of file '%s/%s': invalid group method '%s'",
- line, path, file, key);
- return 0;
- }
-
- // then is the 'after' time
- key = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if(!health_parse_duration(key, after)) {
- error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' after group method",
- line, path, file, key);
- return 0;
- }
-
- // sane defaults
- *every = abs(*after);
-
- // now we may have optional parameters
- while(*s) {
- key = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
- if(!*key) break;
-
- if(!strcasecmp(key, "at")) {
- char *value = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if (!health_parse_duration(value, before)) {
- error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- }
- else if(!strcasecmp(key, HEALTH_EVERY_KEY)) {
- char *value = s;
- while(*s && !isspace(*s)) s++;
- while(*s && isspace(*s)) *s++ = '\0';
-
- if (!health_parse_duration(value, every)) {
- error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
- line, path, file, value, key);
- }
- }
- else if(!strcasecmp(key, "absolute") || !strcasecmp(key, "abs") || !strcasecmp(key, "absolute_sum")) {
- *options |= RRDR_OPTION_ABSOLUTE;
- }
- else if(!strcasecmp(key, "min2max")) {
- *options |= RRDR_OPTION_MIN2MAX;
- }
- else if(!strcasecmp(key, "null2zero")) {
- *options |= RRDR_OPTION_NULL2ZERO;
- }
- else if(!strcasecmp(key, "percentage")) {
- *options |= RRDR_OPTION_PERCENTAGE;
- }
- else if(!strcasecmp(key, "unaligned")) {
- *options |= RRDR_OPTION_NOT_ALIGNED;
- }
- else if(!strcasecmp(key, "of")) {
- if(*s && strcasecmp(s, "all"))
- *dimensions = strdupz(s);
- break;
- }
- else {
- error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
- line, path, file, key);
- }
- }
-
- return 1;
-}
-
-static inline char *tabs2spaces(char *s) {
- char *t = s;
- while(*t) {
- if(unlikely(*t == '\t')) *t = ' ';
- t++;
- }
-
- return s;
-}
-
-static inline char *health_source_file(size_t line, const char *path, const char *filename) {
+inline char *health_config_dir(void) {
char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%zu@%s/%s", line, path, filename);
- return strdupz(buffer);
-}
-
-static inline void strip_quotes(char *s) {
- while(*s) {
- if(*s == '\'' || *s == '"') *s = ' ';
- s++;
- }
-}
-
-int health_readfile(const char *path, const char *filename) {
- debug(D_HEALTH, "Health configuration reading file '%s/%s'", path, filename);
-
- static uint32_t hash_alarm = 0, hash_template = 0, hash_on = 0, hash_families = 0, hash_calc = 0, hash_green = 0, hash_red = 0, hash_warn = 0, hash_crit = 0, hash_exec = 0, hash_every = 0, hash_lookup = 0, hash_units = 0, hash_info = 0, hash_recipient = 0, hash_delay = 0;
- char buffer[HEALTH_CONF_MAX_LINE + 1];
-
- if(unlikely(!hash_alarm)) {
- hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
- hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
- hash_on = simple_uhash(HEALTH_ON_KEY);
- hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
- hash_calc = simple_uhash(HEALTH_CALC_KEY);
- hash_lookup = simple_uhash(HEALTH_LOOKUP_KEY);
- hash_green = simple_uhash(HEALTH_GREEN_KEY);
- hash_red = simple_uhash(HEALTH_RED_KEY);
- hash_warn = simple_uhash(HEALTH_WARN_KEY);
- hash_crit = simple_uhash(HEALTH_CRIT_KEY);
- hash_exec = simple_uhash(HEALTH_EXEC_KEY);
- hash_every = simple_uhash(HEALTH_EVERY_KEY);
- hash_units = simple_hash(HEALTH_UNITS_KEY);
- hash_info = simple_hash(HEALTH_INFO_KEY);
- hash_recipient = simple_hash(HEALTH_RECIPIENT_KEY);
- hash_delay = simple_uhash(HEALTH_DELAY_KEY);
- }
-
- snprintfz(buffer, HEALTH_CONF_MAX_LINE, "%s/%s", path, filename);
- FILE *fp = fopen(buffer, "r");
- if(!fp) {
- error("Health configuration cannot read file '%s'.", buffer);
- return 0;
- }
-
- RRDCALC *rc = NULL;
- RRDCALCTEMPLATE *rt = NULL;
-
- size_t line = 0, append = 0;
- char *s;
- while((s = fgets(&buffer[append], (int)(HEALTH_CONF_MAX_LINE - append), fp)) || append) {
- int stop_appending = !s;
- line++;
- s = trim(buffer);
- if(!s) continue;
-
- append = strlen(s);
- if(!stop_appending && s[append - 1] == '\\') {
- s[append - 1] = ' ';
- append = &s[append] - buffer;
- if(append < HEALTH_CONF_MAX_LINE)
- continue;
- else {
- error("Health configuration has too long muli-line at line %zu of file '%s/%s'.", line, path, filename);
- }
- }
- append = 0;
-
- char *key = s;
- while(*s && *s != ':') s++;
- if(!*s) {
- error("Health configuration has invalid line %zu of file '%s/%s'. It does not contain a ':'. Ignoring it.", line, path, filename);
- continue;
- }
- *s = '\0';
- s++;
-
- char *value = s;
- key = trim(key);
- value = trim(value);
-
- if(!key) {
- error("Health configuration has invalid line %zu of file '%s/%s'. Keyword is empty. Ignoring it.", line, path, filename);
- continue;
- }
-
- if(!value) {
- error("Health configuration has invalid line %zu of file '%s/%s'. value is empty. Ignoring it.", line, path, filename);
- continue;
- }
-
- uint32_t hash = simple_uhash(key);
-
- if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
- if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
- rrdcalc_free(&localhost, rc);
-
- if(rt) {
- if (!rrdcalctemplate_add_template_from_config(&localhost, rt))
- rrdcalctemplate_free(&localhost, rt);
- rt = NULL;
- }
-
- rc = callocz(1, sizeof(RRDCALC));
- rc->next_event_id = 1;
- rc->name = tabs2spaces(strdupz(value));
- rc->hash = simple_hash(rc->name);
- rc->source = health_source_file(line, path, filename);
- rc->green = NAN;
- rc->red = NAN;
- rc->value = NAN;
- rc->old_value = NAN;
- rc->delay_multiplier = 1.0;
-
- if(rrdvar_fix_name(rc->name))
- error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
- }
- else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
- if(rc) {
- if(!rrdcalc_add_alarm_from_config(&localhost, rc))
- rrdcalc_free(&localhost, rc);
- rc = NULL;
- }
-
- if(rt && !rrdcalctemplate_add_template_from_config(&localhost, rt))
- rrdcalctemplate_free(&localhost, rt);
-
- rt = callocz(1, sizeof(RRDCALCTEMPLATE));
- rt->name = tabs2spaces(strdupz(value));
- rt->hash_name = simple_hash(rt->name);
- rt->source = health_source_file(line, path, filename);
- rt->green = NAN;
- rt->red = NAN;
- rt->delay_multiplier = 1.0;
-
- if(rrdvar_fix_name(rt->name))
- error("Health configuration renamed template '%s' to '%s'", value, rt->name);
- }
- else if(rc) {
- if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
- if(rc->chart) {
- if(strcmp(rc->chart, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->chart, value, value);
-
- freez(rc->chart);
- }
- rc->chart = tabs2spaces(strdupz(value));
- rc->hash_chart = simple_hash(rc->chart);
- }
- else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
- health_parse_db_lookup(line, path, filename, value, &rc->group, &rc->after, &rc->before,
- &rc->update_every,
- &rc->options, &rc->dimensions);
- }
- else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
- if(!health_parse_duration(value, &rc->update_every))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' cannot parse duration: '%s'.",
- line, path, filename, rc->name, key, value);
- }
- else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
- char *e;
- rc->green = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rc->name, key, e);
- }
- }
- else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
- char *e;
- rc->red = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rc->name, key, e);
- }
- }
- else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rc->calculation = expression_parse(value, &failed_at, &error);
- if(!rc->calculation) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rc->warning = expression_parse(value, &failed_at, &error);
- if(!rc->warning) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rc->critical = expression_parse(value, &failed_at, &error);
- if(!rc->critical) {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
- if(rc->exec) {
- if(strcmp(rc->exec, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->exec, value, value);
-
- freez(rc->exec);
- }
- rc->exec = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
- if(rc->recipient) {
- if(strcmp(rc->recipient, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->recipient, value, value);
-
- freez(rc->recipient);
- }
- rc->recipient = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
- if(rc->units) {
- if(strcmp(rc->units, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->units, value, value);
-
- freez(rc->units);
- }
- rc->units = tabs2spaces(strdupz(value));
- strip_quotes(rc->units);
- }
- else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
- if(rc->info) {
- if(strcmp(rc->info, value))
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rc->name, key, rc->info, value, value);
-
- freez(rc->info);
- }
- rc->info = tabs2spaces(strdupz(value));
- strip_quotes(rc->info);
- }
- else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
- health_parse_delay(line, path, filename, value, &rc->delay_up_duration, &rc->delay_down_duration, &rc->delay_max_duration, &rc->delay_multiplier);
- }
- else {
- error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has unknown key '%s'.",
- line, path, filename, rc->name, key);
- }
- }
- else if(rt) {
- if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
- if(rt->context) {
- if(strcmp(rt->context, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->context, value, value);
-
- freez(rt->context);
- }
- rt->context = tabs2spaces(strdupz(value));
- rt->hash_context = simple_hash(rt->context);
- }
- else if(hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
- freez(rt->family_match);
- simple_pattern_free(rt->family_pattern);
-
- rt->family_match = tabs2spaces(strdupz(value));
- rt->family_pattern = simple_pattern_create(rt->family_match, SIMPLE_PATTERN_EXACT);
- }
- else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
- health_parse_db_lookup(line, path, filename, value, &rt->group, &rt->after, &rt->before,
- &rt->update_every, &rt->options, &rt->dimensions);
- }
- else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
- if(!health_parse_duration(value, &rt->update_every))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' cannot parse duration: '%s'.",
- line, path, filename, rt->name, key, value);
- }
- else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
- char *e;
- rt->green = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rt->name, key, e);
- }
- }
- else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
- char *e;
- rt->red = strtold(value, &e);
- if(e && *e) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
- line, path, filename, rt->name, key, e);
- }
- }
- else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rt->calculation = expression_parse(value, &failed_at, &error);
- if(!rt->calculation) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rt->warning = expression_parse(value, &failed_at, &error);
- if(!rt->warning) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
- const char *failed_at = NULL;
- int error = 0;
- rt->critical = expression_parse(value, &failed_at, &error);
- if(!rt->critical) {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
- line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
- }
- }
- else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
- if(rt->exec) {
- if(strcmp(rt->exec, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->exec, value, value);
-
- freez(rt->exec);
- }
- rt->exec = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
- if(rt->recipient) {
- if(strcmp(rt->recipient, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->recipient, value, value);
-
- freez(rt->recipient);
- }
- rt->recipient = tabs2spaces(strdupz(value));
- }
- else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
- if(rt->units) {
- if(strcmp(rt->units, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->units, value, value);
-
- freez(rt->units);
- }
- rt->units = tabs2spaces(strdupz(value));
- strip_quotes(rt->units);
- }
- else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
- if(rt->info) {
- if(strcmp(rt->info, value))
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
- line, path, filename, rt->name, key, rt->info, value, value);
-
- freez(rt->info);
- }
- rt->info = tabs2spaces(strdupz(value));
- strip_quotes(rt->info);
- }
- else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
- health_parse_delay(line, path, filename, value, &rt->delay_up_duration, &rt->delay_down_duration, &rt->delay_max_duration, &rt->delay_multiplier);
- }
- else {
- error("Health configuration at line %zu of file '%s/%s' for template '%s' has unknown key '%s'.",
- line, path, filename, rt->name, key);
- }
- }
- else {
- error("Health configuration at line %zu of file '%s/%s' has unknown key '%s'. Expected either '" HEALTH_ALARM_KEY "' or '" HEALTH_TEMPLATE_KEY "'.",
- line, path, filename, key);
- }
- }
-
- if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
- rrdcalc_free(&localhost, rc);
-
- if(rt && !rrdcalctemplate_add_template_from_config(&localhost, rt))
- rrdcalctemplate_free(&localhost, rt);
-
- fclose(fp);
- return 1;
-}
-
-void health_readdir(const char *path) {
- size_t pathlen = strlen(path);
-
- debug(D_HEALTH, "Health configuration reading directory '%s'", path);
-
- DIR *dir = opendir(path);
- if (!dir) {
- error("Health configuration cannot open directory '%s'.", path);
- return;
- }
-
- struct dirent *de = NULL;
- while ((de = readdir(dir))) {
- size_t len = strlen(de->d_name);
-
- if(de->d_type == DT_DIR
- && (
- (de->d_name[0] == '.' && de->d_name[1] == '\0')
- || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
- )) {
- debug(D_HEALTH, "Ignoring directory '%s'", de->d_name);
- continue;
- }
-
- else if(de->d_type == DT_DIR) {
- char *s = mallocz(pathlen + strlen(de->d_name) + 2);
- strcpy(s, path);
- strcat(s, "/");
- strcat(s, de->d_name);
- health_readdir(s);
- freez(s);
- continue;
- }
-
- else if((de->d_type == DT_LNK || de->d_type == DT_REG || de->d_type == DT_UNKNOWN) &&
- len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
- health_readfile(path, de->d_name);
- }
-
- else debug(D_HEALTH, "Ignoring file '%s'", de->d_name);
- }
-
- closedir(dir);
-}
-
-static inline char *health_config_dir(void) {
- char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%s/health.d", config_get("global", "config directory", CONFIG_DIR));
- return config_get("health", "health configuration directory", buffer);
+ snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_config_dir);
+ return config_get(CONFIG_SECTION_HEALTH, "health configuration directory", buffer);
}
void health_init(void) {
debug(D_HEALTH, "Health configuration initializing");
- if(!(health_enabled = config_get_boolean("health", "enabled", 1))) {
+ if(!(default_health_enabled = config_get_boolean(CONFIG_SECTION_HEALTH, "enabled", 1))) {
debug(D_HEALTH, "Health is disabled.");
return;
}
-
- char *pathname = config_get("health", "health db directory", VARLIB_DIR "/health");
- if(mkdir(pathname, 0770) == -1 && errno != EEXIST)
- fatal("Cannot create directory '%s'.", pathname);
-
- char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/health-log.db", pathname);
- health.log_filename = config_get("health", "health db file", filename);
-
- health_alarm_log_load(&localhost);
- health_alarm_log_open();
-
- char *path = health_config_dir();
-
- {
- char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%s/alarm-notify.sh", config_get("global", "plugins directory", PLUGINS_DIR));
- health.health_default_exec = config_get("health", "script to execute on alarm", buffer);
- }
-
- long n = config_get_number("health", "in memory max health log entries", (long)localhost.health_log.max);
- if(n < 10) {
- error("Health configuration has invalid max log entries %ld. Using default %u", n, localhost.health_log.max);
- config_set_number("health", "in memory max health log entries", (long)localhost.health_log.max);
- }
- else localhost.health_log.max = (unsigned int)n;
-
- rrdhost_rwlock(&localhost);
- health_readdir(path);
- rrdhost_unlock(&localhost);
}
// ----------------------------------------------------------------------------
-// JSON generation
-
-static inline void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix) {
- if(value && *value)
- buffer_sprintf(wb, "%s\"%s\":\"%s\"%s", prefix, label, value, suffix);
- else
- buffer_sprintf(wb, "%s\"%s\":null%s", prefix, label, suffix);
-}
-
-static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host) {
- buffer_sprintf(wb, "\n\t{\n"
- "\t\t\"hostname\": \"%s\",\n"
- "\t\t\"unique_id\": %u,\n"
- "\t\t\"alarm_id\": %u,\n"
- "\t\t\"alarm_event_id\": %u,\n"
- "\t\t\"name\": \"%s\",\n"
- "\t\t\"chart\": \"%s\",\n"
- "\t\t\"family\": \"%s\",\n"
- "\t\t\"processed\": %s,\n"
- "\t\t\"updated\": %s,\n"
- "\t\t\"exec_run\": %lu,\n"
- "\t\t\"exec_failed\": %s,\n"
- "\t\t\"exec\": \"%s\",\n"
- "\t\t\"recipient\": \"%s\",\n"
- "\t\t\"exec_code\": %d,\n"
- "\t\t\"source\": \"%s\",\n"
- "\t\t\"units\": \"%s\",\n"
- "\t\t\"info\": \"%s\",\n"
- "\t\t\"when\": %lu,\n"
- "\t\t\"duration\": %lu,\n"
- "\t\t\"non_clear_duration\": %lu,\n"
- "\t\t\"status\": \"%s\",\n"
- "\t\t\"old_status\": \"%s\",\n"
- "\t\t\"delay\": %d,\n"
- "\t\t\"delay_up_to_timestamp\": %lu,\n"
- "\t\t\"updated_by_id\": %u,\n"
- "\t\t\"updates_id\": %u,\n",
- host->hostname,
- ae->unique_id,
- ae->alarm_id,
- ae->alarm_event_id,
- ae->name,
- ae->chart,
- ae->family,
- (ae->flags & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false",
- (ae->flags & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false",
- (unsigned long)ae->exec_run_timestamp,
- (ae->flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false",
- ae->exec?ae->exec:health.health_default_exec,
- ae->recipient?ae->recipient:health.health_default_recipient,
- ae->exec_code,
- ae->source,
- ae->units?ae->units:"",
- ae->info?ae->info:"",
- (unsigned long)ae->when,
- (unsigned long)ae->duration,
- (unsigned long)ae->non_clear_duration,
- rrdcalc_status2string(ae->new_status),
- rrdcalc_status2string(ae->old_status),
- ae->delay,
- (unsigned long)ae->delay_up_to_timestamp,
- ae->updated_by_id,
- ae->updates_id
- );
-
- buffer_strcat(wb, "\t\t\"value\":");
- buffer_rrd_value(wb, ae->new_value);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\t\"old_value\":");
- buffer_rrd_value(wb, ae->old_value);
- buffer_strcat(wb, "\n");
-
- buffer_strcat(wb, "\t}");
-}
-
-void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after) {
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
-
- buffer_strcat(wb, "[");
-
- unsigned int max = host->health_log.max;
- unsigned int count = 0;
- ALARM_ENTRY *ae;
- for(ae = host->health_log.alarms; ae && count < max ; count++, ae = ae->next) {
- if(ae->unique_id > after) {
- if(likely(count)) buffer_strcat(wb, ",");
- health_alarm_entry2json_nolock(wb, ae, host);
- }
- }
-
- buffer_strcat(wb, "\n]\n");
-
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
-}
-
-static inline void health_rrdcalc2json_nolock(BUFFER *wb, RRDCALC *rc) {
- buffer_sprintf(wb,
- "\t\t\"%s.%s\": {\n"
- "\t\t\t\"id\": %lu,\n"
- "\t\t\t\"name\": \"%s\",\n"
- "\t\t\t\"chart\": \"%s\",\n"
- "\t\t\t\"family\": \"%s\",\n"
- "\t\t\t\"active\": %s,\n"
- "\t\t\t\"exec\": \"%s\",\n"
- "\t\t\t\"recipient\": \"%s\",\n"
- "\t\t\t\"source\": \"%s\",\n"
- "\t\t\t\"units\": \"%s\",\n"
- "\t\t\t\"info\": \"%s\",\n"
- "\t\t\t\"status\": \"%s\",\n"
- "\t\t\t\"last_status_change\": %lu,\n"
- "\t\t\t\"last_updated\": %lu,\n"
- "\t\t\t\"next_update\": %lu,\n"
- "\t\t\t\"update_every\": %d,\n"
- "\t\t\t\"delay_up_duration\": %d,\n"
- "\t\t\t\"delay_down_duration\": %d,\n"
- "\t\t\t\"delay_max_duration\": %d,\n"
- "\t\t\t\"delay_multiplier\": %f,\n"
- "\t\t\t\"delay\": %d,\n"
- "\t\t\t\"delay_up_to_timestamp\": %lu,\n"
- , rc->chart, rc->name
- , (unsigned long)rc->id
- , rc->name
- , rc->chart
- , (rc->rrdset && rc->rrdset->family)?rc->rrdset->family:""
- , (rc->rrdset)?"true":"false"
- , rc->exec?rc->exec:health.health_default_exec
- , rc->recipient?rc->recipient:health.health_default_recipient
- , rc->source
- , rc->units?rc->units:""
- , rc->info?rc->info:""
- , rrdcalc_status2string(rc->status)
- , (unsigned long)rc->last_status_change
- , (unsigned long)rc->last_updated
- , (unsigned long)rc->next_update
- , rc->update_every
- , rc->delay_up_duration
- , rc->delay_down_duration
- , rc->delay_max_duration
- , rc->delay_multiplier
- , rc->delay_last
- , (unsigned long)rc->delay_up_to_timestamp
- );
-
- if(RRDCALC_HAS_DB_LOOKUP(rc)) {
- if(rc->dimensions && *rc->dimensions)
- health_string2json(wb, "\t\t\t", "lookup_dimensions", rc->dimensions, ",\n");
-
- buffer_sprintf(wb,
- "\t\t\t\"db_after\": %lu,\n"
- "\t\t\t\"db_before\": %lu,\n"
- "\t\t\t\"lookup_method\": \"%s\",\n"
- "\t\t\t\"lookup_after\": %d,\n"
- "\t\t\t\"lookup_before\": %d,\n"
- "\t\t\t\"lookup_options\": \"",
- (unsigned long) rc->db_after,
- (unsigned long) rc->db_before,
- group_method2string(rc->group),
- rc->after,
- rc->before
- );
- buffer_data_options2string(wb, rc->options);
- buffer_strcat(wb, "\",\n");
- }
-
- if(rc->calculation) {
- health_string2json(wb, "\t\t\t", "calc", rc->calculation->source, ",\n");
- health_string2json(wb, "\t\t\t", "calc_parsed", rc->calculation->parsed_as, ",\n");
- }
-
- if(rc->warning) {
- health_string2json(wb, "\t\t\t", "warn", rc->warning->source, ",\n");
- health_string2json(wb, "\t\t\t", "warn_parsed", rc->warning->parsed_as, ",\n");
- }
-
- if(rc->critical) {
- health_string2json(wb, "\t\t\t", "crit", rc->critical->source, ",\n");
- health_string2json(wb, "\t\t\t", "crit_parsed", rc->critical->parsed_as, ",\n");
- }
-
- buffer_strcat(wb, "\t\t\t\"green\":");
- buffer_rrd_value(wb, rc->green);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\t\t\"red\":");
- buffer_rrd_value(wb, rc->red);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\t\t\"value\":");
- buffer_rrd_value(wb, rc->value);
- buffer_strcat(wb, "\n");
-
- buffer_strcat(wb, "\t\t}");
-}
-
-//void health_rrdcalctemplate2json_nolock(BUFFER *wb, RRDCALCTEMPLATE *rt) {
-//
-//}
-
-void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
- int i;
-
- rrdhost_rdlock(&localhost);
- buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
- "\n\t\"latest_alarm_log_unique_id\": %u,"
- "\n\t\"status\": %s,"
- "\n\t\"now\": %lu,"
- "\n\t\"alarms\": {\n",
- host->hostname,
- (host->health_log.next_log_id > 0)?(host->health_log.next_log_id - 1):0,
- health_enabled?"true":"false",
- (unsigned long)now_realtime_sec());
-
- RRDCALC *rc;
- for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
- if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
- continue;
-
- if(likely(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL)))
- continue;
-
- if(likely(i)) buffer_strcat(wb, ",\n");
- health_rrdcalc2json_nolock(wb, rc);
- i++;
- }
-
-// buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
-// RRDCALCTEMPLATE *rt;
-// for(rt = host->templates; rt ; rt = rt->next)
-// health_rrdcalctemplate2json_nolock(wb, rt);
+// re-load health configuration
- buffer_strcat(wb, "\n\t}\n}\n");
- rrdhost_unlock(&localhost);
-}
+void health_reload_host(RRDHOST *host) {
+ if(unlikely(!host->health_enabled))
+ return;
+ char *path = health_config_dir();
-// ----------------------------------------------------------------------------
-// re-load health configuration
+ // free all running alarms
+ rrdhost_wrlock(host);
-static inline void health_free_all_nolock(RRDHOST *host) {
while(host->templates)
rrdcalctemplate_free(host, host->templates);
while(host->alarms)
rrdcalc_free(host, host->alarms);
-}
-
-void health_reload(void) {
- if(!health_enabled) {
- error("Health reload is requested, but health is not enabled.");
- return;
- }
-
- char *path = health_config_dir();
- // free all running alarms
- rrdhost_rwlock(&localhost);
- health_free_all_nolock(&localhost);
- rrdhost_unlock(&localhost);
+ rrdhost_unlock(host);
// invalidate all previous entries in the alarm log
ALARM_ENTRY *t;
- for(t = localhost.health_log.alarms ; t ; t = t->next) {
+ for(t = host->health_log.alarms ; t ; t = t->next) {
if(t->new_status != RRDCALC_STATUS_REMOVED)
t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
}
+ rrdhost_rdlock(host);
// reset all thresholds to all charts
RRDSET *st;
- for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdset_foreach_read(st, host) {
st->green = NAN;
st->red = NAN;
}
+ rrdhost_unlock(host);
// load the new alarms
- rrdhost_rwlock(&localhost);
- health_readdir(path);
- rrdhost_unlock(&localhost);
+ rrdhost_wrlock(host);
+ health_readdir(host, path);
// link the loaded alarms to their charts
- for(st = localhost.rrdset_root; st ; st = st->next) {
- rrdhost_rwlock(&localhost);
-
+ rrdset_foreach_write(st, host) {
rrdsetcalc_link_matching(st);
rrdcalctemplate_link_matching(st);
-
- rrdhost_unlock(&localhost);
}
+
+ rrdhost_unlock(host);
+}
+
+void health_reload(void) {
+
+ rrd_rdlock();
+
+ RRDHOST *host;
+ rrdhost_foreach_read(host)
+ health_reload_host(host);
+
+ rrd_unlock();
}
// ----------------------------------------------------------------------------
@@ -2601,12 +97,21 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
if(unlikely(ae->new_status < RRDCALC_STATUS_CLEAR)) {
// do not send notifications for internal statuses
+ debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (internal statuses)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
+ goto done;
+ }
+
+ if(unlikely(ae->new_status <= RRDCALC_STATUS_CLEAR && (ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
+ // do not send notifications for disabled statuses
+ debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (it has no-clear-notification enabled)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
+ // mark it as run, so that we will send the same alarm if it happens again
goto done;
}
// find the previous notification for the same alarm
// which we have run the exec script
- {
+ // exception: alarms with HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION set
+ if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
uint32_t id = ae->alarm_id;
ALARM_ENTRY *t;
for(t = ae->next; t ; t = t->next) {
@@ -2637,13 +142,10 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
static char command_to_run[ALARM_EXEC_COMMAND_LENGTH + 1];
pid_t command_pid;
- const char *exec = ae->exec;
- if(!exec) exec = health.health_default_exec;
+ const char *exec = (ae->exec) ? ae->exec : host->health_default_exec;
+ const char *recipient = (ae->recipient) ? ae->recipient : host->health_default_recipient;
- const char *recipient = ae->recipient;
- if(!recipient) recipient = health.health_default_recipient;
-
- snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '%0.0Lf' '%0.0Lf' '%s' '%u' '%u' '%s' '%s'",
+ snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '%0.0Lf' '%0.0Lf' '%s' '%u' '%u' '%s' '%s' '%s' '%s'",
exec,
recipient,
host->hostname,
@@ -2662,7 +164,9 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
(uint32_t)ae->duration,
(uint32_t)ae->non_clear_duration,
ae->units?ae->units:"",
- ae->info?ae->info:""
+ ae->info?ae->info:"",
+ ae->new_value_string,
+ ae->old_value_string
);
ae->flags |= HEALTH_ENTRY_FLAG_EXEC_RUN;
@@ -2704,7 +208,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
uint32_t first_waiting = (host->health_log.alarms)?host->health_log.alarms->unique_id:0;
time_t now = now_realtime_sec();
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *ae;
for(ae = host->health_log.alarms; ae && ae->unique_id >= stop_at_id ; ae = ae->next) {
@@ -2724,13 +228,13 @@ static inline void health_alarm_log_process(RRDHOST *host) {
// remember this for the next iteration
stop_at_id = first_waiting;
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
if(host->health_log.count <= host->health_log.max)
return;
// cleanup excess entries in the log
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *last = NULL;
unsigned int count = host->health_log.max * 2 / 3;
@@ -2746,21 +250,13 @@ static inline void health_alarm_log_process(RRDHOST *host) {
ALARM_ENTRY *t = ae->next;
- freez(ae->name);
- freez(ae->chart);
- freez(ae->family);
- freez(ae->exec);
- freez(ae->recipient);
- freez(ae->source);
- freez(ae->units);
- freez(ae->info);
- freez(ae);
+ health_alarm_log_free_one_nochecks_nounlink(ae);
ae = t;
host->health_log.count--;
}
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
}
static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
@@ -2785,6 +281,16 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
return 0;
}
+ if(unlikely(rrdset_flag_check(rc->rrdset, RRDSET_FLAG_OBSOLETE))) {
+ debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as obsolete", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
+ if(unlikely(!rrdset_flag_check(rc->rrdset, RRDSET_FLAG_ENABLED))) {
+ debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart is not enabled", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
if(unlikely(!rc->rrdset->last_collected_time.tv_sec || rc->rrdset->counter_done < 2)) {
debug(D_HEALTH, "Health not running alarm '%s.%s'. Chart is not fully collected yet.", rc->chart?rc->chart:"NOCHART", rc->name);
return 0;
@@ -2828,299 +334,396 @@ void *health_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- int min_run_every = (int)config_get_number("health", "run at least every seconds", 10);
+ int min_run_every = (int)config_get_number(CONFIG_SECTION_HEALTH, "run at least every seconds", 10);
if(min_run_every < 1) min_run_every = 1;
BUFFER *wb = buffer_create(100);
+ time_t now = now_realtime_sec();
+ time_t now_boottime = now_boottime_sec();
+ time_t last_now = now;
+ time_t last_now_boottime = now_boottime;
+ time_t hibernation_delay = config_get_number(CONFIG_SECTION_HEALTH, "postpone alarms during hibernation for seconds", 60);
+
unsigned int loop = 0;
- while(health_enabled && !netdata_exit) {
+ while(!netdata_exit) {
loop++;
debug(D_HEALTH, "Health monitoring iteration no %u started", loop);
- int oldstate, runnable = 0;
- time_t now = now_realtime_sec();
+ int oldstate, runnable = 0, apply_hibernation_delay = 0;
time_t next_run = now + min_run_every;
RRDCALC *rc;
+ // detect if boottime and realtime have twice the difference
+ // in which case we assume the system was just waken from hibernation
+ if(unlikely(now - last_now > 2 * (now_boottime - last_now_boottime)))
+ apply_hibernation_delay = 1;
+
+ last_now = now;
+ last_now_boottime = now_boottime;
+
if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
error("Cannot set pthread cancel state to DISABLE.");
- rrdhost_rdlock(&localhost);
+ rrd_rdlock();
- // the first loop is to lookup values from the db
- for(rc = localhost.alarms; rc; rc = rc->next) {
- if(unlikely(!rrdcalc_isrunnable(rc, now, &next_run))) {
- if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_RUNNABLE;
+ RRDHOST *host;
+ rrdhost_foreach_read(host) {
+ if(unlikely(!host->health_enabled))
continue;
- }
-
- runnable++;
- rc->old_value = rc->value;
- rc->rrdcalc_flags |= RRDCALC_FLAG_RUNNABLE;
- // 1. if there is database lookup, do it
- // 2. if there is calculation expression, run it
+ if(unlikely(apply_hibernation_delay)) {
- if (unlikely(RRDCALC_HAS_DB_LOOKUP(rc))) {
- /* time_t old_db_timestamp = rc->db_before; */
- int value_is_null = 0;
+ info("Postponing alarm checks for %ld seconds, on host '%s', due to boottime discrepancy (realtime dt: %ld, boottime dt: %ld)."
+ , hibernation_delay
+ , host->hostname
+ , (long)(now - last_now)
+ , (long)(now_boottime - last_now_boottime)
+ );
- int ret = rrd2value(rc->rrdset, wb, &rc->value,
- rc->dimensions, 1, rc->after, rc->before, rc->group,
- rc->options, &rc->db_after, &rc->db_before, &value_is_null);
+ host->health_delay_up_to = now + hibernation_delay;
+ }
- if (unlikely(ret != 200)) {
- // database lookup failed
- rc->value = NAN;
+ if(unlikely(!host->health_enabled || now < host->health_delay_up_to))
+ continue;
- debug(D_HEALTH, "Health alarm '%s.%s': database lookup returned error %d", rc->chart?rc->chart:"NOCHART", rc->name, ret);
+ rrdhost_rdlock(host);
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_ERROR))) {
- rc->rrdcalc_flags |= RRDCALC_FLAG_DB_ERROR;
- error("Health alarm '%s.%s': database lookup returned error %d", rc->chart?rc->chart:"NOCHART", rc->name, ret);
- }
+ // the first loop is to lookup values from the db
+ for(rc = host->alarms; rc; rc = rc->next) {
+ if(unlikely(!rrdcalc_isrunnable(rc, now, &next_run))) {
+ if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE))
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_RUNNABLE;
+ continue;
}
- else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_ERROR))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_ERROR;
- /* - RRDCALC_FLAG_DB_STALE not currently used
- if (unlikely(old_db_timestamp == rc->db_before)) {
- // database is stale
+ runnable++;
+ rc->old_value = rc->value;
+ rc->rrdcalc_flags |= RRDCALC_FLAG_RUNNABLE;
+
+ // ------------------------------------------------------------
+ // if there is database lookup, do it
+
+ if(unlikely(RRDCALC_HAS_DB_LOOKUP(rc))) {
+ /* time_t old_db_timestamp = rc->db_before; */
+ int value_is_null = 0;
+
+ int ret = rrdset2value_api_v1(rc->rrdset
+ , wb
+ , &rc->value
+ , rc->dimensions
+ , 1
+ , rc->after
+ , rc->before
+ , rc->group
+ , rc->options
+ , &rc->db_after
+ , &rc->db_before
+ , &value_is_null
+ );
- debug(D_HEALTH, "Health alarm '%s.%s': database is stale", rc->chart?rc->chart:"NOCHART", rc->name);
+ if(unlikely(ret != 200)) {
+ // database lookup failed
+ rc->value = NAN;
+ rc->rrdcalc_flags |= RRDCALC_FLAG_DB_ERROR;
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))) {
- rc->rrdcalc_flags |= RRDCALC_FLAG_DB_STALE;
- error("Health alarm '%s.%s': database is stale", rc->chart?rc->chart:"NOCHART", rc->name);
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': database lookup returned error %d"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , ret
+ );
}
- }
- else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_STALE;
- */
+ else
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_ERROR;
- if (unlikely(value_is_null)) {
- // collected value is null
+ /* - RRDCALC_FLAG_DB_STALE not currently used
+ if (unlikely(old_db_timestamp == rc->db_before)) {
+ // database is stale
- rc->value = NAN;
+ debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database is stale", host->hostname, rc->chart?rc->chart:"NOCHART", rc->name);
- debug(D_HEALTH, "Health alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
- rc->chart?rc->chart:"NOCHART", rc->name);
+ if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))) {
+ rc->rrdcalc_flags |= RRDCALC_FLAG_DB_STALE;
+ error("Health on host '%s', alarm '%s.%s': database is stale", host->hostname, rc->chart?rc->chart:"NOCHART", rc->name);
+ }
+ }
+ else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_STALE))
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_STALE;
+ */
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_DB_NAN))) {
+ if(unlikely(value_is_null)) {
+ // collected value is null
+ rc->value = NAN;
rc->rrdcalc_flags |= RRDCALC_FLAG_DB_NAN;
- error("Health alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
- rc->chart?rc->chart:"NOCHART", rc->name);
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ );
}
+ else
+ rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_NAN;
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': database lookup gave value " CALCULATED_NUMBER_FORMAT
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->value
+ );
}
- else if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_DB_NAN))
- rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_NAN;
-
- debug(D_HEALTH, "Health alarm '%s.%s': database lookup gave value "
- CALCULATED_NUMBER_FORMAT, rc->chart?rc->chart:"NOCHART", rc->name, rc->value);
- }
- if(unlikely(rc->calculation)) {
- if (unlikely(!expression_evaluate(rc->calculation))) {
- // calculation failed
+ // ------------------------------------------------------------
+ // if there is calculation expression, run it
- rc->value = NAN;
-
- debug(D_HEALTH, "Health alarm '%s.%s': expression '%s' failed: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, rc->calculation->parsed_as, buffer_tostring(rc->calculation->error_msg));
-
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_CALC_ERROR))) {
+ if(unlikely(rc->calculation)) {
+ if(unlikely(!expression_evaluate(rc->calculation))) {
+ // calculation failed
+ rc->value = NAN;
rc->rrdcalc_flags |= RRDCALC_FLAG_CALC_ERROR;
- error("Health alarm '%s.%s': expression '%s' failed: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, rc->calculation->parsed_as, buffer_tostring(rc->calculation->error_msg));
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': expression '%s' failed: %s"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->calculation->parsed_as
+ , buffer_tostring(rc->calculation->error_msg)
+ );
}
- }
- else {
- if (unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_CALC_ERROR))
+ else {
rc->rrdcalc_flags &= ~RRDCALC_FLAG_CALC_ERROR;
- debug(D_HEALTH, "Health alarm '%s.%s': expression '%s' gave value "
- CALCULATED_NUMBER_FORMAT
- ": %s (source: %s)",
- rc->chart?rc->chart:"NOCHART", rc->name,
- rc->calculation->parsed_as,
- rc->calculation->result,
- buffer_tostring(rc->calculation->error_msg),
- rc->source
- );
+ debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': expression '%s' gave value " CALCULATED_NUMBER_FORMAT ": %s (source: %s)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->calculation->parsed_as
+ , rc->calculation->result
+ , buffer_tostring(rc->calculation->error_msg)
+ , rc->source
+ );
- rc->value = rc->calculation->result;
+ rc->value = rc->calculation->result;
+ }
}
}
- }
- rrdhost_unlock(&localhost);
+ rrdhost_unlock(host);
- if(unlikely(runnable && !netdata_exit)) {
- rrdhost_rdlock(&localhost);
+ if(unlikely(runnable && !netdata_exit)) {
+ rrdhost_rdlock(host);
- for(rc = localhost.alarms; rc; rc = rc->next) {
- if(unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE)))
- continue;
+ for(rc = host->alarms; rc; rc = rc->next) {
+ if(unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE)))
+ continue;
- int warning_status = RRDCALC_STATUS_UNDEFINED;
- int critical_status = RRDCALC_STATUS_UNDEFINED;
+ int warning_status = RRDCALC_STATUS_UNDEFINED;
+ int critical_status = RRDCALC_STATUS_UNDEFINED;
- if(likely(rc->warning)) {
- if(unlikely(!expression_evaluate(rc->warning))) {
- // calculation failed
+ // --------------------------------------------------------
+ // check the warning expression
- debug(D_HEALTH, "Health alarm '%s.%s': warning expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->warning->error_msg));
-
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_WARN_ERROR))) {
+ if(likely(rc->warning)) {
+ if(unlikely(!expression_evaluate(rc->warning))) {
+ // calculation failed
rc->rrdcalc_flags |= RRDCALC_FLAG_WARN_ERROR;
- error("Health alarm '%s.%s': warning expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->warning->error_msg));
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': warning expression failed with error: %s"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , buffer_tostring(rc->warning->error_msg)
+ );
}
- }
- else {
- if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_WARN_ERROR))
+ else {
rc->rrdcalc_flags &= ~RRDCALC_FLAG_WARN_ERROR;
-
- debug(D_HEALTH, "Health alarm '%s.%s': warning expression gave value "
- CALCULATED_NUMBER_FORMAT
- ": %s (source: %s)",
- rc->chart?rc->chart:"NOCHART", rc->name,
- rc->warning->result,
- buffer_tostring(rc->warning->error_msg),
- rc->source
- );
-
- warning_status = rrdcalc_value2status(rc->warning->result);
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': warning expression gave value " CALCULATED_NUMBER_FORMAT ": %s (source: %s)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->warning->result
+ , buffer_tostring(rc->warning->error_msg)
+ , rc->source
+ );
+ warning_status = rrdcalc_value2status(rc->warning->result);
+ }
}
- }
- if(likely(rc->critical)) {
- if(unlikely(!expression_evaluate(rc->critical))) {
- // calculation failed
+ // --------------------------------------------------------
+ // check the critical expression
- debug(D_HEALTH, "Health alarm '%s.%s': critical expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->critical->error_msg));
-
- if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_CRIT_ERROR))) {
+ if(likely(rc->critical)) {
+ if(unlikely(!expression_evaluate(rc->critical))) {
+ // calculation failed
rc->rrdcalc_flags |= RRDCALC_FLAG_CRIT_ERROR;
- error("Health alarm '%s.%s': critical expression failed with error: %s",
- rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->critical->error_msg));
+
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': critical expression failed with error: %s"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , buffer_tostring(rc->critical->error_msg)
+ );
}
- }
- else {
- if(unlikely(rc->rrdcalc_flags & RRDCALC_FLAG_CRIT_ERROR))
+ else {
rc->rrdcalc_flags &= ~RRDCALC_FLAG_CRIT_ERROR;
+ debug(D_HEALTH
+ , "Health on host '%s', alarm '%s.%s': critical expression gave value " CALCULATED_NUMBER_FORMAT ": %s (source: %s)"
+ , host->hostname
+ , rc->chart ? rc->chart : "NOCHART"
+ , rc->name
+ , rc->critical->result
+ , buffer_tostring(rc->critical->error_msg)
+ , rc->source
+ );
+ critical_status = rrdcalc_value2status(rc->critical->result);
+ }
+ }
- debug(D_HEALTH, "Health alarm '%s.%s': critical expression gave value "
- CALCULATED_NUMBER_FORMAT
- ": %s (source: %s)",
- rc->chart?rc->chart:"NOCHART", rc->name,
- rc->critical->result,
- buffer_tostring(rc->critical->error_msg),
- rc->source
- );
+ // --------------------------------------------------------
+ // decide the final alarm status
- critical_status = rrdcalc_value2status(rc->critical->result);
+ int status = RRDCALC_STATUS_UNDEFINED;
+
+ switch(warning_status) {
+ case RRDCALC_STATUS_CLEAR:
+ status = RRDCALC_STATUS_CLEAR;
+ break;
+
+ case RRDCALC_STATUS_RAISED:
+ status = RRDCALC_STATUS_WARNING;
+ break;
+
+ default:
+ break;
}
- }
- int status = RRDCALC_STATUS_UNDEFINED;
+ switch(critical_status) {
+ case RRDCALC_STATUS_CLEAR:
+ if(status == RRDCALC_STATUS_UNDEFINED)
+ status = RRDCALC_STATUS_CLEAR;
+ break;
- switch(warning_status) {
- case RRDCALC_STATUS_CLEAR:
- status = RRDCALC_STATUS_CLEAR;
- break;
+ case RRDCALC_STATUS_RAISED:
+ status = RRDCALC_STATUS_CRITICAL;
+ break;
- case RRDCALC_STATUS_RAISED:
- status = RRDCALC_STATUS_WARNING;
- break;
+ default:
+ break;
+ }
- default:
- break;
- }
+ // --------------------------------------------------------
+ // check if the new status and the old differ
- switch(critical_status) {
- case RRDCALC_STATUS_CLEAR:
- if(status == RRDCALC_STATUS_UNDEFINED)
- status = RRDCALC_STATUS_CLEAR;
- break;
+ if(status != rc->status) {
+ int delay = 0;
- case RRDCALC_STATUS_RAISED:
- status = RRDCALC_STATUS_CRITICAL;
- break;
+ // apply trigger hysteresis
- default:
- break;
- }
+ if(now > rc->delay_up_to_timestamp) {
+ rc->delay_up_current = rc->delay_up_duration;
+ rc->delay_down_current = rc->delay_down_duration;
+ rc->delay_last = 0;
+ rc->delay_up_to_timestamp = 0;
+ }
+ else {
+ rc->delay_up_current = (int) (rc->delay_up_current * rc->delay_multiplier);
+ if(rc->delay_up_current > rc->delay_max_duration)
+ rc->delay_up_current = rc->delay_max_duration;
+
+ rc->delay_down_current = (int) (rc->delay_down_current * rc->delay_multiplier);
+ if(rc->delay_down_current > rc->delay_max_duration)
+ rc->delay_down_current = rc->delay_max_duration;
+ }
- if(status != rc->status) {
- int delay = 0;
+ if(status > rc->status)
+ delay = rc->delay_up_current;
+ else
+ delay = rc->delay_down_current;
+
+ // COMMENTED: because we do need to send raising alarms
+ // if(now + delay < rc->delay_up_to_timestamp)
+ // delay = (int)(rc->delay_up_to_timestamp - now);
+
+ rc->delay_last = delay;
+ rc->delay_up_to_timestamp = now + delay;
+
+ // add the alarm into the log
+
+ health_alarm_log(
+ host
+ , rc->id
+ , rc->next_event_id++
+ , now
+ , rc->name
+ , rc->rrdset->id
+ , rc->rrdset->family
+ , rc->exec
+ , rc->recipient
+ , now - rc->last_status_change
+ , rc->old_value
+ , rc->value
+ , rc->status
+ , status
+ , rc->source
+ , rc->units
+ , rc->info
+ , rc->delay_last
+ , (rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION) ? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0
+ );
- if(now > rc->delay_up_to_timestamp) {
- rc->delay_up_current = rc->delay_up_duration;
- rc->delay_down_current = rc->delay_down_duration;
- rc->delay_last = 0;
- rc->delay_up_to_timestamp = 0;
+ rc->last_status_change = now;
+ rc->status = status;
}
- else {
- rc->delay_up_current = (int)(rc->delay_up_current * rc->delay_multiplier);
- if(rc->delay_up_current > rc->delay_max_duration) rc->delay_up_current = rc->delay_max_duration;
- rc->delay_down_current = (int)(rc->delay_down_current * rc->delay_multiplier);
- if(rc->delay_down_current > rc->delay_max_duration) rc->delay_down_current = rc->delay_max_duration;
- }
+ rc->last_updated = now;
+ rc->next_update = now + rc->update_every;
- if(status > rc->status)
- delay = rc->delay_up_current;
- else
- delay = rc->delay_down_current;
+ if(next_run > rc->next_update)
+ next_run = rc->next_update;
+ }
- // COMMENTED: because we do need to send raising alarms
- // if(now + delay < rc->delay_up_to_timestamp)
- // delay = (int)(rc->delay_up_to_timestamp - now);
+ rrdhost_unlock(host);
+ }
- rc->delay_last = delay;
- rc->delay_up_to_timestamp = now + delay;
- health_alarm_log(&localhost, rc->id, rc->next_event_id++, now, rc->name, rc->rrdset->id, rc->rrdset->family, rc->exec, rc->recipient, now - rc->last_status_change, rc->old_value, rc->value, rc->status, status, rc->source, rc->units, rc->info, rc->delay_last);
- rc->last_status_change = now;
- rc->status = status;
- }
+ if(unlikely(netdata_exit))
+ break;
- rc->last_updated = now;
- rc->next_update = now + rc->update_every;
+ // execute notifications
+ // and cleanup
+ health_alarm_log_process(host);
- if (next_run > rc->next_update)
- next_run = rc->next_update;
- }
+ if(unlikely(netdata_exit))
+ break;
- rrdhost_unlock(&localhost);
- }
+ } /* rrdhost_foreach */
+
+ rrd_unlock();
- if (unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
+ if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);
if(unlikely(netdata_exit))
break;
- // execute notifications
- // and cleanup
- health_alarm_log_process(&localhost);
-
- if(unlikely(netdata_exit))
- break;
-
now = now_realtime_sec();
if(now < next_run) {
- debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration in %d secs",
- loop, (int) (next_run - now));
+ debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration in %d secs", loop, (int) (next_run - now));
sleep_usec(USEC_PER_SEC * (usec_t) (next_run - now));
+ now = now_realtime_sec();
}
- else {
+ else
debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration now", loop);
- }
- }
+
+ now_boottime = now_boottime_sec();
+
+ } // forever
buffer_free(wb);
diff --git a/src/health.h b/src/health.h
index 79831d4fc..7028a914b 100644
--- a/src/health.h
+++ b/src/health.h
@@ -1,7 +1,7 @@
#ifndef NETDATA_HEALTH_H
#define NETDATA_HEALTH_H
-extern int health_enabled;
+extern int default_health_enabled;
extern int rrdvar_compare(void *a, void *b);
@@ -119,13 +119,14 @@ typedef struct rrddimvar {
#define RRDCALC_STATUS_WARNING 3
#define RRDCALC_STATUS_CRITICAL 4
-#define RRDCALC_FLAG_DB_ERROR 0x00000001
-#define RRDCALC_FLAG_DB_NAN 0x00000002
-/* #define RRDCALC_FLAG_DB_STALE 0x00000004 */
-#define RRDCALC_FLAG_CALC_ERROR 0x00000008
-#define RRDCALC_FLAG_WARN_ERROR 0x00000010
-#define RRDCALC_FLAG_CRIT_ERROR 0x00000020
-#define RRDCALC_FLAG_RUNNABLE 0x00000040
+#define RRDCALC_FLAG_DB_ERROR 0x00000001
+#define RRDCALC_FLAG_DB_NAN 0x00000002
+/* #define RRDCALC_FLAG_DB_STALE 0x00000004 */
+#define RRDCALC_FLAG_CALC_ERROR 0x00000008
+#define RRDCALC_FLAG_WARN_ERROR 0x00000010
+#define RRDCALC_FLAG_CRIT_ERROR 0x00000020
+#define RRDCALC_FLAG_RUNNABLE 0x00000040
+#define RRDCALC_FLAG_NO_CLEAR_NOTIFICATION 0x80000000
typedef struct rrdcalc {
uint32_t id; // the unique id of this alarm
@@ -274,11 +275,12 @@ typedef struct rrdcalctemplate {
#define RRDCALCTEMPLATE_HAS_CALCULATION(rt) ((rt)->after)
-#define HEALTH_ENTRY_FLAG_PROCESSED 0x00000001
-#define HEALTH_ENTRY_FLAG_UPDATED 0x00000002
-#define HEALTH_ENTRY_FLAG_EXEC_RUN 0x00000004
-#define HEALTH_ENTRY_FLAG_EXEC_FAILED 0x00000008
-#define HEALTH_ENTRY_FLAG_SAVED 0x10000000
+#define HEALTH_ENTRY_FLAG_PROCESSED 0x00000001
+#define HEALTH_ENTRY_FLAG_UPDATED 0x00000002
+#define HEALTH_ENTRY_FLAG_EXEC_RUN 0x00000004
+#define HEALTH_ENTRY_FLAG_EXEC_FAILED 0x00000008
+#define HEALTH_ENTRY_FLAG_SAVED 0x10000000
+#define HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION 0x80000000
typedef struct alarm_entry {
uint32_t unique_id;
@@ -308,6 +310,10 @@ typedef struct alarm_entry {
calculated_number old_value;
calculated_number new_value;
+
+ char *old_value_string;
+ char *new_value_string;
+
int old_status;
int new_status;
@@ -328,7 +334,7 @@ typedef struct alarm_log {
unsigned int count;
unsigned int max;
ALARM_ENTRY *alarms;
- pthread_rwlock_t alarm_log_rwlock;
+ netdata_rwlock_t alarm_log_rwlock;
} ALARM_LOG;
#include "rrd.h"
@@ -363,4 +369,58 @@ extern void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value)
extern const char *rrdcalc_status2string(int status);
+
+extern int health_alarm_log_open(RRDHOST *host);
+extern void health_alarm_log_close(RRDHOST *host);
+extern void health_log_rotate(RRDHOST *host);
+extern void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae);
+extern ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename);
+extern void health_alarm_log_load(RRDHOST *host);
+extern void health_alarm_log(
+ RRDHOST *host,
+ uint32_t alarm_id,
+ uint32_t alarm_event_id,
+ time_t when,
+ const char *name,
+ const char *chart,
+ const char *family,
+ const char *exec,
+ const char *recipient,
+ time_t duration,
+ calculated_number old_value,
+ calculated_number new_value,
+ int old_status,
+ int new_status,
+ const char *source,
+ const char *units,
+ const char *info,
+ int delay,
+ uint32_t flags
+);
+
+extern void health_readdir(RRDHOST *host, const char *path);
+extern char *health_config_dir(void);
+extern void health_reload_host(RRDHOST *host);
+extern void health_alarm_log_free(RRDHOST *host);
+
+extern void rrdcalc_free(RRDHOST *host, RRDCALC *rc);
+extern void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt);
+
+#ifdef NETDATA_HEALTH_INTERNALS
+#define RRDVAR_MAX_LENGTH 1024
+
+extern int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name);
+extern uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id);
+extern int rrdvar_fix_name(char *variable);
+
+extern RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart);
+extern void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc);
+
+extern RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value);
+extern void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv);
+
+extern void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae);
+
+#endif // NETDATA_HEALTH_INTERNALS
+
#endif //NETDATA_HEALTH_H
diff --git a/src/health_config.c b/src/health_config.c
new file mode 100644
index 000000000..ad954cbe1
--- /dev/null
+++ b/src/health_config.c
@@ -0,0 +1,877 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+#define HEALTH_CONF_MAX_LINE 4096
+
+#define HEALTH_ALARM_KEY "alarm"
+#define HEALTH_TEMPLATE_KEY "template"
+#define HEALTH_ON_KEY "on"
+#define HEALTH_FAMILIES_KEY "families"
+#define HEALTH_LOOKUP_KEY "lookup"
+#define HEALTH_CALC_KEY "calc"
+#define HEALTH_EVERY_KEY "every"
+#define HEALTH_GREEN_KEY "green"
+#define HEALTH_RED_KEY "red"
+#define HEALTH_WARN_KEY "warn"
+#define HEALTH_CRIT_KEY "crit"
+#define HEALTH_EXEC_KEY "exec"
+#define HEALTH_RECIPIENT_KEY "to"
+#define HEALTH_UNITS_KEY "units"
+#define HEALTH_INFO_KEY "info"
+#define HEALTH_DELAY_KEY "delay"
+#define HEALTH_OPTIONS_KEY "options"
+
+static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
+ if(!rc->chart) {
+ error("Health configuration for alarm '%s' does not have a chart", rc->name);
+ return 0;
+ }
+
+ if(!rc->update_every) {
+ error("Health configuration for alarm '%s.%s' has no frequency (parameter 'every'). Ignoring it.", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
+ if(!RRDCALC_HAS_DB_LOOKUP(rc) && !rc->warning && !rc->critical) {
+ error("Health configuration for alarm '%s.%s' is useless (no calculation, no warning and no critical evaluation)", rc->chart?rc->chart:"NOCHART", rc->name);
+ return 0;
+ }
+
+ if (rrdcalc_exists(host, rc->chart, rc->name, rc->hash_chart, rc->hash))
+ return 0;
+
+ rc->id = rrdcalc_get_unique_id(host, rc->chart, rc->name, &rc->next_event_id);
+
+ debug(D_HEALTH, "Health configuration adding alarm '%s.%s' (%u): exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
+ rc->chart?rc->chart:"NOCHART",
+ rc->name,
+ rc->id,
+ (rc->exec)?rc->exec:"DEFAULT",
+ (rc->recipient)?rc->recipient:"DEFAULT",
+ rc->green,
+ rc->red,
+ rc->group,
+ rc->after,
+ rc->before,
+ rc->options,
+ (rc->dimensions)?rc->dimensions:"NONE",
+ rc->update_every,
+ (rc->calculation)?rc->calculation->parsed_as:"NONE",
+ (rc->warning)?rc->warning->parsed_as:"NONE",
+ (rc->critical)?rc->critical->parsed_as:"NONE",
+ rc->source,
+ rc->delay_up_duration,
+ rc->delay_down_duration,
+ rc->delay_max_duration,
+ rc->delay_multiplier
+ );
+
+ rrdcalc_create_part2(host, rc);
+ return 1;
+}
+
+static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCALCTEMPLATE *rt) {
+ if(unlikely(!rt->context)) {
+ error("Health configuration for template '%s' does not have a context", rt->name);
+ return 0;
+ }
+
+ if(unlikely(!rt->update_every)) {
+ error("Health configuration for template '%s' has no frequency (parameter 'every'). Ignoring it.", rt->name);
+ return 0;
+ }
+
+ if(unlikely(!RRDCALCTEMPLATE_HAS_CALCULATION(rt) && !rt->warning && !rt->critical)) {
+ error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
+ return 0;
+ }
+
+ RRDCALCTEMPLATE *t, *last = NULL;
+ for (t = host->templates; t ; last = t, t = t->next) {
+ if(unlikely(t->hash_name == rt->hash_name && !strcmp(t->name, rt->name))) {
+ error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
+ return 0;
+ }
+ }
+
+ debug(D_HEALTH, "Health configuration adding template '%s': context '%s', exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
+ rt->name,
+ (rt->context)?rt->context:"NONE",
+ (rt->exec)?rt->exec:"DEFAULT",
+ (rt->recipient)?rt->recipient:"DEFAULT",
+ rt->green,
+ rt->red,
+ rt->group,
+ rt->after,
+ rt->before,
+ rt->options,
+ (rt->dimensions)?rt->dimensions:"NONE",
+ rt->update_every,
+ (rt->calculation)?rt->calculation->parsed_as:"NONE",
+ (rt->warning)?rt->warning->parsed_as:"NONE",
+ (rt->critical)?rt->critical->parsed_as:"NONE",
+ rt->source,
+ rt->delay_up_duration,
+ rt->delay_down_duration,
+ rt->delay_max_duration,
+ rt->delay_multiplier
+ );
+
+ if(likely(last)) {
+ last->next = rt;
+ }
+ else {
+ rt->next = host->templates;
+ host->templates = rt;
+ }
+
+ return 1;
+}
+
+static inline int health_parse_duration(char *string, int *result) {
+ // make sure it is a number
+ if(!*string || !(isdigit(*string) || *string == '+' || *string == '-')) {
+ *result = 0;
+ return 0;
+ }
+
+ char *e = NULL;
+ calculated_number n = strtold(string, &e);
+ if(e && *e) {
+ switch (*e) {
+ case 'Y':
+ *result = (int) (n * 86400 * 365);
+ break;
+ case 'M':
+ *result = (int) (n * 86400 * 30);
+ break;
+ case 'w':
+ *result = (int) (n * 86400 * 7);
+ break;
+ case 'd':
+ *result = (int) (n * 86400);
+ break;
+ case 'h':
+ *result = (int) (n * 3600);
+ break;
+ case 'm':
+ *result = (int) (n * 60);
+ break;
+
+ default:
+ case 's':
+ *result = (int) (n);
+ break;
+ }
+ }
+ else
+ *result = (int)(n);
+
+ return 1;
+}
+
+static inline int health_parse_delay(
+ size_t line, const char *path, const char *file, char *string,
+ int *delay_up_duration,
+ int *delay_down_duration,
+ int *delay_max_duration,
+ float *delay_multiplier) {
+
+ char given_up = 0;
+ char given_down = 0;
+ char given_max = 0;
+ char given_multiplier = 0;
+
+ char *s = string;
+ while(*s) {
+ char *key = s;
+
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if(!*key) break;
+
+ char *value = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if(!strcasecmp(key, "up")) {
+ if (!health_parse_duration(value, delay_up_duration)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_up = 1;
+ }
+ else if(!strcasecmp(key, "down")) {
+ if (!health_parse_duration(value, delay_down_duration)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_down = 1;
+ }
+ else if(!strcasecmp(key, "multiplier")) {
+ *delay_multiplier = strtof(value, NULL);
+ if(isnan(*delay_multiplier) || isinf(*delay_multiplier) || islessequal(*delay_multiplier, 0)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_multiplier = 1;
+ }
+ else if(!strcasecmp(key, "max")) {
+ if (!health_parse_duration(value, delay_max_duration)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid value '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ else given_max = 1;
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
+ line, path, file, key);
+ }
+ }
+
+ if(!given_up)
+ *delay_up_duration = 0;
+
+ if(!given_down)
+ *delay_down_duration = 0;
+
+ if(!given_multiplier)
+ *delay_multiplier = 1.0;
+
+ if(!given_max) {
+ if((*delay_max_duration) < (*delay_up_duration) * (*delay_multiplier))
+ *delay_max_duration = (*delay_up_duration) * (*delay_multiplier);
+
+ if((*delay_max_duration) < (*delay_down_duration) * (*delay_multiplier))
+ *delay_max_duration = (*delay_down_duration) * (*delay_multiplier);
+ }
+
+ return 1;
+}
+
+static inline uint32_t health_parse_options(const char *s) {
+ uint32_t options = 0;
+ char buf[100+1] = "";
+
+ while(*s) {
+ buf[0] = '\0';
+
+ // skip spaces
+ while(*s && isspace(*s))
+ s++;
+
+ // find the next space
+ size_t count = 0;
+ while(*s && count < 100 && !isspace(*s))
+ buf[count++] = *s++;
+
+ if(buf[0]) {
+ buf[count] = '\0';
+
+ if(!strcasecmp(buf, "no-clear-notification") || !strcasecmp(buf, "no-clear"))
+ options |= RRDCALC_FLAG_NO_CLEAR_NOTIFICATION;
+ else
+ error("Ignoring unknown alarm option '%s'", buf);
+ }
+ }
+
+ return options;
+}
+
+static inline int health_parse_db_lookup(
+ size_t line, const char *path, const char *file, char *string,
+ int *group_method, int *after, int *before, int *every,
+ uint32_t *options, char **dimensions
+) {
+ debug(D_HEALTH, "Health configuration parsing database lookup %zu@%s/%s: %s", line, path, file, string);
+
+ if(*dimensions) freez(*dimensions);
+ *dimensions = NULL;
+ *after = 0;
+ *before = 0;
+ *every = 0;
+ *options = 0;
+
+ char *s = string, *key;
+
+ // first is the group method
+ key = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+ if(!*s) {
+ error("Health configuration invalid chart calculation at line %zu of file '%s/%s': expected group method followed by the 'after' time, but got '%s'",
+ line, path, file, key);
+ return 0;
+ }
+
+ if((*group_method = web_client_api_request_v1_data_group(key, -1)) == -1) {
+ error("Health configuration at line %zu of file '%s/%s': invalid group method '%s'",
+ line, path, file, key);
+ return 0;
+ }
+
+ // then is the 'after' time
+ key = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if(!health_parse_duration(key, after)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' after group method",
+ line, path, file, key);
+ return 0;
+ }
+
+ // sane defaults
+ *every = abs(*after);
+
+ // now we may have optional parameters
+ while(*s) {
+ key = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+ if(!*key) break;
+
+ if(!strcasecmp(key, "at")) {
+ char *value = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if (!health_parse_duration(value, before)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ }
+ else if(!strcasecmp(key, HEALTH_EVERY_KEY)) {
+ char *value = s;
+ while(*s && !isspace(*s)) s++;
+ while(*s && isspace(*s)) *s++ = '\0';
+
+ if (!health_parse_duration(value, every)) {
+ error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
+ line, path, file, value, key);
+ }
+ }
+ else if(!strcasecmp(key, "absolute") || !strcasecmp(key, "abs") || !strcasecmp(key, "absolute_sum")) {
+ *options |= RRDR_OPTION_ABSOLUTE;
+ }
+ else if(!strcasecmp(key, "min2max")) {
+ *options |= RRDR_OPTION_MIN2MAX;
+ }
+ else if(!strcasecmp(key, "null2zero")) {
+ *options |= RRDR_OPTION_NULL2ZERO;
+ }
+ else if(!strcasecmp(key, "percentage")) {
+ *options |= RRDR_OPTION_PERCENTAGE;
+ }
+ else if(!strcasecmp(key, "unaligned")) {
+ *options |= RRDR_OPTION_NOT_ALIGNED;
+ }
+ else if(!strcasecmp(key, "of")) {
+ if(*s && strcasecmp(s, "all"))
+ *dimensions = strdupz(s);
+ break;
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s': unknown keyword '%s'",
+ line, path, file, key);
+ }
+ }
+
+ return 1;
+}
+
+static inline char *trim_all_spaces(char *buffer) {
+ char *d = buffer, *s = buffer;
+
+ // skip spaces
+ while(isspace(*s)) s++;
+
+ while(*s) {
+ // copy the non-space part
+ while(*s && !isspace(*s)) *d++ = *s++;
+
+ // add a space if we have to
+ if(*s && isspace(*s)) {
+ *d++ = ' ';
+ s++;
+ }
+
+ // skip spaces
+ while(isspace(*s)) s++;
+ }
+
+ *d = '\0';
+
+ if(d > buffer) {
+ d--;
+ if(isspace(*d)) *d = '\0';
+ }
+
+ if(!buffer[0]) return NULL;
+ return buffer;
+}
+
+static inline char *health_source_file(size_t line, const char *path, const char *filename) {
+ char buffer[FILENAME_MAX + 1];
+ snprintfz(buffer, FILENAME_MAX, "%zu@%s/%s", line, path, filename);
+ return strdupz(buffer);
+}
+
+static inline void strip_quotes(char *s) {
+ while(*s) {
+ if(*s == '\'' || *s == '"') *s = ' ';
+ s++;
+ }
+}
+
+int health_readfile(RRDHOST *host, const char *path, const char *filename) {
+ debug(D_HEALTH, "Health configuration reading file '%s/%s'", path, filename);
+
+ static uint32_t
+ hash_alarm = 0,
+ hash_template = 0,
+ hash_on = 0,
+ hash_families = 0,
+ hash_calc = 0,
+ hash_green = 0,
+ hash_red = 0,
+ hash_warn = 0,
+ hash_crit = 0,
+ hash_exec = 0,
+ hash_every = 0,
+ hash_lookup = 0,
+ hash_units = 0,
+ hash_info = 0,
+ hash_recipient = 0,
+ hash_delay = 0,
+ hash_options = 0;
+
+ char buffer[HEALTH_CONF_MAX_LINE + 1];
+
+ if(unlikely(!hash_alarm)) {
+ hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
+ hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
+ hash_on = simple_uhash(HEALTH_ON_KEY);
+ hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
+ hash_calc = simple_uhash(HEALTH_CALC_KEY);
+ hash_lookup = simple_uhash(HEALTH_LOOKUP_KEY);
+ hash_green = simple_uhash(HEALTH_GREEN_KEY);
+ hash_red = simple_uhash(HEALTH_RED_KEY);
+ hash_warn = simple_uhash(HEALTH_WARN_KEY);
+ hash_crit = simple_uhash(HEALTH_CRIT_KEY);
+ hash_exec = simple_uhash(HEALTH_EXEC_KEY);
+ hash_every = simple_uhash(HEALTH_EVERY_KEY);
+ hash_units = simple_hash(HEALTH_UNITS_KEY);
+ hash_info = simple_hash(HEALTH_INFO_KEY);
+ hash_recipient = simple_hash(HEALTH_RECIPIENT_KEY);
+ hash_delay = simple_uhash(HEALTH_DELAY_KEY);
+ hash_options = simple_uhash(HEALTH_OPTIONS_KEY);
+ }
+
+ snprintfz(buffer, HEALTH_CONF_MAX_LINE, "%s/%s", path, filename);
+ FILE *fp = fopen(buffer, "r");
+ if(!fp) {
+ error("Health configuration cannot read file '%s'.", buffer);
+ return 0;
+ }
+
+ RRDCALC *rc = NULL;
+ RRDCALCTEMPLATE *rt = NULL;
+
+ size_t line = 0, append = 0;
+ char *s;
+ while((s = fgets(&buffer[append], (int)(HEALTH_CONF_MAX_LINE - append), fp)) || append) {
+ int stop_appending = !s;
+ line++;
+ s = trim(buffer);
+ if(!s) continue;
+
+ append = strlen(s);
+ if(!stop_appending && s[append - 1] == '\\') {
+ s[append - 1] = ' ';
+ append = &s[append] - buffer;
+ if(append < HEALTH_CONF_MAX_LINE)
+ continue;
+ else {
+ error("Health configuration has too long muli-line at line %zu of file '%s/%s'.", line, path, filename);
+ }
+ }
+ append = 0;
+
+ char *key = s;
+ while(*s && *s != ':') s++;
+ if(!*s) {
+ error("Health configuration has invalid line %zu of file '%s/%s'. It does not contain a ':'. Ignoring it.", line, path, filename);
+ continue;
+ }
+ *s = '\0';
+ s++;
+
+ char *value = s;
+ key = trim_all_spaces(key);
+ value = trim_all_spaces(value);
+
+ if(!key) {
+ error("Health configuration has invalid line %zu of file '%s/%s'. Keyword is empty. Ignoring it.", line, path, filename);
+ continue;
+ }
+
+ if(!value) {
+ error("Health configuration has invalid line %zu of file '%s/%s'. value is empty. Ignoring it.", line, path, filename);
+ continue;
+ }
+
+ uint32_t hash = simple_uhash(key);
+
+ if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
+ if(rc && !rrdcalc_add_alarm_from_config(host, rc))
+ rrdcalc_free(host, rc);
+
+ if(rt) {
+ if (!rrdcalctemplate_add_template_from_config(host, rt))
+ rrdcalctemplate_free(host, rt);
+ rt = NULL;
+ }
+
+ rc = callocz(1, sizeof(RRDCALC));
+ rc->next_event_id = 1;
+ rc->name = strdupz(value);
+ rc->hash = simple_hash(rc->name);
+ rc->source = health_source_file(line, path, filename);
+ rc->green = NAN;
+ rc->red = NAN;
+ rc->value = NAN;
+ rc->old_value = NAN;
+ rc->delay_multiplier = 1.0;
+
+ if(rrdvar_fix_name(rc->name))
+ error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
+ }
+ else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
+ if(rc) {
+ if(!rrdcalc_add_alarm_from_config(host, rc))
+ rrdcalc_free(host, rc);
+ rc = NULL;
+ }
+
+ if(rt && !rrdcalctemplate_add_template_from_config(host, rt))
+ rrdcalctemplate_free(host, rt);
+
+ rt = callocz(1, sizeof(RRDCALCTEMPLATE));
+ rt->name = strdupz(value);
+ rt->hash_name = simple_hash(rt->name);
+ rt->source = health_source_file(line, path, filename);
+ rt->green = NAN;
+ rt->red = NAN;
+ rt->delay_multiplier = 1.0;
+
+ if(rrdvar_fix_name(rt->name))
+ error("Health configuration renamed template '%s' to '%s'", value, rt->name);
+ }
+ else if(rc) {
+ if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
+ if(rc->chart) {
+ if(strcmp(rc->chart, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->chart, value, value);
+
+ freez(rc->chart);
+ }
+ rc->chart = strdupz(value);
+ rc->hash_chart = simple_hash(rc->chart);
+ }
+ else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
+ health_parse_db_lookup(line, path, filename, value, &rc->group, &rc->after, &rc->before,
+ &rc->update_every,
+ &rc->options, &rc->dimensions);
+ }
+ else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
+ if(!health_parse_duration(value, &rc->update_every))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' cannot parse duration: '%s'.",
+ line, path, filename, rc->name, key, value);
+ }
+ else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
+ char *e;
+ rc->green = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rc->name, key, e);
+ }
+ }
+ else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
+ char *e;
+ rc->red = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rc->name, key, e);
+ }
+ }
+ else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rc->calculation = expression_parse(value, &failed_at, &error);
+ if(!rc->calculation) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rc->warning = expression_parse(value, &failed_at, &error);
+ if(!rc->warning) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rc->critical = expression_parse(value, &failed_at, &error);
+ if(!rc->critical) {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rc->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
+ if(rc->exec) {
+ if(strcmp(rc->exec, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->exec, value, value);
+
+ freez(rc->exec);
+ }
+ rc->exec = strdupz(value);
+ }
+ else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
+ if(rc->recipient) {
+ if(strcmp(rc->recipient, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->recipient, value, value);
+
+ freez(rc->recipient);
+ }
+ rc->recipient = strdupz(value);
+ }
+ else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
+ if(rc->units) {
+ if(strcmp(rc->units, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->units, value, value);
+
+ freez(rc->units);
+ }
+ rc->units = strdupz(value);
+ strip_quotes(rc->units);
+ }
+ else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
+ if(rc->info) {
+ if(strcmp(rc->info, value))
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rc->name, key, rc->info, value, value);
+
+ freez(rc->info);
+ }
+ rc->info = strdupz(value);
+ strip_quotes(rc->info);
+ }
+ else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
+ health_parse_delay(line, path, filename, value, &rc->delay_up_duration, &rc->delay_down_duration, &rc->delay_max_duration, &rc->delay_multiplier);
+ }
+ else if(hash == hash_options && !strcasecmp(key, HEALTH_OPTIONS_KEY)) {
+ rc->options |= health_parse_options(value);
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s' for alarm '%s' has unknown key '%s'.",
+ line, path, filename, rc->name, key);
+ }
+ }
+ else if(rt) {
+ if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
+ if(rt->context) {
+ if(strcmp(rt->context, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->context, value, value);
+
+ freez(rt->context);
+ }
+ rt->context = strdupz(value);
+ rt->hash_context = simple_hash(rt->context);
+ }
+ else if(hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
+ freez(rt->family_match);
+ simple_pattern_free(rt->family_pattern);
+
+ rt->family_match = strdupz(value);
+ rt->family_pattern = simple_pattern_create(rt->family_match, SIMPLE_PATTERN_EXACT);
+ }
+ else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
+ health_parse_db_lookup(line, path, filename, value, &rt->group, &rt->after, &rt->before,
+ &rt->update_every, &rt->options, &rt->dimensions);
+ }
+ else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
+ if(!health_parse_duration(value, &rt->update_every))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' cannot parse duration: '%s'.",
+ line, path, filename, rt->name, key, value);
+ }
+ else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
+ char *e;
+ rt->green = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rt->name, key, e);
+ }
+ }
+ else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
+ char *e;
+ rt->red = strtold(value, &e);
+ if(e && *e) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
+ line, path, filename, rt->name, key, e);
+ }
+ }
+ else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rt->calculation = expression_parse(value, &failed_at, &error);
+ if(!rt->calculation) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rt->warning = expression_parse(value, &failed_at, &error);
+ if(!rt->warning) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
+ const char *failed_at = NULL;
+ int error = 0;
+ rt->critical = expression_parse(value, &failed_at, &error);
+ if(!rt->critical) {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
+ }
+ }
+ else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
+ if(rt->exec) {
+ if(strcmp(rt->exec, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->exec, value, value);
+
+ freez(rt->exec);
+ }
+ rt->exec = strdupz(value);
+ }
+ else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
+ if(rt->recipient) {
+ if(strcmp(rt->recipient, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->recipient, value, value);
+
+ freez(rt->recipient);
+ }
+ rt->recipient = strdupz(value);
+ }
+ else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
+ if(rt->units) {
+ if(strcmp(rt->units, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->units, value, value);
+
+ freez(rt->units);
+ }
+ rt->units = strdupz(value);
+ strip_quotes(rt->units);
+ }
+ else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
+ if(rt->info) {
+ if(strcmp(rt->info, value))
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
+ line, path, filename, rt->name, key, rt->info, value, value);
+
+ freez(rt->info);
+ }
+ rt->info = strdupz(value);
+ strip_quotes(rt->info);
+ }
+ else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
+ health_parse_delay(line, path, filename, value, &rt->delay_up_duration, &rt->delay_down_duration, &rt->delay_max_duration, &rt->delay_multiplier);
+ }
+ else if(hash == hash_options && !strcasecmp(key, HEALTH_OPTIONS_KEY)) {
+ rt->options |= health_parse_options(value);
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has unknown key '%s'.",
+ line, path, filename, rt->name, key);
+ }
+ }
+ else {
+ error("Health configuration at line %zu of file '%s/%s' has unknown key '%s'. Expected either '" HEALTH_ALARM_KEY "' or '" HEALTH_TEMPLATE_KEY "'.",
+ line, path, filename, key);
+ }
+ }
+
+ if(rc && !rrdcalc_add_alarm_from_config(host, rc))
+ rrdcalc_free(host, rc);
+
+ if(rt && !rrdcalctemplate_add_template_from_config(host, rt))
+ rrdcalctemplate_free(host, rt);
+
+ fclose(fp);
+ return 1;
+}
+
+void health_readdir(RRDHOST *host, const char *path) {
+ if(!host->health_enabled) return;
+
+ size_t pathlen = strlen(path);
+
+ debug(D_HEALTH, "Health configuration reading directory '%s'", path);
+
+ DIR *dir = opendir(path);
+ if (!dir) {
+ error("Health configuration cannot open directory '%s'.", path);
+ return;
+ }
+
+ struct dirent *de = NULL;
+ while ((de = readdir(dir))) {
+ size_t len = strlen(de->d_name);
+
+ if(de->d_type == DT_DIR
+ && (
+ (de->d_name[0] == '.' && de->d_name[1] == '\0')
+ || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
+ )) {
+ debug(D_HEALTH, "Ignoring directory '%s'", de->d_name);
+ continue;
+ }
+
+ else if(de->d_type == DT_DIR) {
+ char *s = mallocz(pathlen + strlen(de->d_name) + 2);
+ strcpy(s, path);
+ strcat(s, "/");
+ strcat(s, de->d_name);
+ health_readdir(host, s);
+ freez(s);
+ continue;
+ }
+
+ else if((de->d_type == DT_LNK || de->d_type == DT_REG || de->d_type == DT_UNKNOWN) &&
+ len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
+ health_readfile(host, path, de->d_name);
+ }
+
+ else debug(D_HEALTH, "Ignoring file '%s'", de->d_name);
+ }
+
+ closedir(dir);
+}
+
+
diff --git a/src/health_json.c b/src/health_json.c
new file mode 100644
index 000000000..a9697aaa7
--- /dev/null
+++ b/src/health_json.c
@@ -0,0 +1,256 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+static inline void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix) {
+ if(value && *value)
+ buffer_sprintf(wb, "%s\"%s\":\"%s\"%s", prefix, label, value, suffix);
+ else
+ buffer_sprintf(wb, "%s\"%s\":null%s", prefix, label, suffix);
+}
+
+static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host) {
+ buffer_sprintf(wb,
+ "\n\t{\n"
+ "\t\t\"hostname\": \"%s\",\n"
+ "\t\t\"unique_id\": %u,\n"
+ "\t\t\"alarm_id\": %u,\n"
+ "\t\t\"alarm_event_id\": %u,\n"
+ "\t\t\"name\": \"%s\",\n"
+ "\t\t\"chart\": \"%s\",\n"
+ "\t\t\"family\": \"%s\",\n"
+ "\t\t\"processed\": %s,\n"
+ "\t\t\"updated\": %s,\n"
+ "\t\t\"exec_run\": %lu,\n"
+ "\t\t\"exec_failed\": %s,\n"
+ "\t\t\"exec\": \"%s\",\n"
+ "\t\t\"recipient\": \"%s\",\n"
+ "\t\t\"exec_code\": %d,\n"
+ "\t\t\"source\": \"%s\",\n"
+ "\t\t\"units\": \"%s\",\n"
+ "\t\t\"info\": \"%s\",\n"
+ "\t\t\"when\": %lu,\n"
+ "\t\t\"duration\": %lu,\n"
+ "\t\t\"non_clear_duration\": %lu,\n"
+ "\t\t\"status\": \"%s\",\n"
+ "\t\t\"old_status\": \"%s\",\n"
+ "\t\t\"delay\": %d,\n"
+ "\t\t\"delay_up_to_timestamp\": %lu,\n"
+ "\t\t\"updated_by_id\": %u,\n"
+ "\t\t\"updates_id\": %u,\n"
+ "\t\t\"value_string\": \"%s\",\n"
+ "\t\t\"old_value_string\": \"%s\",\n"
+ , host->hostname
+ , ae->unique_id
+ , ae->alarm_id
+ , ae->alarm_event_id
+ , ae->name
+ , ae->chart
+ , ae->family
+ , (ae->flags & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false"
+ , (ae->flags & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false"
+ , (unsigned long)ae->exec_run_timestamp
+ , (ae->flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false"
+ , ae->exec?ae->exec:host->health_default_exec
+ , ae->recipient?ae->recipient:host->health_default_recipient
+ , ae->exec_code
+ , ae->source
+ , ae->units?ae->units:""
+ , ae->info?ae->info:""
+ , (unsigned long)ae->when
+ , (unsigned long)ae->duration
+ , (unsigned long)ae->non_clear_duration
+ , rrdcalc_status2string(ae->new_status)
+ , rrdcalc_status2string(ae->old_status)
+ , ae->delay
+ , (unsigned long)ae->delay_up_to_timestamp
+ , ae->updated_by_id
+ , ae->updates_id
+ , ae->new_value_string
+ , ae->old_value_string
+ );
+
+ if(unlikely(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
+ buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
+ }
+
+ buffer_strcat(wb, "\t\t\"value\":");
+ buffer_rrd_value(wb, ae->new_value);
+ buffer_strcat(wb, ",\n");
+
+ buffer_strcat(wb, "\t\t\"old_value\":");
+ buffer_rrd_value(wb, ae->old_value);
+ buffer_strcat(wb, "\n");
+
+ buffer_strcat(wb, "\t}");
+}
+
+void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after) {
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+
+ buffer_strcat(wb, "[");
+
+ unsigned int max = host->health_log.max;
+ unsigned int count = 0;
+ ALARM_ENTRY *ae;
+ for(ae = host->health_log.alarms; ae && count < max ; count++, ae = ae->next) {
+ if(ae->unique_id > after) {
+ if(likely(count)) buffer_strcat(wb, ",");
+ health_alarm_entry2json_nolock(wb, ae, host);
+ }
+ }
+
+ buffer_strcat(wb, "\n]\n");
+
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+}
+
+static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
+ char value_string[100 + 1];
+ format_value_and_unit(value_string, 100, rc->value, rc->units, -1);
+
+ buffer_sprintf(wb,
+ "\t\t\"%s.%s\": {\n"
+ "\t\t\t\"id\": %lu,\n"
+ "\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\"chart\": \"%s\",\n"
+ "\t\t\t\"family\": \"%s\",\n"
+ "\t\t\t\"active\": %s,\n"
+ "\t\t\t\"exec\": \"%s\",\n"
+ "\t\t\t\"recipient\": \"%s\",\n"
+ "\t\t\t\"source\": \"%s\",\n"
+ "\t\t\t\"units\": \"%s\",\n"
+ "\t\t\t\"info\": \"%s\",\n"
+ "\t\t\t\"status\": \"%s\",\n"
+ "\t\t\t\"last_status_change\": %lu,\n"
+ "\t\t\t\"last_updated\": %lu,\n"
+ "\t\t\t\"next_update\": %lu,\n"
+ "\t\t\t\"update_every\": %d,\n"
+ "\t\t\t\"delay_up_duration\": %d,\n"
+ "\t\t\t\"delay_down_duration\": %d,\n"
+ "\t\t\t\"delay_max_duration\": %d,\n"
+ "\t\t\t\"delay_multiplier\": %f,\n"
+ "\t\t\t\"delay\": %d,\n"
+ "\t\t\t\"delay_up_to_timestamp\": %lu,\n"
+ "\t\t\t\"value_string\": \"%s\",\n"
+ , rc->chart, rc->name
+ , (unsigned long)rc->id
+ , rc->name
+ , rc->chart
+ , (rc->rrdset && rc->rrdset->family)?rc->rrdset->family:""
+ , (rc->rrdset)?"true":"false"
+ , rc->exec?rc->exec:host->health_default_exec
+ , rc->recipient?rc->recipient:host->health_default_recipient
+ , rc->source
+ , rc->units?rc->units:""
+ , rc->info?rc->info:""
+ , rrdcalc_status2string(rc->status)
+ , (unsigned long)rc->last_status_change
+ , (unsigned long)rc->last_updated
+ , (unsigned long)rc->next_update
+ , rc->update_every
+ , rc->delay_up_duration
+ , rc->delay_down_duration
+ , rc->delay_max_duration
+ , rc->delay_multiplier
+ , rc->delay_last
+ , (unsigned long)rc->delay_up_to_timestamp
+ , value_string
+ );
+
+ if(unlikely(rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION)) {
+ buffer_strcat(wb, "\t\t\t\"no_clear_notification\": true,\n");
+ }
+
+ if(RRDCALC_HAS_DB_LOOKUP(rc)) {
+ if(rc->dimensions && *rc->dimensions)
+ health_string2json(wb, "\t\t\t", "lookup_dimensions", rc->dimensions, ",\n");
+
+ buffer_sprintf(wb,
+ "\t\t\t\"db_after\": %lu,\n"
+ "\t\t\t\"db_before\": %lu,\n"
+ "\t\t\t\"lookup_method\": \"%s\",\n"
+ "\t\t\t\"lookup_after\": %d,\n"
+ "\t\t\t\"lookup_before\": %d,\n"
+ "\t\t\t\"lookup_options\": \"",
+ (unsigned long) rc->db_after,
+ (unsigned long) rc->db_before,
+ group_method2string(rc->group),
+ rc->after,
+ rc->before
+ );
+ buffer_data_options2string(wb, rc->options);
+ buffer_strcat(wb, "\",\n");
+ }
+
+ if(rc->calculation) {
+ health_string2json(wb, "\t\t\t", "calc", rc->calculation->source, ",\n");
+ health_string2json(wb, "\t\t\t", "calc_parsed", rc->calculation->parsed_as, ",\n");
+ }
+
+ if(rc->warning) {
+ health_string2json(wb, "\t\t\t", "warn", rc->warning->source, ",\n");
+ health_string2json(wb, "\t\t\t", "warn_parsed", rc->warning->parsed_as, ",\n");
+ }
+
+ if(rc->critical) {
+ health_string2json(wb, "\t\t\t", "crit", rc->critical->source, ",\n");
+ health_string2json(wb, "\t\t\t", "crit_parsed", rc->critical->parsed_as, ",\n");
+ }
+
+ buffer_strcat(wb, "\t\t\t\"green\":");
+ buffer_rrd_value(wb, rc->green);
+ buffer_strcat(wb, ",\n");
+
+ buffer_strcat(wb, "\t\t\t\"red\":");
+ buffer_rrd_value(wb, rc->red);
+ buffer_strcat(wb, ",\n");
+
+ buffer_strcat(wb, "\t\t\t\"value\":");
+ buffer_rrd_value(wb, rc->value);
+ buffer_strcat(wb, "\n");
+
+ buffer_strcat(wb, "\t\t}");
+}
+
+//void health_rrdcalctemplate2json_nolock(BUFFER *wb, RRDCALCTEMPLATE *rt) {
+//
+//}
+
+void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
+ int i;
+
+ rrdhost_rdlock(host);
+ buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
+ "\n\t\"latest_alarm_log_unique_id\": %u,"
+ "\n\t\"status\": %s,"
+ "\n\t\"now\": %lu,"
+ "\n\t\"alarms\": {\n",
+ host->hostname,
+ (host->health_log.next_log_id > 0)?(host->health_log.next_log_id - 1):0,
+ host->health_enabled?"true":"false",
+ (unsigned long)now_realtime_sec());
+
+ RRDCALC *rc;
+ for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
+ if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
+ continue;
+
+ if(likely(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL)))
+ continue;
+
+ if(likely(i)) buffer_strcat(wb, ",\n");
+ health_rrdcalc2json_nolock(host, wb, rc);
+ i++;
+ }
+
+// buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
+// RRDCALCTEMPLATE *rt;
+// for(rt = host->templates; rt ; rt = rt->next)
+// health_rrdcalctemplate2json_nolock(wb, rt);
+
+ buffer_strcat(wb, "\n\t}\n}\n");
+ rrdhost_unlock(host);
+}
+
+
+
diff --git a/src/health_log.c b/src/health_log.c
new file mode 100644
index 000000000..95abcfe5f
--- /dev/null
+++ b/src/health_log.c
@@ -0,0 +1,465 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// health alarm log load/save
+// no need for locking - only one thread is reading / writing the alarms log
+
+inline int health_alarm_log_open(RRDHOST *host) {
+ if(host->health_log_fp)
+ fclose(host->health_log_fp);
+
+ host->health_log_fp = fopen(host->health_log_filename, "a");
+
+ if(host->health_log_fp) {
+ if (setvbuf(host->health_log_fp, NULL, _IOLBF, 0) != 0)
+ error("HEALTH [%s]: cannot set line buffering on health log file '%s'.", host->hostname, host->health_log_filename);
+ return 0;
+ }
+
+ error("HEALTH [%s]: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", host->hostname, host->health_log_filename);
+ return -1;
+}
+
+inline void health_alarm_log_close(RRDHOST *host) {
+ if(host->health_log_fp) {
+ fclose(host->health_log_fp);
+ host->health_log_fp = NULL;
+ }
+}
+
+inline void health_log_rotate(RRDHOST *host) {
+ static size_t rotate_every = 0;
+
+ if(unlikely(rotate_every == 0)) {
+ rotate_every = (size_t)config_get_number(CONFIG_SECTION_HEALTH, "rotate log every lines", 2000);
+ if(rotate_every < 100) rotate_every = 100;
+ }
+
+ if(unlikely(host->health_log_entries_written > rotate_every)) {
+ health_alarm_log_close(host);
+
+ char old_filename[FILENAME_MAX + 1];
+ snprintfz(old_filename, FILENAME_MAX, "%s.old", host->health_log_filename);
+
+ if(unlink(old_filename) == -1 && errno != ENOENT)
+ error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, old_filename);
+
+ if(link(host->health_log_filename, old_filename) == -1 && errno != ENOENT)
+ error("HEALTH [%s]: cannot move file '%s' to '%s'.", host->hostname, host->health_log_filename, old_filename);
+
+ if(unlink(host->health_log_filename) == -1 && errno != ENOENT)
+ error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, host->health_log_filename);
+
+ // open it with truncate
+ host->health_log_fp = fopen(host->health_log_filename, "w");
+
+ if(host->health_log_fp)
+ fclose(host->health_log_fp);
+ else
+ error("HEALTH [%s]: cannot truncate health log '%s'", host->hostname, host->health_log_filename);
+
+ host->health_log_fp = NULL;
+
+ host->health_log_entries_written = 0;
+ health_alarm_log_open(host);
+ }
+}
+
+inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
+ health_log_rotate(host);
+
+ if(likely(host->health_log_fp)) {
+ if(unlikely(fprintf(host->health_log_fp
+ , "%c\t%s"
+ "\t%08x\t%08x\t%08x\t%08x\t%08x"
+ "\t%08x\t%08x\t%08x"
+ "\t%08x\t%08x\t%08x"
+ "\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s"
+ "\t%d\t%d\t%d\t%d"
+ "\t%Lf\t%Lf"
+ "\n"
+ , (ae->flags & HEALTH_ENTRY_FLAG_SAVED)?'U':'A'
+ , host->hostname
+
+ , ae->unique_id
+ , ae->alarm_id
+ , ae->alarm_event_id
+ , ae->updated_by_id
+ , ae->updates_id
+
+ , (uint32_t)ae->when
+ , (uint32_t)ae->duration
+ , (uint32_t)ae->non_clear_duration
+ , (uint32_t)ae->flags
+ , (uint32_t)ae->exec_run_timestamp
+ , (uint32_t)ae->delay_up_to_timestamp
+
+ , (ae->name)?ae->name:""
+ , (ae->chart)?ae->chart:""
+ , (ae->family)?ae->family:""
+ , (ae->exec)?ae->exec:""
+ , (ae->recipient)?ae->recipient:""
+ , (ae->source)?ae->source:""
+ , (ae->units)?ae->units:""
+ , (ae->info)?ae->info:""
+
+ , ae->exec_code
+ , ae->new_status
+ , ae->old_status
+ , ae->delay
+
+ , (long double)ae->new_value
+ , (long double)ae->old_value
+ ) < 0))
+ error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.", host->hostname, host->health_log_filename);
+ else {
+ ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
+ host->health_log_entries_written++;
+ }
+ }
+}
+
+inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename) {
+ static uint32_t max_unique_id = 0, max_alarm_id = 0;
+
+ errno = 0;
+
+ char *s, *buf = mallocz(65536 + 1);
+ size_t line = 0, len = 0;
+ ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
+
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+
+ while((s = fgets_trim_len(buf, 65536, fp, &len))) {
+ host->health_log_entries_written++;
+ line++;
+
+ int max_entries = 30, entries = 0;
+ char *pointers[max_entries];
+
+ pointers[entries++] = s++;
+ while(*s) {
+ if(unlikely(*s == '\t')) {
+ *s = '\0';
+ pointers[entries++] = ++s;
+ if(entries >= max_entries) {
+ error("HEALTH [%s]: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", host->hostname, line, filename, max_entries);
+ break;
+ }
+ }
+ else s++;
+ }
+
+ if(likely(*pointers[0] == 'U' || *pointers[0] == 'A')) {
+ ALARM_ENTRY *ae = NULL;
+
+ if(entries < 26) {
+ error("HEALTH [%s]: line %zu of file '%s' should have at least 26 entries, but it has %d. Ignoring it.", host->hostname, line, filename, entries);
+ errored++;
+ continue;
+ }
+
+ // check that we have valid ids
+ uint32_t unique_id = (uint32_t)strtoul(pointers[2], NULL, 16);
+ if(!unique_id) {
+ error("HEALTH [%s]: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", host->hostname, line, filename, unique_id, pointers[2]);
+ errored++;
+ continue;
+ }
+
+ uint32_t alarm_id = (uint32_t)strtoul(pointers[3], NULL, 16);
+ if(!alarm_id) {
+ error("HEALTH [%s]: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", host->hostname, line, filename, alarm_id, pointers[3]);
+ errored++;
+ continue;
+ }
+
+ if(unlikely(*pointers[0] == 'A')) {
+ // make sure it is properly numbered
+ if(unlikely(host->health_log.alarms && unique_id < host->health_log.alarms->unique_id)) {
+ error("HEALTH [%s]: line %zu of file '%s' has alarm log entry %u in wrong order. Ignoring it.", host->hostname, line, filename, unique_id);
+ errored++;
+ continue;
+ }
+
+ ae = callocz(1, sizeof(ALARM_ENTRY));
+ }
+ else if(unlikely(*pointers[0] == 'U')) {
+ // find the original
+ for(ae = host->health_log.alarms; ae; ae = ae->next) {
+ if(unlikely(unique_id == ae->unique_id)) {
+ if(unlikely(*pointers[0] == 'A')) {
+ error("HEALTH [%s]: line %zu of file '%s' adds duplicate alarm log entry %u. Using the later."
+ , host->hostname, line, filename, unique_id);
+ *pointers[0] = 'U';
+ duplicate++;
+ }
+ break;
+ }
+ else if(unlikely(unique_id > ae->unique_id)) {
+ // no need to continue
+ // the linked list is sorted
+ ae = NULL;
+ break;
+ }
+ }
+ }
+
+ // if not found, skip this line
+ if(unlikely(!ae)) {
+ // error("HEALTH [%s]: line %zu of file '%s' updates alarm log entry with unique id %u, but it is not found.", host->hostname, line, filename, unique_id);
+ continue;
+ }
+
+ // check for a possible host missmatch
+ //if(strcmp(pointers[1], host->hostname))
+ // error("HEALTH [%s]: line %zu of file '%s' provides an alarm for host '%s' but this is named '%s'.", host->hostname, line, filename, pointers[1], host->hostname);
+
+ ae->unique_id = unique_id;
+ ae->alarm_id = alarm_id;
+ ae->alarm_event_id = (uint32_t)strtoul(pointers[4], NULL, 16);
+ ae->updated_by_id = (uint32_t)strtoul(pointers[5], NULL, 16);
+ ae->updates_id = (uint32_t)strtoul(pointers[6], NULL, 16);
+
+ ae->when = (uint32_t)strtoul(pointers[7], NULL, 16);
+ ae->duration = (uint32_t)strtoul(pointers[8], NULL, 16);
+ ae->non_clear_duration = (uint32_t)strtoul(pointers[9], NULL, 16);
+
+ ae->flags = (uint32_t)strtoul(pointers[10], NULL, 16);
+ ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
+
+ ae->exec_run_timestamp = (uint32_t)strtoul(pointers[11], NULL, 16);
+ ae->delay_up_to_timestamp = (uint32_t)strtoul(pointers[12], NULL, 16);
+
+ freez(ae->name);
+ ae->name = strdupz(pointers[13]);
+ ae->hash_name = simple_hash(ae->name);
+
+ freez(ae->chart);
+ ae->chart = strdupz(pointers[14]);
+ ae->hash_chart = simple_hash(ae->chart);
+
+ freez(ae->family);
+ ae->family = strdupz(pointers[15]);
+
+ freez(ae->exec);
+ ae->exec = strdupz(pointers[16]);
+ if(!*ae->exec) { freez(ae->exec); ae->exec = NULL; }
+
+ freez(ae->recipient);
+ ae->recipient = strdupz(pointers[17]);
+ if(!*ae->recipient) { freez(ae->recipient); ae->recipient = NULL; }
+
+ freez(ae->source);
+ ae->source = strdupz(pointers[18]);
+ if(!*ae->source) { freez(ae->source); ae->source = NULL; }
+
+ freez(ae->units);
+ ae->units = strdupz(pointers[19]);
+ if(!*ae->units) { freez(ae->units); ae->units = NULL; }
+
+ freez(ae->info);
+ ae->info = strdupz(pointers[20]);
+ if(!*ae->info) { freez(ae->info); ae->info = NULL; }
+
+ ae->exec_code = str2i(pointers[21]);
+ ae->new_status = str2i(pointers[22]);
+ ae->old_status = str2i(pointers[23]);
+ ae->delay = str2i(pointers[24]);
+
+ ae->new_value = str2l(pointers[25]);
+ ae->old_value = str2l(pointers[26]);
+
+ static char value_string[100 + 1];
+ freez(ae->old_value_string);
+ freez(ae->new_value_string);
+ ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
+ ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
+
+ // add it to host if not already there
+ if(unlikely(*pointers[0] == 'A')) {
+ ae->next = host->health_log.alarms;
+ host->health_log.alarms = ae;
+ loaded++;
+ }
+ else updated++;
+
+ if(unlikely(ae->unique_id > max_unique_id))
+ max_unique_id = ae->unique_id;
+
+ if(unlikely(ae->alarm_id >= max_alarm_id))
+ max_alarm_id = ae->alarm_id;
+ }
+ else {
+ error("HEALTH [%s]: line %zu of file '%s' is invalid (unrecognized entry type '%s').", host->hostname, line, filename, pointers[0]);
+ errored++;
+ }
+ }
+
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+
+ freez(buf);
+
+ if(!max_unique_id) max_unique_id = (uint32_t)now_realtime_sec();
+ if(!max_alarm_id) max_alarm_id = (uint32_t)now_realtime_sec();
+
+ host->health_log.next_log_id = max_unique_id + 1;
+ host->health_log.next_alarm_id = max_alarm_id + 1;
+
+ debug(D_HEALTH, "HEALTH [%s]: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", host->hostname, filename, loaded, updated, errored, duplicate);
+ return loaded;
+}
+
+inline void health_alarm_log_load(RRDHOST *host) {
+ health_alarm_log_close(host);
+
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s.old", host->health_log_filename);
+ FILE *fp = fopen(filename, "r");
+ if(!fp)
+ error("HEALTH [%s]: cannot open health file: %s", host->hostname, filename);
+ else {
+ health_alarm_log_read(host, fp, filename);
+ fclose(fp);
+ }
+
+ host->health_log_entries_written = 0;
+ fp = fopen(host->health_log_filename, "r");
+ if(!fp)
+ error("HEALTH [%s]: cannot open health file: %s", host->hostname, host->health_log_filename);
+ else {
+ health_alarm_log_read(host, fp, host->health_log_filename);
+ fclose(fp);
+ }
+
+ health_alarm_log_open(host);
+}
+
+
+// ----------------------------------------------------------------------------
+// health alarm log management
+
+inline void health_alarm_log(
+ RRDHOST *host,
+ uint32_t alarm_id,
+ uint32_t alarm_event_id,
+ time_t when,
+ const char *name,
+ const char *chart,
+ const char *family,
+ const char *exec,
+ const char *recipient,
+ time_t duration,
+ calculated_number old_value,
+ calculated_number new_value,
+ int old_status,
+ int new_status,
+ const char *source,
+ const char *units,
+ const char *info,
+ int delay,
+ uint32_t flags
+) {
+ debug(D_HEALTH, "Health adding alarm log entry with id: %u", host->health_log.next_log_id);
+
+ ALARM_ENTRY *ae = callocz(1, sizeof(ALARM_ENTRY));
+ ae->name = strdupz(name);
+ ae->hash_name = simple_hash(ae->name);
+
+ if(chart) {
+ ae->chart = strdupz(chart);
+ ae->hash_chart = simple_hash(ae->chart);
+ }
+
+ if(family)
+ ae->family = strdupz(family);
+
+ if(exec) ae->exec = strdupz(exec);
+ if(recipient) ae->recipient = strdupz(recipient);
+ if(source) ae->source = strdupz(source);
+ if(units) ae->units = strdupz(units);
+ if(info) ae->info = strdupz(info);
+
+ ae->unique_id = host->health_log.next_log_id++;
+ ae->alarm_id = alarm_id;
+ ae->alarm_event_id = alarm_event_id;
+ ae->when = when;
+ ae->old_value = old_value;
+ ae->new_value = new_value;
+
+ static char value_string[100 + 1];
+ ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
+ ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
+
+ ae->old_status = old_status;
+ ae->new_status = new_status;
+ ae->duration = duration;
+ ae->delay = delay;
+ ae->delay_up_to_timestamp = when + delay;
+
+ ae->flags |= flags;
+
+ if(ae->old_status == RRDCALC_STATUS_WARNING || ae->old_status == RRDCALC_STATUS_CRITICAL)
+ ae->non_clear_duration += ae->duration;
+
+ // link it
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ ae->next = host->health_log.alarms;
+ host->health_log.alarms = ae;
+ host->health_log.count++;
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+
+ // match previous alarms
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ ALARM_ENTRY *t;
+ for(t = host->health_log.alarms ; t ; t = t->next) {
+ if(t != ae && t->alarm_id == ae->alarm_id) {
+ if(!(t->flags & HEALTH_ENTRY_FLAG_UPDATED) && !t->updated_by_id) {
+ t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
+ t->updated_by_id = ae->unique_id;
+ ae->updates_id = t->unique_id;
+
+ if((t->new_status == RRDCALC_STATUS_WARNING || t->new_status == RRDCALC_STATUS_CRITICAL) &&
+ (t->old_status == RRDCALC_STATUS_WARNING || t->old_status == RRDCALC_STATUS_CRITICAL))
+ ae->non_clear_duration += t->non_clear_duration;
+
+ health_alarm_log_save(host, t);
+ }
+
+ // no need to continue
+ break;
+ }
+ }
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+
+ health_alarm_log_save(host, ae);
+}
+
+inline void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae) {
+ freez(ae->name);
+ freez(ae->chart);
+ freez(ae->family);
+ freez(ae->exec);
+ freez(ae->recipient);
+ freez(ae->source);
+ freez(ae->units);
+ freez(ae->info);
+ freez(ae->old_value_string);
+ freez(ae->new_value_string);
+ freez(ae);
+}
+
+inline void health_alarm_log_free(RRDHOST *host) {
+ rrdhost_check_wrlock(host);
+
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+
+ ALARM_ENTRY *ae;
+ while((ae = host->health_log.alarms)) {
+ host->health_log.alarms = ae->next;
+ health_alarm_log_free_one_nochecks_nounlink(ae);
+ }
+
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+}
diff --git a/src/inlined.h b/src/inlined.h
index e776f830e..0dc11c950 100644
--- a/src/inlined.h
+++ b/src/inlined.h
@@ -3,6 +3,19 @@
#include "common.h"
+#ifdef KERNEL_32BIT
+typedef uint32_t kernel_uint_t;
+#define str2kernel_uint_t(string) str2uint32_t(string)
+#define KERNEL_UINT_FORMAT "%u"
+#else
+typedef uint64_t kernel_uint_t;
+#define str2kernel_uint_t(string) str2uint64_t(string)
+#define KERNEL_UINT_FORMAT "%" PRIu64
+#endif
+
+#define str2pid_t(string) str2uint32_t(string)
+
+
// for faster execution, allow the compiler to inline
// these functions that are called thousands of times per second
@@ -70,6 +83,26 @@ static inline long str2l(const char *s) {
return n;
}
+static inline uint32_t str2uint32_t(const char *s) {
+ uint32_t n = 0;
+ char c;
+ for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) {
+ n *= 10;
+ n += c - '0';
+ }
+ return n;
+}
+
+static inline uint64_t str2uint64_t(const char *s) {
+ uint64_t n = 0;
+ char c;
+ for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) {
+ n *= 10;
+ n += c - '0';
+ }
+ return n;
+}
+
static inline unsigned long str2ul(const char *s) {
unsigned long n = 0;
char c;
@@ -95,12 +128,24 @@ static inline unsigned long long str2ull(const char *s) {
#undef strcmp
#endif
#define strcmp(a, b) strsame(a, b)
+#endif // NETDATA_STRCMP_OVERRIDE
+
static inline int strsame(const char *a, const char *b) {
if(unlikely(a == b)) return 0;
while(*a && *a == *b) { a++; b++; }
return *a - *b;
}
-#endif // NETDATA_STRSAME
+
+static inline char *strncpyz(char *dst, const char *src, size_t n) {
+ char *p = dst;
+
+ while (*src && n--)
+ *dst++ = *src++;
+
+ *dst = '\0';
+
+ return p;
+}
static inline int read_single_number_file(const char *filename, unsigned long long *result) {
char buffer[30 + 1];
diff --git a/src/ipc.c b/src/ipc.c
index a5ab342d3..1dabf5e19 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -57,7 +57,7 @@ static inline int ipc_sem_get_limits(struct ipc_limits *lim) {
static char filename[FILENAME_MAX + 1] = "";
if(unlikely(!filename[0]))
- snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", netdata_configured_host_prefix);
if(unlikely(!ff)) {
ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
@@ -184,23 +184,27 @@ int do_ipc(int update_every, usec_t dt) {
return 1;
}
- arrays_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.arrays.max");
- semaphores_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.max");
+ arrays_max = rrdvar_custom_host_variable_create(localhost, "ipc.semaphores.arrays.max");
+ semaphores_max = rrdvar_custom_host_variable_create(localhost, "ipc.semaphores.max");
if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
// create the charts
- semaphores = rrdset_find("system.ipc_semaphores");
+ semaphores = rrdset_find_localhost("system.ipc_semaphores");
if(!semaphores) {
- semaphores = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ semaphores = rrdset_create_localhost("system", "ipc_semaphores", NULL, "ipc semaphores", NULL
+ , "IPC Semaphores", "semaphores", 1000, localhost->rrd_update_every
+ , RRDSET_TYPE_AREA);
+ rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- arrays = rrdset_find("system.ipc_semaphore_arrays");
+ arrays = rrdset_find_localhost("system.ipc_semaphore_arrays");
if(!arrays) {
- arrays = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(arrays, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ arrays = rrdset_create_localhost("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL
+ , "IPC Semaphore Arrays", "arrays", 1000, localhost->rrd_update_every
+ , RRDSET_TYPE_AREA);
+ rrddim_add(arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
}
diff --git a/src/locks.h b/src/locks.h
new file mode 100644
index 000000000..76533f636
--- /dev/null
+++ b/src/locks.h
@@ -0,0 +1,294 @@
+#ifndef NETDATA_LOCKS_H
+#define NETDATA_LOCKS_H
+
+// ----------------------------------------------------------------------------
+// mutex
+
+typedef pthread_mutex_t netdata_mutex_t;
+
+#define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+static inline int __netdata_mutex_init(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_init(mutex, NULL);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to initialize (code %d).", ret);
+ return ret;
+}
+
+static inline int __netdata_mutex_lock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_lock(mutex);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to get lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_trylock(mutex);
+ return ret;
+}
+
+static inline int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_unlock(mutex);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to unlock (code %d).", ret);
+ return ret;
+}
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+static inline int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_init(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_lock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_trylock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_unlock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+#define netdata_mutex_init(mutex) netdata_mutex_init_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_lock(mutex) netdata_mutex_lock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_trylock(mutex) netdata_mutex_trylock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_unlock(mutex) netdata_mutex_unlock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex)
+#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex)
+#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex)
+#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex)
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+
+// ----------------------------------------------------------------------------
+// r/w lock
+
+typedef pthread_rwlock_t netdata_rwlock_t;
+
+#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+
+static inline int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_destroy(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to destroy lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_init(rwlock, NULL);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to initialize lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_rdlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to obtain read lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_wrlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to obtain write lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_unlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to release lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_tryrdlock(rwlock);
+ return ret;
+}
+
+static inline int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_trywrlock(rwlock);
+ return ret;
+}
+
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+static inline int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_destroy(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_init(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_rdlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_wrlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_unlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_tryrdlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_trywrlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+#define netdata_rwlock_destroy(rwlock) netdata_rwlock_destroy_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_init(rwlock) netdata_rwlock_init_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_rdlock(rwlock) netdata_rwlock_rdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_wrlock(rwlock) netdata_rwlock_wrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_unlock(rwlock) netdata_rwlock_unlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_tryrdlock(rwlock) netdata_rwlock_tryrdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_trywrlock(rwlock) netdata_rwlock_trywrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define netdata_rwlock_destroy(rwlock) __netdata_rwlock_destroy(rwlock)
+#define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock)
+#define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock)
+#define netdata_rwlock_wrlock(rwlock) __netdata_rwlock_wrlock(rwlock)
+#define netdata_rwlock_unlock(rwlock) __netdata_rwlock_unlock(rwlock)
+#define netdata_rwlock_tryrdlock(rwlock) __netdata_rwlock_tryrdlock(rwlock)
+#define netdata_rwlock_trywrlock(rwlock) __netdata_rwlock_trywrlock(rwlock)
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+#endif //NETDATA_LOCKS_H
diff --git a/src/log.c b/src/log.c
index d4c7fa14d..855ecaee6 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,7 +1,7 @@
#include "common.h"
const char *program_name = "";
-unsigned long long debug_flags = DEBUG;
+uint64_t debug_flags = DEBUG;
int access_log_syslog = 1;
int error_log_syslog = 1;
@@ -257,8 +257,8 @@ void info_int( const char *file, const char *function, const unsigned long line,
log_date(stderr);
va_start( args, fmt );
- if(debug_flags) fprintf(stderr, "%s: INFO: (%04lu@%-10.10s:%-15.15s):", program_name, line, file, function);
- else fprintf(stderr, "%s: INFO: ", program_name);
+ if(debug_flags) fprintf(stderr, "%s: INFO : (%04lu@%-10.10s:%-15.15s): ", program_name, line, file, function);
+ else fprintf(stderr, "%s: INFO : ", program_name);
vfprintf( stderr, fmt, args );
va_end( args );
diff --git a/src/log.h b/src/log.h
index e61ffdd08..d8ff0654b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -1,38 +1,40 @@
#ifndef NETDATA_LOG_H
#define NETDATA_LOG_H 1
-#define D_WEB_BUFFER 0x00000001
-#define D_WEB_CLIENT 0x00000002
-#define D_LISTENER 0x00000004
-#define D_WEB_DATA 0x00000008
-#define D_OPTIONS 0x00000010
-#define D_PROCNETDEV_LOOP 0x00000020
-#define D_RRD_STATS 0x00000040
-#define D_WEB_CLIENT_ACCESS 0x00000080
-#define D_TC_LOOP 0x00000100
-#define D_DEFLATE 0x00000200
-#define D_CONFIG 0x00000400
-#define D_PLUGINSD 0x00000800
-#define D_CHILDS 0x00001000
-#define D_EXIT 0x00002000
-#define D_CHECKS 0x00004000
-#define D_NFACCT_LOOP 0x00008000
-#define D_PROCFILE 0x00010000
-#define D_RRD_CALLS 0x00020000
-#define D_DICTIONARY 0x00040000
-#define D_MEMORY 0x00080000
-#define D_CGROUP 0x00100000
-#define D_REGISTRY 0x00200000
-#define D_VARIABLES 0x00400000
-#define D_HEALTH 0x00800000
-#define D_CONNECT_TO 0x01000000
-#define D_SYSTEM 0x80000000
+#define D_WEB_BUFFER 0x0000000000000001
+#define D_WEB_CLIENT 0x0000000000000002
+#define D_LISTENER 0x0000000000000004
+#define D_WEB_DATA 0x0000000000000008
+#define D_OPTIONS 0x0000000000000010
+#define D_PROCNETDEV_LOOP 0x0000000000000020
+#define D_RRD_STATS 0x0000000000000040
+#define D_WEB_CLIENT_ACCESS 0x0000000000000080
+#define D_TC_LOOP 0x0000000000000100
+#define D_DEFLATE 0x0000000000000200
+#define D_CONFIG 0x0000000000000400
+#define D_PLUGINSD 0x0000000000000800
+#define D_CHILDS 0x0000000000001000
+#define D_EXIT 0x0000000000002000
+#define D_CHECKS 0x0000000000004000
+#define D_NFACCT_LOOP 0x0000000000008000
+#define D_PROCFILE 0x0000000000010000
+#define D_RRD_CALLS 0x0000000000020000
+#define D_DICTIONARY 0x0000000000040000
+#define D_MEMORY 0x0000000000080000
+#define D_CGROUP 0x0000000000100000
+#define D_REGISTRY 0x0000000000200000
+#define D_VARIABLES 0x0000000000400000
+#define D_HEALTH 0x0000000000800000
+#define D_CONNECT_TO 0x0000000001000000
+#define D_RRDHOST 0x0000000002000000
+#define D_LOCKS 0x0000000004000000
+#define D_SYSTEM 0x8000000000000000
//#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
//#define DEBUG 0xffffffff
#define DEBUG (0)
-extern unsigned long long debug_flags;
+extern uint64_t debug_flags;
extern const char *program_name;
diff --git a/src/macos_fw.c b/src/macos_fw.c
index a62aa7a7e..c47da52f1 100644
--- a/src/macos_fw.c
+++ b/src/macos_fw.c
@@ -136,12 +136,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
total_disk_writes += diskstat.bytes_write;
}
- st = rrdset_find_bytype("disk", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk", diskstat.name, NULL, diskstat.name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("disk", diskstat.name, NULL, diskstat.name, "disk.io"
+ , "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every
+ , RRDSET_TYPE_AREA);
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -161,13 +163,15 @@ int do_macos_iokit(int update_every, usec_t dt) {
CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes);
}
- st = rrdset_find_bytype("disk_ops", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_ops", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops"
+ , "Disk Completed I/O Operations", "operations/s", 2001
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -187,12 +191,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write);
}
- st = rrdset_find_bytype("disk_util", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_util", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_util", diskstat.name, NULL, diskstat.name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_util", diskstat.name, NULL, diskstat.name, "disk.util"
+ , "Disk Utilization Time", "% of time working", 2004, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "utilization", NULL, 1, 10000000, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "utilization", NULL, 1, 10000000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -212,13 +218,15 @@ int do_macos_iokit(int update_every, usec_t dt) {
CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write);
}
- st = rrdset_find_bytype("disk_iotime", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_iotime", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime"
+ , "Disk Total I/O Time", "milliseconds/s", 2022, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -236,13 +244,15 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_await", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_await", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_await", diskstat.name, NULL, diskstat.name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_await", diskstat.name, NULL, diskstat.name, "disk.await"
+ , "Average Completed I/O Operation Time", "ms per operation"
+ , 2005, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -254,13 +264,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_avgsz", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_avgsz", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz"
+ , "Average Completed I/O Operation Bandwidth"
+ , "kilobytes per operation", 2006, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -272,12 +285,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("disk_svctm", diskstat.name);
+ st = rrdset_find_bytype_localhost("disk_svctm", diskstat.name);
if (unlikely(!st)) {
- st = rrdset_create("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm"
+ , "Average Service Time", "ms per operation", 2007
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "svctm", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "svctm", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -301,11 +316,12 @@ int do_macos_iokit(int update_every, usec_t dt) {
}
if (likely(do_io)) {
- st = rrdset_find_bytype("system", "io");
+ st = rrdset_find_bytype_localhost("system", "io");
if (unlikely(!st)) {
- st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "in", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150
+ , update_every, RRDSET_TYPE_AREA);
+ rrddim_add(st, "in", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "out", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -340,17 +356,17 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------------
if (likely(do_space)) {
- st = rrdset_find_bytype("disk_space", mntbuf[i].f_mntonname);
+ st = rrdset_find_bytype_localhost("disk_space", mntbuf[i].f_mntonname);
if (unlikely(!st)) {
snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023,
- update_every,
- RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname
+ , "disk.space", title, "GB", 2023, update_every
+ , RRDSET_TYPE_STACKED);
- rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
- RRDDIM_ABSOLUTE);
+ RRD_ALGORITHM_ABSOLUTE);
} else
rrdset_next(st);
@@ -363,15 +379,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------------
if (likely(do_inodes)) {
- st = rrdset_find_bytype("disk_inodes", mntbuf[i].f_mntonname);
+ st = rrdset_find_bytype_localhost("disk_inodes", mntbuf[i].f_mntonname);
if (unlikely(!st)) {
snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
- st = rrdset_create("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024,
- update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname
+ , "disk.inodes", title, "Inodes", 2024, update_every
+ , RRDSET_TYPE_STACKED);
- rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE);
} else
rrdset_next(st);
@@ -398,12 +415,13 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth"
+ , "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -413,15 +431,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_packets", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_packets", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets"
+ , "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "multicast_received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "multicast_sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -433,13 +452,14 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_errors", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_errors", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors"
+ , "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -449,12 +469,13 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_drops", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_drops", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops"
+ , "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -463,14 +484,16 @@ int do_macos_iokit(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("net_events", ifa->ifa_name);
+ st = rrdset_find_bytype_localhost("net_events", ifa->ifa_name);
if (unlikely(!st)) {
- st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events"
+ , "Network Interface Events", "events/s", 7006, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/macos_mach_smi.c b/src/macos_mach_smi.c
index d86a03220..da2825513 100644
--- a/src/macos_mach_smi.c
+++ b/src/macos_mach_smi.c
@@ -48,14 +48,15 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
error("DISABLED: system.cpu");
} else {
- st = rrdset_find_bytype("system", "cpu");
+ st = rrdset_find_bytype_localhost("system", "cpu");
if (unlikely(!st)) {
- st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization"
+ , "percentage", 100, update_every, RRDSET_TYPE_STACKED);
- rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rrddim_hide(st, "idle");
}
else rrdset_next(st);
@@ -84,18 +85,19 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
error("DISABLED: mem.pgfaults");
} else {
if (likely(do_ram)) {
- st = rrdset_find("system.ram");
+ st = rrdset_find_localhost("system.ram");
if (unlikely(!st)) {
- st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "active", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "wired", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "throttled", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "compressor", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "inactive", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "purgeable", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "speculative", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "free", NULL, system_pagesize, 1048576, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200
+ , update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(st, "active", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "wired", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "throttled", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "compressor", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "inactive", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "purgeable", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "speculative", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -113,12 +115,13 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_swapio)) {
- st = rrdset_find("system.swapio");
+ st = rrdset_find_localhost("system.swapio");
if (unlikely(!st)) {
- st = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "in", NULL, system_pagesize, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "in", NULL, system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -130,20 +133,21 @@ int do_macos_mach_smi(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_pgfaults)) {
- st = rrdset_find("mem.pgfaults");
+ st = rrdset_find_localhost("mem.pgfaults");
if (unlikely(!st)) {
- st = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "memory", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "cow", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "pagein", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "pageout", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "compress", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "decompress", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "zero_fill", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "reactivate", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "purge", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults"
+ , "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "memory", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "cow", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "pagein", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "pageout", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "compress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "decompress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "zero_fill", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "reactivate", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "purge", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/macos_sysctl.c b/src/macos_sysctl.c
index 955b70757..af229fb61 100644
--- a/src/macos_sysctl.c
+++ b/src/macos_sysctl.c
@@ -24,8 +24,6 @@
#define MIN_LOADAVG_UPDATE_EVERY 5
int do_macos_sysctl(int update_every, usec_t dt) {
- (void)dt;
-
static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1,
do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_ecn = -1,
do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1,
@@ -43,10 +41,10 @@ int do_macos_sysctl(int update_every, usec_t dt) {
do_tcp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP packets", 1);
do_tcp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP errors", 1);
do_tcp_handshake = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP handshake issues", 1);
- do_ecn = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
+ do_ecn = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syscookies = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_connaborts = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
do_udp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP packets", 1);
do_udp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP errors", 1);
do_icmp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP packets", 1);
@@ -55,17 +53,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
do_ip_fragsout = config_get_boolean("plugin:macos:sysctl", "ipv4 fragments sent", 1);
do_ip_fragsin = config_get_boolean("plugin:macos:sysctl", "ipv4 fragments assembly", 1);
do_ip_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 errors", 1);
- do_ip6_packets = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsout = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_fragsin = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
- do_ip6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6 = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_redir = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_echos = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_router = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_neighbor = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp6_types = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
+ do_ip6_packets = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 packets", CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsout = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments sent", CONFIG_BOOLEAN_AUTO);
+ do_ip6_fragsin = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments assembly", CONFIG_BOOLEAN_AUTO);
+ do_ip6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp6 = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_redir = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp redirects", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_errors = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_echos = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp echos", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_router = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp router", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_neighbor = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp neighbor", CONFIG_BOOLEAN_AUTO);
+ do_icmp6_types = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp types", CONFIG_BOOLEAN_AUTO);
do_uptime = config_get_boolean("plugin:macos:sysctl", "system uptime", 1);
}
@@ -77,7 +75,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
size_t size;
// NEEDED BY: do_loadavg
- static usec_t last_loadavg_usec = 0;
+ static usec_t next_loadavg_dt = 0;
struct loadavg sysload;
// NEEDED BY: do_swap
@@ -210,19 +208,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (last_loadavg_usec <= dt) {
+ if (next_loadavg_dt <= dt) {
if (likely(do_loadavg)) {
- if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
+ if (unlikely(GETSYSCTL_BY_NAME("vm.loadavg", sysload))) {
do_loadavg = 0;
error("DISABLED: system.load");
} else {
- st = rrdset_find_bytype("system", "load");
+ st = rrdset_find_bytype_localhost("system", "load");
if (unlikely(!st)) {
- st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "load", NULL, "load", NULL, "System Load Average", "load"
+ , 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)
+ ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -233,24 +233,25 @@ int do_macos_sysctl(int update_every, usec_t dt) {
}
}
- last_loadavg_usec = st->update_every * USEC_PER_SEC;
+ next_loadavg_dt = st->update_every * USEC_PER_SEC;
}
- else last_loadavg_usec -= dt;
+ else next_loadavg_dt -= dt;
// --------------------------------------------------------------------
if (likely(do_swap)) {
- if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
+ if (unlikely(GETSYSCTL_BY_NAME("vm.swapusage", swap_usage))) {
do_swap = 0;
error("DISABLED: system.swap");
} else {
- st = rrdset_find("system.swap");
+ st = rrdset_find_localhost("system.swap");
if (unlikely(!st)) {
- st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201
+ , update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "free", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -293,12 +294,13 @@ int do_macos_sysctl(int update_every, usec_t dt) {
iftot.ift_obytes += if2m->ifm_data.ifi_obytes;
}
}
- st = rrdset_find("system.ipv4");
+ st = rrdset_find_localhost("system.ipv4");
if (unlikely(!st)) {
- st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s"
+ , 500, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -313,7 +315,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
- if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.tcp.stats", tcpstat))){
do_tcp_packets = 0;
error("DISABLED: ipv4.tcppackets");
do_tcp_errors = 0;
@@ -330,14 +332,13 @@ int do_macos_sysctl(int update_every, usec_t dt) {
error("DISABLED: ipv4.ecnpkts");
} else {
if (likely(do_tcp_packets)) {
- st = rrdset_find("ipv4.tcppackets");
+ st = rrdset_find_localhost("ipv4.tcppackets");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
- "packets/s",
- 2600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets"
+ , "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -349,16 +350,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_tcp_errors)) {
- st = rrdset_find("ipv4.tcperrors");
+ st = rrdset_find_localhost("ipv4.tcperrors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
- "packets/s",
- 2700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s"
+ , 2700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -371,17 +371,16 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_tcp_handshake)) {
- st = rrdset_find("ipv4.tcphandshake");
+ st = rrdset_find_localhost("ipv4.tcphandshake");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
- "IPv4 TCP Handshake Issues",
- "events/s", 2900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues"
+ , "events/s", 2900, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -394,16 +393,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop))) {
- do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpconnaborts");
+ if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop))) {
+ do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpconnaborts");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts"
+ , "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -416,13 +416,14 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
- do_tcpext_ofo = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpofo");
+ if (do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
+ do_tcpext_ofo = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpofo");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue"
+ , "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -432,16 +433,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
- do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
+ if (do_tcpext_syscookies == CONFIG_BOOLEAN_YES || (do_tcpext_syscookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
+ do_tcpext_syscookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find("ipv4.tcpsyncookies");
+ st = rrdset_find_localhost("ipv4.tcpsyncookies");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies"
+ , "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -453,15 +455,16 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
- do_ecn = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.ecnpkts");
+ if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
+ do_ecn = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.ecnpkts");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics"
+ , "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -477,20 +480,20 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/udp.html
if (likely(do_udp_packets || do_udp_errors)) {
- if (unlikely(GETSYSCTL("net.inet.udp.stats", udpstat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.udp.stats", udpstat))) {
do_udp_packets = 0;
error("DISABLED: ipv4.udppackets");
do_udp_errors = 0;
error("DISABLED: ipv4.udperrors");
} else {
if (likely(do_udp_packets)) {
- st = rrdset_find("ipv4.udppackets");
+ st = rrdset_find_localhost("ipv4.udppackets");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
- "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets"
+ , "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -502,17 +505,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_udp_errors)) {
- st = rrdset_find("ipv4.udperrors");
+ st = rrdset_find_localhost("ipv4.udperrors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
- 2701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s"
+ , 2701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -529,7 +532,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp_packets || do_icmpmsg)) {
- if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.icmp.stats", icmpstat))) {
do_icmp_packets = 0;
error("DISABLED: ipv4.icmp");
error("DISABLED: ipv4.icmp_errors");
@@ -545,14 +548,13 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp_packets)) {
- st = rrdset_find("ipv4.icmp");
+ st = rrdset_find_localhost("ipv4.icmp");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
- 2602,
- update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s"
+ , 2602, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -563,15 +565,14 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find("ipv4.icmp_errors");
+ st = rrdset_find_localhost("ipv4.icmp_errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
- "packets/s",
- 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors"
+ , "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -585,15 +586,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmpmsg)) {
- st = rrdset_find("ipv4.icmpmsg");
+ st = rrdset_find_localhost("ipv4.icmpmsg");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
- "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages"
+ , "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchoReps", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -611,7 +612,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
if (likely(do_ip_packets || do_ip_fragsout || do_ip_fragsin || do_ip_errors)) {
- if (unlikely(GETSYSCTL("net.inet.ip.stats", ipstat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet.ip.stats", ipstat))) {
do_ip_packets = 0;
error("DISABLED: ipv4.packets");
do_ip_fragsout = 0;
@@ -622,15 +623,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
error("DISABLED: ipv4.errors");
} else {
if (likely(do_ip_packets)) {
- st = rrdset_find("ipv4.packets");
+ st = rrdset_find_localhost("ipv4.packets");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s",
- 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s"
+ , 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -644,15 +645,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip_fragsout)) {
- st = rrdset_find("ipv4.fragsout");
+ st = rrdset_find_localhost("ipv4.fragsout");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent"
+ , "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -665,16 +666,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip_fragsin)) {
- st = rrdset_find("ipv4.fragsin");
+ st = rrdset_find_localhost("ipv4.fragsin");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "fragsin", NULL, "fragments", NULL,
- "IPv4 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly"
+ , "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -687,21 +687,20 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip_errors)) {
- st = rrdset_find("ipv4.errors");
+ st = rrdset_find_localhost("ipv4.errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s",
- 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -719,7 +718,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
- if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet6.ip6.stats", ip6stat))) {
do_ip6_packets = 0;
error("DISABLED: ipv6.packets");
do_ip6_fragsout = 0;
@@ -729,19 +728,19 @@ int do_macos_sysctl(int update_every, usec_t dt) {
do_ip6_errors = 0;
error("DISABLED: ipv6.errors");
} else {
- if (do_ip6_packets == CONFIG_ONDEMAND_YES || (do_ip6_packets == CONFIG_ONDEMAND_ONDEMAND &&
+ if (do_ip6_packets == CONFIG_BOOLEAN_YES || (do_ip6_packets == CONFIG_BOOLEAN_AUTO &&
(ip6stat.ip6s_localout || ip6stat.ip6s_total ||
ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
- do_ip6_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.packets");
+ do_ip6_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.packets");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000,
- update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s"
+ , 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -754,19 +753,19 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ip6_fragsout == CONFIG_ONDEMAND_YES || (do_ip6_fragsout == CONFIG_ONDEMAND_ONDEMAND &&
+ if (do_ip6_fragsout == CONFIG_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO &&
(ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
ip6stat.ip6s_ofragments))) {
- do_ip6_fragsout = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsout");
+ do_ip6_fragsout = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.fragsout");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent",
- "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent"
+ , "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -778,20 +777,20 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ip6_fragsin == CONFIG_ONDEMAND_YES || (do_ip6_fragsin == CONFIG_ONDEMAND_ONDEMAND &&
+ if (do_ip6_fragsin == CONFIG_BOOLEAN_YES || (do_ip6_fragsin == CONFIG_BOOLEAN_AUTO &&
(ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
- do_ip6_fragsin = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.fragsin");
+ do_ip6_fragsin = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.fragsin");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly",
- "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly"
+ , "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -804,7 +803,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_ip6_errors == CONFIG_ONDEMAND_YES || (do_ip6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_ip6_errors == CONFIG_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && (
ip6stat.ip6s_toosmall ||
ip6stat.ip6s_odropped ||
ip6stat.ip6s_badoptions ||
@@ -814,22 +813,22 @@ int do_macos_sysctl(int update_every, usec_t dt) {
ip6stat.ip6s_tooshort ||
ip6stat.ip6s_cantforward ||
ip6stat.ip6s_noroute))) {
- do_ip6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.errors");
+ do_ip6_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.errors");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002,
- update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -851,7 +850,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_icmp6 || do_icmp6_redir || do_icmp6_errors || do_icmp6_echos || do_icmp6_router || do_icmp6_neighbor || do_icmp6_types)) {
- if (unlikely(GETSYSCTL("net.inet6.icmp6.stats", icmp6stat))) {
+ if (unlikely(GETSYSCTL_BY_NAME("net.inet6.icmp6.stats", icmp6stat))) {
do_icmp6 = 0;
error("DISABLED: ipv6.icmp");
} else {
@@ -860,15 +859,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
icmp6_total.msgs_out += icmp6stat.icp6s_outhist[i];
}
icmp6_total.msgs_in += icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort;
- if (do_icmp6 == CONFIG_ONDEMAND_YES || (do_icmp6 == CONFIG_ONDEMAND_ONDEMAND && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
- do_icmp6 = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmp");
+ if (do_icmp6 == CONFIG_BOOLEAN_YES || (do_icmp6 == CONFIG_BOOLEAN_AUTO && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
+ do_icmp6 = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmp");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages",
- "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s"
+ , 10000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -879,15 +878,15 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_redir == CONFIG_ONDEMAND_YES || (do_icmp6_redir == CONFIG_ONDEMAND_ONDEMAND && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
- do_icmp6_redir = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpredir");
+ if (do_icmp6_redir == CONFIG_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
+ do_icmp6_redir = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmpredir");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects",
- "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects"
+ , "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -898,7 +897,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_errors == CONFIG_ONDEMAND_YES || (do_icmp6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_errors == CONFIG_BOOLEAN_YES || (do_icmp6_errors == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_badcode ||
icmp6stat.icp6s_badlen ||
icmp6stat.icp6s_checksum ||
@@ -910,22 +909,23 @@ int do_macos_sysctl(int update_every, usec_t dt) {
icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
- do_icmp6_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmperrors");
+ do_icmp6_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmperrors");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors"
+ , "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -944,20 +944,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_echos == CONFIG_ONDEMAND_YES || (do_icmp6_echos == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_echos == CONFIG_BOOLEAN_YES || (do_icmp6_echos == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
- do_icmp6_echos = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpechos");
+ do_icmp6_echos = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmpechos");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s"
+ , 10200, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -970,20 +971,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_router == CONFIG_ONDEMAND_YES || (do_icmp6_router == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_router == CONFIG_BOOLEAN_YES || (do_icmp6_router == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
- do_icmp6_router = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmprouter");
+ do_icmp6_router = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmprouter");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages"
+ , "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -996,20 +998,21 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_neighbor == CONFIG_ONDEMAND_YES || (do_icmp6_neighbor == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_neighbor == CONFIG_BOOLEAN_YES || (do_icmp6_neighbor == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
- do_icmp6_neighbor = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmpneighbor");
+ do_icmp6_neighbor = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmpneighbor");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages"
+ , "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -1022,7 +1025,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if (do_icmp6_types == CONFIG_ONDEMAND_YES || (do_icmp6_types == CONFIG_ONDEMAND_ONDEMAND && (
+ if (do_icmp6_types == CONFIG_BOOLEAN_YES || (do_icmp6_types == CONFIG_BOOLEAN_AUTO && (
icmp6stat.icp6s_inhist[1] ||
icmp6stat.icp6s_inhist[128] ||
icmp6stat.icp6s_inhist[129] ||
@@ -1033,22 +1036,22 @@ int do_macos_sysctl(int update_every, usec_t dt) {
icmp6stat.icp6s_outhist[133] ||
icmp6stat.icp6s_outhist[135] ||
icmp6stat.icp6s_outhist[136]))) {
- do_icmp6_types = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv6.icmptypes");
+ do_icmp6_types = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv6.icmptypes");
if (unlikely(!st)) {
- st = rrdset_create("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types",
- "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types"
+ , "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
} else
rrdset_next(st);
@@ -1070,16 +1073,17 @@ int do_macos_sysctl(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if (likely(do_uptime)) {
- if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
+ if (unlikely(GETSYSCTL_BY_NAME("kern.boottime", boot_time))) {
do_uptime = 0;
error("DISABLED: system.uptime");
} else {
clock_gettime(CLOCK_REALTIME, &cur_time);
- st = rrdset_find("system.uptime");
+ st = rrdset_find_localhost("system.uptime");
if(unlikely(!st)) {
- st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000
+ , update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -1091,7 +1095,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
return 0;
}
-int getsysctl(const char *name, void *ptr, size_t len)
+int getsysctl_by_name(const char *name, void *ptr, size_t len)
{
size_t nlen = len;
diff --git a/src/main.c b/src/main.c
index ca134fcb0..a72585e28 100644
--- a/src/main.c
+++ b/src/main.c
@@ -10,7 +10,7 @@ void netdata_cleanup_and_exit(int ret) {
debug(D_EXIT, "Called: netdata_cleanup_and_exit()");
// save the database
- rrdset_save_all();
+ rrdhost_save_all();
// unlink the pid
if(pidfile[0]) {
@@ -23,7 +23,8 @@ void netdata_cleanup_and_exit(int ret) {
//kill_childs();
// free database
- rrdset_free_all();
+ sleep(2);
+ rrdhost_free_all();
#endif
info("netdata exiting. Bye bye...");
@@ -34,49 +35,55 @@ struct netdata_static_thread static_threads[] = {
#ifdef INTERNAL_PLUGIN_NFACCT
// nfacct requires root access
// so, we build it as an external plugin with setuid to root
- {"nfacct", "plugins", "nfacct", 1, NULL, NULL, nfacct_main},
+ {"nfacct", CONFIG_SECTION_PLUGINS, "nfacct", 1, NULL, NULL, nfacct_main},
#endif
- {"tc", "plugins", "tc", 1, NULL, NULL, tc_main},
- {"idlejitter", "plugins", "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
+ {"tc", CONFIG_SECTION_PLUGINS, "tc", 1, NULL, NULL, tc_main},
+ {"idlejitter", CONFIG_SECTION_PLUGINS, "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
#if defined(__FreeBSD__)
- {"freebsd", "plugins", "freebsd", 1, NULL, NULL, freebsd_main},
+ {"freebsd", CONFIG_SECTION_PLUGINS, "freebsd", 1, NULL, NULL, freebsd_main},
#elif defined(__APPLE__)
- {"macos", "plugins", "macos", 1, NULL, NULL, macos_main},
+ {"macos", CONFIG_SECTION_PLUGINS, "macos", 1, NULL, NULL, macos_main},
#else
- {"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
- {"diskspace", "plugins", "diskspace", 1, NULL, NULL, proc_diskspace_main},
+ {"proc", CONFIG_SECTION_PLUGINS, "proc", 1, NULL, NULL, proc_main},
+ {"diskspace", CONFIG_SECTION_PLUGINS, "diskspace", 1, NULL, NULL, proc_diskspace_main},
+ {"cgroups", CONFIG_SECTION_PLUGINS, "cgroups", 1, NULL, NULL, cgroups_main},
#endif /* __FreeBSD__, __APPLE__*/
- {"cgroups", "plugins", "cgroups", 1, NULL, NULL, cgroups_main},
- {"check", "plugins", "checks", 0, NULL, NULL, checks_main},
- {"backends", NULL, NULL, 1, NULL, NULL, backends_main},
- {"health", NULL, NULL, 1, NULL, NULL, health_main},
- {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main},
- {"web", NULL, NULL, 1, NULL, NULL, socket_listen_main_multi_threaded},
- {"web-single-threaded", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded},
- {NULL, NULL, NULL, 0, NULL, NULL, NULL}
+ {"check", CONFIG_SECTION_PLUGINS, "checks", 0, NULL, NULL, checks_main},
+ {"backends", NULL, NULL, 1, NULL, NULL, backends_main},
+ {"health", NULL, NULL, 1, NULL, NULL, health_main},
+ {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main},
+ {"web", NULL, NULL, 1, NULL, NULL, socket_listen_main_multi_threaded},
+ {"web-single-threaded", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded},
+ {"push-metrics", NULL, NULL, 0, NULL, NULL, rrdpush_sender_thread},
+ {NULL, NULL, NULL, 0, NULL, NULL, NULL}
};
void web_server_threading_selection(void) {
- int threaded = config_get_boolean("global", "multi threaded web server", 1);
+ web_server_mode = web_server_mode_id(config_get(CONFIG_SECTION_WEB, "mode", web_server_mode_name(web_server_mode)));
+
+ int multi_threaded = (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED);
+ int single_threaded = (web_server_mode == WEB_SERVER_MODE_SINGLE_THREADED);
int i;
for(i = 0; static_threads[i].name ; i++) {
if(static_threads[i].start_routine == socket_listen_main_multi_threaded)
- static_threads[i].enabled = threaded?1:0;
+ static_threads[i].enabled = multi_threaded;
if(static_threads[i].start_routine == socket_listen_main_single_threaded)
- static_threads[i].enabled = threaded?0:1;
+ static_threads[i].enabled = single_threaded;
}
- web_client_timeout = (int) config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
+ web_client_timeout = (int) config_get_number(CONFIG_SECTION_WEB, "disconnect idle clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
- web_donotrack_comply = config_get_boolean("global", "respect web browser do not track policy", web_donotrack_comply);
+ respect_web_browser_do_not_track_policy = config_get_boolean(CONFIG_SECTION_WEB, "respect do not track policy", respect_web_browser_do_not_track_policy);
+ web_x_frame_options = config_get(CONFIG_SECTION_WEB, "x-frame-options response header", "");
+ if(!*web_x_frame_options) web_x_frame_options = NULL;
#ifdef NETDATA_WITH_ZLIB
- web_enable_gzip = config_get_boolean("global", "enable web responses gzip compression", web_enable_gzip);
+ web_enable_gzip = config_get_boolean(CONFIG_SECTION_WEB, "enable gzip compression", web_enable_gzip);
- char *s = config_get("global", "web compression strategy", "default");
+ char *s = config_get(CONFIG_SECTION_WEB, "gzip compression strategy", "default");
if(!strcmp(s, "default"))
web_gzip_strategy = Z_DEFAULT_STRATEGY;
else if(!strcmp(s, "filtered"))
@@ -92,7 +99,7 @@ void web_server_threading_selection(void) {
web_gzip_strategy = Z_DEFAULT_STRATEGY;
}
- web_gzip_level = (int)config_get_number("global", "web compression level", 3);
+ web_gzip_level = (int)config_get_number(CONFIG_SECTION_WEB, "gzip compression level", 3);
if(web_gzip_level < 1) {
error("Invalid compression level %d. Valid levels are 1 (fastest) to 9 (best ratio). Proceeding with level 1 (fastest compression).", web_gzip_level);
web_gzip_level = 1;
@@ -218,12 +225,12 @@ struct option_def options[] = {
{ 'h', "Display this help message.", NULL, NULL},
{ 'P', "File to save a pid while running.", "filename", "do not save pid to a file"},
{ 'i', "The IP address to listen to.", "IP", "all IP addresses IPv4 and IPv6"},
- { 'k', "Check health configuration and exit.", NULL, NULL},
{ 'p', "API/Web port to use.", "port", "19999"},
{ 's', "Prefix for /proc and /sys (for containers).", "path", "no prefix"},
{ 't', "The internal clock of netdata.", "seconds", "1"},
{ 'u', "Run as user.", "username", "netdata"},
{ 'v', "Print netdata version and exit.", NULL, NULL},
+ { 'V', "Print netdata version and exit.", NULL, NULL},
{ 'W', "See Advanced options below.", "options", NULL},
};
@@ -256,7 +263,7 @@ void help(int exitcode) {
" +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->\n"
"\n"
" Copyright (C) 2016-2017, Costa Tsaousis <costa@tsaousis.gr>\n"
- " Released under GNU Public License v3 or later.\n"
+ " Released under GNU General Public License v3 or later.\n"
" All rights reserved.\n"
"\n"
" Home Page : https://my-netdata.io\n"
@@ -332,10 +339,191 @@ static const char *verify_required_directory(const char *dir) {
return dir;
}
-int main(int argc, char **argv)
-{
- char *hostname = "localhost";
- int i, check_config = 0;
+void log_init(void) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/debug.log", netdata_configured_log_dir);
+ stdout_filename = config_get(CONFIG_SECTION_GLOBAL, "debug log", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s/error.log", netdata_configured_log_dir);
+ stderr_filename = config_get(CONFIG_SECTION_GLOBAL, "error log", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s/access.log", netdata_configured_log_dir);
+ stdaccess_filename = config_get(CONFIG_SECTION_GLOBAL, "access log", filename);
+
+ error_log_throttle_period_backup =
+ error_log_throttle_period = config_get_number(CONFIG_SECTION_GLOBAL, "errors flood protection period", error_log_throttle_period);
+ error_log_errors_per_period = (unsigned long)config_get_number(CONFIG_SECTION_GLOBAL, "errors to trigger flood protection", (long long int)error_log_errors_per_period);
+
+ setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get(CONFIG_SECTION_GLOBAL, "errors flood protection period" , ""), 1);
+ setenv("NETDATA_ERRORS_PER_PERIOD", config_get(CONFIG_SECTION_GLOBAL, "errors to trigger flood protection", ""), 1);
+}
+
+static void backwards_compatible_config() {
+ // allow existing configurations to work with the current version of netdata
+
+ if(config_exists(CONFIG_SECTION_GLOBAL, "multi threaded web server")) {
+ int mode = config_get_boolean(CONFIG_SECTION_GLOBAL, "multi threaded web server", 1);
+ web_server_mode = (mode)?WEB_SERVER_MODE_MULTI_THREADED:WEB_SERVER_MODE_SINGLE_THREADED;
+ }
+
+ // move [global] options to the [web] section
+ config_move(CONFIG_SECTION_GLOBAL, "http port listen backlog",
+ CONFIG_SECTION_WEB, "listen backlog");
+
+ config_move(CONFIG_SECTION_GLOBAL, "bind socket to IP",
+ CONFIG_SECTION_WEB, "bind to");
+
+ config_move(CONFIG_SECTION_GLOBAL, "bind to",
+ CONFIG_SECTION_WEB, "bind to");
+
+ config_move(CONFIG_SECTION_GLOBAL, "port",
+ CONFIG_SECTION_WEB, "default port");
+
+ config_move(CONFIG_SECTION_GLOBAL, "default port",
+ CONFIG_SECTION_WEB, "default port");
+
+ config_move(CONFIG_SECTION_GLOBAL, "disconnect idle web clients after seconds",
+ CONFIG_SECTION_WEB, "disconnect idle clients after seconds");
+
+ config_move(CONFIG_SECTION_GLOBAL, "respect web browser do not track policy",
+ CONFIG_SECTION_WEB, "respect do not track policy");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web x-frame-options header",
+ CONFIG_SECTION_WEB, "x-frame-options response header");
+
+ config_move(CONFIG_SECTION_GLOBAL, "enable web responses gzip compression",
+ CONFIG_SECTION_WEB, "enable gzip compression");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web compression strategy",
+ CONFIG_SECTION_WEB, "gzip compression strategy");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web compression level",
+ CONFIG_SECTION_WEB, "gzip compression level");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web files owner",
+ CONFIG_SECTION_WEB, "web files owner");
+
+ config_move(CONFIG_SECTION_GLOBAL, "web files group",
+ CONFIG_SECTION_WEB, "web files group");
+}
+
+static void get_netdata_configured_variables() {
+ backwards_compatible_config();
+
+ // ------------------------------------------------------------------------
+ // get the hostname
+
+ char buf[HOSTNAME_MAX + 1];
+ if(gethostname(buf, HOSTNAME_MAX) == -1)
+ error("Cannot get machine hostname.");
+
+ netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", buf);
+ debug(D_OPTIONS, "hostname set to '%s'", netdata_configured_hostname);
+
+ netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", CONFIG_DIR);
+
+ // ------------------------------------------------------------------------
+ // get default database size
+
+ default_rrd_history_entries = (int) config_get_number(CONFIG_SECTION_GLOBAL, "history", align_entries_to_pagesize(default_rrd_memory_mode, RRD_DEFAULT_HISTORY_ENTRIES));
+
+ long h = align_entries_to_pagesize(default_rrd_memory_mode, default_rrd_history_entries);
+ if(h != default_rrd_history_entries) {
+ config_set_number(CONFIG_SECTION_GLOBAL, "history", h);
+ default_rrd_history_entries = (int)h;
+ }
+
+ if(default_rrd_history_entries < 5 || default_rrd_history_entries > RRD_HISTORY_ENTRIES_MAX) {
+ error("Invalid history entries %d given. Defaulting to %d.", default_rrd_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
+ default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
+ }
+
+ // ------------------------------------------------------------------------
+ // get default database update frequency
+
+ default_rrd_update_every = (int) config_get_number(CONFIG_SECTION_GLOBAL, "update every", UPDATE_EVERY);
+ if(default_rrd_update_every < 1 || default_rrd_update_every > 600) {
+ error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", default_rrd_update_every, UPDATE_EVERY_MAX);
+ default_rrd_update_every = UPDATE_EVERY;
+ }
+
+ // ------------------------------------------------------------------------
+ // let the plugins know the min update_every
+
+ // get system paths
+ netdata_configured_config_dir = config_get(CONFIG_SECTION_GLOBAL, "config directory", CONFIG_DIR);
+ netdata_configured_log_dir = config_get(CONFIG_SECTION_GLOBAL, "log directory", LOG_DIR);
+ netdata_configured_plugins_dir = config_get(CONFIG_SECTION_GLOBAL, "plugins directory", PLUGINS_DIR);
+ netdata_configured_web_dir = config_get(CONFIG_SECTION_GLOBAL, "web files directory", WEB_DIR);
+ netdata_configured_cache_dir = config_get(CONFIG_SECTION_GLOBAL, "cache directory", CACHE_DIR);
+ netdata_configured_varlib_dir = config_get(CONFIG_SECTION_GLOBAL, "lib directory", VARLIB_DIR);
+ netdata_configured_home_dir = config_get(CONFIG_SECTION_GLOBAL, "home directory", CACHE_DIR);
+
+ // ------------------------------------------------------------------------
+ // get default memory mode for the database
+
+ default_rrd_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_GLOBAL, "memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));
+
+ // ------------------------------------------------------------------------
+
+ netdata_configured_host_prefix = config_get(CONFIG_SECTION_GLOBAL, "host access prefix", "");
+
+ // --------------------------------------------------------------------
+ // get KSM settings
+
+#ifdef MADV_MERGEABLE
+ enable_ksm = config_get_boolean(CONFIG_SECTION_GLOBAL, "memory deduplication (ksm)", enable_ksm);
+#endif
+
+ // --------------------------------------------------------------------
+ // get various system parameters
+
+ get_system_HZ();
+ get_system_cpus();
+ get_system_pid_max();
+}
+
+void set_global_environment() {
+ {
+ char b[16];
+ snprintfz(b, 15, "%d", default_rrd_update_every);
+ setenv("NETDATA_UPDATE_EVERY", b, 1);
+ }
+
+ setenv("NETDATA_HOSTNAME" , netdata_configured_hostname, 1);
+ setenv("NETDATA_CONFIG_DIR" , verify_required_directory(netdata_configured_config_dir), 1);
+ setenv("NETDATA_PLUGINS_DIR", verify_required_directory(netdata_configured_plugins_dir), 1);
+ setenv("NETDATA_WEB_DIR" , verify_required_directory(netdata_configured_web_dir), 1);
+ setenv("NETDATA_CACHE_DIR" , verify_required_directory(netdata_configured_cache_dir), 1);
+ setenv("NETDATA_LIB_DIR" , verify_required_directory(netdata_configured_varlib_dir), 1);
+ setenv("NETDATA_LOG_DIR" , verify_required_directory(netdata_configured_log_dir), 1);
+ setenv("HOME" , verify_required_directory(netdata_configured_home_dir), 1);
+ setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
+
+ // avoid flood calls to stat(/etc/localtime)
+ // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
+ setenv("TZ", ":/etc/localtime", 0);
+
+ // set the path we need
+ char path[1024 + 1], *p = getenv("PATH");
+ if(!p) p = "/bin:/usr/bin";
+ snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
+ setenv("PATH", config_get(CONFIG_SECTION_PLUGINS, "PATH environment variable", path), 1);
+
+ // python options
+ p = getenv("PYTHONPATH");
+ if(!p) p = "";
+ setenv("PYTHONPATH", config_get(CONFIG_SECTION_PLUGINS, "PYTHONPATH environment variable", p), 1);
+
+ // disable buffering for python plugins
+ setenv("PYTHONUNBUFFERED", "1", 1);
+
+ // switch to standard locale for plugins
+ setenv("LC_ALL", "C", 1);
+}
+
+int main(int argc, char **argv) {
+ int i;
int config_loaded = 0;
int dont_fork = 0;
size_t wanted_stacksize = 0, stacksize = 0;
@@ -360,12 +548,12 @@ int main(int argc, char **argv)
remove_option(i, &argc, argv);
}
else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) {
- config_set("global", "host access prefix", argv[i+1]);
+ config_set(CONFIG_SECTION_GLOBAL, "host access prefix", argv[i+1]);
fprintf(stderr, "%s: deprecated option -- %s -- please use -s instead.\n", argv[0], argv[i]);
remove_option(i, &argc, argv);
}
else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) {
- config_set("global", "history", argv[i+1]);
+ config_set(CONFIG_SECTION_GLOBAL, "history", argv[i+1]);
fprintf(stderr, "%s: deprecated option -- %s -- This option will be removed with V2.*.\n", argv[0], argv[i]);
remove_option(i, &argc, argv);
}
@@ -395,7 +583,7 @@ int main(int argc, char **argv)
while( (opt = getopt(argc, argv, optstring)) != -1 ) {
switch(opt) {
case 'c':
- if(load_config(optarg, 1) != 1) {
+ if(config_load(optarg, 1) != 1) {
error("Cannot load configuration file %s.", optarg);
exit(1);
}
@@ -411,38 +599,42 @@ int main(int argc, char **argv)
help(0);
break;
case 'i':
- config_set("global", "bind to", optarg);
- break;
- case 'k':
- dont_fork = 1;
- check_config = 1;
+ config_set(CONFIG_SECTION_WEB, "bind to", optarg);
break;
case 'P':
strncpy(pidfile, optarg, FILENAME_MAX);
pidfile[FILENAME_MAX] = '\0';
break;
case 'p':
- config_set("global", "default port", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "default port", optarg);
break;
case 's':
- config_set("global", "host access prefix", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "host access prefix", optarg);
break;
case 't':
- config_set("global", "update every", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "update every", optarg);
break;
case 'u':
- config_set("global", "run as user", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "run as user", optarg);
break;
case 'v':
- // TODO: Outsource version to makefile which can compute version from git.
- printf("netdata %s\n", VERSION);
+ case 'V':
+ printf("%s %s\n", program_name, program_version);
return 0;
case 'W':
{
char* stacksize_string = "stacksize=";
char* debug_flags_string = "debug_flags=";
if(strcmp(optarg, "unittest") == 0) {
- rrd_update_every = 1;
+ default_rrd_update_every = 1;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ if(!config_loaded) config_load(NULL, 0);
+ get_netdata_configured_variables();
+ default_rrd_update_every = 1;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ default_health_enabled = 0;
+ rrd_init("unittest");
+ default_rrdpush_enabled = 0;
if(run_all_mockup_tests()) exit(1);
if(unit_test_storage()) exit(1);
fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
@@ -492,11 +684,11 @@ int main(int argc, char **argv)
}
else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) {
optarg += strlen(stacksize_string);
- config_set("global", "pthread stack size", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "pthread stack size", optarg);
}
else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) {
optarg += strlen(debug_flags_string);
- config_set("global", "debug flags", optarg);
+ config_set(CONFIG_SECTION_GLOBAL, "debug flags", optarg);
debug_flags = strtoull(optarg, NULL, 0);
}
}
@@ -508,150 +700,85 @@ int main(int argc, char **argv)
}
}
+#ifdef _SC_OPEN_MAX
+ // close all open file descriptors, except the standard ones
+ // the caller may have left open files (lxc-attach has this issue)
+ {
+ int fd;
+ for(fd = (int) (sysconf(_SC_OPEN_MAX) - 1); fd > 2; fd--)
+ if(fd_is_valid(fd)) close(fd);
+ }
+#endif
+
if(!config_loaded)
- load_config(NULL, 0);
+ config_load(NULL, 0);
+ // ------------------------------------------------------------------------
+ // initialize netdata
{
- char *pmax = config_get("global", "glibc malloc arena max for plugins", "1");
+ char *pmax = config_get(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for plugins", "1");
if(pmax && *pmax)
setenv("MALLOC_ARENA_MAX", pmax, 1);
#if defined(HAVE_C_MALLOPT)
- int i = config_get_number("global", "glibc malloc arena max for netdata", 1);
+ i = (int)config_get_number(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for netdata", 1);
if(i > 0)
mallopt(M_ARENA_MAX, 1);
#endif
- char *config_dir = config_get("global", "config directory", CONFIG_DIR);
-
// prepare configuration environment variables for the plugins
- setenv("NETDATA_CONFIG_DIR" , verify_required_directory(config_dir) , 1);
- setenv("NETDATA_PLUGINS_DIR", verify_required_directory(config_get("global", "plugins directory" , PLUGINS_DIR)), 1);
- setenv("NETDATA_WEB_DIR" , verify_required_directory(config_get("global", "web files directory", WEB_DIR)) , 1);
- setenv("NETDATA_CACHE_DIR" , verify_required_directory(config_get("global", "cache directory" , CACHE_DIR)) , 1);
- setenv("NETDATA_LIB_DIR" , verify_required_directory(config_get("global", "lib directory" , VARLIB_DIR)) , 1);
- setenv("NETDATA_LOG_DIR" , verify_required_directory(config_get("global", "log directory" , LOG_DIR)) , 1);
-
- setenv("NETDATA_HOST_PREFIX", config_get("global", "host access prefix" , "") , 1);
- setenv("HOME" , config_get("global", "home directory" , CACHE_DIR) , 1);
- // disable buffering for python plugins
- setenv("PYTHONUNBUFFERED", "1", 1);
-
- // avoid flood calls to stat(/etc/localtime)
- // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
- setenv("TZ", ":/etc/localtime", 0);
+ get_netdata_configured_variables();
+ set_global_environment();
// work while we are cd into config_dir
// to allow the plugins refer to their config
// files using relative filenames
- if(chdir(config_dir) == -1)
- fatal("Cannot cd to '%s'", config_dir);
-
- char path[1024 + 1], *p = getenv("PATH");
- if(!p) p = "/bin:/usr/bin";
- snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
- setenv("PATH", config_get("plugins", "PATH environment variable", path), 1);
+ if(chdir(netdata_configured_config_dir) == -1)
+ fatal("Cannot cd to '%s'", netdata_configured_config_dir);
}
char *user = NULL;
+
{
- char *flags = config_get("global", "debug flags", "0x00000000");
+ // --------------------------------------------------------------------
+ // get the debugging flags from the configuration file
+
+ char *flags = config_get(CONFIG_SECTION_GLOBAL, "debug flags", "0x0000000000000000");
setenv("NETDATA_DEBUG_FLAGS", flags, 1);
debug_flags = strtoull(flags, NULL, 0);
- debug(D_OPTIONS, "Debug flags set to '0x%8llx'.", debug_flags);
+ debug(D_OPTIONS, "Debug flags set to '0x%" PRIX64 "'.", debug_flags);
if(debug_flags != 0) {
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#ifdef HAVE_SYS_PRCTL_H
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-#endif /* __FreeBSD__ || __APPLE__*/
- }
-
- // --------------------------------------------------------------------
-
-#ifdef MADV_MERGEABLE
- enable_ksm = config_get_boolean("global", "memory deduplication (ksm)", enable_ksm);
-#else
-#warning "Kernel memory deduplication (KSM) is not available"
#endif
+ }
- // --------------------------------------------------------------------
-
- global_host_prefix = config_get("global", "host access prefix", "");
- setenv("NETDATA_HOST_PREFIX", global_host_prefix, 1);
- get_system_HZ();
- get_system_cpus();
- get_system_pid_max();
-
// --------------------------------------------------------------------
+ // get log filenames and settings
- stdout_filename = config_get("global", "debug log", LOG_DIR "/debug.log");
- stderr_filename = config_get("global", "error log", LOG_DIR "/error.log");
- stdaccess_filename = config_get("global", "access log", LOG_DIR "/access.log");
-
- error_log_throttle_period_backup =
- error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
- setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period" , ""), 1);
-
- error_log_errors_per_period = (unsigned long)config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
- setenv("NETDATA_ERRORS_PER_PERIOD" , config_get("global", "errors to trigger flood protection", ""), 1);
-
- if(check_config) {
- stdout_filename = stderr_filename = stdaccess_filename = "system";
- error_log_throttle_period = 0;
- error_log_errors_per_period = 0;
- }
+ log_init();
error_log_limit_unlimited();
- // --------------------------------------------------------------------
-
- rrd_memory_mode = rrd_memory_mode_id(config_get("global", "memory mode", rrd_memory_mode_name(rrd_memory_mode)));
// --------------------------------------------------------------------
-
+ // load stream.conf
{
- char hostnamebuf[HOSTNAME_MAX + 1];
- if(gethostname(hostnamebuf, HOSTNAME_MAX) == -1)
- error("WARNING: Cannot get machine hostname.");
- hostname = config_get("global", "hostname", hostnamebuf);
- debug(D_OPTIONS, "hostname set to '%s'", hostname);
- setenv("NETDATA_HOSTNAME", hostname, 1);
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/stream.conf", netdata_configured_config_dir);
+ appconfig_load(&stream_config, filename, 0);
}
- // --------------------------------------------------------------------
-
- rrd_default_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
- if(rrd_default_history_entries < 5 || rrd_default_history_entries > RRD_HISTORY_ENTRIES_MAX) {
- error("Invalid history entries %d given. Defaulting to %d.", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
- rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
- }
- else {
- debug(D_OPTIONS, "save lines set to %d.", rrd_default_history_entries);
- }
-
- // --------------------------------------------------------------------
-
- rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
- if(rrd_update_every < 1 || rrd_update_every > 600) {
- error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", rrd_update_every, UPDATE_EVERY_MAX);
- rrd_update_every = UPDATE_EVERY;
- }
- else debug(D_OPTIONS, "update timer set to %d.", rrd_update_every);
-
- // let the plugins know the min update_every
- {
- char buf[16];
- snprintfz(buf, 15, "%d", rrd_update_every);
- setenv("NETDATA_UPDATE_EVERY", buf, 1);
- }
// --------------------------------------------------------------------
+ // setup process signals
// block signals while initializing threads.
// this causes the threads to block signals.
@@ -697,7 +824,9 @@ int main(int argc, char **argv)
if(sigaction(SIGUSR2, &sa, NULL) == -1)
error("Failed to change signal handler for SIGUSR2");
+
// --------------------------------------------------------------------
+ // get the required stack size of the threads of netdata
i = pthread_attr_init(&attr);
if(i != 0)
@@ -709,30 +838,44 @@ int main(int argc, char **argv)
else
debug(D_OPTIONS, "initial pthread stack size is %zu bytes", stacksize);
- wanted_stacksize = (size_t)config_get_number("global", "pthread stack size", (long)stacksize);
+ wanted_stacksize = (size_t)config_get_number(CONFIG_SECTION_GLOBAL, "pthread stack size", (long)stacksize);
+
// --------------------------------------------------------------------
+ // check which threads are enabled and initialize them
for (i = 0; static_threads[i].name != NULL ; i++) {
struct netdata_static_thread *st = &static_threads[i];
- if(st->config_name) st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
- if(st->enabled && st->init_routine) st->init_routine();
+ if(st->config_name)
+ st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
+
+ if(st->enabled && st->init_routine)
+ st->init_routine();
}
- // --------------------------------------------------------------------
+ // --------------------------------------------------------------------
// get the user we should run
+
// IMPORTANT: this is required before web_files_uid()
- user = config_get("global", "run as user" , (getuid() == 0)?NETDATA_USER:"");
+ if(getuid() == 0) {
+ user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER);
+ }
+ else {
+ struct passwd *passwd = getpwuid(getuid());
+ user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:"");
+ }
// IMPORTANT: these have to run once, while single threaded
web_files_uid(); // IMPORTANT: web_files_uid() before web_files_gid()
web_files_gid();
+
// --------------------------------------------------------------------
+ // create the listening sockets
- if(!check_config)
+ if(web_server_mode != WEB_SERVER_MODE_NONE)
create_listen_sockets();
}
@@ -744,20 +887,22 @@ int main(int argc, char **argv)
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
-#if !(defined(__FreeBSD__) || defined(__APPLE__))
+#ifdef HAVE_SYS_PRCTL_H
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-#endif /* __FreeBSD__ || __APPLE__*/
+#endif
}
#endif /* NETDATA_INTERNAL_CHECKS */
+
// fork, switch user, create pid file, set process priority
if(become_daemon(dont_fork, user) == -1)
fatal("Cannot daemonize myself.");
info("netdata started on pid %d.", getpid());
+
// ------------------------------------------------------------------------
- // get default pthread stack size
+ // set default pthread stack size - after we have forked
if(stacksize < wanted_stacksize) {
i = pthread_attr_setstacksize(&attr, wanted_stacksize);
@@ -767,29 +912,19 @@ int main(int argc, char **argv)
debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
}
- // ------------------------------------------------------------------------
- // initialize rrd host
-
- rrdhost_init(hostname);
// ------------------------------------------------------------------------
- // initialize the registry
+ // initialize rrd, registry, health, rrdpush, etc.
- registry_init();
-
- // ------------------------------------------------------------------------
- // initialize health monitoring
+ rrd_init(netdata_configured_hostname);
- health_init();
-
- if(check_config)
- exit(1);
// ------------------------------------------------------------------------
// enable log flood protection
error_log_limit_reset();
+
// ------------------------------------------------------------------------
// spawn the threads
@@ -814,6 +949,7 @@ int main(int argc, char **argv)
info("netdata initialization completed. Enjoy real-time performance monitoring!");
+
// ------------------------------------------------------------------------
// block signals while initializing threads.
sigset_t sigset;
diff --git a/src/main.h b/src/main.h
index 49afaef12..38df0fea4 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,8 +1,6 @@
#ifndef NETDATA_MAIN_H
#define NETDATA_MAIN_H 1
-extern volatile sig_atomic_t netdata_exit;
-
/**
* This struct contains information about command line options.
*/
diff --git a/src/plugin_checks.c b/src/plugin_checks.c
index fcc542e68..3a0a83bda 100644
--- a/src/plugin_checks.c
+++ b/src/plugin_checks.c
@@ -11,23 +11,26 @@ void *checks_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- usec_t usec = 0, susec = rrd_update_every * USEC_PER_SEC, loop_usec = 0, total_susec = 0;
+ usec_t usec = 0, susec = localhost->rrd_update_every * USEC_PER_SEC, loop_usec = 0, total_susec = 0;
struct timeval now, last, loop;
RRDSET *check1, *check2, *check3, *apps_cpu = NULL;
- check1 = rrdset_create("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(check1, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check1, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ check1 = rrdset_create_localhost("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds"
+ , "a million !", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(check1, "absolute", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check1, "incremental", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- check2 = rrdset_create("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(check2, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check2, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ check2 = rrdset_create_localhost("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds"
+ , "a million !", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(check2, "absolute", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check2, "incremental", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- check3 = rrdset_create("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference", "microseconds diff", 99999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(check3, "caller", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check3, "netdata", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ check3 = rrdset_create_localhost("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference"
+ , "microseconds diff", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(check3, "caller", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check3, "netdata", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
now_realtime_timeval(&last);
while(1) {
@@ -39,8 +42,8 @@ void *checks_main(void *ptr) {
usec = loop_usec - susec;
debug(D_PROCNETDEV_LOOP, "CHECK: last loop took %llu usec (worked for %llu, sleeped for %llu).", loop_usec, usec, susec);
- if(usec < (rrd_update_every * USEC_PER_SEC / 2ULL)) susec = (rrd_update_every * USEC_PER_SEC) - usec;
- else susec = rrd_update_every * USEC_PER_SEC / 2ULL;
+ if(usec < (localhost->rrd_update_every * USEC_PER_SEC / 2ULL)) susec = (localhost->rrd_update_every * USEC_PER_SEC) - usec;
+ else susec = localhost->rrd_update_every * USEC_PER_SEC / 2ULL;
// --------------------------------------------------------------------
// Calculate loop time
@@ -68,7 +71,7 @@ void *checks_main(void *ptr) {
// --------------------------------------------------------------------
// check chart 3
- if(!apps_cpu) apps_cpu = rrdset_find("apps.cpu");
+ if(!apps_cpu) apps_cpu = rrdset_find_localhost("apps.cpu");
if(check3->counter_done) rrdset_next_usec(check3, loop_usec);
now_realtime_timeval(&loop);
rrddim_set(check3, "caller", (long long) dt_usec(&loop, &check1->last_collected_time));
diff --git a/src/plugin_freebsd.c b/src/plugin_freebsd.c
index bdc3599ea..31ab6e0c4 100644
--- a/src/plugin_freebsd.c
+++ b/src/plugin_freebsd.c
@@ -1,5 +1,62 @@
#include "common.h"
+static struct freebsd_module {
+ const char *name;
+ const char *dim;
+
+ int enabled;
+
+ int (*func)(int update_every, usec_t dt);
+ usec_t duration;
+
+ RRDDIM *rd;
+
+} freebsd_modules[] = {
+
+ // system metrics
+ { .name = "kern.cp_time", .dim = "cp_time", .enabled = 1, .func = do_kern_cp_time },
+ { .name = "vm.loadavg", .dim = "loadavg", .enabled = 1, .func = do_vm_loadavg },
+ { .name = "system.ram", .dim = "system_ram", .enabled = 1, .func = do_system_ram },
+ { .name = "vm.swap_info", .dim = "swap", .enabled = 1, .func = do_vm_swap_info },
+ { .name = "vm.stats.vm.v_swappgs", .dim = "swap_io", .enabled = 1, .func = do_vm_stats_sys_v_swappgs },
+ { .name = "vm.vmtotal", .dim = "vmtotal", .enabled = 1, .func = do_vm_vmtotal },
+ { .name = "vm.stats.vm.v_forks", .dim = "forks", .enabled = 1, .func = do_vm_stats_sys_v_forks },
+ { .name = "vm.stats.sys.v_swtch", .dim = "context_swtch", .enabled = 1, .func = do_vm_stats_sys_v_swtch },
+ { .name = "hw.intrcnt", .dim = "hw_intr", .enabled = 1, .func = do_hw_intcnt },
+ { .name = "vm.stats.sys.v_intr", .dim = "dev_intr", .enabled = 1, .func = do_vm_stats_sys_v_intr },
+ { .name = "vm.stats.sys.v_soft", .dim = "soft_intr", .enabled = 1, .func = do_vm_stats_sys_v_soft },
+ { .name = "net.isr", .dim = "net_isr", .enabled = 1, .func = do_net_isr },
+ { .name = "kern.ipc.sem", .dim = "semaphores", .enabled = 1, .func = do_kern_ipc_sem },
+ { .name = "kern.ipc.shm", .dim = "shared_memory", .enabled = 1, .func = do_kern_ipc_shm },
+ { .name = "kern.ipc.msq", .dim = "message_queues", .enabled = 1, .func = do_kern_ipc_msq },
+ { .name = "uptime", .dim = "uptime", .enabled = 1, .func = do_uptime },
+
+ // memory metrics
+ { .name = "vm.stats.vm.v_pgfaults", .dim = "pgfaults", .enabled = 1, .func = do_vm_stats_sys_v_pgfaults },
+
+ // CPU metrics
+ { .name = "kern.cp_times", .dim = "cp_times", .enabled = 1, .func = do_kern_cp_times },
+
+ // disk metrics
+ { .name = "kern.devstat", .dim = "kern_devstat", .enabled = 1, .func = do_kern_devstat },
+ { .name = "getmntinfo", .dim = "getmntinfo", .enabled = 1, .func = do_getmntinfo },
+
+ // network metrics
+ { .name = "net.inet.tcp.states", .dim = "tcp_states", .enabled = 1, .func = do_net_inet_tcp_states },
+ { .name = "net.inet.tcp.stats", .dim = "tcp_stats", .enabled = 1, .func = do_net_inet_tcp_stats },
+ { .name = "net.inet.udp.stats", .dim = "udp_stats", .enabled = 1, .func = do_net_inet_udp_stats },
+ { .name = "net.inet.icmp.stats", .dim = "icmp_stats", .enabled = 1, .func = do_net_inet_icmp_stats },
+ { .name = "net.inet.ip.stats", .dim = "ip_stats", .enabled = 1, .func = do_net_inet_ip_stats },
+ { .name = "net.inet6.ip6.stats", .dim = "ip6_stats", .enabled = 1, .func = do_net_inet6_ip6_stats },
+ { .name = "net.inet6.icmp6.stats", .dim = "icmp6_stats", .enabled = 1, .func = do_net_inet6_icmp6_stats },
+
+ // network interfaces metrics
+ { .name = "getifaddrs", .dim = "getifaddrs", .enabled = 1, .func = do_getifaddrs },
+
+ // the terminator of this array
+ { .name = NULL, .dim = NULL, .enabled = 0, .func = NULL }
+};
+
void *freebsd_main(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
@@ -11,46 +68,80 @@ void *freebsd_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- // disable (by default) various interface that are not needed
- /*
- config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
- config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
- */
+ int vdo_cpu_netdata = config_get_boolean("plugin:freebsd", "netdata server resources", 1);
- // when ZERO, attempt to do it
- int vdo_cpu_netdata = !config_get_boolean("plugin:freebsd", "netdata server resources", 1);
- int vdo_freebsd_sysctl = !config_get_boolean("plugin:freebsd", "sysctl", 1);
+ // initialize FreeBSD plugin
+ if (freebsd_plugin_init())
+ netdata_exit = 1;
- // keep track of the time each module was called
- unsigned long long sutime_freebsd_sysctl = 0ULL;
+ // check the enabled status for each module
+ int i;
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
- usec_t step = rrd_update_every * USEC_PER_SEC;
- for(;;) {
- usec_t now = now_realtime_usec();
- usec_t next = now - (now % step) + step;
+ pm->enabled = config_get_boolean("plugin:freebsd", pm->name, pm->enabled);
+ pm->duration = 0ULL;
+ pm->rd = NULL;
+ }
- while(now < next) {
- sleep_usec(next - now);
- now = now_realtime_usec();
- }
+ usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+
+ for(;;) {
+ usec_t hb_dt = heartbeat_next(&hb, step);
+ usec_t duration = 0ULL;
if(unlikely(netdata_exit)) break;
// BEGIN -- the job to be done
- if(!vdo_freebsd_sysctl) {
- debug(D_PROCNETDEV_LOOP, "FREEBSD: calling do_freebsd_sysctl().");
- now = now_realtime_usec();
- vdo_freebsd_sysctl = do_freebsd_sysctl(rrd_update_every, (sutime_freebsd_sysctl > 0)?now - sutime_freebsd_sysctl:0ULL);
- sutime_freebsd_sysctl = now;
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
+ if(unlikely(!pm->enabled)) continue;
+
+ debug(D_PROCNETDEV_LOOP, "FREEBSD calling %s.", pm->name);
+
+ pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
+ pm->duration = heartbeat_dt_usec(&hb) - duration;
+ duration += pm->duration;
+
+ if(unlikely(netdata_exit)) break;
}
- if(unlikely(netdata_exit)) break;
// END -- the job is done
// --------------------------------------------------------------------
- if(!vdo_cpu_netdata) {
+ if(vdo_cpu_netdata) {
+ static RRDSET *st = NULL;
+
+ if(unlikely(!st)) {
+ st = rrdset_find_bytype_localhost("netdata", "plugin_freebsd_modules");
+
+ if(!st) {
+ st = rrdset_create_localhost("netdata", "plugin_freebsd_modules", NULL, "freebsd", NULL
+ , "NetData FreeBSD Plugin Modules Durations", "milliseconds/run", 132001
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
+ if(unlikely(!pm->enabled)) continue;
+
+ pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ }
+ }
+ }
+ else rrdset_next(st);
+
+ for(i = 0 ; freebsd_modules[i].name ;i++) {
+ struct freebsd_module *pm = &freebsd_modules[i];
+ if(unlikely(!pm->enabled)) continue;
+
+ rrddim_set_by_pointer(st, pm->rd, pm->duration);
+ }
+ rrdset_done(st);
+
global_statistics_charts();
registry_statistics();
}
@@ -62,18 +153,3 @@ void *freebsd_main(void *ptr) {
pthread_exit(NULL);
return NULL;
}
-
-int getsysctl(const char *name, void *ptr, size_t len)
-{
- size_t nlen = len;
-
- if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
- error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
- return 1;
- }
- if (unlikely(nlen != len)) {
- error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
- return 1;
- }
- return 0;
-}
diff --git a/src/plugin_freebsd.h b/src/plugin_freebsd.h
index e4767a091..166c64338 100644
--- a/src/plugin_freebsd.h
+++ b/src/plugin_freebsd.h
@@ -3,12 +3,117 @@
#include <sys/sysctl.h>
-#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
-
void *freebsd_main(void *ptr);
-int getsysctl(const char *name, void *ptr, size_t len);
+extern int freebsd_plugin_init();
+
+extern int do_vm_loadavg(int update_every, usec_t dt);
+extern int do_vm_vmtotal(int update_every, usec_t dt);
+extern int do_kern_cp_time(int update_every, usec_t dt);
+extern int do_kern_cp_times(int update_every, usec_t dt);
+extern int do_hw_intcnt(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_intr(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_soft(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swtch(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_forks(int update_every, usec_t dt);
+extern int do_vm_swap_info(int update_every, usec_t dt);
+extern int do_system_ram(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt);
+extern int do_kern_ipc_sem(int update_every, usec_t dt);
+extern int do_kern_ipc_shm(int update_every, usec_t dt);
+extern int do_kern_ipc_msq(int update_every, usec_t dt);
+extern int do_uptime(int update_every, usec_t dt);
+extern int do_net_isr(int update_every, usec_t dt);
+extern int do_net_inet_tcp_states(int update_every, usec_t dt);
+extern int do_net_inet_tcp_stats(int update_every, usec_t dt);
+extern int do_net_inet_udp_stats(int update_every, usec_t dt);
+extern int do_net_inet_icmp_stats(int update_every, usec_t dt);
+extern int do_net_inet_ip_stats(int update_every, usec_t dt);
+extern int do_net_inet6_ip6_stats(int update_every, usec_t dt);
+extern int do_net_inet6_icmp6_stats(int update_every, usec_t dt);
+extern int do_getifaddrs(int update_every, usec_t dt);
+extern int do_getmntinfo(int update_every, usec_t dt);
+extern int do_kern_devstat(int update_every, usec_t dt);
+
+#define GETSYSCTL_MIB(name, mib) getsysctl_mib(name, mib, sizeof(mib)/sizeof(int))
+
+static inline int getsysctl_mib(const char *name, int *mib, size_t len)
+{
+ size_t nlen = len;
+
+ if (unlikely(sysctlnametomib(name, mib, &nlen) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(nlen != len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+ return 1;
+ }
+ return 0;
+}
+
+#define GETSYSCTL_SIMPLE(name, mib, var) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), &(var), sizeof(var))
+#define GETSYSCTL_WSIZE(name, mib, var, size) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), var, size)
+
+static inline int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len)
+{
+ size_t nlen = len;
+
+ if (unlikely(!mib[0]))
+ if (unlikely(getsysctl_mib(name, mib, miblen)))
+ return 1;
+
+ if (unlikely(sysctl(mib, miblen, ptr, &nlen, NULL, 0) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(nlen != len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define GETSYSCTL_SIZE(name, mib, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), NULL, &(size))
+#define GETSYSCTL(name, mib, var, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), &(var), &(size))
+
+static inline int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len)
+{
+ size_t nlen = *len;
+
+ if (unlikely(!mib[0]))
+ if (unlikely(getsysctl_mib(name, mib, miblen)))
+ return 1;
+
+ if (unlikely(sysctl(mib, miblen, ptr, len, NULL, 0) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(ptr != NULL && nlen != *len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)*len, (unsigned long)nlen);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
+
+static inline int getsysctl_by_name(const char *name, void *ptr, size_t len)
+{
+ size_t nlen = len;
-extern int do_freebsd_sysctl(int update_every, usec_t dt);
+ if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
+ error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+ return 1;
+ }
+ if (unlikely(nlen != len)) {
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+ return 1;
+ }
+ return 0;
+}
#endif /* NETDATA_PLUGIN_FREEBSD_H */
diff --git a/src/plugin_idlejitter.c b/src/plugin_idlejitter.c
index 7d4a4c189..2ed78160c 100644
--- a/src/plugin_idlejitter.c
+++ b/src/plugin_idlejitter.c
@@ -19,10 +19,11 @@ void *cpuidlejitter_main(void *ptr) {
sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
}
- RRDSET *st = rrdset_find("system.idlejitter");
+ RRDSET *st = rrdset_find_localhost("system.idlejitter");
if(!st) {
- st = rrdset_create("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter", "microseconds lost/s", 9999, rrd_update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "jitter", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter"
+ , "microseconds lost/s", 9999, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "jitter", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
struct timeval before, after;
@@ -30,11 +31,13 @@ void *cpuidlejitter_main(void *ptr) {
for(counter = 0; 1 ;counter++) {
usec_t usec = 0, susec = 0;
- while(susec < (rrd_update_every * USEC_PER_SEC)) {
+ if(netdata_exit) break;
- now_realtime_timeval(&before);
+ while(susec < (localhost->rrd_update_every * USEC_PER_SEC)) {
+
+ now_monotonic_timeval(&before);
sleep_usec(sleep_ms * 1000);
- now_realtime_timeval(&after);
+ now_monotonic_timeval(&after);
// calculate the time it took for a full loop
usec = dt_usec(&after, &before);
diff --git a/src/plugin_macos.c b/src/plugin_macos.c
index 3955c1414..4e84a084d 100644
--- a/src/plugin_macos.c
+++ b/src/plugin_macos.c
@@ -11,12 +11,6 @@ void *macos_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- // disable (by default) various interface that are not needed
- /*
- config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
- config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
- */
-
// when ZERO, attempt to do it
int vdo_cpu_netdata = !config_get_boolean("plugin:macos", "netdata server resources", 1);
int vdo_macos_sysctl = !config_get_boolean("plugin:macos", "sysctl", 1);
@@ -28,15 +22,11 @@ void *macos_main(void *ptr) {
unsigned long long sutime_macos_mach_smi = 0ULL;
unsigned long long sutime_macos_iokit = 0ULL;
- usec_t step = rrd_update_every * USEC_PER_SEC;
+ usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;;) {
- usec_t now = now_realtime_usec();
- usec_t next = now - (now % step) + step;
-
- while(now < next) {
- sleep_usec(next - now);
- now = now_realtime_usec();
- }
+ usec_t hb_dt = heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
@@ -44,25 +34,19 @@ void *macos_main(void *ptr) {
if(!vdo_macos_sysctl) {
debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_sysctl().");
- now = now_realtime_usec();
- vdo_macos_sysctl = do_macos_sysctl(rrd_update_every, (sutime_macos_sysctl > 0)?now - sutime_macos_sysctl:0ULL);
- sutime_macos_sysctl = now;
+ vdo_macos_sysctl = do_macos_sysctl(localhost->rrd_update_every, hb_dt);
}
if(unlikely(netdata_exit)) break;
if(!vdo_macos_mach_smi) {
debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_mach_smi().");
- now = now_realtime_usec();
- vdo_macos_mach_smi = do_macos_mach_smi(rrd_update_every, (sutime_macos_mach_smi > 0)?now - sutime_macos_mach_smi:0ULL);
- sutime_macos_mach_smi = now;
+ vdo_macos_mach_smi = do_macos_mach_smi(localhost->rrd_update_every, hb_dt);
}
if(unlikely(netdata_exit)) break;
if(!vdo_macos_iokit) {
debug(D_PROCNETDEV_LOOP, "MACOS: calling do_macos_iokit().");
- now = now_realtime_usec();
- vdo_macos_iokit = do_macos_iokit(rrd_update_every, (sutime_macos_iokit > 0)?now - sutime_macos_iokit:0ULL);
- sutime_macos_iokit = now;
+ vdo_macos_iokit = do_macos_iokit(localhost->rrd_update_every, hb_dt);
}
if(unlikely(netdata_exit)) break;
diff --git a/src/plugin_macos.h b/src/plugin_macos.h
index a21e5601d..6ccf3e861 100644
--- a/src/plugin_macos.h
+++ b/src/plugin_macos.h
@@ -3,9 +3,9 @@
void *macos_main(void *ptr);
-#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
-extern int getsysctl(const char *name, void *ptr, size_t len);
+extern int getsysctl_by_name(const char *name, void *ptr, size_t len);
extern int do_macos_sysctl(int update_every, usec_t dt);
extern int do_macos_mach_smi(int update_every, usec_t dt);
diff --git a/src/plugin_nfacct.c b/src/plugin_nfacct.c
index 7aae33c0c..4c691be05 100644
--- a/src/plugin_nfacct.c
+++ b/src/plugin_nfacct.c
@@ -1,196 +1,809 @@
#include "common.h"
#ifdef INTERNAL_PLUGIN_NFACCT
+
+#ifdef HAVE_LIBMNL
#include <libmnl/libmnl.h>
-#include <libnetfilter_acct/libnetfilter_acct.h>
-struct mynfacct {
- const char *name;
- uint64_t pkts;
- uint64_t bytes;
- struct nfacct *nfacct;
+static inline size_t mnl_buffer_size() {
+ long s = MNL_SOCKET_BUFFER_SIZE;
+ if(s <= 0) return 8192;
+ return (size_t)s;
+}
+
+// ----------------------------------------------------------------------------
+// DO_NFSTAT - collect netfilter connection tracker statistics via netlink
+// example: https://github.com/formorer/pkg-conntrack-tools/blob/master/src/conntrack.c
+
+#ifdef HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
+#define DO_NFSTAT 1
+
+#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
+#define RRD_TYPE_NET_STAT_CONNTRACK "netlink" // FIXME: should be "conntrack" when merged with the /proc plugin
+
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static struct {
+ int update_every;
+ char *buf;
+ size_t buf_size;
+ struct mnl_socket *mnl;
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+ unsigned int seq;
+ uint32_t portid;
+
+ struct nlattr *tb[CTA_STATS_MAX+1];
+ const char *attr2name[CTA_STATS_MAX+1];
+ kernel_uint_t metrics[CTA_STATS_MAX+1];
+
+ struct nlattr *tb_exp[CTA_STATS_EXP_MAX+1];
+ const char *attr2name_exp[CTA_STATS_EXP_MAX+1];
+ kernel_uint_t metrics_exp[CTA_STATS_EXP_MAX+1];
+} nfstat_root = {
+ .update_every = 1,
+ .buf = NULL,
+ .buf_size = 0,
+ .mnl = NULL,
+ .nlh = NULL,
+ .nfh = NULL,
+ .seq = 0,
+ .portid = 0,
+ .tb = {},
+ .attr2name = {
+ [CTA_STATS_SEARCHED] = "searched",
+ [CTA_STATS_FOUND] = "found",
+ [CTA_STATS_NEW] = "new",
+ [CTA_STATS_INVALID] = "invalid",
+ [CTA_STATS_IGNORE] = "ignore",
+ [CTA_STATS_DELETE] = "delete",
+ [CTA_STATS_DELETE_LIST] = "delete_list",
+ [CTA_STATS_INSERT] = "insert",
+ [CTA_STATS_INSERT_FAILED] = "insert_failed",
+ [CTA_STATS_DROP] = "drop",
+ [CTA_STATS_EARLY_DROP] = "early_drop",
+ [CTA_STATS_ERROR] = "icmp_error",
+ [CTA_STATS_SEARCH_RESTART] = "search_restart",
+ },
+ .metrics = {},
+ .tb_exp = {},
+ .attr2name_exp = {
+ [CTA_STATS_EXP_NEW] = "new",
+ [CTA_STATS_EXP_CREATE] = "created",
+ [CTA_STATS_EXP_DELETE] = "deleted",
+ },
+ .metrics_exp = {}
};
-struct nfacct_list {
- int size;
- int len;
- struct mynfacct data[];
-} *nfacct_list = NULL;
-static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
- if(data) {};
+static int nfstat_init(int update_every) {
+ nfstat_root.update_every = update_every;
- if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
- int size = (nfacct_list) ? nfacct_list->size : 0;
- int len = (nfacct_list) ? nfacct_list->len : 0;
- size++;
+ nfstat_root.buf_size = mnl_buffer_size();
+ nfstat_root.buf = mallocz(nfstat_root.buf_size);
- info("nfacct.plugin: increasing nfacct_list to size %d", size);
+ nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
+ if(!nfstat_root.mnl) {
+ error("NFSTAT: mnl_socket_open() failed");
+ return 1;
+ }
- nfacct_list = reallocz(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
+ nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
- nfacct_list->data[len].nfacct = nfacct_alloc();
- if(!nfacct_list->data[size - 1].nfacct) {
- error("nfacct.plugin: nfacct_alloc() failed.");
- free(nfacct_list);
- nfacct_list = NULL;
- return MNL_CB_OK;
- }
+ if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ error("NFSTAT: mnl_socket_bind() failed");
+ return 1;
+ }
+ nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
+
+ return 0;
+}
- nfacct_list->size = size;
- nfacct_list->len = len;
+static void nfstat_cleanup() {
+ if(nfstat_root.mnl) {
+ mnl_socket_close(nfstat_root.mnl);
+ nfstat_root.mnl = NULL;
}
- if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
- error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
+ freez(nfstat_root.buf);
+ nfstat_root.buf = NULL;
+ nfstat_root.buf_size = 0;
+}
+
+static struct nlmsghdr * nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, uint8_t family, uint32_t seq) {
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (subsys << 8) | type;
+ nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+ nlh->nlmsg_seq = seq;
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = family;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ return nlh;
+}
+
+static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) {
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
return MNL_CB_OK;
+
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ error("NFSTAT: mnl_attr_validate() failed");
+ return MNL_CB_ERROR;
}
- nfacct_list->data[nfacct_list->len].name = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
- nfacct_list->data[nfacct_list->len].pkts = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
- nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int nfstat_callback(const struct nlmsghdr *nlh, void *data) {
+ (void)data;
+
+ struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, nfstat_root.tb);
+
+ // printf("cpu=%-4u\t", ntohs(nfg->res_id));
+
+ int i;
+ // add the metrics of this CPU into the metrics
+ for (i = 0; i < CTA_STATS_MAX+1; i++) {
+ if (nfstat_root.tb[i]) {
+ // printf("%s=%u ", nfstat_root.attr2name[i], ntohl(mnl_attr_get_u32(nfstat_root.tb[i])));
+ nfstat_root.metrics[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb[i]));
+ }
+ }
+ // printf("\n");
- nfacct_list->len++;
return MNL_CB_OK;
}
-void *nfacct_main(void *ptr) {
- struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+static int nfstat_collect_conntrack() {
+ // zero all metrics - we will sum the metrics of all CPUs later
+ int i;
+ for (i = 0; i < CTA_STATS_MAX+1; i++)
+ nfstat_root.metrics[i] = 0;
- info("NFACCT thread created with task id %d", gettid());
+ // prepare the request
+ nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
- if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
- error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
+ // send the request
+ if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
+ error("NFSTAT: mnl_socket_sendto() failed");
+ return 1;
+ }
- if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
- error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
+ // get the reply
+ ssize_t ret;
+ while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
+ if(mnl_cb_run(
+ nfstat_root.buf
+ , (size_t)ret
+ , nfstat_root.nlh->nlmsg_seq
+ , nfstat_root.portid
+ , nfstat_callback
+ , NULL
+ ) <= MNL_CB_STOP)
+ break;
+ }
+
+ // verify we run without issues
+ if (ret == -1) {
+ error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+ return 1;
+ }
- char buf[MNL_SOCKET_BUFFER_SIZE];
- struct mnl_socket *nl = NULL;
- struct nlmsghdr *nlh = NULL;
- unsigned int seq = 0, portid = 0;
+ return 0;
+}
- seq = now_realtime_sec() - 1;
+static int nfexp_stats_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
- nl = mnl_socket_open(NETLINK_NETFILTER);
- if(!nl) {
- error("nfacct.plugin: mnl_socket_open() failed");
- goto cleanup;
+ if (mnl_attr_type_valid(attr, CTA_STATS_EXP_MAX) < 0)
+ return MNL_CB_OK;
+
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ error("NFSTAT EXP: mnl_attr_validate() failed");
+ return MNL_CB_ERROR;
}
- if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
- error("nfacct.plugin: mnl_socket_bind() failed");
- goto cleanup;
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int nfstat_callback_exp(const struct nlmsghdr *nlh, void *data) {
+ (void)data;
+
+ struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*nfg), nfexp_stats_attr_cb, nfstat_root.tb_exp);
+
+ int i;
+ for (i = 0; i < CTA_STATS_EXP_MAX+1; i++) {
+ if (nfstat_root.tb_exp[i]) {
+ nfstat_root.metrics_exp[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb_exp[i]));
+ }
}
- portid = mnl_socket_get_portid(nl);
- // ------------------------------------------------------------------------
+ return MNL_CB_OK;
+}
- struct timeval last, now;
- usec_t usec = 0, susec = 0;
- RRDSET *st = NULL;
+static int nfstat_collect_conntrack_expectations() {
+ // zero all metrics - we will sum the metrics of all CPUs later
+ int i;
+ for (i = 0; i < CTA_STATS_EXP_MAX+1; i++)
+ nfstat_root.metrics_exp[i] = 0;
- now_realtime_timeval(&last);
+ // prepare the request
+ nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
- // ------------------------------------------------------------------------
+ // send the request
+ if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
+ error("NFSTAT: mnl_socket_sendto() failed");
+ return 1;
+ }
- while(1) {
- if(unlikely(netdata_exit)) break;
+ // get the reply
+ ssize_t ret;
+ while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
+ if(mnl_cb_run(
+ nfstat_root.buf
+ , (size_t)ret
+ , nfstat_root.nlh->nlmsg_seq
+ , nfstat_root.portid
+ , nfstat_callback_exp
+ , NULL
+ ) <= MNL_CB_STOP)
+ break;
+ }
- seq++;
+ // verify we run without issues
+ if (ret == -1) {
+ error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nfstat_collect() {
+ nfstat_root.seq++;
+
+ if(nfstat_collect_conntrack())
+ return 1;
+
+ if(nfstat_collect_conntrack_expectations())
+ return 1;
+
+ return 0;
+}
- nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
- if(!nlh) {
- error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
- goto cleanup;
+static void nfstat_send_metrics() {
+
+ {
+ static RRDSET *st_new = NULL;
+ static RRDDIM *rd_new = NULL, *rd_ignore = NULL, *rd_invalid = NULL;
+
+ if(!st_new) {
+ st_new = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_new"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker New Connections"
+ , "connections/s"
+ , 3001
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rd_new = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_ignore = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_IGNORE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_invalid = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_INVALID], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_new);
- if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
- error("nfacct.plugin: mnl_socket_send");
- goto cleanup;
+ rrddim_set_by_pointer(st_new, rd_new, (collected_number) nfstat_root.metrics[CTA_STATS_NEW]);
+ rrddim_set_by_pointer(st_new, rd_ignore, (collected_number) nfstat_root.metrics[CTA_STATS_IGNORE]);
+ rrddim_set_by_pointer(st_new, rd_invalid, (collected_number) nfstat_root.metrics[CTA_STATS_INVALID]);
+
+ rrdset_done(st_new);
+ }
+
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_changes = NULL;
+ static RRDDIM *rd_inserted = NULL, *rd_deleted = NULL, *rd_delete_list = NULL;
+
+ if(!st_changes) {
+ st_changes = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Changes"
+ , "changes/s"
+ , 3002
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_changes, RRDSET_FLAG_DETAIL);
+
+ rd_inserted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_INSERT], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_deleted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_delete_list = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE_LIST], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_changes);
- if(nfacct_list) nfacct_list->len = 0;
+ rrddim_set_by_pointer(st_changes, rd_inserted, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT]);
+ rrddim_set_by_pointer(st_changes, rd_deleted, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE]);
+ rrddim_set_by_pointer(st_changes, rd_delete_list, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE_LIST]);
- int ret;
- while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
- if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
+ rrdset_done(st_changes);
+ }
+
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_search = NULL;
+ static RRDDIM *rd_searched = NULL, *rd_restarted = NULL, *rd_found = NULL;
+
+ if(!st_search) {
+ st_search = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_search"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Searches"
+ , "searches/s"
+ , 3010
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_search, RRDSET_FLAG_DETAIL);
+
+ rd_searched = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCHED], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_restarted = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCH_RESTART], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_found = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_FOUND], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_search);
+
+ rrddim_set_by_pointer(st_search, rd_searched, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCHED]);
+ rrddim_set_by_pointer(st_search, rd_restarted, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCH_RESTART]);
+ rrddim_set_by_pointer(st_search, rd_found, (collected_number) nfstat_root.metrics[CTA_STATS_FOUND]);
- if (ret == -1) {
- error("nfacct.plugin: error communicating with kernel.");
- goto cleanup;
+ rrdset_done(st_search);
+ }
+
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_errors = NULL;
+ static RRDDIM *rd_error = NULL, *rd_insert_failed = NULL, *rd_drop = NULL, *rd_early_drop = NULL;
+
+ if(!st_errors) {
+ st_errors = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Errors"
+ , "events/s"
+ , 3005
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_errors, RRDSET_FLAG_DETAIL);
+
+ rd_error = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_ERROR], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_insert_failed = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_INSERT_FAILED], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_early_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_EARLY_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
+ else
+ rrdset_next(st_errors);
- // --------------------------------------------------------------------
+ rrddim_set_by_pointer(st_errors, rd_error, (collected_number) nfstat_root.metrics[CTA_STATS_ERROR]);
+ rrddim_set_by_pointer(st_errors, rd_insert_failed, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT_FAILED]);
+ rrddim_set_by_pointer(st_errors, rd_drop, (collected_number) nfstat_root.metrics[CTA_STATS_DROP]);
+ rrddim_set_by_pointer(st_errors, rd_early_drop, (collected_number) nfstat_root.metrics[CTA_STATS_EARLY_DROP]);
- now_realtime_timeval(&now);
- usec = dt_usec(&now, &last) - susec;
- debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
+ rrdset_done(st_errors);
+ }
- if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
- else susec = rrd_update_every * 1000000ULL / 2ULL;
+ // ----------------------------------------------------------------
+
+ {
+ static RRDSET *st_expect = NULL;
+ static RRDDIM *rd_new = NULL, *rd_created = NULL, *rd_deleted = NULL;
+
+ if(!st_expect) {
+ st_expect = rrdset_create_localhost(
+ RRD_TYPE_NET_STAT_NETFILTER
+ , RRD_TYPE_NET_STAT_CONNTRACK "_expect"
+ , NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK
+ , NULL
+ , "Connection Tracker Expectations"
+ , "expectations/s"
+ , 3003
+ , nfstat_root.update_every
+ , RRDSET_TYPE_LINE
+ );
+ rrdset_flag_set(st_expect, RRDSET_FLAG_DETAIL);
+
+ rd_created = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_CREATE], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_deleted = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rd_new = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+ else
+ rrdset_next(st_expect);
+ rrddim_set_by_pointer(st_expect, rd_created, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_CREATE]);
+ rrddim_set_by_pointer(st_expect, rd_deleted, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_DELETE]);
+ rrddim_set_by_pointer(st_expect, rd_new, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_NEW]);
- // --------------------------------------------------------------------
+ rrdset_done(st_expect);
+ }
+
+}
+
+#endif // HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
- if(nfacct_list && nfacct_list->len) {
- int i;
- st = rrdset_find_bytype("netfilter", "nfacct_packets");
- if(!st) {
- st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 3206, rrd_update_every, RRDSET_TYPE_STACKED);
+// ----------------------------------------------------------------------------
+// DO_NFACCT - collect netfilter accounting statistics via netlink
- for(i = 0; i < nfacct_list->len ; i++)
- rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+#ifdef HAVE_LIBNETFILTER_ACCT
+#define DO_NFACCT 1
+
+#include <libnetfilter_acct/libnetfilter_acct.h>
- for(i = 0; i < nfacct_list->len ; i++) {
- RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+struct nfacct_data {
+ char *name;
+ uint32_t hash;
- if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
- if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
- }
+ uint64_t pkts;
+ uint64_t bytes;
- rrdset_done(st);
+ RRDDIM *rd_bytes;
+ RRDDIM *rd_packets;
- // ----------------------------------------------------------------
+ int updated;
- st = rrdset_find_bytype("netfilter", "nfacct_bytes");
- if(!st) {
- st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 3207, rrd_update_every, RRDSET_TYPE_STACKED);
+ struct nfacct_data *next;
+};
- for(i = 0; i < nfacct_list->len ; i++)
- rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
- }
- else rrdset_next(st);
+static struct {
+ int update_every;
+ char *buf;
+ size_t buf_size;
+ struct mnl_socket *mnl;
+ struct nlmsghdr *nlh;
+ unsigned int seq;
+ uint32_t portid;
+ struct nfacct *nfacct_buffer;
+ struct nfacct_data *nfacct_metrics;
+} nfacct_root = {
+ .update_every = 1,
+ .buf = NULL,
+ .buf_size = 0,
+ .mnl = NULL,
+ .nlh = NULL,
+ .seq = 0,
+ .portid = 0,
+ .nfacct_buffer = NULL,
+ .nfacct_metrics = NULL
+};
- for(i = 0; i < nfacct_list->len ; i++) {
- RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t hash) {
+ struct nfacct_data *d = NULL, *last = NULL;
+ for(d = nfacct_root.nfacct_metrics; d ; last = d, d = d->next) {
+ if(unlikely(d->hash == hash && !strcmp(d->name, name)))
+ return d;
+ }
- if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
- if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
- }
+ d = callocz(1, sizeof(struct nfacct_data));
+ d->name = strdupz(name);
+ d->hash = hash;
- rrdset_done(st);
+ if(!last) {
+ d->next = nfacct_root.nfacct_metrics;
+ nfacct_root.nfacct_metrics = d;
+ }
+ else {
+ d->next = last->next;
+ last->next = d;
+ }
+
+ return d;
+}
+
+static int nfacct_init(int update_every) {
+ nfacct_root.update_every = update_every;
+
+ nfacct_root.buf_size = mnl_buffer_size();
+ nfacct_root.buf = mallocz(nfacct_root.buf_size);
+
+ nfacct_root.nfacct_buffer = nfacct_alloc();
+ if(!nfacct_root.nfacct_buffer) {
+ error("nfacct.plugin: nfacct_alloc() failed.");
+ return 0;
+ }
+
+ nfacct_root.seq = (unsigned int)now_realtime_sec() - 1;
+
+ nfacct_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
+ if(!nfacct_root.mnl) {
+ error("nfacct.plugin: mnl_socket_open() failed");
+ return 1;
+ }
+
+ if(mnl_socket_bind(nfacct_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ error("nfacct.plugin: mnl_socket_bind() failed");
+ return 1;
+ }
+ nfacct_root.portid = mnl_socket_get_portid(nfacct_root.mnl);
+
+ return 0;
+}
+
+static void nfacct_cleanup() {
+ if(nfacct_root.mnl) {
+ mnl_socket_close(nfacct_root.mnl);
+ nfacct_root.mnl = NULL;
+ }
+
+ if(nfacct_root.nfacct_buffer) {
+ nfacct_free(nfacct_root.nfacct_buffer);
+ nfacct_root.nfacct_buffer = NULL;
+ }
+
+ freez(nfacct_root.buf);
+ nfacct_root.buf = NULL;
+ nfacct_root.buf_size = 0;
+
+ // FIXME: cleanup the metrics linked list
+}
+
+static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
+ (void)data;
+
+ if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
+ error("NFACCT: nfacct_nlmsg_parse_payload() failed.");
+ return MNL_CB_OK;
+ }
+
+ const char *name = nfacct_attr_get_str(nfacct_root.nfacct_buffer, NFACCT_ATTR_NAME);
+ uint32_t hash = simple_hash(name);
+
+ struct nfacct_data *d = nfacct_data_get(name, hash);
+
+ d->pkts = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_PKTS);
+ d->bytes = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_BYTES);
+ d->updated = 1;
+
+ return MNL_CB_OK;
+}
+
+static int nfacct_collect() {
+ // mark all old metrics as not-updated
+ struct nfacct_data *d;
+ for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
+ d->updated = 0;
+
+ // prepare the request
+ nfacct_root.seq++;
+ nfacct_root.nlh = nfacct_nlmsg_build_hdr(nfacct_root.buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)nfacct_root.seq);
+ if(!nfacct_root.nlh) {
+ error("NFACCT: nfacct_nlmsg_build_hdr() failed");
+ return 1;
+ }
+
+ // send the request
+ if(mnl_socket_sendto(nfacct_root.mnl, nfacct_root.nlh, nfacct_root.nlh->nlmsg_len) < 0) {
+ error("NFACCT: mnl_socket_sendto() failed");
+ return 1;
+ }
+
+ // get the reply
+ ssize_t ret;
+ while((ret = mnl_socket_recvfrom(nfacct_root.mnl, nfacct_root.buf, nfacct_root.buf_size)) > 0) {
+ if(mnl_cb_run(
+ nfacct_root.buf
+ , (size_t)ret
+ , nfacct_root.seq
+ , nfacct_root.portid
+ , nfacct_callback
+ , NULL
+ ) <= 0)
+ break;
+ }
+
+ // verify we run without issues
+ if (ret == -1) {
+ error("NFACCT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+ return 1;
+ }
+
+ return 0;
+}
+
+static void nfacct_send_metrics() {
+ static RRDSET *st_bytes = NULL, *st_packets = NULL;
+
+ if(!nfacct_root.nfacct_metrics) return;
+ struct nfacct_data *d;
+
+ if(!st_packets) {
+ st_packets = rrdset_create_localhost(
+ "netfilter"
+ , "nfacct_packets"
+ , NULL
+ , "nfacct"
+ , NULL
+ , "Netfilter Accounting Packets"
+ , "packets/s"
+ , 3206
+ , nfacct_root.update_every
+ , RRDSET_TYPE_STACKED
+ );
+ }
+ else rrdset_next(st_packets);
+
+ for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
+ if(likely(d->updated)) {
+ if(unlikely(!d->rd_packets))
+ d->rd_packets = rrddim_add(
+ st_packets
+ , d->name
+ , NULL
+ , 1
+ , nfacct_root.update_every
+ , RRD_ALGORITHM_INCREMENTAL
+ );
+
+ rrddim_set_by_pointer(
+ st_packets
+ , d->rd_packets
+ , (collected_number)d->pkts
+ );
}
+ }
+
+ rrdset_done(st_packets);
+
+ // ----------------------------------------------------------------
+
+ st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
+ if(!st_bytes) {
+ st_bytes = rrdset_create_localhost(
+ "netfilter"
+ , "nfacct_bytes"
+ , NULL
+ , "nfacct"
+ , NULL
+ , "Netfilter Accounting Bandwidth"
+ , "kilobytes/s"
+ , 3207
+ , nfacct_root.update_every
+ , RRDSET_TYPE_STACKED
+ );
+ }
+ else rrdset_next(st_bytes);
+
+ for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
+ if(likely(d->updated)) {
+ if(unlikely(!d->rd_bytes))
+ d->rd_bytes = rrddim_add(
+ st_bytes
+ , d->name
+ , NULL
+ , 1
+ , 1000 * nfacct_root.update_every
+ , RRD_ALGORITHM_INCREMENTAL
+ );
+
+ rrddim_set_by_pointer(
+ st_bytes
+ , d->rd_bytes
+ , (collected_number)d->bytes
+ );
+ }
+ }
+
+ rrdset_done(st_bytes);
+}
+
+#endif // HAVE_LIBNETFILTER_ACCT
+#endif // HAVE_LIBMNL
+
+// ----------------------------------------------------------------------------
+
+void *nfacct_main(void *ptr) {
+ struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+
+ info("NETFILTER thread created with task id %d", gettid());
+
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("NETFILTER: Cannot set pthread cancel type to DEFERRED.");
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("NETFILTER: Cannot set pthread cancel state to ENABLE.");
- // --------------------------------------------------------------------
- usleep(susec);
+ int update_every = (int)config_get_number("plugin:netfilter", "update every", localhost->rrd_update_every);
+ if(update_every < localhost->rrd_update_every)
+ update_every = localhost->rrd_update_every;
- // copy current to last
- memmove(&last, &now, sizeof(struct timeval));
+#ifdef DO_NFACCT
+ int nfacct = !nfacct_init(update_every);
+#endif
+
+#ifdef DO_NFSTAT
+ int nfstat = !nfstat_init(update_every);
+#endif
+
+ // ------------------------------------------------------------------------
+
+ usec_t step = update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+ for(;;) {
+ heartbeat_dt_usec(&hb);
+ heartbeat_next(&hb, step);
+
+ if(unlikely(netdata_exit)) break;
+
+#ifdef DO_NFACCT
+ if(likely(nfacct)) {
+ nfacct = !nfacct_collect();
+
+ if(likely(nfacct))
+ nfacct_send_metrics();
+ }
+#endif
+
+#ifdef DO_NFSTAT
+ if(likely(nfstat)) {
+ nfstat = !nfstat_collect();
+
+ if(likely(nfstat))
+ nfstat_send_metrics();
+ }
+#endif
}
-cleanup:
- info("NFACCT thread exiting");
+ info("NETFILTER thread exiting");
- if(nl) mnl_socket_close(nl);
+#ifdef DO_NFACCT
+ nfacct_cleanup();
+#endif
+
+#ifdef DO_NFSTAT
+ nfstat_cleanup();
+#endif
static_thread->enabled = 0;
pthread_exit(NULL);
return NULL;
}
-#endif
+
+#endif // INTERNAL_PLUGIN_NFACCT
diff --git a/src/plugin_proc.c b/src/plugin_proc.c
index 9b66b7c28..2ca77491d 100644
--- a/src/plugin_proc.c
+++ b/src/plugin_proc.c
@@ -7,7 +7,6 @@ static struct proc_module {
int enabled;
int (*func)(int update_every, usec_t dt);
- usec_t last_run_usec;
usec_t duration;
RRDDIM *rd;
@@ -76,20 +75,17 @@ void *proc_main(void *ptr) {
struct proc_module *pm = &proc_modules[i];
pm->enabled = config_get_boolean("plugin:proc", pm->name, 1);
- pm->last_run_usec = 0ULL;
pm->duration = 0ULL;
pm->rd = NULL;
}
- usec_t step = rrd_update_every * USEC_PER_SEC;
- for(;;) {
- usec_t now = now_monotonic_usec();
- usec_t next = now - (now % step) + step;
+ usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
- while(now < next) {
- sleep_usec(next - now);
- now = now_monotonic_usec();
- }
+ for(;;) {
+ usec_t hb_dt = heartbeat_next(&hb, step);
+ usec_t duration = 0ULL;
if(unlikely(netdata_exit)) break;
@@ -101,11 +97,9 @@ void *proc_main(void *ptr) {
debug(D_PROCNETDEV_LOOP, "PROC calling %s.", pm->name);
- pm->enabled = !pm->func(rrd_update_every, (pm->last_run_usec > 0)?now - pm->last_run_usec:0ULL);
- pm->last_run_usec = now;
-
- now = now_monotonic_usec();
- pm->duration = now - pm->last_run_usec;
+ pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
+ pm->duration = heartbeat_dt_usec(&hb) - duration;
+ duration += pm->duration;
if(unlikely(netdata_exit)) break;
}
@@ -118,16 +112,18 @@ void *proc_main(void *ptr) {
static RRDSET *st = NULL;
if(unlikely(!st)) {
- st = rrdset_find_bytype("netdata", "plugin_proc_modules");
+ st = rrdset_find_bytype_localhost("netdata", "plugin_proc_modules");
if(!st) {
- st = rrdset_create("netdata", "plugin_proc_modules", NULL, "proc", NULL, "NetData Proc Plugin Modules Durations", "milliseconds/run", 132001, rrd_update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("netdata", "plugin_proc_modules", NULL, "proc", NULL
+ , "NetData Proc Plugin Modules Durations", "milliseconds/run", 132001
+ , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
for(i = 0 ; proc_modules[i].name ;i++) {
struct proc_module *pm = &proc_modules[i];
if(unlikely(!pm->enabled)) continue;
- pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
}
}
@@ -163,7 +159,7 @@ int get_numa_node_count(void)
numa_node_count = 0;
char name[FILENAME_MAX + 1];
- snprintfz(name, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/devices/system/node");
+ snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/node");
char *dirname = config_get("plugin:proc:/sys/devices/system/node", "directory to monitor", name);
DIR *dir = opendir(dirname);
diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c
index 43e6dd7c5..37133e044 100644
--- a/src/plugin_proc_diskspace.c
+++ b/src/plugin_proc_diskspace.c
@@ -1,6 +1,8 @@
#include "common.h"
-#define DELAULT_EXLUDED_PATHS "/proc/* /sys/* /var/run/user/* /run/user/*"
+#define DELAULT_EXLUDED_PATHS "/proc/* /sys/* /var/run/user/* /run/user/* /snap/* /var/lib/docker/*"
+#define DEFAULT_EXCLUDED_FILESYSTEMS ""
+#define CONFIG_SECTION_DISKSPACE "plugin:proc:diskspace"
static struct mountinfo *disk_mountinfo_root = NULL;
static int check_for_new_mountpoints_every = 15;
@@ -14,17 +16,19 @@ static inline void mountinfo_reload(int force) {
mountinfo_free(disk_mountinfo_root);
// re-read mountinfo in case something changed
- disk_mountinfo_root = mountinfo_read(1);
+ disk_mountinfo_root = mountinfo_read(0);
last_loaded = now;
}
}
-// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
+// Data to be stored in DICTIONARY dict_mountpoints used by do_disk_space_stats().
// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
struct mount_point_metadata {
int do_space;
int do_inodes;
+ int shown_error;
+ int updated;
size_t collected; // the number of times this has been collected
@@ -39,41 +43,86 @@ struct mount_point_metadata {
RRDDIM *rd_inodes_reserved;
};
+static DICTIONARY *dict_mountpoints = NULL;
+
+#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE); st = NULL; } } while(st)
+
+int mount_point_cleanup(void *entry, void *data) {
+ (void)data;
+
+ struct mount_point_metadata *mp = (struct mount_point_metadata *)entry;
+ if(!mp) return 0;
+
+ if(likely(mp->updated)) {
+ mp->updated = 0;
+ return 0;
+ }
+
+ if(likely(mp->collected)) {
+ mp->collected = 0;
+ mp->updated = 0;
+ mp->shown_error = 0;
+
+ mp->rd_space_avail = NULL;
+ mp->rd_space_used = NULL;
+ mp->rd_space_reserved = NULL;
+
+ mp->rd_inodes_avail = NULL;
+ mp->rd_inodes_used = NULL;
+ mp->rd_inodes_reserved = NULL;
+
+ rrdset_obsolete_and_pointer_null(mp->st_space);
+ rrdset_obsolete_and_pointer_null(mp->st_inodes);
+ }
+
+ return 0;
+}
+
static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
const char *family = mi->mount_point;
const char *disk = mi->persistent_id;
- static DICTIONARY *mount_points = NULL;
static SIMPLE_PATTERN *excluded_mountpoints = NULL;
+ static SIMPLE_PATTERN *excluded_filesystems = NULL;
int do_space, do_inodes;
- if(unlikely(!mount_points)) {
- const char *s;
+ if(unlikely(!dict_mountpoints)) {
SIMPLE_PREFIX_MODE mode = SIMPLE_PATTERN_EXACT;
- if(config_exists("plugin:proc:/proc/diskstats", "exclude space metrics on paths") && !config_exists("plugin:proc:diskspace", "exclude space metrics on paths")) {
- // the config exists in the old section
- s = config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
+ if(config_move("plugin:proc:/proc/diskstats", "exclude space metrics on paths", CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths") != -1) {
+ // old configuration, enable backwards compatibility
mode = SIMPLE_PATTERN_PREFIX;
}
- else
- s = config_get("plugin:proc:diskspace", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
- mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
- excluded_mountpoints = simple_pattern_create(s, mode);
+ excluded_mountpoints = simple_pattern_create(
+ config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths", DELAULT_EXLUDED_PATHS),
+ mode
+ );
+
+ excluded_filesystems = simple_pattern_create(
+ config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on filesystems", DEFAULT_EXCLUDED_FILESYSTEMS),
+ SIMPLE_PATTERN_EXACT
+ );
+
+ dict_mountpoints = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
}
- struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point);
+ struct mount_point_metadata *m = dictionary_get(dict_mountpoints, mi->mount_point);
if(unlikely(!m)) {
char var_name[4096 + 1];
snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point);
- int def_space = config_get_boolean_ondemand("plugin:proc:diskspace", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
- int def_inodes = config_get_boolean_ondemand("plugin:proc:diskspace", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
+ int def_space = config_get_boolean_ondemand(CONFIG_SECTION_DISKSPACE, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
+ int def_inodes = config_get_boolean_ondemand(CONFIG_SECTION_DISKSPACE, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
if(unlikely(simple_pattern_matches(excluded_mountpoints, mi->mount_point))) {
- def_space = CONFIG_ONDEMAND_NO;
- def_inodes = CONFIG_ONDEMAND_NO;
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
+ }
+
+ if(unlikely(simple_pattern_matches(excluded_filesystems, mi->filesystem))) {
+ def_space = CONFIG_BOOLEAN_NO;
+ def_inodes = CONFIG_BOOLEAN_NO;
}
do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
@@ -82,6 +131,8 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
struct mount_point_metadata mp = {
.do_space = do_space,
.do_inodes = do_inodes,
+ .shown_error = 0,
+ .updated = 0,
.collected = 0,
@@ -96,14 +147,12 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
.rd_inodes_reserved = NULL
};
- m = dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
- }
- else {
- do_space = m->do_space;
- do_inodes = m->do_inodes;
+ m = dictionary_set(dict_mountpoints, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
}
- if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO))
+ m->updated = 1;
+
+ if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
return;
if(unlikely(mi->flags & MOUNTINFO_READONLY && !m->collected))
@@ -111,9 +160,18 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
struct statvfs buff_statvfs;
if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
- error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk);
+ if(!m->shown_error) {
+ error("Failed statvfs() for '%s' (disk '%s', filesystem '%s', root '%s')"
+ , mi->mount_point
+ , disk
+ , mi->filesystem?mi->filesystem:""
+ , mi->root?mi->root:""
+ );
+ m->shown_error = 1;
+ }
return;
}
+ m->shown_error = 0;
// logic found at get_fs_usage() in coreutils
unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
@@ -150,19 +208,30 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
int rendered = 0;
- if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
+ if(m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (bavail || breserved_root || bused))) {
if(unlikely(!m->st_space)) {
- m->do_space = CONFIG_ONDEMAND_YES;
- m->st_space = rrdset_find_bytype("disk_space", disk);
+ m->do_space = CONFIG_BOOLEAN_YES;
+ m->st_space = rrdset_find_bytype_localhost("disk_space", disk);
if(unlikely(!m->st_space)) {
char title[4096 + 1];
snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source);
- m->st_space = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
+ m->st_space = rrdset_create_localhost(
+ "disk_space"
+ , disk
+ , NULL
+ , family
+ , "disk.space"
+ , title
+ , "GB"
+ , 2023
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
- m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL, bsize, 1024 * 1024 * 1024, RRDDIM_ABSOLUTE);
- m->rd_space_used = rrddim_add(m->st_space, "used", NULL, bsize, 1024 * 1024 * 1024, RRDDIM_ABSOLUTE);
- m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root", bsize, 1024 * 1024 * 1024, RRDDIM_ABSOLUTE);
+ m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL, (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_used = rrddim_add(m->st_space, "used", NULL, (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root", (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(m->st_space);
@@ -177,19 +246,30 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
// --------------------------------------------------------------------------
- if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
+ if(m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (favail || freserved_root || fused))) {
if(unlikely(!m->st_inodes)) {
- m->do_inodes = CONFIG_ONDEMAND_YES;
- m->st_inodes = rrdset_find_bytype("disk_inodes", disk);
+ m->do_inodes = CONFIG_BOOLEAN_YES;
+ m->st_inodes = rrdset_find_bytype_localhost("disk_inodes", disk);
if(unlikely(!m->st_inodes)) {
char title[4096 + 1];
snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source);
- m->st_inodes = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
+ m->st_inodes = rrdset_create_localhost(
+ "disk_inodes"
+ , disk
+ , NULL
+ , family
+ , "disk.inodes"
+ , title
+ , "Inodes"
+ , 2024
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
- m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
- m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
- m->rd_inodes_reserved = rrddim_add(m->st_inodes, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+ m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ m->rd_inodes_reserved = rrddim_add(m->st_inodes, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(m->st_inodes);
@@ -221,30 +301,23 @@ void *proc_diskspace_main(void *ptr) {
int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1);
- int update_every = (int)config_get_number("plugin:proc:diskspace", "update every", rrd_update_every);
- if(update_every < rrd_update_every)
- update_every = rrd_update_every;
+ int update_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "update every", localhost->rrd_update_every);
+ if(update_every < localhost->rrd_update_every)
+ update_every = localhost->rrd_update_every;
- check_for_new_mountpoints_every = (int)config_get_number("plugin:proc:diskspace", "check for new mount points every", check_for_new_mountpoints_every);
+ check_for_new_mountpoints_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "check for new mount points every", check_for_new_mountpoints_every);
if(check_for_new_mountpoints_every < update_every)
check_for_new_mountpoints_every = update_every;
struct rusage thread;
- usec_t last = 0, dt = 0;
+ usec_t duration = 0;
usec_t step = update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
for(;;) {
- usec_t now = now_monotonic_usec();
- usec_t next = now - (now % step) + step;
-
- dt = (last)?now - last:0;
-
- while(now < next) {
- sleep_usec(next - now);
- now = now_monotonic_usec();
- }
-
- last = now;
+ duration = heartbeat_dt_usec(&hb);
+ /* usec_t hb_dt = */ heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
@@ -270,6 +343,8 @@ void *proc_diskspace_main(void *ptr) {
if(unlikely(netdata_exit)) break;
+ dictionary_get_all(dict_mountpoints, mount_point_cleanup, NULL);
+
if(vdo_cpu_netdata) {
static RRDSET *stcpu_thread = NULL, *st_duration = NULL;
static RRDDIM *rd_user = NULL, *rd_system = NULL, *rd_duration = NULL;
@@ -279,13 +354,23 @@ void *proc_diskspace_main(void *ptr) {
getrusage(RUSAGE_THREAD, &thread);
if(!stcpu_thread) {
- stcpu_thread = rrdset_find("netdata.plugin_diskspace");
- if(!stcpu_thread) stcpu_thread = rrdset_create("netdata", "plugin_diskspace", NULL, "diskspace", NULL
- , "NetData Disk Space Plugin CPU usage", "milliseconds/s", 132020
- , update_every, RRDSET_TYPE_STACKED);
-
- rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ stcpu_thread = rrdset_find_localhost("netdata.plugin_diskspace");
+ if(!stcpu_thread)
+ stcpu_thread = rrdset_create_localhost(
+ "netdata"
+ , "plugin_diskspace"
+ , NULL
+ , "diskspace"
+ , NULL
+ , "NetData Disk Space Plugin CPU usage"
+ , "milliseconds/s"
+ , 132020
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(stcpu_thread);
@@ -297,17 +382,27 @@ void *proc_diskspace_main(void *ptr) {
// ----------------------------------------------------------------
if(!st_duration) {
- st_duration = rrdset_find("netdata.plugin_diskspace_dt");
- if(!st_duration) st_duration = rrdset_create("netdata", "plugin_diskspace_dt", NULL, "diskspace", NULL
- , "NetData Disk Space Plugin Duration", "milliseconds/run", 132021
- , update_every, RRDSET_TYPE_AREA);
-
- rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st_duration = rrdset_find_localhost("netdata.plugin_diskspace_dt");
+ if(!st_duration)
+ st_duration = rrdset_create_localhost(
+ "netdata"
+ , "plugin_diskspace_dt"
+ , NULL
+ , "diskspace"
+ , NULL
+ , "NetData Disk Space Plugin Duration"
+ , "milliseconds/run"
+ , 132021
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(st_duration);
- rrddim_set_by_pointer(st_duration, rd_duration, dt);
+ rrddim_set_by_pointer(st_duration, rd_duration, duration);
rrdset_done(st_duration);
// ----------------------------------------------------------------
diff --git a/src/plugin_tc.c b/src/plugin_tc.c
index 0fa595320..7dcfedb33 100644
--- a/src/plugin_tc.c
+++ b/src/plugin_tc.c
@@ -1,7 +1,6 @@
#include "common.h"
-#define RRD_TYPE_TC "tc"
-#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
+#define RRD_TYPE_TC "tc"
// ----------------------------------------------------------------------------
// /sbin/tc processor
@@ -25,6 +24,9 @@ struct tc_class {
char hasparent;
char isleaf;
+ char isqdisc;
+ char render;
+
unsigned long long bytes;
unsigned long long packets;
unsigned long long dropped;
@@ -68,6 +70,7 @@ struct tc_device {
char enabled_dropped;
char enabled_tokens;
char enabled_ctokens;
+ char enabled_all_classes_qdiscs;
RRDSET *st_bytes;
RRDSET *st_packets;
@@ -184,103 +187,171 @@ static inline void tc_device_classes_cleanup(struct tc_device *d) {
}
static inline void tc_device_commit(struct tc_device *d) {
- static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1;
+ static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1, enabled_all_classes_qdiscs = -1;
if(unlikely(enable_new_interfaces == -1)) {
- enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
- enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- enable_tokens = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_ONDEMAND_NO);
- enable_ctokens = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_ONDEMAND_NO);
+ enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_YES);
+ enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_BOOLEAN_AUTO);
+ enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_BOOLEAN_AUTO);
+ enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_BOOLEAN_AUTO);
+ enable_tokens = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_BOOLEAN_NO);
+ enable_ctokens = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_BOOLEAN_NO);
+ enabled_all_classes_qdiscs = config_get_boolean_ondemand("plugin:tc", "enable show all classes and qdiscs for all interfaces", CONFIG_BOOLEAN_NO);
+ }
+
+ if(unlikely(d->enabled == (char)-1)) {
+ char var_name[CONFIG_MAX_NAME + 1];
+ snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
+
+ d->enabled = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
+ d->enabled_bytes = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
+ d->enabled_packets = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
+ d->enabled_dropped = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
+ d->enabled_tokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
+ d->enabled_ctokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
+
+ snprintfz(var_name, CONFIG_MAX_NAME, "show all classes for %s", d->id);
+ d->enabled_all_classes_qdiscs = (char)config_get_boolean_ondemand("plugin:tc", var_name, enabled_all_classes_qdiscs);
}
// we only need to add leaf classes
- struct tc_class *c, *x;
+ struct tc_class *c, *x /*, *root = NULL */;
unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0, tokens_sum = 0, ctokens_sum = 0;
- int active_classes = 0;
+ int active_nodes = 0, updated_classes = 0, updated_qdiscs = 0;
+
+ // prepare all classes
+ // we set reasonable defaults for the rest of the code below
- // set all classes
for(c = d->classes ; c ; c = c->next) {
- c->isleaf = 1;
- c->hasparent = 0;
+ c->render = 0; // do not render this class
+
+ c->isleaf = 1; // this is a leaf class
+ c->hasparent = 0; // without a parent
if(unlikely(!c->updated))
- c->unupdated++;
- else
- c->unupdated = 0;
+ c->unupdated++; // increase its unupdated counter
+ else {
+ c->unupdated = 0; // reset its unupdated counter
+
+ // count how many of each kind
+ if(c->isqdisc)
+ updated_qdiscs++;
+ else
+ updated_classes++;
+ }
}
- // mark the classes as leafs and parents
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ if(unlikely(!d->enabled || (!updated_classes && !updated_qdiscs))) {
+ debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. It is not enabled/updated.", d->name?d->name:d->id);
+ tc_device_classes_cleanup(d);
+ return;
+ }
- for(x = d->classes ; x ; x = x->next) {
- if(unlikely(!x->updated)) continue;
+ if(unlikely(updated_classes && updated_qdiscs)) {
+ error("TC: device '%s' has active both classes (%d) and qdiscs (%d). Will render only qdiscs.", d->id, updated_classes, updated_qdiscs);
- if(unlikely(c == x)) continue;
+ // set all classes to !updated
+ for(c = d->classes ; c ; c = c->next)
+ if(unlikely(!c->isqdisc && c->updated))
+ c->updated = 0;
- if(x->parentid && (
- ( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
- (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
- // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
- c->isleaf = 0;
- x->hasparent = 1;
- }
- }
+ updated_classes = 0;
}
- // debugging only
- /*
- if(unlikely(debug_flags & D_TC_LOOP)) {
- for(c = d->classes ; c ; c = c->next) {
- if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device '%s', class %s, OK", d->name, c->id);
- else debug(D_TC_LOOP, "TC: Device '%s', class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
+ // mark the classes as leafs and parents
+ //
+ // TC is hierarchical:
+ // - classes can have other classes in them
+ // - the same is true for qdiscs (i.e. qdiscs have classes, that have other qdiscs)
+ //
+ // we need to present a chart with leaf nodes only, so that the sum
+ // of all dimensions of the chart, will be the total utilization
+ // of the interface.
+ //
+ // here we try to find the ones we need to report
+ // by default all nodes are marked with: isleaf = 1 (see above)
+ //
+ // so, here we remove the isleaf flag from nodes in the middle
+ // and we add the hasparent flag to leaf nodes we found their parent
+ if(likely(!d->enabled_all_classes_qdiscs)) {
+ for(c = d->classes; c; c = c->next) {
+ if(unlikely(!c->updated)) continue;
+
+ //debug(D_TC_LOOP, "TC: In device '%s', %s '%s' has leafid: '%s' and parentid '%s'.",
+ // d->id,
+ // c->isqdisc?"qdisc":"class",
+ // c->id,
+ // c->leafid?c->leafid:"NULL",
+ // c->parentid?c->parentid:"NULL");
+
+ // find if c is leaf or not
+ for(x = d->classes; x; x = x->next) {
+ if(unlikely(!x->updated || c == x || !x->parentid)) continue;
+
+ // classes have both parentid and leafid
+ // qdiscs have only parentid
+ // the following works for both (it is an OR)
+
+ if((c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
+ (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) {
+ // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id);
+ c->isleaf = 0;
+ x->hasparent = 1;
+ }
+ }
}
}
- */
- // we need at least a class
for(c = d->classes ; c ; c = c->next) {
- // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
- if(unlikely(c->updated && c->isleaf && c->hasparent)) {
- active_classes++;
+ if(unlikely(!c->updated)) continue;
+
+ // debug(D_TC_LOOP, "TC: device '%s', %s '%s' isleaf=%d, hasparent=%d", d->id, (c->isqdisc)?"qdisc":"class", c->id, c->isleaf, c->hasparent);
+
+ if(unlikely((c->isleaf && c->hasparent) || d->enabled_all_classes_qdiscs)) {
+ c->render = 1;
+ active_nodes++;
bytes_sum += c->bytes;
packets_sum += c->packets;
dropped_sum += c->dropped;
tokens_sum += c->tokens;
ctokens_sum += c->ctokens;
}
- }
- if(unlikely(!active_classes)) {
- debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
- tc_device_classes_cleanup(d);
- return;
+ //if(unlikely(!c->hasparent)) {
+ // if(root) error("TC: multiple root class/qdisc for device '%s' (old: '%s', new: '%s')", d->id, root->id, c->id);
+ // root = c;
+ // debug(D_TC_LOOP, "TC: found root class/qdisc '%s'", root->id);
+ //}
}
- if(unlikely(d->enabled == (char)-1)) {
- char var_name[CONFIG_MAX_NAME + 1];
- snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
- d->enabled = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
-
- snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
- d->enabled_bytes = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
+#ifdef NETDATA_INTERNAL_CHECKS
+ // dump all the list to see what we know
- snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
- d->enabled_packets = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
-
- snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
- d->enabled_dropped = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
-
- snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
- d->enabled_tokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
+ if(unlikely(debug_flags & D_TC_LOOP)) {
+ for(c = d->classes ; c ; c = c->next) {
+ if(c->render) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", d->name, c->id);
+ else debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, IGNORE (updated: %d, isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->updated, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
+ }
+ }
+#endif
- snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
- d->enabled_ctokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
+ if(unlikely(!active_nodes)) {
+ debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No useful classes/qdiscs.", d->name?d->name:d->id);
+ tc_device_classes_cleanup(d);
+ return;
}
- debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d), classes = %d (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
+ debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d, all_classes_qdiscs: %d/%d), classes: (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
d->name?d->name:d->id,
d->enabled, enable_new_interfaces,
d->enabled_bytes, enable_bytes,
@@ -288,7 +359,7 @@ static inline void tc_device_commit(struct tc_device *d) {
d->enabled_dropped, enable_dropped,
d->enabled_tokens, enable_tokens,
d->enabled_ctokens, enable_ctokens,
- active_classes,
+ d->enabled_all_classes_qdiscs, enabled_all_classes_qdiscs,
bytes_sum,
packets_sum,
dropped_sum,
@@ -296,287 +367,226 @@ static inline void tc_device_commit(struct tc_device *d) {
ctokens_sum
);
- if(likely(d->enabled)) {
- // --------------------------------------------------------------------
- // bytes
+ // --------------------------------------------------------------------
+ // bytes
- if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) {
- d->enabled_bytes = CONFIG_ONDEMAND_YES;
+ if(d->enabled_bytes == CONFIG_BOOLEAN_YES || (d->enabled_bytes == CONFIG_BOOLEAN_AUTO && bytes_sum)) {
+ d->enabled_bytes = CONFIG_BOOLEAN_YES;
- if(unlikely(!d->st_bytes)) {
- d->st_bytes = rrdset_find_bytype(RRD_TYPE_TC, d->id);
- if(unlikely(!d->st_bytes)) {
- debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
- d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);
- }
- }
- else {
- debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_bytes);
+ if(unlikely(!d->st_bytes))
+ d->st_bytes = rrdset_create_localhost(RRD_TYPE_TC, d->id, d->name ? d->name : d->id
+ , d->family ? d->family : d->id, RRD_TYPE_TC ".qos", "Class Usage"
+ , "kilobits/s", 7000, localhost->rrd_update_every
+ , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE
+ : RRDSET_TYPE_STACKED);
- if(unlikely(d->name_updated && d->name && strcmp(d->id, d->name) != 0)) {
- rrdset_set_name(d->st_bytes, d->name);
- d->name_updated = 0;
- }
+ else {
+ rrdset_next(d->st_bytes);
+ if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, d->name);
- // FIXME
- // update the family
- }
+ // FIXME
+ // update the family
+ }
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_bytes)) {
- c->rd_bytes = rrddim_find(d->st_bytes, c->id);
- if(unlikely(!c->rd_bytes)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_bytes->id, c->id, c->name);
+ if(unlikely(!c->rd_bytes))
+ c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
- // new class, we have to add it
- c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_bytes->id, c->id);
- }
+ rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
+ }
+ rrdset_done(d->st_bytes);
+ }
- rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
+ // --------------------------------------------------------------------
+ // packets
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_bytes->id, c->rd_bytes->id, c->name);
- rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
- }
- }
- }
- rrdset_done(d->st_bytes);
- }
+ if(d->enabled_packets == CONFIG_BOOLEAN_YES || (d->enabled_packets == CONFIG_BOOLEAN_AUTO && packets_sum)) {
+ d->enabled_packets = CONFIG_BOOLEAN_YES;
- // --------------------------------------------------------------------
- // packets
-
- if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) {
- d->enabled_packets = CONFIG_ONDEMAND_YES;
+ if(unlikely(!d->st_packets)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
- if(unlikely(!d->st_packets)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ d->st_packets = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010
+ , localhost->rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE
+ : RRDSET_TYPE_STACKED);
+ }
+ else {
+ rrdset_next(d->st_packets);
+
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
-
- d->st_packets = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_packets)) {
- debug(D_TC_LOOP, "TC: Creating new _packets chart for device '%s'", d->name?d->name:d->id);
- d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, RRDSET_TYPE_STACKED);
- }
+ rrdset_set_name(d->st_packets, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _packets chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_packets);
- // FIXME
- // update the family
- }
+ // FIXME
+ // update the family
+ }
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_packets)) {
- c->rd_packets = rrddim_find(d->st_packets, c->id);
- if(unlikely(!c->rd_packets)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_packets->id, c->id, c->name);
+ if(unlikely(!c->rd_packets))
+ c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_packets, c->rd_packets, c->name);
- // new class, we have to add it
- c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_packets->id, c->id);
- }
+ rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
+ }
+ rrdset_done(d->st_packets);
+ }
- rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
+ // --------------------------------------------------------------------
+ // dropped
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_packets->id, c->rd_packets->id, c->name);
- rrddim_set_name(d->st_packets, c->rd_packets, c->name);
- }
- }
- }
- rrdset_done(d->st_packets);
+ if(d->enabled_dropped == CONFIG_BOOLEAN_YES || (d->enabled_dropped == CONFIG_BOOLEAN_AUTO && dropped_sum)) {
+ d->enabled_dropped = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_dropped)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
+
+ d->st_dropped = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s"
+ , 7020, localhost->rrd_update_every
+ , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE
+ : RRDSET_TYPE_STACKED);
}
+ else {
+ rrdset_next(d->st_dropped);
- // --------------------------------------------------------------------
- // dropped
-
- if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) {
- d->enabled_dropped = CONFIG_ONDEMAND_YES;
-
- if(unlikely(!d->st_dropped)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
-
- d->st_dropped = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_dropped)) {
- debug(D_TC_LOOP, "TC: Creating new _dropped chart for device '%s'", d->name?d->name:d->id);
- d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, RRDSET_TYPE_STACKED);
- }
+ rrdset_set_name(d->st_dropped, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _dropped chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_dropped);
- // FIXME
- // update the family
- }
+ // FIXME
+ // update the family
+ }
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_dropped)) {
- c->rd_dropped = rrddim_find(d->st_dropped, c->id);
- if(unlikely(!c->rd_dropped)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_dropped->id, c->id, c->name);
+ if(unlikely(!c->rd_dropped))
+ c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
- // new class, we have to add it
- c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_dropped->id, c->id);
- }
+ rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
+ }
+ rrdset_done(d->st_dropped);
+ }
- rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
+ // --------------------------------------------------------------------
+ // tokens
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_dropped->id, c->rd_dropped->id, c->name);
- rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
- }
- }
- }
- rrdset_done(d->st_dropped);
+ if(d->enabled_tokens == CONFIG_BOOLEAN_YES || (d->enabled_tokens == CONFIG_BOOLEAN_AUTO && tokens_sum)) {
+ d->enabled_tokens = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_tokens)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
+
+ d->st_tokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030
+ , localhost->rrd_update_every, RRDSET_TYPE_LINE);
}
+ else {
+ rrdset_next(d->st_tokens);
- // --------------------------------------------------------------------
- // tokens
-
- if(d->enabled_tokens == CONFIG_ONDEMAND_YES || (d->enabled_tokens == CONFIG_ONDEMAND_ONDEMAND && tokens_sum)) {
- d->enabled_tokens = CONFIG_ONDEMAND_YES;
-
- if(unlikely(!d->st_tokens)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
-
- d->st_tokens = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_tokens)) {
- debug(D_TC_LOOP, "TC: Creating new _tokens chart for device '%s'", d->name?d->name:d->id);
- d->st_tokens = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030, rrd_update_every, RRDSET_TYPE_LINE);
- }
+ rrdset_set_name(d->st_tokens, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _tokens chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_tokens);
- // FIXME
- // update the family
+ // FIXME
+ // update the family
+ }
+
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
+
+ if(unlikely(!c->rd_tokens)) {
+ c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_tokens, c->rd_tokens, c->name);
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
+ rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens);
+ }
+ rrdset_done(d->st_tokens);
+ }
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_tokens)) {
- c->rd_tokens = rrddim_find(d->st_tokens, c->id);
- if(unlikely(!c->rd_tokens)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_tokens->id, c->id, c->name);
+ // --------------------------------------------------------------------
+ // ctokens
- // new class, we have to add it
- c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_ABSOLUTE);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_tokens->id, c->id);
- }
+ if(d->enabled_ctokens == CONFIG_BOOLEAN_YES || (d->enabled_ctokens == CONFIG_BOOLEAN_AUTO && ctokens_sum)) {
+ d->enabled_ctokens = CONFIG_BOOLEAN_YES;
- rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens);
+ if(unlikely(!d->st_ctokens)) {
+ char id[RRD_ID_LENGTH_MAX + 1];
+ char name[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id);
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_tokens->id, c->rd_tokens->id, c->name);
- rrddim_set_name(d->st_tokens, c->rd_tokens, c->name);
- }
- }
- }
- rrdset_done(d->st_tokens);
+ d->st_ctokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id
+ , RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040
+ , localhost->rrd_update_every, RRDSET_TYPE_LINE);
}
+ else {
+ debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id);
+ rrdset_next(d->st_ctokens);
- // --------------------------------------------------------------------
- // ctokens
-
- if(d->enabled_ctokens == CONFIG_ONDEMAND_YES || (d->enabled_ctokens == CONFIG_ONDEMAND_ONDEMAND && ctokens_sum)) {
- d->enabled_ctokens = CONFIG_ONDEMAND_YES;
-
- if(unlikely(!d->st_ctokens)) {
- char id[RRD_ID_LENGTH_MAX + 1];
+ if(unlikely(d->name_updated)) {
char name[RRD_ID_LENGTH_MAX + 1];
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id);
snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
-
- d->st_ctokens = rrdset_find_bytype(RRD_TYPE_TC, id);
- if(unlikely(!d->st_ctokens)) {
- debug(D_TC_LOOP, "TC: Creating new _ctokens chart for device '%s'", d->name?d->name:d->id);
- d->st_ctokens = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040, rrd_update_every, RRDSET_TYPE_LINE);
- }
+ rrdset_set_name(d->st_ctokens, name);
}
- else {
- debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id);
- rrdset_next(d->st_ctokens);
-
- // FIXME
- // update the family
- }
-
- for(c = d->classes ; c ; c = c->next) {
- if(unlikely(!c->updated)) continue;
- if(c->isleaf && c->hasparent) {
- if(unlikely(!c->rd_ctokens)) {
- c->rd_ctokens = rrddim_find(d->st_ctokens, c->id);
- if(unlikely(!c->rd_ctokens)) {
- debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_ctokens->id, c->id, c->name);
+ // FIXME
+ // update the family
+ }
- // new class, we have to add it
- c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_ABSOLUTE);
- }
- else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_ctokens->id, c->id);
- }
+ for(c = d->classes ; c ; c = c->next) {
+ if(unlikely(!c->render)) continue;
- rrddim_set_by_pointer(d->st_ctokens, c->rd_ctokens, c->ctokens);
+ if(unlikely(!c->rd_ctokens))
+ c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ else if(unlikely(c->name_updated))
+ rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name);
- // if it has a name, different to the id
- if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
- // update the rrd dimension with the new name
- debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_ctokens->id, c->rd_ctokens->id, c->name);
- rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name);
- }
- }
- }
- rrdset_done(d->st_ctokens);
+ rrddim_set_by_pointer(d->st_ctokens, c->rd_ctokens, c->ctokens);
}
+ rrdset_done(d->st_ctokens);
}
tc_device_classes_cleanup(d);
}
-static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
-{
+static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name) {
+ if(unlikely(!name || !*name)) return;
+
struct tc_class *c = tc_class_index_find(d, id, 0);
if(likely(c)) {
- freez(c->name);
- c->name = NULL;
+ if(likely(c->name)) {
+ if(!strcmp(c->name, name)) return;
+ freez(c->name);
+ c->name = NULL;
+ }
if(likely(name && *name && strcmp(c->id, name) != 0)) {
debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
@@ -587,10 +597,15 @@ static inline void tc_device_set_class_name(struct tc_device *d, char *id, char
}
static inline void tc_device_set_device_name(struct tc_device *d, char *name) {
- freez(d->name);
- d->name = NULL;
+ if(unlikely(!name || !*name)) return;
+
+ if(d->name) {
+ if(!strcmp(d->name, name)) return;
+ freez(d->name);
+ d->name = NULL;
+ }
- if(likely(name && *name && strcmp(d->id, name) != 0)) {
+ if(likely(name && *name && strcmp(d->id, name))) {
debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
d->name = strdupz(name);
d->name_updated = 1;
@@ -639,7 +654,7 @@ static inline struct tc_device *tc_device_create(char *id)
return(d);
}
-static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
+static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char qdisc, char *parentid, char *leafid)
{
struct tc_class *c = tc_class_index_find(n, id, 0);
@@ -655,6 +670,7 @@ static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char
c->id = strdupz(id);
c->hash = simple_hash(c->id);
+ c->isqdisc = qdisc;
if(parentid && *parentid) {
c->parentid = strdupz(parentid);
c->parent_hash = simple_hash(c->parentid);
@@ -767,6 +783,7 @@ void *tc_main(void *ptr) {
uint32_t BEGIN_HASH = simple_hash("BEGIN");
uint32_t END_HASH = simple_hash("END");
+ uint32_t QDISC_HASH = simple_hash("qdisc");
uint32_t CLASS_HASH = simple_hash("class");
uint32_t SENT_HASH = simple_hash("Sent");
uint32_t LENDED_HASH = simple_hash("lended:");
@@ -780,7 +797,7 @@ void *tc_main(void *ptr) {
#endif
uint32_t first_hash;
- snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR));
+ snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", netdata_configured_plugins_dir);
char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
for(;1;) {
@@ -790,7 +807,7 @@ void *tc_main(void *ptr) {
struct tc_device *device = NULL;
struct tc_class *class = NULL;
- snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every);
+ snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, localhost->rrd_update_every);
debug(D_TC_LOOP, "executing '%s'", buffer);
fp = mypopen(buffer, (pid_t *)&tc_child_pid);
@@ -815,25 +832,51 @@ void *tc_main(void *ptr) {
first_hash = simple_hash(words[0]);
- if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
+ if(unlikely(device && ((first_hash == CLASS_HASH && strcmp(words[0], "class") == 0) || (first_hash == QDISC_HASH && strcmp(words[0], "qdisc") == 0)))) {
// debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
- // words[1] : class type
- // words[2] : N:XX
- // words[3] : parent or root
- if(likely(words[1] && words[2] && words[3] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0))) {
- //char *type = words[1]; // the class: htb, fq_codel, etc
+ char *type = words[1]; // the class/qdisc type: htb, fq_codel, etc
+ char *id = words[2]; // the class/qdisc major:minor
+ char *parent = words[3]; // the word 'parent' or 'root'
+ char *parentid = words[4]; // parentid
+ char *leaf = words[5]; // the word 'leaf'
+ char *leafid = words[6]; // leafid
+
+ int parent_is_root = 0;
+ int parent_is_parent = 0;
+ if(likely(parent)) {
+ parent_is_parent = !strcmp(parent, "parent");
- // we are only interested for HTB classes
- //if(strcmp(type, "htb") != 0) continue;
+ if(!parent_is_parent)
+ parent_is_root = !strcmp(parent, "root");
+ }
+
+ if(likely(type && id && (parent_is_root || parent_is_parent))) {
+ char qdisc = 0;
+
+ if(first_hash == QDISC_HASH) {
+ qdisc = 1;
- char *id = words[2]; // the class major:minor
- char *parent = words[3]; // 'parent' or 'root'
- char *parentid = words[4]; // the parent's id
- char *leaf = words[5]; // 'leaf'
- char *leafid = words[6]; // leafid
+ if(!strcmp(type, "ingress")) {
+ // we don't want to get the ingress qdisc
+ // there should be an IFB interface for this
+
+ class = NULL;
+ continue;
+ }
+
+ if(parent_is_parent && parentid) {
+ // eliminate the minor number from parentid
+ // why: parentid is the id of the parent class
+ // but major: is also the id of the parent qdisc
+
+ char *s = parentid;
+ while(*s && *s != ':') s++;
+ if(*s == ':') s[1] = '\0';
+ }
+ }
- if(strcmp(parent, "root") == 0) {
+ if(parent_is_root) {
parentid = NULL;
leafid = NULL;
}
@@ -847,7 +890,7 @@ void *tc_main(void *ptr) {
leafid = leafbuf;
}
- class = tc_class_add(device, id, parentid, leafid);
+ class = tc_class_add(device, id, qdisc, parentid, leafid);
}
else {
// clear the last class
@@ -946,11 +989,13 @@ void *tc_main(void *ptr) {
// debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
getrusage(RUSAGE_THREAD, &thread);
- if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu");
+ if(unlikely(!stcpu)) stcpu = rrdset_find_localhost("netdata.plugin_tc_cpu");
if(unlikely(!stcpu)) {
- stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED);
- rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ stcpu = rrdset_create_localhost("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL
+ , "NetData TC CPU usage", "milliseconds/s", 135000, localhost->rrd_update_every
+ , RRDSET_TYPE_STACKED);
+ rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(stcpu);
@@ -958,10 +1003,12 @@ void *tc_main(void *ptr) {
rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
rrdset_done(stcpu);
- if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time");
+ if(unlikely(!sttime)) sttime = rrdset_find_localhost("netdata.plugin_tc_time");
if(unlikely(!sttime)) {
- sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA);
- rrddim_add(sttime, "run_time", "run time", 1, 1, RRDDIM_ABSOLUTE);
+ sttime = rrdset_create_localhost("netdata", "plugin_tc_time", NULL, "tc.helper", NULL
+ , "NetData TC script execution", "milliseconds/run", 135001
+ , localhost->rrd_update_every, RRDSET_TYPE_AREA);
+ rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(sttime);
@@ -1009,7 +1056,7 @@ void *tc_main(void *ptr) {
goto cleanup;
}
- sleep((unsigned int) rrd_update_every);
+ sleep((unsigned int) localhost->rrd_update_every);
}
cleanup:
diff --git a/src/plugins_d.c b/src/plugins_d.c
index 4b83b5281..7fa19eaf0 100644
--- a/src/plugins_d.c
+++ b/src/plugins_d.c
@@ -83,302 +83,315 @@ static int pluginsd_split_words(char *str, char **words, int max_words) {
return i;
}
+inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
+ int enabled = cd->enabled;
-void *pluginsd_worker_thread(void *arg)
-{
- struct plugind *cd = (struct plugind *)arg;
- cd->obsolete = 0;
+ if(!fp || !enabled) {
+ cd->enabled = 0;
+ return 0;
+ }
- char line[PLUGINSD_LINE_MAX + 1];
+ size_t count = 0;
-#ifdef DETACH_PLUGINS_FROM_NETDATA
- usec_t usec = 0, susec = 0;
- struct timeval last = {0, 0} , now = {0, 0};
-#endif
+ char line[PLUGINSD_LINE_MAX + 1];
char *words[MAX_WORDS] = { NULL };
+ /* uint32_t HOST_HASH = simple_hash("HOST"); */
uint32_t BEGIN_HASH = simple_hash("BEGIN");
uint32_t END_HASH = simple_hash("END");
uint32_t FLUSH_HASH = simple_hash("FLUSH");
uint32_t CHART_HASH = simple_hash("CHART");
uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
uint32_t DISABLE_HASH = simple_hash("DISABLE");
-#ifdef DETACH_PLUGINS_FROM_NETDATA
- uint32_t MYPID_HASH = simple_hash("MYPID");
- uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
-#endif
- size_t count = 0;
+ RRDSET *st = NULL;
+ uint32_t hash;
- for(;;) {
+ errno = 0;
+ clearerr(fp);
+
+ if(unlikely(fileno(fp) == -1)) {
+ error("PLUGINSD: %s: file is not a valid stream.", cd->fullfilename);
+ goto cleanup;
+ }
+
+ while(!ferror(fp)) {
if(unlikely(netdata_exit)) break;
- FILE *fp = mypopen(cd->cmd, &cd->pid);
- if(unlikely(!fp)) {
- error("Cannot popen(\"%s\", \"r\").", cd->cmd);
+ char *r = fgets(line, PLUGINSD_LINE_MAX, fp);
+ if(unlikely(!r)) {
+ error("PLUGINSD: %s : read failed.", cd->fullfilename);
break;
}
- info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
+ if(unlikely(netdata_exit)) break;
- RRDSET *st = NULL;
- uint32_t hash;
+ line[PLUGINSD_LINE_MAX] = '\0';
- while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
- if(unlikely(netdata_exit)) break;
+ // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
- line[PLUGINSD_LINE_MAX] = '\0';
+ int w = pluginsd_split_words(line, words, MAX_WORDS);
+ char *s = words[0];
+ if(unlikely(!s || !*s || !w)) {
+ // debug(D_PLUGINSD, "PLUGINSD: empty line");
+ continue;
+ }
- // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
+ // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
- int w = pluginsd_split_words(line, words, MAX_WORDS);
- char *s = words[0];
- if(unlikely(!s || !*s || !w)) {
- // debug(D_PLUGINSD, "PLUGINSD: empty line");
- continue;
- }
+ if(likely(!simple_hash_strcmp(s, "SET", &hash))) {
+ char *dimension = words[1];
+ char *value = words[2];
- // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
+ if(unlikely(!dimension || !*dimension)) {
+ error("PLUGINSD: '%s' is requesting a SET on chart '%s' of host '%s', without a dimension. Disabling it.", cd->fullfilename, st->id, host->hostname);
+ enabled = 0;
+ break;
+ }
- if(likely(!simple_hash_strcmp(s, "SET", &hash))) {
- char *dimension = words[1];
- char *value = words[2];
+ if(unlikely(!value || !*value)) value = NULL;
- if(unlikely(!dimension || !*dimension)) {
- error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>", host->hostname);
+ enabled = 0;
+ break;
+ }
- if(unlikely(!value || !*value)) value = NULL;
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
-
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
+ if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
+ }
+ else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
+ char *id = words[1];
+ char *microseconds_txt = words[2];
- if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
+ if(unlikely(!id)) {
+ error("PLUGINSD: '%s' is requesting a BEGIN without a chart id for host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
}
- else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
- char *id = words[1];
- char *microseconds_txt = words[2];
- if(unlikely(!id)) {
- error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ st = rrdset_find(host, id);
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", cd->fullfilename, id, host->hostname);
+ enabled = 0;
+ break;
+ }
- st = rrdset_find(id);
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ if(likely(st->counter_done)) {
+ usec_t microseconds = 0;
+ if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt);
- if(likely(st->counter_done)) {
- usec_t microseconds = 0;
- if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt);
- if(microseconds) rrdset_next_usec(st, microseconds);
- else rrdset_next(st);
+ if(likely(microseconds)) {
+ if(trust_durations)
+ rrdset_next_usec_unfiltered(st, microseconds);
+ else
+ rrdset_next_usec(st, microseconds);
}
+ else rrdset_next(st);
}
- else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
+ }
+ else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting an END, without a BEGIN on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
+ rrdset_done(st);
+ st = NULL;
- rrdset_done(st);
- st = NULL;
+ count++;
+ }
+/* else if(likely(hash == HOST_HASH && !strcmp(s, "HOST"))) {
+ char *guid = words[1];
+ char *hostname = words[2];
- count++;
+ if(unlikely(!guid || !*guid)) {
+ error("PLUGINSD: '%s' is requesting HOST with guid '%s' and hostname '%s', without a guid. Disabling it.", cd->fullfilename, guid?guid:"", hostname?hostname:"");
+ enabled = 0;
+ break;
}
- else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
- debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
- st = NULL;
+ if(unlikely(!hostname || !*hostname)) {
+ error("PLUGINSD: '%s' is requesting HOST with guid '%s' and hostname '%s', without a hostname. Disabling it.", cd->fullfilename, guid?guid:"", hostname?hostname:"");
+ enabled = 0;
+ break;
}
- else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
- int noname = 0;
- st = NULL;
-
- if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
- noname = 1;
-
- char *type = words[1];
- char *id = NULL;
- if(likely(type)) {
- id = strchr(type, '.');
- if(likely(id)) { *id = '\0'; id++; }
- }
- char *name = words[2];
- char *title = words[3];
- char *units = words[4];
- char *family = words[5];
- char *context = words[6];
- char *chart = words[7];
- char *priority_s = words[8];
- char *update_every_s = words[9];
-
- if(unlikely(!type || !*type || !id || !*id)) {
- error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
- int priority = 1000;
- if(likely(priority_s)) priority = str2i(priority_s);
-
- int update_every = cd->update_every;
- if(likely(update_every_s)) update_every = str2i(update_every_s);
- if(unlikely(!update_every)) update_every = cd->update_every;
-
- int chart_type = RRDSET_TYPE_LINE;
- if(unlikely(chart)) chart_type = rrdset_type_id(chart);
-
- if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
- if(unlikely(!family || !*family)) family = NULL;
- if(unlikely(!context || !*context)) context = NULL;
-
- st = rrdset_find_bytype(type, id);
- if(unlikely(!st)) {
- debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
- , type, id
- , name?name:""
- , family?family:""
- , context?context:""
- , rrdset_type_name(chart_type)
- , priority
- , update_every
- );
-
- st = rrdset_create(type, id, name, family, context, title, units, priority, update_every, chart_type);
- cd->update_every = update_every;
- }
- else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
+ host = rrdhost_find_or_create(hostname, guid);
+ } */
+ else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
+ debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
+ st = NULL;
+ }
+ else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
+ int noname = 0;
+ st = NULL;
+
+ if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
+ noname = 1;
+
+ char *type = words[1];
+ char *id = NULL;
+ if(likely(type)) {
+ id = strchr(type, '.');
+ if(likely(id)) { *id = '\0'; id++; }
+ }
+ char *name = words[2];
+ char *title = words[3];
+ char *units = words[4];
+ char *family = words[5];
+ char *context = words[6];
+ char *chart = words[7];
+ char *priority_s = words[8];
+ char *update_every_s = words[9];
+
+ if(unlikely(!type || !*type || !id || !*id)) {
+ error("PLUGINSD: '%s' is requesting a CHART, without a type.id, on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
}
- else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
- char *id = words[1];
- char *name = words[2];
- char *algorithm = words[3];
- char *multiplier_s = words[4];
- char *divisor_s = words[5];
- char *options = words[6];
-
- if(unlikely(!id || !*id)) {
- error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
-
- if(unlikely(!st)) {
- error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
- }
- long multiplier = 1;
- if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
- if(unlikely(!multiplier)) multiplier = 1;
-
- long divisor = 1;
- if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
- if(unlikely(!divisor)) divisor = 1;
-
- if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
-
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
- , st->id
- , id
- , name?name:""
- , rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
- , multiplier
- , divisor
- , options?options:""
- );
-
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
- rd->flags = 0x00000000;
- if(options && *options) {
- if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
- if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
- if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
- }
- }
- else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
+ int priority = 1000;
+ if(likely(priority_s)) priority = str2i(priority_s);
+
+ int update_every = cd->update_every;
+ if(likely(update_every_s)) update_every = str2i(update_every_s);
+ if(unlikely(!update_every)) update_every = cd->update_every;
+
+ RRDSET_TYPE chart_type = RRDSET_TYPE_LINE;
+ if(unlikely(chart)) chart_type = rrdset_type_id(chart);
+
+ if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
+ if(unlikely(!family || !*family)) family = NULL;
+ if(unlikely(!context || !*context)) context = NULL;
+
+ st = rrdset_find_bytype(host, type, id);
+ if(unlikely(!st)) {
+ debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
+ , type, id
+ , name?name:""
+ , family?family:""
+ , context?context:""
+ , rrdset_type_name(chart_type)
+ , priority
+ , update_every
+ );
+
+ st = rrdset_create(host, type, id, name, family, context, title, units, priority, update_every, chart_type);
+ cd->update_every = update_every;
}
- else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
- info("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
+ else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
+ }
+ else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
+ char *id = words[1];
+ char *name = words[2];
+ char *algorithm = words[3];
+ char *multiplier_s = words[4];
+ char *divisor_s = words[5];
+ char *options = words[6];
+
+ if(unlikely(!id || !*id)) {
+ error("PLUGINSD: '%s' is requesting a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", cd->fullfilename, host->hostname, st?st->id:"UNSET");
+ enabled = 0;
break;
}
-#ifdef DETACH_PLUGINS_FROM_NETDATA
- else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
- char *pid_s = words[1];
- pid_t pid = strtod(pid_s, NULL, 0);
- if(likely(pid)) cd->pid = pid;
- debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
+ if(unlikely(!st)) {
+ error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART, on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
+ enabled = 0;
+ break;
}
- else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
- error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
- now_realtime_timeval(&now);
- if(unlikely(!usec && !susec)) {
- // our first run
- susec = cd->rrd_update_every * USEC_PER_SEC;
+ long multiplier = 1;
+ if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
+ if(unlikely(!multiplier)) multiplier = 1;
+
+ long divisor = 1;
+ if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
+ if(unlikely(!divisor)) divisor = 1;
+
+ if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
+ , st->id
+ , id
+ , name?name:""
+ , rrd_algorithm_name(rrd_algorithm_id(algorithm))
+ , multiplier
+ , divisor
+ , options?options:""
+ );
+
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ rd = rrddim_add(st, id, name, multiplier, divisor, rrd_algorithm_id(algorithm));
+ rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
+ rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
+ if(options && *options) {
+ if(strstr(options, "hidden") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
+ if(strstr(options, "noreset") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
+ if(strstr(options, "nooverflow") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
}
- else {
- // second+ run
- usec = dt_usec(&now, &last) - susec;
- error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
- if(unlikely(usec < (rrd_update_every * USEC_PER_SEC / 2ULL))) susec = (rrd_update_every * USEC_PER_SEC) - usec;
- else susec = rrd_update_every * USEC_PER_SEC / 2ULL;
- }
-
- error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
- usleep(susec);
- killpid(cd->pid, SIGCONT);
- memmove(&last, &now, sizeof(struct timeval));
- break;
- }
-#endif
- else {
- error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
- cd->enabled = 0;
- killpid(cd->pid, SIGTERM);
- break;
}
+ else if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
+ }
+ else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
+ info("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
+ enabled = 0;
+ break;
}
- if(likely(count)) {
- cd->successful_collections += count;
- cd->serial_failures = 0;
+ else {
+ error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata, for host '%s'. Disabling it.", cd->fullfilename, s, host->hostname);
+ enabled = 0;
+ break;
}
- else
- cd->serial_failures++;
+ }
+
+cleanup:
+ cd->enabled = enabled;
+
+ if(likely(count)) {
+ cd->successful_collections += count;
+ cd->serial_failures = 0;
+ }
+ else
+ cd->serial_failures++;
+
+ return count;
+}
+
+void *pluginsd_worker_thread(void *arg) {
+ struct plugind *cd = (struct plugind *)arg;
+ cd->obsolete = 0;
+
+ size_t count = 0;
+
+ for(;;) {
+ if(unlikely(netdata_exit)) break;
+
+ FILE *fp = mypopen(cd->cmd, &cd->pid);
+ if(unlikely(!fp)) {
+ error("Cannot popen(\"%s\", \"r\").", cd->cmd);
+ break;
+ }
+
+ info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
+
+ count = pluginsd_process(localhost, cd, fp, 0);
+ error("PLUGINSD: plugin '%s' disconnected.", cd->fullfilename);
+
+ killpid(cd->pid, SIGTERM);
info("PLUGINSD: '%s' on pid %d stopped after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
// get the return code
int code = mypclose(fp, cd->pid);
-
+
if(unlikely(netdata_exit)) break;
else if(code != 0) {
// the plugin reports failure
@@ -442,24 +455,23 @@ void *pluginsd_main(void *ptr) {
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("Cannot set pthread cancel state to ENABLE.");
- char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
- int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
- int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
+ int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1);
+ int scan_frequency = (int) config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
DIR *dir = NULL;
struct dirent *file = NULL;
struct plugind *cd;
// enable the apps plugin by default
- // config_get_boolean("plugins", "apps", 1);
+ // config_get_boolean(CONFIG_SECTION_PLUGINS, "apps", 1);
if(scan_frequency < 1) scan_frequency = 1;
for(;;) {
if(unlikely(netdata_exit)) break;
- dir = opendir(dir_name);
+ dir = opendir(netdata_configured_plugins_dir);
if(unlikely(!dir)) {
- error("Cannot open directory '%s'.", dir_name);
+ error("Cannot open directory '%s'.", netdata_configured_plugins_dir);
goto cleanup;
}
@@ -479,7 +491,7 @@ void *pluginsd_main(void *ptr) {
char pluginname[CONFIG_MAX_NAME + 1];
snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
- int enabled = config_get_boolean("plugins", pluginname, automatic_run);
+ int enabled = config_get_boolean(CONFIG_SECTION_PLUGINS, pluginname, automatic_run);
if(unlikely(!enabled)) {
debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name);
@@ -503,10 +515,10 @@ void *pluginsd_main(void *ptr) {
snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
strncpyz(cd->filename, file->d_name, FILENAME_MAX);
- snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
+ snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", netdata_configured_plugins_dir, cd->filename);
cd->enabled = enabled;
- cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
+ cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every);
cd->started_t = now_realtime_sec();
char *def = "";
diff --git a/src/plugins_d.h b/src/plugins_d.h
index 3c74355a3..d34c4030c 100644
--- a/src/plugins_d.h
+++ b/src/plugins_d.h
@@ -11,7 +11,7 @@ struct plugind {
char filename[FILENAME_MAX+1]; // just the filename
char fullfilename[FILENAME_MAX+1]; // with path
- char cmd[PLUGINSD_CMD_MAX+1]; // the command that is executes
+ char cmd[PLUGINSD_CMD_MAX+1]; // the command that it executes
pid_t pid;
pthread_t thread;
@@ -34,5 +34,6 @@ struct plugind {
extern struct plugind *pluginsd_root;
extern void *pluginsd_main(void *ptr);
+extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations);
#endif /* NETDATA_PLUGINS_D_H */
diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c
index 9ccac6dc7..a1b4072dd 100644
--- a/src/proc_diskstats.c
+++ b/src/proc_diskstats.c
@@ -6,6 +6,9 @@
#define DISK_TYPE_PARTITION 2
#define DISK_TYPE_CONTAINER 3
+#define CONFIG_SECTION_DISKSTATS "plugin:proc:/proc/diskstats"
+#define DELAULT_EXLUDED_DISKS "loop* ram*"
+
static struct disk {
char *disk; // the name of the disk (sda, sdb, etc)
unsigned long major;
@@ -25,9 +28,24 @@ static struct disk {
int do_util;
int do_backlog;
+ int updated;
+
+ RRDSET *st_avgsz;
+ RRDSET *st_await;
+ RRDSET *st_backlog;
+ RRDSET *st_io;
+ RRDSET *st_iotime;
+ RRDSET *st_mops;
+ RRDSET *st_ops;
+ RRDSET *st_qops;
+ RRDSET *st_svctm;
+ RRDSET *st_util;
+
struct disk *next;
} *disk_root = NULL;
+#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE); st = NULL; } } while(st)
+
static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
@@ -46,7 +64,7 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
// not found
// create a new disk structure
- d = (struct disk *)mallocz(sizeof(struct disk));
+ d = (struct disk *)callocz(1, sizeof(struct disk));
d->disk = strdupz(disk);
d->major = major;
@@ -72,8 +90,8 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
// get the default path for finding info about the block device
if(unlikely(!path_find_block_device[0])) {
- snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
- snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
+ snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s");
+ snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer));
}
// find if it is a partition
@@ -126,12 +144,12 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
// find the disk sector size
if(unlikely(!path_to_get_hw_sector_size[0])) {
- snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
- snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
+ snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size");
+ snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer));
}
if(unlikely(!path_to_get_hw_sector_size_partitions[0])) {
- snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
- snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
+ snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
+ snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size for partitions", buffer));
}
{
@@ -170,7 +188,7 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
}
static inline int is_major_enabled(int major) {
- static char *major_configs = NULL;
+ static int8_t *major_configs = NULL;
static size_t major_size = 0;
if(major < 0) return 1;
@@ -178,7 +196,7 @@ static inline int is_major_enabled(int major) {
size_t wanted_size = (size_t)major + 1;
if(major_size < wanted_size) {
- major_configs = reallocz(major_configs, wanted_size);
+ major_configs = reallocz(major_configs, wanted_size * sizeof(int8_t));
size_t i;
for(i = major_size; i < wanted_size ; i++)
@@ -190,43 +208,40 @@ static inline int is_major_enabled(int major) {
if(major_configs[major] == -1) {
char buffer[CONFIG_MAX_NAME + 1];
snprintfz(buffer, CONFIG_MAX_NAME, "performance metrics for disks with major %d", major);
- major_configs[major] = (char)config_get_boolean("plugin:proc:/proc/diskstats", buffer, 1);
+ major_configs[major] = (char)config_get_boolean(CONFIG_SECTION_DISKSTATS, buffer, 1);
}
- return major_configs[major];
+ return (int)major_configs[major];
}
int do_proc_diskstats(int update_every, usec_t dt) {
- (void)dt;
-
static procfile *ff = NULL;
- static int global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
- global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
- global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_ONDEMAND,
- global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
- global_do_io = CONFIG_ONDEMAND_ONDEMAND,
- global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
- global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
- global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
- global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
- global_do_util = CONFIG_ONDEMAND_ONDEMAND,
- global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
+ static int global_enable_new_disks_detected_at_runtime = CONFIG_BOOLEAN_YES,
+ global_enable_performance_for_physical_disks = CONFIG_BOOLEAN_AUTO,
+ global_enable_performance_for_virtual_disks = CONFIG_BOOLEAN_AUTO,
+ global_enable_performance_for_partitions = CONFIG_BOOLEAN_NO,
+ global_do_io = CONFIG_BOOLEAN_AUTO,
+ global_do_ops = CONFIG_BOOLEAN_AUTO,
+ global_do_mops = CONFIG_BOOLEAN_AUTO,
+ global_do_iotime = CONFIG_BOOLEAN_AUTO,
+ global_do_qops = CONFIG_BOOLEAN_AUTO,
+ global_do_util = CONFIG_BOOLEAN_AUTO,
+ global_do_backlog = CONFIG_BOOLEAN_AUTO,
globals_initialized = 0;
if(unlikely(!globals_initialized)) {
- global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
-
- global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
- global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
- global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
-
- global_do_io = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
- global_do_ops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
- global_do_mops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
- global_do_iotime = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
- global_do_qops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
- global_do_util = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
- global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
+ global_enable_new_disks_detected_at_runtime = config_get_boolean(CONFIG_SECTION_DISKSTATS, "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
+ global_enable_performance_for_physical_disks = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for physical disks", global_enable_performance_for_physical_disks);
+ global_enable_performance_for_virtual_disks = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
+ global_enable_performance_for_partitions = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "performance metrics for partitions", global_enable_performance_for_partitions);
+
+ global_do_io = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "bandwidth for all disks", global_do_io);
+ global_do_ops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "operations for all disks", global_do_ops);
+ global_do_mops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "merged operations for all disks", global_do_mops);
+ global_do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "i/o time for all disks", global_do_iotime);
+ global_do_qops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "queued operations for all disks", global_do_qops);
+ global_do_util = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "utilization percentage for all disks", global_do_util);
+ global_do_backlog = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "backlog for all disks", global_do_backlog);
globals_initialized = 1;
}
@@ -235,8 +250,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/diskstats");
- ff = procfile_open(config_get("plugin:proc:/proc/diskstats", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/diskstats");
+ ff = procfile_open(config_get(CONFIG_SECTION_DISKSTATS, "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(unlikely(!ff)) return 0;
@@ -318,7 +333,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// get a disk structure for the disk
struct disk *d = get_disk(major, minor, disk);
-
+ d->updated = 1;
// --------------------------------------------------------------------------
// Set its family based on mount point
@@ -331,25 +346,41 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// Check the configuration for the device
if(unlikely(!d->configured)) {
+ d->configured = 1;
+
+ static SIMPLE_PATTERN *excluded_disks = NULL;
+
+ if(unlikely(!excluded_disks)) {
+ excluded_disks = simple_pattern_create(
+ config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DELAULT_EXLUDED_DISKS),
+ SIMPLE_PATTERN_EXACT
+ );
+ }
+
+ int def_enable = global_enable_new_disks_detected_at_runtime;
+
+ if(def_enable != CONFIG_BOOLEAN_NO && simple_pattern_matches(excluded_disks, disk))
+ def_enable = CONFIG_BOOLEAN_NO;
+
char var_name[4096 + 1];
snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
- int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
- if(unlikely(def_enable == CONFIG_ONDEMAND_NO)) {
+ def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable);
+ if(unlikely(def_enable == CONFIG_BOOLEAN_NO)) {
// the user does not want any metrics for this disk
- d->do_io = CONFIG_ONDEMAND_NO;
- d->do_ops = CONFIG_ONDEMAND_NO;
- d->do_mops = CONFIG_ONDEMAND_NO;
- d->do_iotime = CONFIG_ONDEMAND_NO;
- d->do_qops = CONFIG_ONDEMAND_NO;
- d->do_util = CONFIG_ONDEMAND_NO;
- d->do_backlog = CONFIG_ONDEMAND_NO;
+ d->do_io = CONFIG_BOOLEAN_NO;
+ d->do_ops = CONFIG_BOOLEAN_NO;
+ d->do_mops = CONFIG_BOOLEAN_NO;
+ d->do_iotime = CONFIG_BOOLEAN_NO;
+ d->do_qops = CONFIG_BOOLEAN_NO;
+ d->do_util = CONFIG_BOOLEAN_NO;
+ d->do_backlog = CONFIG_BOOLEAN_NO;
}
else {
// this disk is enabled
// check its direct settings
- int def_performance = CONFIG_ONDEMAND_ONDEMAND;
+ int def_performance = CONFIG_BOOLEAN_AUTO;
// since this is 'on demand' we can figure the performance settings
// based on the type of disk
@@ -380,16 +411,16 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// check the user configuration (this will also show our 'on demand' decision)
def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
- int ddo_io = CONFIG_ONDEMAND_NO,
- ddo_ops = CONFIG_ONDEMAND_NO,
- ddo_mops = CONFIG_ONDEMAND_NO,
- ddo_iotime = CONFIG_ONDEMAND_NO,
- ddo_qops = CONFIG_ONDEMAND_NO,
- ddo_util = CONFIG_ONDEMAND_NO,
- ddo_backlog = CONFIG_ONDEMAND_NO;
+ int ddo_io = CONFIG_BOOLEAN_NO,
+ ddo_ops = CONFIG_BOOLEAN_NO,
+ ddo_mops = CONFIG_BOOLEAN_NO,
+ ddo_iotime = CONFIG_BOOLEAN_NO,
+ ddo_qops = CONFIG_BOOLEAN_NO,
+ ddo_util = CONFIG_BOOLEAN_NO,
+ ddo_backlog = CONFIG_BOOLEAN_NO;
// we enable individual performance charts only when def_performance is not disabled
- if(unlikely(def_performance != CONFIG_ONDEMAND_NO)) {
+ if(unlikely(def_performance != CONFIG_BOOLEAN_NO)) {
ddo_io = global_do_io,
ddo_ops = global_do_ops,
ddo_mops = global_do_mops,
@@ -407,144 +438,216 @@ int do_proc_diskstats(int update_every, usec_t dt) {
d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
}
-
- d->configured = 1;
}
- RRDSET *st;
-
// --------------------------------------------------------------------------
// Do performance metrics
- if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
- d->do_io = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
- if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
+ if(d->do_io == CONFIG_BOOLEAN_YES || (d->do_io == CONFIG_BOOLEAN_AUTO && (readsectors || writesectors))) {
+ d->do_io = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_io)) {
+ d->st_io = rrdset_create_localhost(
+ RRD_TYPE_DISK
+ , disk
+ , NULL
+ , family
+ , "disk.io"
+ , "Disk I/O Bandwidth"
+ , "kilobytes/s"
+ , 2000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_io);
- last_readsectors = rrddim_set(st, "reads", readsectors);
- last_writesectors = rrddim_set(st, "writes", writesectors);
- rrdset_done(st);
+ last_readsectors = rrddim_set(d->st_io, "reads", readsectors);
+ last_writesectors = rrddim_set(d->st_io, "writes", writesectors);
+ rrdset_done(d->st_io);
}
// --------------------------------------------------------------------
- if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
- d->do_ops = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_ops", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if(d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes))) {
+ d->do_ops = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_ops)) {
+ d->st_ops = rrdset_create_localhost(
+ "disk_ops"
+ , disk
+ , NULL
+ , family
+ , "disk.ops"
+ , "Disk Completed I/O Operations"
+ , "operations/s"
+ , 2001
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_ops, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_ops);
- last_reads = rrddim_set(st, "reads", reads);
- last_writes = rrddim_set(st, "writes", writes);
- rrdset_done(st);
+ last_reads = rrddim_set(d->st_ops, "reads", reads);
+ last_writes = rrddim_set(d->st_ops, "writes", writes);
+ rrdset_done(d->st_ops);
}
// --------------------------------------------------------------------
- if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
- d->do_qops = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_qops", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ if(d->do_qops == CONFIG_BOOLEAN_YES || (d->do_qops == CONFIG_BOOLEAN_AUTO && queued_ios)) {
+ d->do_qops = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_qops)) {
+ d->st_qops = rrdset_create_localhost(
+ "disk_qops"
+ , disk
+ , NULL
+ , family
+ , "disk.qops"
+ , "Disk Current I/O Operations"
+ , "operations"
+ , 2002
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_qops, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_qops);
- rrddim_set(st, "operations", queued_ios);
- rrdset_done(st);
+ rrddim_set(d->st_qops, "operations", queued_ios);
+ rrdset_done(d->st_qops);
}
// --------------------------------------------------------------------
- if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
- d->do_backlog = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_backlog", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
+ if(d->do_backlog == CONFIG_BOOLEAN_YES || (d->do_backlog == CONFIG_BOOLEAN_AUTO && backlog_ms)) {
+ d->do_backlog = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_backlog)) {
+ d->st_backlog = rrdset_create_localhost(
+ "disk_backlog"
+ , disk
+ , NULL
+ , family
+ , "disk.backlog"
+ , "Disk Backlog"
+ , "backlog (ms)"
+ , 2003
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(d->st_backlog, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_backlog, "backlog", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_backlog);
- rrddim_set(st, "backlog", backlog_ms);
- rrdset_done(st);
+ rrddim_set(d->st_backlog, "backlog", backlog_ms);
+ rrdset_done(d->st_backlog);
}
// --------------------------------------------------------------------
- if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
- d->do_util = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_util", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
+ if(d->do_util == CONFIG_BOOLEAN_YES || (d->do_util == CONFIG_BOOLEAN_AUTO && busy_ms)) {
+ d->do_util = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_util)) {
+ d->st_util = rrdset_create_localhost(
+ "disk_util"
+ , disk
+ , NULL
+ , family
+ , "disk.util"
+ , "Disk Utilization Time"
+ , "% of time working"
+ , 2004
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(d->st_util, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_util, "utilization", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_util);
- last_busy_ms = rrddim_set(st, "utilization", busy_ms);
- rrdset_done(st);
+ last_busy_ms = rrddim_set(d->st_util, "utilization", busy_ms);
+ rrdset_done(d->st_util);
}
// --------------------------------------------------------------------
- if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
- d->do_mops = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_mops", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if(d->do_mops == CONFIG_BOOLEAN_YES || (d->do_mops == CONFIG_BOOLEAN_AUTO && (mreads || mwrites))) {
+ d->do_mops = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_mops)) {
+ d->st_mops = rrdset_create_localhost(
+ "disk_mops"
+ , disk
+ , NULL
+ , family
+ , "disk.mops"
+ , "Disk Merged Operations"
+ , "merged operations/s"
+ , 2021
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_mops, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_mops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_mops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_mops);
- rrddim_set(st, "reads", mreads);
- rrddim_set(st, "writes", mwrites);
- rrdset_done(st);
+ rrddim_set(d->st_mops, "reads", mreads);
+ rrddim_set(d->st_mops, "writes", mwrites);
+ rrdset_done(d->st_mops);
}
// --------------------------------------------------------------------
- if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
- d->do_iotime = CONFIG_ONDEMAND_YES;
-
- st = rrdset_find_bytype("disk_iotime", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ if(d->do_iotime == CONFIG_BOOLEAN_YES || (d->do_iotime == CONFIG_BOOLEAN_AUTO && (readms || writems))) {
+ d->do_iotime = CONFIG_BOOLEAN_YES;
+
+ if(unlikely(!d->st_iotime)) {
+ d->st_iotime = rrdset_create_localhost(
+ "disk_iotime"
+ , disk
+ , NULL
+ , family
+ , "disk.iotime"
+ , "Disk Total I/O Time"
+ , "milliseconds/s"
+ , 2022
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_iotime, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_iotime);
- last_readms = rrddim_set(st, "reads", readms);
- last_writems = rrddim_set(st, "writes", writems);
- rrdset_done(st);
+ last_readms = rrddim_set(d->st_iotime, "reads", readms);
+ last_writems = rrddim_set(d->st_iotime, "writes", writems);
+ rrdset_done(d->st_iotime);
}
// --------------------------------------------------------------------
@@ -552,54 +655,127 @@ int do_proc_diskstats(int update_every, usec_t dt) {
// only if this is not the first time we run
if(likely(dt)) {
- if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
- (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
- st = rrdset_find_bytype("disk_await", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ if( (d->do_iotime == CONFIG_BOOLEAN_YES || (d->do_iotime == CONFIG_BOOLEAN_AUTO && (readms || writems))) &&
+ (d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes)))) {
+
+ if(unlikely(!d->st_await)) {
+ d->st_await = rrdset_create_localhost(
+ "disk_await"
+ , disk
+ , NULL
+ , family
+ , "disk.await"
+ , "Average Completed I/O Operation Time"
+ , "ms per operation"
+ , 2005
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_await, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_await, "reads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(d->st_await, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_await);
- rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
- rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
- rrdset_done(st);
+ rrddim_set(d->st_await, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
+ rrddim_set(d->st_await, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
+ rrdset_done(d->st_await);
}
- if( (d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
- (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
- st = rrdset_find_bytype("disk_avgsz", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
-
- rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
+ if( (d->do_io == CONFIG_BOOLEAN_YES || (d->do_io == CONFIG_BOOLEAN_AUTO && (readsectors || writesectors))) &&
+ (d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes)))) {
+
+ if(unlikely(!d->st_avgsz)) {
+ d->st_avgsz = rrdset_create_localhost(
+ "disk_avgsz"
+ , disk
+ , NULL
+ , family
+ , "disk.avgsz"
+ , "Average Completed I/O Operation Bandwidth"
+ , "kilobytes per operation"
+ , 2006
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrdset_flag_set(d->st_avgsz, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_avgsz, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(d->st_avgsz, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_avgsz);
- rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
- rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
- rrdset_done(st);
+ rrddim_set(d->st_avgsz, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
+ rrddim_set(d->st_avgsz, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
+ rrdset_done(d->st_avgsz);
}
- if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
- (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
- st = rrdset_find_bytype("disk_svctm", disk);
- if(unlikely(!st)) {
- st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ if( (d->do_util == CONFIG_BOOLEAN_YES || (d->do_util == CONFIG_BOOLEAN_AUTO && busy_ms)) &&
+ (d->do_ops == CONFIG_BOOLEAN_YES || (d->do_ops == CONFIG_BOOLEAN_AUTO && (reads || writes)))) {
+
+ if(unlikely(!d->st_svctm)) {
+ d->st_svctm = rrdset_create_localhost(
+ "disk_svctm"
+ , disk
+ , NULL
+ , family
+ , "disk.svctm"
+ , "Average Service Time"
+ , "ms per operation"
+ , 2007
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_svctm, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(d->st_svctm, "svctm", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
- else rrdset_next(st);
+ else rrdset_next(d->st_svctm);
+
+ rrddim_set(d->st_svctm, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
+ rrdset_done(d->st_svctm);
+ }
+ }
+ }
- rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
- rrdset_done(st);
+ // cleanup removed disks
+
+ struct disk *d = disk_root, *last = NULL;
+ while(d) {
+ if(unlikely(!d->updated)) {
+ struct disk *t = d;
+
+ rrdset_obsolete_and_pointer_null(d->st_avgsz);
+ rrdset_obsolete_and_pointer_null(d->st_await);
+ rrdset_obsolete_and_pointer_null(d->st_backlog);
+ rrdset_obsolete_and_pointer_null(d->st_io);
+ rrdset_obsolete_and_pointer_null(d->st_iotime);
+ rrdset_obsolete_and_pointer_null(d->st_mops);
+ rrdset_obsolete_and_pointer_null(d->st_ops);
+ rrdset_obsolete_and_pointer_null(d->st_qops);
+ rrdset_obsolete_and_pointer_null(d->st_svctm);
+ rrdset_obsolete_and_pointer_null(d->st_util);
+
+ if(d == disk_root) {
+ disk_root = d = d->next;
+ last = NULL;
+ }
+ else if(last) {
+ last->next = d = d->next;
}
+
+ freez(t->disk);
+ freez(t->mount_point);
+ freez(t);
+ }
+ else {
+ d->updated = 0;
+ last = d;
+ d = d->next;
}
}
diff --git a/src/proc_interrupts.c b/src/proc_interrupts.c
index f663c0fdd..082e1f57b 100644
--- a/src/proc_interrupts.c
+++ b/src/proc_interrupts.c
@@ -59,7 +59,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/interrupts");
ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(unlikely(!ff))
@@ -146,8 +146,9 @@ int do_proc_interrupts(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("system", "interrupts");
- if(unlikely(!st)) st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_find_bytype_localhost("system", "interrupts");
+ if(unlikely(!st)) st = rrdset_create_localhost("system", "interrupts", NULL, "interrupts", NULL, "System interrupts"
+ , "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
else rrdset_next(st);
for(l = 0; l < lines ;l++) {
@@ -159,7 +160,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
irr->rd = rrddim_find(st, irr->id);
if(unlikely(!irr->rd))
- irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->rd, irr->name);
@@ -181,11 +182,12 @@ int do_proc_interrupts(int update_every, usec_t dt) {
char id[50+1];
snprintfz(id, 50, "cpu%d_interrupts", c);
- st = rrdset_find_bytype("cpu", id);
+ st = rrdset_find_bytype_localhost("cpu", id);
if(unlikely(!st)) {
char title[100+1];
snprintfz(title, 100, "CPU%d Interrupts", c);
- st = rrdset_create("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s", 1100 + c, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s",
+ 1100 + c, update_every, RRDSET_TYPE_STACKED);
}
else rrdset_next(st);
@@ -195,7 +197,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
if(unlikely(!irr->cpu[c].rd)) {
irr->cpu[c].rd = rrddim_find(st, irr->id);
if(unlikely(!irr->cpu[c].rd))
- irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->cpu[c].rd, irr->name);
}
diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c
index 4326ffb7d..e7863f114 100644
--- a/src/proc_loadavg.c
+++ b/src/proc_loadavg.c
@@ -6,12 +6,12 @@
int do_proc_loadavg(int update_every, usec_t dt) {
static procfile *ff = NULL;
static int do_loadavg = -1, do_all_processes = -1;
- static usec_t last_loadavg_usec = 0;
+ static usec_t next_loadavg_dt = 0;
static RRDSET *load_chart = NULL, *processes_chart = NULL;
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/loadavg");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/loadavg");
ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
@@ -47,15 +47,18 @@ int do_proc_loadavg(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(last_loadavg_usec <= dt) {
+ if(next_loadavg_dt <= dt) {
if(likely(do_loadavg)) {
if(unlikely(!load_chart)) {
- load_chart = rrdset_find_byname("system.load");
+ load_chart = rrdset_find_byname_localhost("system.load");
if(unlikely(!load_chart)) {
- load_chart = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
- rrddim_add(load_chart, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(load_chart, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(load_chart, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ load_chart = rrdset_create_localhost("system", "load", NULL, "load", NULL, "System Load Average"
+ , "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)
+ ? MIN_LOADAVG_UPDATE_EVERY : update_every
+ , RRDSET_TYPE_LINE);
+ rrddim_add(load_chart, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(load_chart, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(load_chart, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
}
else
@@ -67,18 +70,20 @@ int do_proc_loadavg(int update_every, usec_t dt) {
rrdset_done(load_chart);
}
- last_loadavg_usec = load_chart->update_every * USEC_PER_SEC;
+ next_loadavg_dt = load_chart->update_every * USEC_PER_SEC;
}
- else last_loadavg_usec -= dt;
+ else next_loadavg_dt -= dt;
// --------------------------------------------------------------------
if(likely(do_all_processes)) {
if(unlikely(!processes_chart)) {
- processes_chart = rrdset_find_byname("system.active_processes");
+ processes_chart = rrdset_find_byname_localhost("system.active_processes");
if(unlikely(!processes_chart)) {
- processes_chart = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
- rrddim_add(processes_chart, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ processes_chart = rrdset_create_localhost("system", "active_processes", NULL, "processes", NULL
+ , "System Active Processes", "processes", 750, update_every
+ , RRDSET_TYPE_LINE);
+ rrddim_add(processes_chart, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
}
else rrdset_next(processes_chart);
diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c
index 19ba8da3c..6b0219cc9 100644
--- a/src/proc_meminfo.c
+++ b/src/proc_meminfo.c
@@ -55,8 +55,8 @@ int do_proc_meminfo(int update_every, usec_t dt) {
if(unlikely(!arl_base)) {
do_ram = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
- do_swap = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "system swap", CONFIG_ONDEMAND_ONDEMAND);
- do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_ONDEMAND_ONDEMAND);
+ do_swap = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "system swap", CONFIG_BOOLEAN_AUTO);
+ do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_BOOLEAN_AUTO);
do_committed = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
do_writeback = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
do_kernel = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
@@ -109,7 +109,7 @@ int do_proc_meminfo(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/meminfo");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/meminfo");
ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
@@ -140,14 +140,15 @@ int do_proc_meminfo(int update_every, usec_t dt) {
unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
if(do_ram) {
- st = rrdset_find("system.ram");
+ st = rrdset_find_localhost("system.ram");
if(!st) {
- st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every
+ , RRDSET_TYPE_STACKED);
- rrddim_add(st, "free", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "cached", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "buffers", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "buffers", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -162,16 +163,17 @@ int do_proc_meminfo(int update_every, usec_t dt) {
unsigned long long SwapUsed = SwapTotal - SwapFree;
- if(SwapTotal || SwapUsed || SwapFree || do_swap == CONFIG_ONDEMAND_YES) {
- do_swap = CONFIG_ONDEMAND_YES;
+ if(SwapTotal || SwapUsed || SwapFree || do_swap == CONFIG_BOOLEAN_YES) {
+ do_swap = CONFIG_BOOLEAN_YES;
- st = rrdset_find("system.swap");
+ st = rrdset_find_localhost("system.swap");
if(!st) {
- st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every
+ , RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "free", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -182,15 +184,16 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(arl_hwcorrupted->flags & ARL_ENTRY_FLAG_FOUND && (do_hwcorrupt == CONFIG_ONDEMAND_YES || (do_hwcorrupt == CONFIG_ONDEMAND_ONDEMAND && HardwareCorrupted > 0))) {
- do_hwcorrupt = CONFIG_ONDEMAND_YES;
+ if(arl_hwcorrupted->flags & ARL_ENTRY_FLAG_FOUND && (do_hwcorrupt == CONFIG_BOOLEAN_YES || (do_hwcorrupt == CONFIG_BOOLEAN_AUTO && HardwareCorrupted > 0))) {
+ do_hwcorrupt = CONFIG_BOOLEAN_YES;
- st = rrdset_find("mem.hwcorrupt");
+ st = rrdset_find_localhost("mem.hwcorrupt");
if(!st) {
- st = rrdset_create("mem", "hwcorrupt", NULL, "ecc", NULL, "Hardware Corrupted ECC", "MB", 9000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("mem", "hwcorrupt", NULL, "ecc", NULL, "Hardware Corrupted ECC", "MB", 9000
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -201,12 +204,13 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_committed) {
- st = rrdset_find("mem.committed");
+ st = rrdset_find_localhost("mem.committed");
if(!st) {
- st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB"
+ , 5000, update_every, RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -217,16 +221,17 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_writeback) {
- st = rrdset_find("mem.writeback");
+ st = rrdset_find_localhost("mem.writeback");
if(!st) {
- st = rrdset_create("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "Dirty", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "Writeback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "Bounce", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "Dirty", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "Writeback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "Bounce", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -241,15 +246,16 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_kernel) {
- st = rrdset_find("mem.kernel");
+ st = rrdset_find_localhost("mem.kernel");
if(!st) {
- st = rrdset_create("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
-
- rrddim_add(st, "Slab", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "KernelStack", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "PageTables", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000
+ , update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "Slab", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "KernelStack", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "PageTables", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -263,13 +269,14 @@ int do_proc_meminfo(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_slab) {
- st = rrdset_find("mem.slab");
+ st = rrdset_find_localhost("mem.slab");
if(!st) {
- st = rrdset_create("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500
+ , update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "reclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "reclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c
index 82661abd4..1b00758d5 100644
--- a/src/proc_net_dev.c
+++ b/src/proc_net_dev.c
@@ -8,6 +8,7 @@ struct netdev {
// flags
int configured;
int enabled;
+ int updated;
int do_bandwidth;
int do_packets;
@@ -18,23 +19,23 @@ struct netdev {
int do_events;
// data collected
- unsigned long long rbytes;
- unsigned long long rpackets;
- unsigned long long rerrors;
- unsigned long long rdrops;
- unsigned long long rfifo;
- unsigned long long rframe;
- unsigned long long rcompressed;
- unsigned long long rmulticast;
-
- unsigned long long tbytes;
- unsigned long long tpackets;
- unsigned long long terrors;
- unsigned long long tdrops;
- unsigned long long tfifo;
- unsigned long long tcollisions;
- unsigned long long tcarrier;
- unsigned long long tcompressed;
+ kernel_uint_t rbytes;
+ kernel_uint_t rpackets;
+ kernel_uint_t rerrors;
+ kernel_uint_t rdrops;
+ kernel_uint_t rfifo;
+ kernel_uint_t rframe;
+ kernel_uint_t rcompressed;
+ kernel_uint_t rmulticast;
+
+ kernel_uint_t tbytes;
+ kernel_uint_t tpackets;
+ kernel_uint_t terrors;
+ kernel_uint_t tdrops;
+ kernel_uint_t tfifo;
+ kernel_uint_t tcollisions;
+ kernel_uint_t tcarrier;
+ kernel_uint_t tcompressed;
// charts
RRDSET *st_bandwidth;
@@ -67,26 +68,73 @@ struct netdev {
struct netdev *next;
};
-static struct netdev *netdev_root = NULL;
+static struct netdev *netdev_root = NULL, *netdev_last_used = NULL;
+
+static size_t netdev_added = 0, netdev_found = 0;
+
+static void netdev_free(struct netdev *d) {
+ if(d->st_bandwidth) rrdset_flag_set(d->st_bandwidth, RRDSET_FLAG_OBSOLETE);
+ if(d->st_packets) rrdset_flag_set(d->st_packets, RRDSET_FLAG_OBSOLETE);
+ if(d->st_errors) rrdset_flag_set(d->st_errors, RRDSET_FLAG_OBSOLETE);
+ if(d->st_drops) rrdset_flag_set(d->st_drops, RRDSET_FLAG_OBSOLETE);
+ if(d->st_fifo) rrdset_flag_set(d->st_fifo, RRDSET_FLAG_OBSOLETE);
+ if(d->st_compressed) rrdset_flag_set(d->st_compressed, RRDSET_FLAG_OBSOLETE);
+ if(d->st_events) rrdset_flag_set(d->st_events, RRDSET_FLAG_OBSOLETE);
+
+ netdev_added--;
+ freez(d->name);
+ freez(d);
+}
+
+static void netdev_cleanup() {
+ if(likely(netdev_found == netdev_added)) return;
+
+ netdev_added = 0;
+ struct netdev *d = netdev_root, *last = NULL;
+ while(d) {
+ if(unlikely(!d->updated)) {
+ // info("Removing network device '%s', linked after '%s'", d->name, last?last->name:"ROOT");
+
+ if(netdev_last_used == d)
+ netdev_last_used = last;
+
+ struct netdev *t = d;
+
+ if(d == netdev_root || !last)
+ netdev_root = d = d->next;
+
+ else
+ last->next = d = d->next;
+
+ t->next = NULL;
+ netdev_free(t);
+ }
+ else {
+ netdev_added++;
+ last = d;
+ d->updated = 0;
+ d = d->next;
+ }
+ }
+}
static struct netdev *get_netdev(const char *name) {
- static struct netdev *last = NULL;
struct netdev *d;
uint32_t hash = simple_hash(name);
// search it, from the last position to the end
- for(d = last ; d ; d = d->next) {
+ for(d = netdev_last_used ; d ; d = d->next) {
if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
- last = d->next;
+ netdev_last_used = d->next;
return d;
}
}
// search it from the beginning to the last position we used
- for(d = netdev_root ; d != last ; d = d->next) {
+ for(d = netdev_root ; d != netdev_last_used ; d = d->next) {
if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
- last = d->next;
+ netdev_last_used = d->next;
return d;
}
}
@@ -96,6 +144,7 @@ static struct netdev *get_netdev(const char *name) {
d->name = strdupz(name);
d->hash = simple_hash(d->name);
d->len = strlen(d->name);
+ netdev_added++;
// link it to the end
if(netdev_root) {
@@ -111,22 +160,21 @@ static struct netdev *get_netdev(const char *name) {
int do_proc_net_dev(int update_every, usec_t dt) {
(void)dt;
-
static SIMPLE_PATTERN *disabled_list = NULL;
static procfile *ff = NULL;
static int enable_new_interfaces = -1;
static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
if(unlikely(enable_new_interfaces == -1)) {
- enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
+ enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
- do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+ do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_BOOLEAN_AUTO);
+ do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_BOOLEAN_AUTO);
disabled_list = simple_pattern_create(
config_get("plugin:proc:/proc/net/dev", "disable by default interfaces matching", "lo fireqos* *-ifb")
@@ -135,7 +183,7 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/dev");
ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -143,12 +191,16 @@ int do_proc_net_dev(int update_every, usec_t dt) {
ff = procfile_readall(ff);
if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
+ netdev_found = 0;
+
size_t lines = procfile_lines(ff), l;
for(l = 2; l < lines ;l++) {
// require 17 words on each line
if(unlikely(procfile_linewords(ff, l) < 17)) continue;
struct netdev *d = get_netdev(procfile_lineword(ff, l, 0));
+ d->updated = 1;
+ netdev_found++;
if(unlikely(!d->configured)) {
// this is the first time we see this interface
@@ -165,207 +217,293 @@ int do_proc_net_dev(int update_every, usec_t dt) {
snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", d->name);
d->enabled = config_get_boolean_ondemand(var_name, "enabled", d->enabled);
- if(d->enabled == CONFIG_ONDEMAND_NO)
+ if(d->enabled == CONFIG_BOOLEAN_NO)
continue;
- d->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth);
- d->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets);
- d->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors);
- d->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops);
- d->do_fifo = config_get_boolean_ondemand(var_name, "fifo", do_fifo);
+ d->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth);
+ d->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets);
+ d->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors);
+ d->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops);
+ d->do_fifo = config_get_boolean_ondemand(var_name, "fifo", do_fifo);
d->do_compressed = config_get_boolean_ondemand(var_name, "compressed", do_compressed);
- d->do_events = config_get_boolean_ondemand(var_name, "events", do_events);
+ d->do_events = config_get_boolean_ondemand(var_name, "events", do_events);
}
if(unlikely(!d->enabled))
continue;
- d->rbytes = str2ull(procfile_lineword(ff, l, 1));
- d->rpackets = str2ull(procfile_lineword(ff, l, 2));
- d->rerrors = str2ull(procfile_lineword(ff, l, 3));
- d->rdrops = str2ull(procfile_lineword(ff, l, 4));
- d->rfifo = str2ull(procfile_lineword(ff, l, 5));
- d->rframe = str2ull(procfile_lineword(ff, l, 6));
- d->rcompressed = str2ull(procfile_lineword(ff, l, 7));
- d->rmulticast = str2ull(procfile_lineword(ff, l, 8));
-
- d->tbytes = str2ull(procfile_lineword(ff, l, 9));
- d->tpackets = str2ull(procfile_lineword(ff, l, 10));
- d->terrors = str2ull(procfile_lineword(ff, l, 11));
- d->tdrops = str2ull(procfile_lineword(ff, l, 12));
- d->tfifo = str2ull(procfile_lineword(ff, l, 13));
- d->tcollisions = str2ull(procfile_lineword(ff, l, 14));
- d->tcarrier = str2ull(procfile_lineword(ff, l, 15));
- d->tcompressed = str2ull(procfile_lineword(ff, l, 16));
+ if(likely(d->do_bandwidth != CONFIG_BOOLEAN_NO)) {
+ d->rbytes = str2kernel_uint_t(procfile_lineword(ff, l, 1));
+ d->tbytes = str2kernel_uint_t(procfile_lineword(ff, l, 9));
+ }
+
+ if(likely(d->do_packets != CONFIG_BOOLEAN_NO)) {
+ d->rpackets = str2kernel_uint_t(procfile_lineword(ff, l, 2));
+ d->rmulticast = str2kernel_uint_t(procfile_lineword(ff, l, 8));
+ d->tpackets = str2kernel_uint_t(procfile_lineword(ff, l, 10));
+ }
+
+ if(likely(d->do_errors != CONFIG_BOOLEAN_NO)) {
+ d->rerrors = str2kernel_uint_t(procfile_lineword(ff, l, 3));
+ d->terrors = str2kernel_uint_t(procfile_lineword(ff, l, 11));
+ }
+
+ if(likely(d->do_drops != CONFIG_BOOLEAN_NO)) {
+ d->rdrops = str2kernel_uint_t(procfile_lineword(ff, l, 4));
+ d->tdrops = str2kernel_uint_t(procfile_lineword(ff, l, 12));
+ }
+
+ if(likely(d->do_fifo != CONFIG_BOOLEAN_NO)) {
+ d->rfifo = str2kernel_uint_t(procfile_lineword(ff, l, 5));
+ d->tfifo = str2kernel_uint_t(procfile_lineword(ff, l, 13));
+ }
+
+ if(likely(d->do_compressed != CONFIG_BOOLEAN_NO)) {
+ d->rcompressed = str2kernel_uint_t(procfile_lineword(ff, l, 7));
+ d->tcompressed = str2kernel_uint_t(procfile_lineword(ff, l, 16));
+ }
+
+ if(likely(d->do_events != CONFIG_BOOLEAN_NO)) {
+ d->rframe = str2kernel_uint_t(procfile_lineword(ff, l, 6));
+ d->tcollisions = str2kernel_uint_t(procfile_lineword(ff, l, 14));
+ d->tcarrier = str2kernel_uint_t(procfile_lineword(ff, l, 15));
+ }
// --------------------------------------------------------------------
- if(unlikely((d->do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (d->rbytes || d->tbytes))))
- d->do_bandwidth = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_bandwidth == CONFIG_BOOLEAN_AUTO && (d->rbytes || d->tbytes))))
+ d->do_bandwidth = CONFIG_BOOLEAN_YES;
- if(d->do_bandwidth == CONFIG_ONDEMAND_YES) {
+ if(d->do_bandwidth == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_bandwidth)) {
- d->st_bandwidth = rrdset_find_bytype("net", d->name);
- if(!d->st_bandwidth)
- d->st_bandwidth = rrdset_create("net", d->name, NULL, d->name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
-
- d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ d->st_bandwidth = rrdset_create_localhost(
+ "net"
+ , d->name
+ , NULL
+ , d->name
+ , "net.net"
+ , "Bandwidth"
+ , "kilobits/s"
+ , 7000
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_bandwidth);
- rrddim_set_by_pointer(d->st_bandwidth, d->rd_rbytes, d->rbytes);
- rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, d->tbytes);
+ rrddim_set_by_pointer(d->st_bandwidth, d->rd_rbytes, (collected_number)d->rbytes);
+ rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, (collected_number)d->tbytes);
rrdset_done(d->st_bandwidth);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_packets == CONFIG_ONDEMAND_ONDEMAND && (d->rpackets || d->tpackets || d->rmulticast))))
- d->do_packets = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_packets == CONFIG_BOOLEAN_AUTO && (d->rpackets || d->tpackets || d->rmulticast))))
+ d->do_packets = CONFIG_BOOLEAN_YES;
- if(d->do_packets == CONFIG_ONDEMAND_YES) {
+ if(d->do_packets == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_packets)) {
- d->st_packets = rrdset_find_bytype("net_packets", d->name);
-
- if(!d->st_packets)
- d->st_packets = rrdset_create("net_packets", d->name, NULL, d->name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
- d->st_packets->isdetail = 1;
-
- d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ d->st_packets = rrdset_create_localhost(
+ "net_packets"
+ , d->name
+ , NULL
+ , d->name
+ , "net.packets"
+ , "Packets"
+ , "packets/s"
+ , 7001
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_packets, RRDSET_FLAG_DETAIL);
+
+ d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_packets);
- rrddim_set_by_pointer(d->st_packets, d->rd_rpackets, d->rpackets);
- rrddim_set_by_pointer(d->st_packets, d->rd_tpackets, d->tpackets);
- rrddim_set_by_pointer(d->st_packets, d->rd_rmulticast, d->rmulticast);
+ rrddim_set_by_pointer(d->st_packets, d->rd_rpackets, (collected_number)d->rpackets);
+ rrddim_set_by_pointer(d->st_packets, d->rd_tpackets, (collected_number)d->tpackets);
+ rrddim_set_by_pointer(d->st_packets, d->rd_rmulticast, (collected_number)d->rmulticast);
rrdset_done(d->st_packets);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_errors == CONFIG_ONDEMAND_ONDEMAND && (d->rerrors || d->terrors))))
- d->do_errors = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_errors == CONFIG_BOOLEAN_AUTO && (d->rerrors || d->terrors))))
+ d->do_errors = CONFIG_BOOLEAN_YES;
- if(d->do_errors == CONFIG_ONDEMAND_YES) {
+ if(d->do_errors == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_errors)) {
- d->st_errors = rrdset_find_bytype("net_errors", d->name);
-
- if(!d->st_errors)
- d->st_errors = rrdset_create("net_errors", d->name, NULL, d->name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
-
- d->st_errors->isdetail = 1;
- d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_errors = rrdset_create_localhost(
+ "net_errors"
+ , d->name
+ , NULL
+ , d->name
+ , "net.errors"
+ , "Interface Errors"
+ , "errors/s"
+ , 7002
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_errors, RRDSET_FLAG_DETAIL);
+
+ d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_errors);
- rrddim_set_by_pointer(d->st_errors, d->rd_rerrors, d->rerrors);
- rrddim_set_by_pointer(d->st_errors, d->rd_terrors, d->terrors);
+ rrddim_set_by_pointer(d->st_errors, d->rd_rerrors, (collected_number)d->rerrors);
+ rrddim_set_by_pointer(d->st_errors, d->rd_terrors, (collected_number)d->terrors);
rrdset_done(d->st_errors);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_drops == CONFIG_ONDEMAND_ONDEMAND && (d->rdrops || d->tdrops))))
- d->do_drops = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_drops == CONFIG_BOOLEAN_AUTO && (d->rdrops || d->tdrops))))
+ d->do_drops = CONFIG_BOOLEAN_YES;
- if(d->do_drops == CONFIG_ONDEMAND_YES) {
+ if(d->do_drops == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_drops)) {
- d->st_drops = rrdset_find_bytype("net_drops", d->name);
-
- if(!d->st_drops)
- d->st_drops = rrdset_create("net_drops", d->name, NULL, d->name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
-
- d->st_drops->isdetail = 1;
- d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_drops = rrdset_create_localhost(
+ "net_drops"
+ , d->name
+ , NULL
+ , d->name
+ , "net.drops"
+ , "Interface Drops"
+ , "drops/s"
+ , 7003
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_drops, RRDSET_FLAG_DETAIL);
+
+ d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_drops);
- rrddim_set_by_pointer(d->st_drops, d->rd_rdrops, d->rdrops);
- rrddim_set_by_pointer(d->st_drops, d->rd_tdrops, d->tdrops);
+ rrddim_set_by_pointer(d->st_drops, d->rd_rdrops, (collected_number)d->rdrops);
+ rrddim_set_by_pointer(d->st_drops, d->rd_tdrops, (collected_number)d->tdrops);
rrdset_done(d->st_drops);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_fifo == CONFIG_ONDEMAND_ONDEMAND && (d->rfifo || d->tfifo))))
- d->do_fifo = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_fifo == CONFIG_BOOLEAN_AUTO && (d->rfifo || d->tfifo))))
+ d->do_fifo = CONFIG_BOOLEAN_YES;
- if(d->do_fifo == CONFIG_ONDEMAND_YES) {
+ if(d->do_fifo == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_fifo)) {
- d->st_fifo = rrdset_find_bytype("net_fifo", d->name);
- if(!d->st_fifo)
- d->st_fifo = rrdset_create("net_fifo", d->name, NULL, d->name, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
-
- d->st_fifo->isdetail = 1;
-
- d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_fifo = rrdset_create_localhost(
+ "net_fifo"
+ , d->name
+ , NULL
+ , d->name
+ , "net.fifo"
+ , "Interface FIFO Buffer Errors"
+ , "errors"
+ , 7004
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_fifo, RRDSET_FLAG_DETAIL);
+
+ d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_fifo);
- rrddim_set_by_pointer(d->st_fifo, d->rd_rfifo, d->rfifo);
- rrddim_set_by_pointer(d->st_fifo, d->rd_tfifo, d->tfifo);
+ rrddim_set_by_pointer(d->st_fifo, d->rd_rfifo, (collected_number)d->rfifo);
+ rrddim_set_by_pointer(d->st_fifo, d->rd_tfifo, (collected_number)d->tfifo);
rrdset_done(d->st_fifo);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_compressed == CONFIG_ONDEMAND_ONDEMAND && (d->rcompressed || d->tcompressed))))
- d->do_compressed = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_compressed == CONFIG_BOOLEAN_AUTO && (d->rcompressed || d->tcompressed))))
+ d->do_compressed = CONFIG_BOOLEAN_YES;
- if(d->do_compressed == CONFIG_ONDEMAND_YES) {
+ if(d->do_compressed == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_compressed)) {
- d->st_compressed = rrdset_find_bytype("net_compressed", d->name);
- if(!d->st_compressed)
- d->st_compressed = rrdset_create("net_compressed", d->name, NULL, d->name, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
-
- d->st_compressed->isdetail = 1;
- d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_compressed = rrdset_create_localhost(
+ "net_compressed"
+ , d->name
+ , NULL
+ , d->name
+ , "net.compressed"
+ , "Compressed Packets"
+ , "packets/s"
+ , 7005
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_compressed, RRDSET_FLAG_DETAIL);
+
+ d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_compressed);
- rrddim_set_by_pointer(d->st_compressed, d->rd_rcompressed, d->rcompressed);
- rrddim_set_by_pointer(d->st_compressed, d->rd_tcompressed, d->tcompressed);
+ rrddim_set_by_pointer(d->st_compressed, d->rd_rcompressed, (collected_number)d->rcompressed);
+ rrddim_set_by_pointer(d->st_compressed, d->rd_tcompressed, (collected_number)d->tcompressed);
rrdset_done(d->st_compressed);
}
// --------------------------------------------------------------------
- if(unlikely((d->do_events == CONFIG_ONDEMAND_ONDEMAND && (d->rframe || d->tcollisions || d->tcarrier))))
- d->do_events = CONFIG_ONDEMAND_YES;
+ if(unlikely((d->do_events == CONFIG_BOOLEAN_AUTO && (d->rframe || d->tcollisions || d->tcarrier))))
+ d->do_events = CONFIG_BOOLEAN_YES;
- if(d->do_events == CONFIG_ONDEMAND_YES) {
+ if(d->do_events == CONFIG_BOOLEAN_YES) {
if(unlikely(!d->st_events)) {
- d->st_events = rrdset_find_bytype("net_events", d->name);
- if(!d->st_events)
- d->st_events = rrdset_create("net_events", d->name, NULL, d->name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
- d->st_events->isdetail = 1;
-
- d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
- d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
- d->rd_tcarrier = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ d->st_events = rrdset_create_localhost(
+ "net_events"
+ , d->name
+ , NULL
+ , d->name
+ , "net.events"
+ , "Network Interface Events"
+ , "events/s"
+ , 7006
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(d->st_events, RRDSET_FLAG_DETAIL);
+
+ d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->rd_tcarrier = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(d->st_events);
- rrddim_set_by_pointer(d->st_events, d->rd_rframe, d->rframe);
- rrddim_set_by_pointer(d->st_events, d->rd_tcollisions, d->tcollisions);
- rrddim_set_by_pointer(d->st_events, d->rd_tcarrier, d->tcarrier);
+ rrddim_set_by_pointer(d->st_events, d->rd_rframe, (collected_number)d->rframe);
+ rrddim_set_by_pointer(d->st_events, d->rd_tcollisions, (collected_number)d->tcollisions);
+ rrddim_set_by_pointer(d->st_events, d->rd_tcarrier, (collected_number)d->tcarrier);
rrdset_done(d->st_events);
}
}
+ netdev_cleanup();
+
return 0;
}
diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c
index 34cadaea7..16a3234df 100644
--- a/src/proc_net_ip_vs_stats.c
+++ b/src/proc_net_ip_vs_stats.c
@@ -3,6 +3,7 @@
#define RRD_TYPE_NET_IPVS "ipvs"
int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
+ (void)dt;
static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
static procfile *ff = NULL;
@@ -10,11 +11,9 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
if(do_packets == -1) do_packets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
- if(dt) {};
-
if(!ff) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/ip_vs_stats");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/ip_vs_stats");
ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -41,11 +40,13 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_sockets) {
- st = rrdset_find(RRD_TYPE_NET_IPVS ".sockets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".sockets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS New Connections", "connections/s", 3101, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL
+ , "IPVS New Connections", "connections/s", 3101, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -56,12 +57,13 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_packets) {
- st = rrdset_find(RRD_TYPE_NET_IPVS ".packets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".packets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets", "packets/s", 3102, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets"
+ , "packets/s", 3102, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -73,12 +75,13 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_bandwidth) {
- st = rrdset_find(RRD_TYPE_NET_IPVS ".net");
+ st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".net");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth", "kilobits/s", 3100, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth"
+ , "kilobits/s", 3100, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c
index 8741a71c9..2677a6c17 100644
--- a/src/proc_net_netstat.c
+++ b/src/proc_net_netstat.c
@@ -98,19 +98,19 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
hash_ipext = simple_hash("IpExt");
hash_tcpext = simple_hash("TcpExt");
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
- do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ecn = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
-
- do_tcpext_reorder = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP reorders", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_syscookies = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_ofo = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_connaborts = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
- do_tcpext_memory = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP memory pressures", CONFIG_ONDEMAND_ONDEMAND);
+ do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_BOOLEAN_AUTO);
+ do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_BOOLEAN_AUTO);
+ do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_BOOLEAN_AUTO);
+ do_ecn = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "ECN packets", CONFIG_BOOLEAN_AUTO);
+
+ do_tcpext_reorder = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP reorders", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_syscookies = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_ofo = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_connaborts = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
+ do_tcpext_memory = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP memory pressures", CONFIG_BOOLEAN_AUTO);
arl_ipext = arl_create("netstat/ipext", NULL, 60);
arl_tcpext = arl_create("netstat/tcpext", NULL, 60);
@@ -118,38 +118,38 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
// IPv4
- if(do_bandwidth != CONFIG_ONDEMAND_NO) {
+ if(do_bandwidth != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InOctets", &ipext_InOctets);
arl_expect(arl_ipext, "OutOctets", &ipext_OutOctets);
}
- if(do_inerrors != CONFIG_ONDEMAND_NO) {
+ if(do_inerrors != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InNoRoutes", &ipext_InNoRoutes);
arl_expect(arl_ipext, "InTruncatedPkts", &ipext_InTruncatedPkts);
arl_expect(arl_ipext, "InCsumErrors", &ipext_InCsumErrors);
}
- if(do_mcast != CONFIG_ONDEMAND_NO) {
+ if(do_mcast != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InMcastOctets", &ipext_InMcastOctets);
arl_expect(arl_ipext, "OutMcastOctets", &ipext_OutMcastOctets);
}
- if(do_mcast_p != CONFIG_ONDEMAND_NO) {
+ if(do_mcast_p != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InMcastPkts", &ipext_InMcastPkts);
arl_expect(arl_ipext, "OutMcastPkts", &ipext_OutMcastPkts);
}
- if(do_bcast != CONFIG_ONDEMAND_NO) {
+ if(do_bcast != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InBcastPkts", &ipext_InBcastPkts);
arl_expect(arl_ipext, "OutBcastPkts", &ipext_OutBcastPkts);
}
- if(do_bcast_p != CONFIG_ONDEMAND_NO) {
+ if(do_bcast_p != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InBcastOctets", &ipext_InBcastOctets);
arl_expect(arl_ipext, "OutBcastOctets", &ipext_OutBcastOctets);
}
- if(do_ecn != CONFIG_ONDEMAND_NO) {
+ if(do_ecn != CONFIG_BOOLEAN_NO) {
arl_expect(arl_ipext, "InNoECTPkts", &ipext_InNoECTPkts);
arl_expect(arl_ipext, "InECT1Pkts", &ipext_InECT1Pkts);
arl_expect(arl_ipext, "InECT0Pkts", &ipext_InECT0Pkts);
@@ -159,27 +159,27 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
// IPv4 TCP
- if(do_tcpext_reorder != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_reorder != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPFACKReorder", &tcpext_TCPFACKReorder);
arl_expect(arl_tcpext, "TCPSACKReorder", &tcpext_TCPSACKReorder);
arl_expect(arl_tcpext, "TCPRenoReorder", &tcpext_TCPRenoReorder);
arl_expect(arl_tcpext, "TCPTSReorder", &tcpext_TCPTSReorder);
}
- if(do_tcpext_syscookies != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_syscookies != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "SyncookiesSent", &tcpext_SyncookiesSent);
arl_expect(arl_tcpext, "SyncookiesRecv", &tcpext_SyncookiesRecv);
arl_expect(arl_tcpext, "SyncookiesFailed", &tcpext_SyncookiesFailed);
}
- if(do_tcpext_ofo != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_ofo != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPOFOQueue", &tcpext_TCPOFOQueue);
arl_expect(arl_tcpext, "TCPOFODrop", &tcpext_TCPOFODrop);
arl_expect(arl_tcpext, "TCPOFOMerge", &tcpext_TCPOFOMerge);
arl_expect(arl_tcpext, "OfoPruned", &tcpext_OfoPruned);
}
- if(do_tcpext_connaborts != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_connaborts != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPAbortOnData", &tcpext_TCPAbortOnData);
arl_expect(arl_tcpext, "TCPAbortOnClose", &tcpext_TCPAbortOnClose);
arl_expect(arl_tcpext, "TCPAbortOnMemory", &tcpext_TCPAbortOnMemory);
@@ -188,14 +188,14 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
arl_expect(arl_tcpext, "TCPAbortFailed", &tcpext_TCPAbortFailed);
}
- if(do_tcpext_memory != CONFIG_ONDEMAND_NO) {
+ if(do_tcpext_memory != CONFIG_BOOLEAN_NO) {
arl_expect(arl_tcpext, "TCPMemoryPressures", &tcpext_TCPMemoryPressures);
}
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/netstat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/netstat");
ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -206,6 +206,9 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
size_t lines = procfile_lines(ff), l;
size_t words;
+ arl_begin(arl_ipext);
+ arl_begin(arl_tcpext);
+
for(l = 0; l < lines ;l++) {
char *key = procfile_lineword(ff, l, 0);
uint32_t hash = simple_hash(key);
@@ -219,21 +222,21 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
continue;
}
- arl_begin(arl_ipext);
parse_line_pair(ff, arl_ipext, h, l);
RRDSET *st;
// --------------------------------------------------------------------
- if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (ipext_InOctets || ipext_OutOctets))) {
- do_bandwidth = CONFIG_ONDEMAND_YES;
- st = rrdset_find("system.ipv4");
+ if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (ipext_InOctets || ipext_OutOctets))) {
+ do_bandwidth = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("system.ipv4");
if(unlikely(!st)) {
- st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s"
+ , 500, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -244,16 +247,17 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_inerrors == CONFIG_ONDEMAND_YES || (do_inerrors == CONFIG_ONDEMAND_ONDEMAND && (ipext_InNoRoutes || ipext_InTruncatedPkts))) {
- do_inerrors = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.inerrors");
+ if(do_inerrors == CONFIG_BOOLEAN_YES || (do_inerrors == CONFIG_BOOLEAN_AUTO && (ipext_InNoRoutes || ipext_InTruncatedPkts))) {
+ do_inerrors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.inerrors");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors", "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors"
+ , "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InNoRoutes", "noroutes", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", "truncated", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", "checksum", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InNoRoutes", "noroutes", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTruncatedPkts", "truncated", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", "checksum", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -265,15 +269,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (ipext_InMcastOctets || ipext_OutMcastOctets))) {
- do_mcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.mcast");
+ if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (ipext_InMcastOctets || ipext_OutMcastOctets))) {
+ do_mcast = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.mcast");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth"
+ , "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InMcastOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMcastOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMcastOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMcastOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -284,15 +289,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (ipext_InBcastOctets || ipext_OutBcastOctets))) {
- do_bcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.bcast");
+ if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (ipext_InBcastOctets || ipext_OutBcastOctets))) {
+ do_bcast = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.bcast");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth"
+ , "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InBcastOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutBcastOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InBcastOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutBcastOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -303,15 +309,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (ipext_InMcastPkts || ipext_OutMcastPkts))) {
- do_mcast_p = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.mcastpkts");
+ if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InMcastPkts || ipext_OutMcastPkts))) {
+ do_mcast_p = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.mcastpkts");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets", "packets/s", 8600, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets"
+ , "packets/s", 8600, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InMcastPkts", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -322,15 +329,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bcast_p == CONFIG_ONDEMAND_YES || (do_bcast_p == CONFIG_ONDEMAND_ONDEMAND && (ipext_InBcastPkts || ipext_OutBcastPkts))) {
- do_bcast_p = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.bcastpkts");
+ if(do_bcast_p == CONFIG_BOOLEAN_YES || (do_bcast_p == CONFIG_BOOLEAN_AUTO && (ipext_InBcastPkts || ipext_OutBcastPkts))) {
+ do_bcast_p = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.bcastpkts");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets", "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets"
+ , "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InBcastPkts", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutBcastPkts", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -341,17 +349,18 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (ipext_InCEPkts || ipext_InECT0Pkts || ipext_InECT1Pkts || ipext_InNoECTPkts))) {
- do_ecn = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.ecnpkts");
+ if(do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (ipext_InCEPkts || ipext_InECT0Pkts || ipext_InECT1Pkts || ipext_InNoECTPkts))) {
+ do_ecn = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.ecnpkts");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics"
+ , "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -371,20 +380,20 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
continue;
}
- arl_begin(arl_tcpext);
parse_line_pair(ff, arl_tcpext, h, l);
RRDSET *st;
// --------------------------------------------------------------------
- if(do_tcpext_memory == CONFIG_ONDEMAND_YES || (do_tcpext_memory == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPMemoryPressures))) {
- do_tcpext_memory = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpmemorypressures");
+ if(do_tcpext_memory == CONFIG_BOOLEAN_YES || (do_tcpext_memory == CONFIG_BOOLEAN_AUTO && (tcpext_TCPMemoryPressures))) {
+ do_tcpext_memory = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpmemorypressures");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpmemorypressures", NULL, "tcp", NULL, "TCP Memory Pressures", "events/s", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcpmemorypressures", NULL, "tcp", NULL, "TCP Memory Pressures"
+ , "events/s", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "TCPMemoryPressures", "pressures", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "TCPMemoryPressures", "pressures", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -394,18 +403,19 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPAbortOnData || tcpext_TCPAbortOnClose || tcpext_TCPAbortOnMemory || tcpext_TCPAbortOnTimeout || tcpext_TCPAbortOnLinger || tcpext_TCPAbortFailed))) {
- do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpconnaborts");
+ if(do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpext_TCPAbortOnData || tcpext_TCPAbortOnClose || tcpext_TCPAbortOnMemory || tcpext_TCPAbortOnTimeout || tcpext_TCPAbortOnLinger || tcpext_TCPAbortFailed))) {
+ do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpconnaborts");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPAbortFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts"
+ , "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortOnLinger", "linger", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPAbortFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -419,16 +429,18 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
}
// --------------------------------------------------------------------
- if(do_tcpext_reorder == CONFIG_ONDEMAND_YES || (do_tcpext_reorder == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPRenoReorder || tcpext_TCPFACKReorder || tcpext_TCPSACKReorder || tcpext_TCPTSReorder))) {
- do_tcpext_reorder = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpreorders");
+ if(do_tcpext_reorder == CONFIG_BOOLEAN_YES || (do_tcpext_reorder == CONFIG_BOOLEAN_AUTO && (tcpext_TCPRenoReorder || tcpext_TCPFACKReorder || tcpext_TCPSACKReorder || tcpext_TCPTSReorder))) {
+ do_tcpext_reorder = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpreorders");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpreorders", NULL, "tcp", NULL, "TCP Reordered Packets by Detection Method", "packets/s", 3020, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "TCPTSReorder", "timestamp", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPSACKReorder", "sack", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPFACKReorder", "fack", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPRenoReorder", "reno", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("ipv4", "tcpreorders", NULL, "tcp", NULL
+ , "TCP Reordered Packets by Detection Method", "packets/s", 3020
+ , update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "TCPTSReorder", "timestamp", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPSACKReorder", "sack", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPFACKReorder", "fack", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPRenoReorder", "reno", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -441,16 +453,17 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && (tcpext_TCPOFOQueue || tcpext_TCPOFODrop || tcpext_TCPOFOMerge))) {
- do_tcpext_ofo = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpofo");
+ if(do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && (tcpext_TCPOFOQueue || tcpext_TCPOFODrop || tcpext_TCPOFOMerge))) {
+ do_tcpext_ofo = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpofo");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue"
+ , "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPOFODrop", "dropped", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "TCPOFOMerge", "merged", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OfoPruned", "pruned", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPOFODrop", "dropped", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "TCPOFOMerge", "merged", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OfoPruned", "pruned", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -463,15 +476,16 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpext_SyncookiesSent || tcpext_SyncookiesRecv || tcpext_SyncookiesFailed))) {
- do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
- st = rrdset_find("ipv4.tcpsyncookies");
+ if(do_tcpext_syscookies == CONFIG_BOOLEAN_YES || (do_tcpext_syscookies == CONFIG_BOOLEAN_AUTO && (tcpext_SyncookiesSent || tcpext_SyncookiesRecv || tcpext_SyncookiesFailed))) {
+ do_tcpext_syscookies = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("ipv4.tcpsyncookies");
if(unlikely(!st)) {
- st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies"
+ , "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_rpc_nfs.c b/src/proc_net_rpc_nfs.c
index 9dba08d56..0df919635 100644
--- a/src/proc_net_rpc_nfs.c
+++ b/src/proc_net_rpc_nfs.c
@@ -136,7 +136,7 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(!ff) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfs");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/rpc/nfs");
ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -269,13 +269,14 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_net == 2) {
- st = rrdset_find_bytype("nfs", "net");
+ st = rrdset_find_bytype_localhost("nfs", "net");
if(!st) {
- st = rrdset_create("nfs", "net", NULL, "network", NULL, "NFS Client Network", "operations/s", 5007, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("nfs", "net", NULL, "network", NULL, "NFS Client Network", "operations/s", 5007
+ , update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -291,14 +292,15 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_rpc == 2) {
- st = rrdset_find_bytype("nfs", "rpc");
+ st = rrdset_find_bytype_localhost("nfs", "rpc");
if(!st) {
- st = rrdset_create("nfs", "rpc", NULL, "rpc", NULL, "NFS Client Remote Procedure Calls Statistics", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("nfs", "rpc", NULL, "rpc", NULL, "NFS Client Remote Procedure Calls Statistics"
+ , "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "calls", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "retransmits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "auth_refresh", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "retransmits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "auth_refresh", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -312,12 +314,13 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(do_proc2 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfs", "proc2");
+ st = rrdset_find_bytype_localhost("nfs", "proc2");
if(!st) {
- st = rrdset_create("nfs", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Client Remote Procedure Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfs", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Client Remote Procedure Calls"
+ , "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfs_proc2_values[i].present ; i++)
- rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -331,12 +334,13 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(do_proc3 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfs", "proc3");
+ st = rrdset_find_bytype_localhost("nfs", "proc3");
if(!st) {
- st = rrdset_create("nfs", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Client Remote Procedure Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfs", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Client Remote Procedure Calls"
+ , "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfs_proc3_values[i].present ; i++)
- rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -350,12 +354,13 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
if(do_proc4 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfs", "proc4");
+ st = rrdset_find_bytype_localhost("nfs", "proc4");
if(!st) {
- st = rrdset_create("nfs", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Client Remote Procedure Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfs", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Client Remote Procedure Calls"
+ , "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfs_proc4_values[i].present ; i++)
- rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_rpc_nfsd.c b/src/proc_net_rpc_nfsd.c
index 02a8c8f90..b0ed58d13 100644
--- a/src/proc_net_rpc_nfsd.c
+++ b/src/proc_net_rpc_nfsd.c
@@ -210,15 +210,14 @@ struct nfsd_procs nfsd4_ops_values[] = {
int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
+ (void)dt;
static procfile *ff = NULL;
static int do_rc = -1, do_fh = -1, do_io = -1, do_th = -1, do_ra = -1, do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1, do_proc4ops = -1;
static int ra_warning = 0, th_warning = 0, proc2_warning = 0, proc3_warning = 0, proc4_warning = 0, proc4ops_warning = 0;
- if(dt) {};
-
if(!ff) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfsd");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/rpc/nfsd");
ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfsd", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
}
if(!ff) return 1;
@@ -493,13 +492,14 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_rc == 2) {
- st = rrdset_find_bytype("nfsd", "readcache");
+ st = rrdset_find_bytype_localhost("nfsd", "readcache");
if(!st) {
- st = rrdset_create("nfsd", "readcache", NULL, "cache", NULL, "NFS Server Read Cache", "reads/s", 5000, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "readcache", NULL, "cache", NULL, "NFS Server Read Cache", "reads/s"
+ , 5000, update_every, RRDSET_TYPE_STACKED);
- rrddim_add(st, "hits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "nocache", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "nocache", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -512,16 +512,17 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_fh == 2) {
- st = rrdset_find_bytype("nfsd", "filehandles");
+ st = rrdset_find_bytype_localhost("nfsd", "filehandles");
if(!st) {
- st = rrdset_create("nfsd", "filehandles", NULL, "filehandles", NULL, "NFS Server File Handles", "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "stale", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "total_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("nfsd", "filehandles", NULL, "filehandles", NULL, "NFS Server File Handles"
+ , "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "stale", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "total_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -536,12 +537,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_io == 2) {
- st = rrdset_find_bytype("nfsd", "io");
+ st = rrdset_find_bytype_localhost("nfsd", "io");
if(!st) {
- st = rrdset_create("nfsd", "io", NULL, "io", NULL, "NFS Server I/O", "kilobytes/s", 5002, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("nfsd", "io", NULL, "io", NULL, "NFS Server I/O", "kilobytes/s", 5002
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "read", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(st, "write", NULL, -1, 1000, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "read", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "write", NULL, -1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -553,42 +555,47 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_th == 2) {
- st = rrdset_find_bytype("nfsd", "threads");
+ st = rrdset_find_bytype_localhost("nfsd", "threads");
if(!st) {
- st = rrdset_create("nfsd", "threads", NULL, "threads", NULL, "NFS Server Threads", "threads", 5003, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("nfsd", "threads", NULL, "threads", NULL, "NFS Server Threads", "threads", 5003
+ , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "threads", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "threads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
rrddim_set(st, "threads", th_threads);
rrdset_done(st);
- st = rrdset_find_bytype("nfsd", "threads_fullcnt");
+ st = rrdset_find_bytype_localhost("nfsd", "threads_fullcnt");
if(!st) {
- st = rrdset_create("nfsd", "threads_fullcnt", NULL, "threads", NULL, "NFS Server Threads Full Count", "ops/s", 5004, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("nfsd", "threads_fullcnt", NULL, "threads", NULL
+ , "NFS Server Threads Full Count", "ops/s", 5004, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "full_count", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "full_count", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
rrddim_set(st, "full_count", th_fullcnt);
rrdset_done(st);
- st = rrdset_find_bytype("nfsd", "threads_histogram");
+ st = rrdset_find_bytype_localhost("nfsd", "threads_histogram");
if(!st) {
- st = rrdset_create("nfsd", "threads_histogram", NULL, "threads", NULL, "NFS Server Threads Usage Histogram", "percentage", 5005, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "0%-10%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "10%-20%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "20%-30%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "30%-40%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "40%-50%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "50%-60%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "60%-70%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "70%-80%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "80%-90%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
- rrddim_add(st, "90%-100%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("nfsd", "threads_histogram", NULL, "threads", NULL
+ , "NFS Server Threads Usage Histogram", "percentage", 5005, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "0%-10%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "10%-20%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "20%-30%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "30%-40%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "40%-50%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "50%-60%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "60%-70%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "70%-80%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "80%-90%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "90%-100%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -608,21 +615,22 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ra == 2) {
- st = rrdset_find_bytype("nfsd", "readahead");
+ st = rrdset_find_bytype_localhost("nfsd", "readahead");
if(!st) {
- st = rrdset_create("nfsd", "readahead", NULL, "readahead", NULL, "NFS Server Read Ahead Depth", "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "10%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "20%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "30%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "40%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "50%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "60%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "70%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "80%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "90%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "100%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ st = rrdset_create_localhost("nfsd", "readahead", NULL, "readahead", NULL, "NFS Server Read Ahead Depth"
+ , "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(st, "10%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "20%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "30%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "40%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "50%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "60%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "70%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "80%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "90%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "100%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
}
else rrdset_next(st);
@@ -646,13 +654,14 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_net == 2) {
- st = rrdset_find_bytype("nfsd", "net");
+ st = rrdset_find_bytype_localhost("nfsd", "net");
if(!st) {
- st = rrdset_create("nfsd", "net", NULL, "network", NULL, "NFS Server Network Statistics", "packets/s", 5007, update_every, RRDSET_TYPE_STACKED);
- st->isdetail = 1;
+ st = rrdset_create_localhost("nfsd", "net", NULL, "network", NULL, "NFS Server Network Statistics"
+ , "packets/s", 5007, update_every, RRDSET_TYPE_STACKED);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -668,14 +677,16 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_rpc == 2) {
- st = rrdset_find_bytype("nfsd", "rpc");
+ st = rrdset_find_bytype_localhost("nfsd", "rpc");
if(!st) {
- st = rrdset_create("nfsd", "rpc", NULL, "rpc", NULL, "NFS Server Remote Procedure Calls Statistics", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "calls", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "bad_format", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "bad_auth", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost("nfsd", "rpc", NULL, "rpc", NULL
+ , "NFS Server Remote Procedure Calls Statistics", "calls/s", 5008, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "bad_format", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "bad_auth", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -692,12 +703,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc2 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc2");
+ st = rrdset_find_bytype_localhost("nfsd", "proc2");
if(!st) {
- st = rrdset_create("nfsd", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Server Remote Procedure Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Server Remote Procedure Calls"
+ , "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd_proc2_values[i].present ; i++)
- rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -711,12 +723,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc3 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc3");
+ st = rrdset_find_bytype_localhost("nfsd", "proc3");
if(!st) {
- st = rrdset_create("nfsd", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Server Remote Procedure Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Server Remote Procedure Calls"
+ , "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd_proc3_values[i].present ; i++)
- rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -730,12 +743,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc4 == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc4");
+ st = rrdset_find_bytype_localhost("nfsd", "proc4");
if(!st) {
- st = rrdset_create("nfsd", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Server Remote Procedure Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Server Remote Procedure Calls"
+ , "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd_proc4_values[i].present ; i++)
- rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -749,12 +763,13 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
if(do_proc4ops == 2) {
unsigned int i;
- st = rrdset_find_bytype("nfsd", "proc4ops");
+ st = rrdset_find_bytype_localhost("nfsd", "proc4ops");
if(!st) {
- st = rrdset_create("nfsd", "proc4ops", NULL, "nfsv2ops", NULL, "NFS v4 Server Operations", "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("nfsd", "proc4ops", NULL, "nfsv2ops", NULL, "NFS v4 Server Operations"
+ , "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
for(i = 0; nfsd4_ops_values[i].present ; i++)
- rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c
index cd5c250ae..ba7b40013 100644
--- a/src/proc_net_snmp.c
+++ b/src/proc_net_snmp.c
@@ -355,7 +355,7 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/snmp");
ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -392,14 +392,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".packets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets"
+ , "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -413,14 +414,16 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_fragsout) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".fragsout");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL
+ , "IPv4 Fragments Sent", "packets/s", 3010, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -433,14 +436,16 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_fragsin) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".fragsin");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL
+ , "IPv4 Fragments Reassembly", "packets/s", 3011, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -453,19 +458,20 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_ip_errors) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors"
+ , "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -497,12 +503,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_icmp_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".icmp");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmp");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s", 2602, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets"
+ , "packets/s", 2602, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -511,13 +518,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
rrdset_done(st);
- st = rrdset_find(RRD_TYPE_NET_SNMP ".icmp_errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmp_errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmp_errors", NULL, "icmp", NULL
+ , "IPv4 ICMP Errors", "packets/s", 2603, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -543,12 +552,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
if(do_icmpmsg) {
int i;
- st = rrdset_find(RRD_TYPE_NET_SNMP ".icmpmsg");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmpmsg");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages", "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages"
+ , "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
for(i = 0; icmpmsg_data[i].name ;i++)
- rrddim_add(st, icmpmsg_data[i].name, icmpmsg_data[i].label, icmpmsg_data[i].multiplier, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, icmpmsg_data[i].name, icmpmsg_data[i].label, icmpmsg_data[i].multiplier, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -578,11 +588,12 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
if(do_tcp_sockets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcpsock");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections"
+ , "active connections", 2500, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "CurrEstab", "connections", 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -593,12 +604,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_tcp_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcppackets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets"
+ , "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -610,14 +622,15 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_tcp_errors) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcperrors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors"
+ , "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -630,16 +643,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_tcp_handshake) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcphandshake");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL
+ , "IPv4 TCP Handshake Issues", "events/s", 2900, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutRsts", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -671,12 +686,13 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// see http://net-snmp.sourceforge.net/docs/mibs/udp.html
if(do_udp_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udppackets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets"
+ , "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -688,17 +704,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_udp_errors) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udperrors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors"
+ , "events/s", 2701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -730,12 +747,14 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_udplite_packets) {
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udplite");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udplite", NULL, "udplite", NULL, "IPv4 UDPLite Packets", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udplite", NULL, "udplite", NULL
+ , "IPv4 UDPLite Packets", "packets/s", 2603, update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -743,16 +762,18 @@ int do_proc_net_snmp(int update_every, usec_t dt) {
rrddim_set(st, "OutDatagrams", *udplite_OutDatagrams);
rrdset_done(st);
- st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite_errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udplite_errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_SNMP, "udplite_errors", NULL, "udplite", NULL, "IPv4 UDPLite Errors", "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udplite_errors", NULL, "udplite", NULL
+ , "IPv4 UDPLite Errors", "packets/s", 2604, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_snmp6.c b/src/proc_net_snmp6.c
index 51d7121a1..8c4581c1b 100644
--- a/src/proc_net_snmp6.c
+++ b/src/proc_net_snmp6.c
@@ -126,28 +126,28 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
static unsigned long long UdpLite6InCsumErrors = 0ULL;
if(unlikely(!arl_base)) {
- do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
- do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
- do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
- do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
- do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_ONDEMAND_ONDEMAND);
- do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_ONDEMAND_ONDEMAND);
- do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_ONDEMAND_ONDEMAND);
- do_udplite_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_ONDEMAND_ONDEMAND);
- do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
- do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_redir = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_echos = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_groupmemb = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_router = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_neighbor = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_mldv2 = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_ONDEMAND_ONDEMAND);
- do_icmp_types = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
- do_ect = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_ONDEMAND_ONDEMAND);
+ do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_BOOLEAN_AUTO);
+ do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_BOOLEAN_AUTO);
+ do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_BOOLEAN_AUTO);
+ do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_BOOLEAN_AUTO);
+ do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_BOOLEAN_AUTO);
+ do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_BOOLEAN_AUTO);
+ do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_BOOLEAN_AUTO);
+ do_udplite_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_BOOLEAN_AUTO);
+ do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_BOOLEAN_AUTO);
+ do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_BOOLEAN_AUTO);
+ do_icmp = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_BOOLEAN_AUTO);
+ do_icmp_redir = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_BOOLEAN_AUTO);
+ do_icmp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_BOOLEAN_AUTO);
+ do_icmp_echos = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_BOOLEAN_AUTO);
+ do_icmp_groupmemb = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_BOOLEAN_AUTO);
+ do_icmp_router = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_BOOLEAN_AUTO);
+ do_icmp_neighbor = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_BOOLEAN_AUTO);
+ do_icmp_mldv2 = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_BOOLEAN_AUTO);
+ do_icmp_types = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_BOOLEAN_AUTO);
+ do_ect = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_BOOLEAN_AUTO);
arl_base = arl_create("snmp6", NULL, 60);
arl_expect(arl_base, "Ip6InReceives", &Ip6InReceives);
@@ -246,7 +246,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp6");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/snmp6");
ff = procfile_open(config_get("plugin:proc:/proc/net/snmp6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
@@ -276,14 +276,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (Ip6InOctets || Ip6OutOctets))) {
- do_bandwidth = CONFIG_ONDEMAND_YES;
- st = rrdset_find("system.ipv6");
+ if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (Ip6InOctets || Ip6OutOctets))) {
+ do_bandwidth = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost("system.ipv6");
if(unlikely(!st)) {
- st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -294,16 +295,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_packets == CONFIG_ONDEMAND_YES || (do_ip_packets == CONFIG_ONDEMAND_ONDEMAND && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
- do_ip_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".packets");
+ if(do_ip_packets == CONFIG_BOOLEAN_YES || (do_ip_packets == CONFIG_BOOLEAN_AUTO && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
+ do_ip_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".packets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets"
+ , "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -316,16 +318,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_fragsout == CONFIG_ONDEMAND_YES || (do_ip_fragsout == CONFIG_ONDEMAND_ONDEMAND && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
- do_ip_fragsout = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsout");
+ if(do_ip_fragsout == CONFIG_BOOLEAN_YES || (do_ip_fragsout == CONFIG_BOOLEAN_AUTO && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
+ do_ip_fragsout = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".fragsout");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent"
+ , "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -337,23 +340,25 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_fragsin == CONFIG_ONDEMAND_YES || (do_ip_fragsin == CONFIG_ONDEMAND_ONDEMAND
+ if(do_ip_fragsin == CONFIG_BOOLEAN_YES || (do_ip_fragsin == CONFIG_BOOLEAN_AUTO
&& (
Ip6ReasmOKs
|| Ip6ReasmFails
|| Ip6ReasmTimeout
|| Ip6ReasmReqds
))) {
- do_ip_fragsin = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsin");
+ do_ip_fragsin = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".fragsin");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL
+ , "IPv6 Fragments Reassembly", "packets/s", 3011, update_every
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -366,7 +371,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ip_errors == CONFIG_ONDEMAND_YES || (do_ip_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_ip_errors == CONFIG_BOOLEAN_YES || (do_ip_errors == CONFIG_BOOLEAN_AUTO
&& (
Ip6InDiscards
|| Ip6OutDiscards
@@ -377,23 +382,24 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Ip6InTruncatedPkts
|| Ip6InNoRoutes
))) {
- do_ip_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".errors");
+ do_ip_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".errors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -413,14 +419,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udp_packets == CONFIG_ONDEMAND_YES || (do_udp_packets == CONFIG_ONDEMAND_ONDEMAND && (Udp6InDatagrams || Udp6OutDatagrams))) {
- do_udp_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udppackets");
+ if(do_udp_packets == CONFIG_BOOLEAN_YES || (do_udp_packets == CONFIG_BOOLEAN_AUTO && (Udp6InDatagrams || Udp6OutDatagrams))) {
+ do_udp_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udppackets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets"
+ , "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -431,7 +438,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udp_errors == CONFIG_ONDEMAND_YES || (do_udp_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_udp_errors == CONFIG_BOOLEAN_YES || (do_udp_errors == CONFIG_BOOLEAN_AUTO
&& (
Udp6InErrors
|| Udp6NoPorts
@@ -440,18 +447,19 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Udp6InCsumErrors
|| Udp6IgnoredMulti
))) {
- do_udp_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udperrors");
+ do_udp_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udperrors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors"
+ , "events/s", 3701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -466,14 +474,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udplite_packets == CONFIG_ONDEMAND_YES || (do_udplite_packets == CONFIG_ONDEMAND_ONDEMAND && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
- do_udplite_packets = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udplitepackets");
+ if(do_udplite_packets == CONFIG_BOOLEAN_YES || (do_udplite_packets == CONFIG_BOOLEAN_AUTO && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
+ do_udplite_packets = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udplitepackets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL, "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL
+ , "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -484,7 +493,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_udplite_errors == CONFIG_ONDEMAND_YES || (do_udplite_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_udplite_errors == CONFIG_BOOLEAN_YES || (do_udplite_errors == CONFIG_BOOLEAN_AUTO
&& (
UdpLite6InErrors
|| UdpLite6NoPorts
@@ -493,17 +502,18 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Udp6InCsumErrors
|| UdpLite6InCsumErrors
))) {
- do_udplite_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
+ do_udplite_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL, "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL
+ , "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -517,15 +527,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
- do_mcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcast");
+ if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
+ do_mcast = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".mcast");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL, "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL
+ , "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -536,15 +548,17 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
- do_bcast = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".bcast");
+ if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
+ do_bcast = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".bcast");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL, "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL
+ , "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every
+ , RRDSET_TYPE_AREA);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -555,15 +569,16 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
- do_mcast_p = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcastpkts");
+ if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
+ do_mcast_p = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".mcastpkts");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL, "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL
+ , "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -574,14 +589,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp == CONFIG_ONDEMAND_YES || (do_icmp == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMsgs || Icmp6OutMsgs))) {
- do_icmp = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmp");
+ if(do_icmp == CONFIG_BOOLEAN_YES || (do_icmp == CONFIG_BOOLEAN_AUTO && (Icmp6InMsgs || Icmp6OutMsgs))) {
+ do_icmp = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmp");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages"
+ , "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -592,14 +608,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_redir == CONFIG_ONDEMAND_YES || (do_icmp_redir == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InRedirects || Icmp6OutRedirects))) {
- do_icmp_redir = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpredir");
+ if(do_icmp_redir == CONFIG_BOOLEAN_YES || (do_icmp_redir == CONFIG_BOOLEAN_AUTO && (Icmp6InRedirects || Icmp6OutRedirects))) {
+ do_icmp_redir = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpredir");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects", "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects"
+ , "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -610,7 +627,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_errors == CONFIG_ONDEMAND_YES || (do_icmp_errors == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_errors == CONFIG_BOOLEAN_YES || (do_icmp_errors == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InErrors
|| Icmp6OutErrors
@@ -624,23 +641,24 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Icmp6OutTimeExcds
|| Icmp6OutParmProblems
))) {
- do_icmp_errors = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmperrors");
+ do_icmp_errors = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmperrors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
- rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors"
+ , "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -660,22 +678,23 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_echos == CONFIG_ONDEMAND_YES || (do_icmp_echos == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_echos == CONFIG_BOOLEAN_YES || (do_icmp_echos == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InEchos
|| Icmp6OutEchos
|| Icmp6InEchoReplies
|| Icmp6OutEchoReplies
))) {
- do_icmp_echos = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpechos");
+ do_icmp_echos = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpechos");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo"
+ , "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -688,7 +707,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_groupmemb == CONFIG_ONDEMAND_YES || (do_icmp_groupmemb == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_groupmemb == CONFIG_BOOLEAN_YES || (do_icmp_groupmemb == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InGroupMembQueries
|| Icmp6OutGroupMembQueries
@@ -697,17 +716,19 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Icmp6InGroupMembReductions
|| Icmp6OutGroupMembReductions
))) {
- do_icmp_groupmemb = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".groupmemb");
+ do_icmp_groupmemb = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".groupmemb");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL, "IPv6 ICMP Group Membership", "messages/s", 10300, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InQueries", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutQueries", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InResponses", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutResponses", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InReductions", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutReductions", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL
+ , "IPv6 ICMP Group Membership", "messages/s", 10300, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InQueries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutQueries", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InResponses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutResponses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InReductions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutReductions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -722,22 +743,23 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_router == CONFIG_ONDEMAND_YES || (do_icmp_router == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_router == CONFIG_BOOLEAN_YES || (do_icmp_router == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InRouterSolicits
|| Icmp6OutRouterSolicits
|| Icmp6InRouterAdvertisements
|| Icmp6OutRouterAdvertisements
))) {
- do_icmp_router = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmprouter");
+ do_icmp_router = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmprouter");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages"
+ , "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -750,22 +772,24 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_neighbor == CONFIG_ONDEMAND_YES || (do_icmp_neighbor == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_neighbor == CONFIG_BOOLEAN_YES || (do_icmp_neighbor == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InNeighborSolicits
|| Icmp6OutNeighborSolicits
|| Icmp6InNeighborAdvertisements
|| Icmp6OutNeighborAdvertisements
))) {
- do_icmp_neighbor = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
+ do_icmp_neighbor = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL
+ , "IPv6 Neighbor Messages", "messages/s", 10500, update_every
+ , RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -778,14 +802,15 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_mldv2 == CONFIG_ONDEMAND_YES || (do_icmp_mldv2 == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
- do_icmp_mldv2 = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
+ if(do_icmp_mldv2 == CONFIG_BOOLEAN_YES || (do_icmp_mldv2 == CONFIG_BOOLEAN_AUTO && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
+ do_icmp_mldv2 = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports", "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports"
+ , "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -796,7 +821,7 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_icmp_types == CONFIG_ONDEMAND_YES || (do_icmp_types == CONFIG_ONDEMAND_ONDEMAND
+ if(do_icmp_types == CONFIG_BOOLEAN_YES || (do_icmp_types == CONFIG_BOOLEAN_AUTO
&& (
Icmp6InType1
|| Icmp6InType128
@@ -809,21 +834,22 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
|| Icmp6OutType135
|| Icmp6OutType143
))) {
- do_icmp_types = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmptypes");
+ do_icmp_types = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmptypes");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types", "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types"
+ , "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -842,22 +868,23 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ect == CONFIG_ONDEMAND_YES || (do_ect == CONFIG_ONDEMAND_ONDEMAND
+ if(do_ect == CONFIG_BOOLEAN_YES || (do_ect == CONFIG_BOOLEAN_AUTO
&& (
Ip6InNoECTPkts
|| Ip6InECT1Pkts
|| Ip6InECT0Pkts
|| Ip6InCEPkts
))) {
- do_ect = CONFIG_ONDEMAND_YES;
- st = rrdset_find(RRD_TYPE_NET_SNMP6 ".ect");
+ do_ect = CONFIG_BOOLEAN_YES;
+ st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".ect");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets", "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets"
+ , "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "InCEPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "InCEPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_softnet_stat.c b/src/proc_net_softnet_stat.c
index 2f4eb3e66..40946a7a5 100644
--- a/src/proc_net_softnet_stat.c
+++ b/src/proc_net_softnet_stat.c
@@ -24,7 +24,7 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/softnet_stat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/softnet_stat");
ff = procfile_open(config_get("plugin:proc:/proc/net/softnet_stat", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -77,12 +77,13 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("system", "softnet_stat");
+ st = rrdset_find_bytype_localhost("system", "softnet_stat");
if(unlikely(!st)) {
- st = rrdset_create("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat", "events/s", 955, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat"
+ , "events/s", 955, update_every, RRDSET_TYPE_LINE);
for(w = 0; w < allocated_columns ;w++)
if(unlikely(softnet_column_name(w)))
- rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -97,15 +98,16 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) {
char id[50+1];
snprintfz(id, 50, "cpu%zu_softnet_stat", l);
- st = rrdset_find_bytype("cpu", id);
+ st = rrdset_find_bytype_localhost("cpu", id);
if(unlikely(!st)) {
char title[100+1];
snprintfz(title, 100, "CPU%zu softnet_stat", l);
- st = rrdset_create("cpu", id, NULL, "softnet_stat", NULL, title, "events/s", 4101 + l, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("cpu", id, NULL, "softnet_stat", NULL, title, "events/s", 4101 + l
+ , update_every, RRDSET_TYPE_LINE);
for(w = 0; w < allocated_columns ;w++)
if(unlikely(softnet_column_name(w)))
- rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_stat_conntrack.c b/src/proc_net_stat_conntrack.c
index b9c724983..e04b80a3e 100644
--- a/src/proc_net_stat_conntrack.c
+++ b/src/proc_net_stat_conntrack.c
@@ -16,10 +16,10 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
if(unlikely(do_sockets == -1)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/nf_conntrack");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/stat/nf_conntrack");
nf_conntrack_filename = config_get("plugin:proc:/proc/net/stat/nf_conntrack", "filename to monitor", filename);
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_max");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_max");
nf_conntrack_max_filename = config_get("plugin:proc:/proc/sys/net/netfilter/nf_conntrack_max", "filename to monitor", filename);
usec_since_last_max = get_max_every = config_get_number("plugin:proc:/proc/sys/net/netfilter/nf_conntrack_max", "read every seconds", 10) * USEC_PER_SEC;
@@ -35,7 +35,7 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
do_sockets = 1;
if(!read_full) {
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_count");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sys/net/netfilter/nf_conntrack_count");
nf_conntrack_count_filename = config_get("plugin:proc:/proc/sys/net/netfilter/nf_conntrack_count", "filename to monitor", filename);
if(read_single_number_file(nf_conntrack_count_filename, &aentries))
@@ -47,7 +47,7 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
if(!do_sockets && !read_full)
return 1;
- rrdvar_max = rrdvar_custom_host_variable_create(&localhost, "netfilter.conntrack.max");
+ rrdvar_max = rrdvar_custom_host_variable_create(localhost, "netfilter.conntrack.max");
}
if(likely(read_full)) {
@@ -130,11 +130,13 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_sockets) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 3000, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections"
+ , "active connections", 3000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -145,13 +147,15 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_new) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 3001, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections"
+ , "connections/s", 3001, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "ignore", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -164,14 +168,16 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_changes) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 3002, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "delete_list", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s"
+ , 3002, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "inserted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "delete_list", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -184,14 +190,16 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_expect) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 3003, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations"
+ , "expectations/s", 3003, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "created", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -204,14 +212,16 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_search) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 3010, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "restarted", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "found", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches"
+ , "searches/s", 3010, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "searched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "restarted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "found", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -224,15 +234,17 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_errors) {
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 3005, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
-
- rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "insert_failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "early_drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL
+ , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s"
+ , 3005, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(st, "icmp_error", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "insert_failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "early_drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_net_stat_synproxy.c b/src/proc_net_stat_synproxy.c
index 6bb0a3c69..5a1fc30eb 100644
--- a/src/proc_net_stat_synproxy.c
+++ b/src/proc_net_stat_synproxy.c
@@ -10,15 +10,15 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
static procfile *ff = NULL;
if(unlikely(do_entries == -1)) {
- do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
- do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
- do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
- do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
+ do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_BOOLEAN_AUTO);
+ do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_BOOLEAN_AUTO);
+ do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_BOOLEAN_AUTO);
+ do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_BOOLEAN_AUTO);
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/stat/synproxy");
ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
return 1;
@@ -57,14 +57,16 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
- do_entries = CONFIG_ONDEMAND_YES;
+ if((do_entries == CONFIG_BOOLEAN_AUTO && events) || do_entries == CONFIG_BOOLEAN_YES) {
+ do_entries = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 3304, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 3304
+ , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "entries", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -74,14 +76,16 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
- do_syns = CONFIG_ONDEMAND_YES;
+ if((do_syns == CONFIG_BOOLEAN_AUTO && events) || do_syns == CONFIG_BOOLEAN_YES) {
+ do_syns = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 3301, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s"
+ , 3301, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -91,14 +95,16 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
- do_reopened = CONFIG_ONDEMAND_YES;
+ if((do_reopened == CONFIG_BOOLEAN_AUTO && events) || do_reopened == CONFIG_BOOLEAN_YES) {
+ do_reopened = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 3303, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened"
+ , "connections/s", 3303, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "reopened", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -108,16 +114,18 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
- do_cookies = CONFIG_ONDEMAND_YES;
+ if((do_cookies == CONFIG_BOOLEAN_AUTO && events) || do_cookies == CONFIG_BOOLEAN_YES) {
+ do_cookies = CONFIG_BOOLEAN_YES;
- st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
+ st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
if(unlikely(!st)) {
- st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 3302, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL
+ , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 3302
+ , update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "valid", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st, "retransmits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
diff --git a/src/proc_self_mountinfo.c b/src/proc_self_mountinfo.c
index d07f22510..bb031a9ab 100644
--- a/src/proc_self_mountinfo.c
+++ b/src/proc_self_mountinfo.c
@@ -175,10 +175,10 @@ static inline int is_read_only(const char *s) {
// read the whole mountinfo into a linked list
struct mountinfo *mountinfo_read(int do_statvfs) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", netdata_configured_host_prefix);
procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
- snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", netdata_configured_host_prefix);
ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return NULL;
}
@@ -293,7 +293,7 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
struct mountinfo *mt;
for(mt = root; mt; mt = mt->next) {
- if(unlikely(mt->st_dev == mi->st_dev && !(mi->flags & MOUNTINFO_NO_STAT))) {
+ if(unlikely(mt->st_dev == mi->st_dev && !(mt->flags & MOUNTINFO_IS_SAME_DEV))) {
if(strlen(mi->mount_point) < strlen(mt->mount_point))
mt->flags |= MOUNTINFO_IS_SAME_DEV;
else
@@ -319,7 +319,7 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
}
// check if it has size
- if(do_statvfs) {
+ if(do_statvfs && !(mi->flags & MOUNTINFO_IS_DUMMY)) {
struct statvfs buff_statvfs;
if(unlikely(statvfs(mi->mount_point, &buff_statvfs) < 0)) {
mi->flags |= MOUNTINFO_NO_STAT;
diff --git a/src/proc_softirqs.c b/src/proc_softirqs.c
index c7b10d70d..560e2acb2 100644
--- a/src/proc_softirqs.c
+++ b/src/proc_softirqs.c
@@ -58,7 +58,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/softirqs");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/softirqs");
ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -128,8 +128,9 @@ int do_proc_softirqs(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find_bytype("system", "softirqs");
- if(unlikely(!st)) st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_find_bytype_localhost("system", "softirqs");
+ if(unlikely(!st)) st = rrdset_create_localhost("system", "softirqs", NULL, "softirqs", NULL, "System softirqs"
+ , "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
else rrdset_next(st);
for(l = 0; l < lines ;l++) {
@@ -141,7 +142,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
irr->rd = rrddim_find(st, irr->id);
if(unlikely(!irr->rd))
- irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->rd, irr->name);
@@ -163,7 +164,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
char id[50+1];
snprintfz(id, 50, "cpu%d_softirqs", c);
- st = rrdset_find_bytype("cpu", id);
+ st = rrdset_find_bytype_localhost("cpu", id);
if(unlikely(!st)) {
// find if everything is zero
unsigned long long core_sum = 0 ;
@@ -176,7 +177,8 @@ int do_proc_softirqs(int update_every, usec_t dt) {
char title[100+1];
snprintfz(title, 100, "CPU%d softirqs", c);
- st = rrdset_create("cpu", id, NULL, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost("cpu", id, NULL, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c
+ , update_every, RRDSET_TYPE_STACKED);
}
else rrdset_next(st);
@@ -186,7 +188,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
if(unlikely(!irr->cpu[c].rd)) {
irr->cpu[c].rd = rrddim_find(st, irr->id);
if(unlikely(!irr->cpu[c].rd))
- irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+ irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
else
rrddim_set_name(st, irr->cpu[c].rd, irr->name);
}
diff --git a/src/proc_stat.c b/src/proc_stat.c
index f7e6d5bc0..04f0896cd 100644
--- a/src/proc_stat.c
+++ b/src/proc_stat.c
@@ -24,7 +24,7 @@ int do_proc_stat(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/stat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/stat");
ff = procfile_open(config_get("plugin:proc:/proc/stat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -91,24 +91,25 @@ int do_proc_stat(int update_every, usec_t dt) {
}
if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
- st = rrdset_find_bytype(type, id);
+ st = rrdset_find_bytype_localhost(type, id);
if(unlikely(!st)) {
- st = rrdset_create(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
+ st = rrdset_create_localhost(type, id, NULL, family, context, title, "percentage", priority
+ , update_every, RRDSET_TYPE_STACKED);
long multiplier = 1;
long divisor = 1; // sysconf(_SC_CLK_TCK);
- rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "guest", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "steal", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "softirq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "irq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
- rrddim_add(st, "iowait", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-
- rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "guest", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "steal", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "softirq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "irq", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "user", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "system", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "nice", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+ rrddim_add(st, "iowait", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+
+ rrddim_add(st, "idle", NULL, multiplier, divisor, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rrddim_hide(st, "idle");
}
else rrdset_next(st);
@@ -132,12 +133,13 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_interrupts)) {
- st = rrdset_find_bytype("system", "intr");
+ st = rrdset_find_bytype_localhost("system", "intr");
if(unlikely(!st)) {
- st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts"
+ , "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -151,11 +153,12 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_context)) {
- st = rrdset_find_bytype("system", "ctxt");
+ st = rrdset_find_bytype_localhost("system", "ctxt");
if(unlikely(!st)) {
- st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches"
+ , "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -177,12 +180,13 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_forks)) {
- st = rrdset_find_bytype("system", "forks");
+ st = rrdset_find_bytype_localhost("system", "forks");
if(unlikely(!st)) {
- st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ st = rrdset_create_localhost("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s"
+ , 700, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
- rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st);
@@ -193,12 +197,13 @@ int do_proc_stat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(likely(do_processes)) {
- st = rrdset_find_bytype("system", "processes");
+ st = rrdset_find_bytype_localhost("system", "processes");
if(unlikely(!st)) {
- st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("system", "processes", NULL, "processes", NULL, "System Processes", "processes"
+ , 600, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/src/proc_sys_kernel_random_entropy_avail.c
index 388406e0b..fea8900d3 100644
--- a/src/proc_sys_kernel_random_entropy_avail.c
+++ b/src/proc_sys_kernel_random_entropy_avail.c
@@ -7,7 +7,7 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/kernel/random/entropy_avail");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/sys/kernel/random/entropy_avail");
ff = procfile_open(config_get("plugin:proc:/proc/sys/kernel/random/entropy_avail", "filename to monitor", filename), "", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -17,10 +17,11 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
unsigned long long entropy = str2ull(procfile_lineword(ff, 0, 0));
- RRDSET *st = rrdset_find_bytype("system", "entropy");
+ RRDSET *st = rrdset_find_bytype_localhost("system", "entropy");
if(unlikely(!st)) {
- st = rrdset_create("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "entropy", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000
+ , update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "entropy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/proc_uptime.c b/src/proc_uptime.c
index 9f341a33f..f74cccb97 100644
--- a/src/proc_uptime.c
+++ b/src/proc_uptime.c
@@ -13,7 +13,7 @@ int do_proc_uptime(int update_every, usec_t dt) {
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/uptime");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/uptime");
ff = procfile_open(config_get("plugin:proc:/proc/uptime", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff))
@@ -39,11 +39,12 @@ int do_proc_uptime(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(unlikely(!st))
- st = rrdset_find("system.uptime");
+ st = rrdset_find_localhost("system.uptime");
if(unlikely(!st)) {
- st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "uptime", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000
+ , update_every, RRDSET_TYPE_LINE);
+ rrddim_add(st, "uptime", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c
index ea917b989..847487363 100644
--- a/src/proc_vmstat.c
+++ b/src/proc_vmstat.c
@@ -25,10 +25,10 @@ int do_proc_vmstat(int update_every, usec_t dt) {
static unsigned long long pswpout = 0ULL;
if(unlikely(!arl_base)) {
- do_swapio = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "swap i/o", CONFIG_ONDEMAND_ONDEMAND);
+ do_swapio = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "swap i/o", CONFIG_BOOLEAN_AUTO);
do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
- do_numa = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "system-wide numa metric summary", CONFIG_ONDEMAND_ONDEMAND);
+ do_numa = config_get_boolean_ondemand("plugin:proc:/proc/vmstat", "system-wide numa metric summary", CONFIG_BOOLEAN_AUTO);
arl_base = arl_create("vmstat", NULL, 60);
@@ -39,7 +39,7 @@ int do_proc_vmstat(int update_every, usec_t dt) {
arl_expect(arl_base, "pswpin", &pswpin);
arl_expect(arl_base, "pswpout", &pswpout);
- if(do_numa == CONFIG_ONDEMAND_YES || (do_numa == CONFIG_ONDEMAND_ONDEMAND && get_numa_node_count() >= 2)) {
+ if(do_numa == CONFIG_BOOLEAN_YES || (do_numa == CONFIG_BOOLEAN_AUTO && get_numa_node_count() >= 2)) {
arl_expect(arl_base, "numa_foreign", &numa_foreign);
arl_expect(arl_base, "numa_hint_faults_local", &numa_hint_faults_local);
arl_expect(arl_base, "numa_hint_faults", &numa_hint_faults);
@@ -56,13 +56,13 @@ int do_proc_vmstat(int update_every, usec_t dt) {
// when all the expected metrics are collected.
// Also ARL will not parse their values.
has_numa = 0;
- do_numa = CONFIG_ONDEMAND_NO;
+ do_numa = CONFIG_BOOLEAN_NO;
}
}
if(unlikely(!ff)) {
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/vmstat");
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/vmstat");
ff = procfile_open(config_get("plugin:proc:/proc/vmstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) return 1;
}
@@ -87,15 +87,16 @@ int do_proc_vmstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(pswpin || pswpout || do_swapio == CONFIG_ONDEMAND_YES) {
- do_swapio = CONFIG_ONDEMAND_YES;
+ if(pswpin || pswpout || do_swapio == CONFIG_BOOLEAN_YES) {
+ do_swapio = CONFIG_BOOLEAN_YES;
static RRDSET *st_swapio = NULL;
if(unlikely(!st_swapio)) {
- st_swapio = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+ st_swapio = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
- rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
+ rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_swapio);
@@ -109,10 +110,11 @@ int do_proc_vmstat(int update_every, usec_t dt) {
if(do_io) {
static RRDSET *st_io = NULL;
if(unlikely(!st_io)) {
- st_io = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
+ st_io = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150
+ , update_every, RRDSET_TYPE_AREA);
- rrddim_add(st_io, "in", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_io, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_io);
@@ -126,11 +128,12 @@ int do_proc_vmstat(int update_every, usec_t dt) {
if(do_pgfaults) {
static RRDSET *st_pgfaults = NULL;
if(unlikely(!st_pgfaults)) {
- st_pgfaults = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
- st_pgfaults->isdetail = 1;
+ st_pgfaults = rrdset_create_localhost("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults"
+ , "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL);
- rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_pgfaults);
@@ -149,27 +152,28 @@ int do_proc_vmstat(int update_every, usec_t dt) {
has_numa = (numa_local || numa_foreign || numa_interleave || numa_other || numa_pte_updates ||
numa_huge_pte_updates || numa_hint_faults || numa_hint_faults_local || numa_pages_migrated) ? 1 : 0;
- if(do_numa == CONFIG_ONDEMAND_YES || (do_numa == CONFIG_ONDEMAND_ONDEMAND && has_numa)) {
- do_numa = CONFIG_ONDEMAND_YES;
+ if(do_numa == CONFIG_BOOLEAN_YES || (do_numa == CONFIG_BOOLEAN_AUTO && has_numa)) {
+ do_numa = CONFIG_BOOLEAN_YES;
static RRDSET *st_numa = NULL;
if(unlikely(!st_numa)) {
- st_numa = rrdset_create("mem", "numa", NULL, "numa", NULL, "NUMA events", "events/s", 800, update_every, RRDSET_TYPE_LINE);
- st_numa->isdetail = 1;
+ st_numa = rrdset_create_localhost("mem", "numa", NULL, "numa", NULL, "NUMA events", "events/s", 800
+ , update_every, RRDSET_TYPE_LINE);
+ rrdset_flag_set(st_numa, RRDSET_FLAG_DETAIL);
// These depend on CONFIG_NUMA in the kernel.
- rrddim_add(st_numa, "local", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "foreign", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "interleave", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "other", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st_numa, "local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "foreign", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "interleave", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "other", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
// The following stats depend on CONFIG_NUMA_BALANCING in the
// kernel.
- rrddim_add(st_numa, "pte updates", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "huge pte updates", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "hint faults", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "hint faults local", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st_numa, "pages migrated", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ rrddim_add(st_numa, "pte updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "huge pte updates", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "hint faults", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "hint faults local", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(st_numa, "pages migrated", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else rrdset_next(st_numa);
diff --git a/src/procfile.c b/src/procfile.c
index 6f52bf465..3a89e8353 100644
--- a/src/procfile.c
+++ b/src/procfile.c
@@ -15,6 +15,27 @@ size_t procfile_max_lines = PFLINES_INCREASE_STEP;
size_t procfile_max_words = PFWORDS_INCREASE_STEP;
size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER;
+
+// ----------------------------------------------------------------------------
+
+char *procfile_filename(procfile *ff) {
+ if(ff->filename[0]) return ff->filename;
+
+ char buffer[FILENAME_MAX + 1];
+ snprintfz(buffer, FILENAME_MAX, "/proc/self/fd/%d", ff->fd);
+
+ ssize_t l = readlink(buffer, ff->filename, FILENAME_MAX);
+ if(unlikely(l == -1))
+ snprintfz(ff->filename, FILENAME_MAX, "unknown filename for fd %d", ff->fd);
+ else
+ ff->filename[l] = '\0';
+
+ // on non-linux systems, something like this will be needed
+ // fcntl(ff->fd, F_GETPATH, ff->filename)
+
+ return ff->filename;
+}
+
// ----------------------------------------------------------------------------
// An array of words
@@ -106,15 +127,10 @@ static inline void pflines_free(pflines *fl) {
// ----------------------------------------------------------------------------
// The procfile
-#define PF_CHAR_IS_SEPARATOR ' '
-#define PF_CHAR_IS_NEWLINE 'N'
-#define PF_CHAR_IS_WORD 'W'
-#define PF_CHAR_IS_QUOTE 'Q'
-#define PF_CHAR_IS_OPEN 'O'
-#define PF_CHAR_IS_CLOSE 'C'
-
void procfile_close(procfile *ff) {
- debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
+ if(unlikely(!ff)) return;
+
+ debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", procfile_filename(ff));
if(likely(ff->lines)) pflines_free(ff->lines);
if(likely(ff->words)) pfwords_free(ff->words);
@@ -126,113 +142,119 @@ void procfile_close(procfile *ff) {
static inline void procfile_parser(procfile *ff) {
// debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
- register char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data;
- register char *separators = ff->separators;
- char quote = 0;
- size_t l = 0, w = 0, opened = 0;
+ char *s = ff->data // our current position
+ , *e = &ff->data[ff->len] // the terminating null
+ , *t = ff->data; // the first character of a quoted or a parenthesized string
+
+ // the look up array to find our type of character
+ PF_CHAR_TYPE *separators = ff->separators;
+
+ char quote = 0; // the quote character - only when in quoted string
+
+ size_t
+ l = 0 // counts the number of lines we added
+ , w = 0 // counts the number of words we added
+ , opened = 0; // counts the number of open parenthesis
ff->lines = pflines_add(ff->lines, w);
while(likely(s < e)) {
// we are not at the end
+ PF_CHAR_TYPE ct = separators[(unsigned char)(*s)];
- switch(separators[(unsigned char)(*s)]) {
- case PF_CHAR_IS_OPEN:
- if(s == t) {
- opened++;
- t = ++s;
- }
- else if(opened) {
- opened++;
- s++;
- }
- else
- s++;
- break;
-
- case PF_CHAR_IS_CLOSE:
- if(opened) {
- opened--;
-
- if(!opened) {
- *s = '\0';
- ff->words = pfwords_add(ff->words, t);
- ff->lines->lines[l].words++;
- w++;
-
- t = ++s;
- }
- else
- s++;
- }
- else
- s++;
- break;
+ // this is faster than a switch()
+ if(likely(ct == PF_CHAR_IS_WORD)) {
+ s++;
+ }
+ else if(likely(ct == PF_CHAR_IS_SEPARATOR)) {
+ if(unlikely(quote || opened)) {
+ // we are inside a quote
+ s++;
+ continue;
+ }
- case PF_CHAR_IS_QUOTE:
- if(unlikely(!quote && s == t)) {
- // quote opened at the beginning
- quote = *s;
- t = ++s;
- }
- else if(unlikely(quote && quote == *s)) {
- // quote closed
- quote = 0;
+ if(unlikely(s == t)) {
+ // skip all leading white spaces
+ t = ++s;
+ continue;
+ }
- *s = '\0';
- ff->words = pfwords_add(ff->words, t);
- ff->lines->lines[l].words++;
- w++;
+ // end of word
+ *s = '\0';
- t = ++s;
- }
- else
- s++;
- break;
+ ff->words = pfwords_add(ff->words, t);
+ ff->lines->lines[l].words++;
+ w++;
- case PF_CHAR_IS_SEPARATOR:
- if(unlikely(quote || opened)) {
- // we are inside a quote
- s++;
- break;
- }
+ t = ++s;
+ }
+ else if(likely(ct == PF_CHAR_IS_NEWLINE)) {
+ // end of line
+ *s = '\0';
- if(unlikely(s == t)) {
- // skip all leading white spaces
- t = ++s;
- break;
- }
+ ff->words = pfwords_add(ff->words, t);
+ ff->lines->lines[l].words++;
+ w++;
- // end of word
- *s = '\0';
+ // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
- ff->words = pfwords_add(ff->words, t);
- ff->lines->lines[l].words++;
- w++;
+ ff->lines = pflines_add(ff->lines, w);
+ l++;
+ t = ++s;
+ }
+ else if(likely(ct == PF_CHAR_IS_QUOTE)) {
+ if(unlikely(!quote && s == t)) {
+ // quote opened at the beginning
+ quote = *s;
t = ++s;
- break;
+ }
+ else if(unlikely(quote && quote == *s)) {
+ // quote closed
+ quote = 0;
- case PF_CHAR_IS_NEWLINE:
- // end of line
*s = '\0';
-
ff->words = pfwords_add(ff->words, t);
ff->lines->lines[l].words++;
w++;
- // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
-
- ff->lines = pflines_add(ff->lines, w);
- l++;
-
t = ++s;
- break;
+ }
+ else
+ s++;
+ }
+ else if(likely(ct == PF_CHAR_IS_OPEN)) {
+ if(s == t) {
+ opened++;
+ t = ++s;
+ }
+ else if(opened) {
+ opened++;
+ s++;
+ }
+ else
+ s++;
+ }
+ else if(likely(ct == PF_CHAR_IS_CLOSE)) {
+ if(opened) {
+ opened--;
- default:
+ if(!opened) {
+ *s = '\0';
+ ff->words = pfwords_add(ff->words, t);
+ ff->lines->lines[l].words++;
+ w++;
+
+ t = ++s;
+ }
+ else
+ s++;
+ }
+ else
s++;
- break;
}
+ else
+ fatal("Internal Error: procfile_readall() does not handle all the cases.");
}
if(likely(s > t && t < e)) {
@@ -250,26 +272,24 @@ static inline void procfile_parser(procfile *ff) {
}
procfile *procfile_readall(procfile *ff) {
- debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
+ // debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
- ssize_t r = 1;
- ff->len = 0;
-
- while(likely(r > 0)) {
+ ff->len = 0; // zero the used size
+ ssize_t r = 1; // read at least once
+ while(r > 0) {
ssize_t s = ff->len;
ssize_t x = ff->size - s;
if(unlikely(!x)) {
- debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
-
+ debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", procfile_filename(ff));
ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
ff->size += PROCFILE_INCREMENT_BUFFER;
}
- debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
+ debug(D_PROCFILE, "Reading file '%s', from position %zd with length %zd", procfile_filename(ff), s, (ssize_t)(ff->size - s));
r = read(ff->fd, &ff->data[s], ff->size - s);
if(unlikely(r == -1)) {
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", procfile_filename(ff));
procfile_close(ff);
return NULL;
}
@@ -277,9 +297,9 @@ procfile *procfile_readall(procfile *ff) {
ff->len += r;
}
- debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
+ // debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
procfile_close(ff);
return NULL;
}
@@ -294,29 +314,37 @@ procfile *procfile_readall(procfile *ff) {
if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
}
- debug(D_PROCFILE, "File '%s' updated.", ff->filename);
+ // debug(D_PROCFILE, "File '%s' updated.", ff->filename);
return ff;
}
-static void procfile_set_separators(procfile *ff, const char *separators) {
- static char def[256] = { [0 ... 255] = 0 };
+static inline void procfile_set_separators(procfile *ff, const char *separators) {
+ static PF_CHAR_TYPE def[256];
+ static char initilized = 0;
- if(unlikely(!def[255])) {
+ if(unlikely(!initilized)) {
// this is thread safe
- // we check that the last byte is non-zero
- // if it is zero, multiple threads may be executing this at the same time
- // setting in def[] the exact same values
- int i;
- for(i = 0; likely(i < 256) ;i++) {
- if(unlikely(i == '\n' || i == '\r')) def[i] = PF_CHAR_IS_NEWLINE;
- else if(unlikely(isspace(i) || !isprint(i))) def[i] = PF_CHAR_IS_SEPARATOR;
- else def[i] = PF_CHAR_IS_WORD;
+ // if initialized is zero, multiple threads may be executing
+ // this code at the same time, setting in def[] the exact same values
+ int i = 256;
+ while(i--) {
+ if(unlikely(i == '\n' || i == '\r'))
+ def[i] = PF_CHAR_IS_NEWLINE;
+
+ else if(unlikely(isspace(i) || !isprint(i)))
+ def[i] = PF_CHAR_IS_SEPARATOR;
+
+ else
+ def[i] = PF_CHAR_IS_WORD;
}
+
+ initilized = 1;
}
// copy the default
- char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
- while(likely(ffd != ffe)) *ffs++ = *ffd++;
+ PF_CHAR_TYPE *ffs = ff->separators, *ffd = def, *ffe = &def[256];
+ while(ffd != ffe)
+ *ffs++ = *ffd++;
// set the separators
if(unlikely(!separators))
@@ -324,47 +352,50 @@ static void procfile_set_separators(procfile *ff, const char *separators) {
ffs = ff->separators;
const char *s = separators;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
}
void procfile_set_quotes(procfile *ff, const char *quotes) {
+ PF_CHAR_TYPE *ffs = ff->separators;
+
// remove all quotes
- int i;
- for(i = 0; i < 256 ; i++)
- if(unlikely(ff->separators[i] == PF_CHAR_IS_QUOTE))
- ff->separators[i] = PF_CHAR_IS_WORD;
+ int i = 256;
+ while(i--)
+ if(unlikely(ffs[i] == PF_CHAR_IS_QUOTE))
+ ffs[i] = PF_CHAR_IS_WORD;
// if nothing given, return
if(unlikely(!quotes || !*quotes))
return;
// set the quotes
- char *ffs = ff->separators;
const char *s = quotes;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
}
void procfile_set_open_close(procfile *ff, const char *open, const char *close) {
+ PF_CHAR_TYPE *ffs = ff->separators;
+
// remove all open/close
- int i;
- for(i = 0; i < 256 ; i++)
- if(unlikely(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE))
- ff->separators[i] = PF_CHAR_IS_WORD;
+ int i = 256;
+ while(i--)
+ if(unlikely(ffs[i] == PF_CHAR_IS_OPEN || ffs[i] == PF_CHAR_IS_CLOSE))
+ ffs[i] = PF_CHAR_IS_WORD;
// if nothing given, return
if(unlikely(!open || !*open || !close || !*close))
return;
// set the openings
- char *ffs = ff->separators;
const char *s = open;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_OPEN;
+ // set the closings
s = close;
- while(likely(*s))
+ while(*s)
ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
}
@@ -379,7 +410,9 @@ procfile *procfile_open(const char *filename, const char *separators, uint32_t f
size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
procfile *ff = mallocz(sizeof(procfile) + size);
- strncpyz(ff->filename, filename, FILENAME_MAX);
+
+ //strncpyz(ff->filename, filename, FILENAME_MAX);
+ ff->filename[0] = '\0';
ff->fd = fd;
ff->size = size;
@@ -406,7 +439,8 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa
return NULL;
}
- strncpyz(ff->filename, filename, FILENAME_MAX);
+ //strncpyz(ff->filename, filename, FILENAME_MAX);
+ ff->filename[0] = '\0';
ff->flags = flags;
@@ -423,7 +457,7 @@ void procfile_print(procfile *ff) {
size_t lines = procfile_lines(ff), l;
char *s;
- debug(D_PROCFILE, "File '%s' with %zu lines and %zu words", ff->filename, ff->lines->len, ff->words->len);
+ debug(D_PROCFILE, "File '%s' with %zu lines and %zu words", procfile_filename(ff), ff->lines->len, ff->words->len);
for(l = 0; likely(l < lines) ;l++) {
size_t words = procfile_linewords(ff, l);
diff --git a/src/procfile.h b/src/procfile.h
index a586ba48d..98765697f 100644
--- a/src/procfile.h
+++ b/src/procfile.h
@@ -58,15 +58,25 @@ typedef struct {
#define PROCFILE_FLAG_DEFAULT 0x00000000
#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001
+typedef enum procfile_separator {
+ PF_CHAR_IS_SEPARATOR,
+ PF_CHAR_IS_NEWLINE,
+ PF_CHAR_IS_WORD,
+ PF_CHAR_IS_QUOTE,
+ PF_CHAR_IS_OPEN,
+ PF_CHAR_IS_CLOSE
+} PF_CHAR_TYPE;
+
typedef struct {
- char filename[FILENAME_MAX + 1];
+ char filename[FILENAME_MAX + 1]; // not populated until profile_filename() is called
+
uint32_t flags;
int fd; // the file desriptor
size_t len; // the bytes we have placed into data
size_t size; // the bytes we have allocated for data
pflines *lines;
pfwords *words;
- char separators[256];
+ PF_CHAR_TYPE separators[256];
char data[]; // allocated buffer to keep file contents
} procfile;
@@ -89,6 +99,8 @@ extern void procfile_print(procfile *ff);
extern void procfile_set_quotes(procfile *ff, const char *quotes);
extern void procfile_set_open_close(procfile *ff, const char *open, const char *close);
+extern char *procfile_filename(procfile *ff);
+
// ----------------------------------------------------------------------------
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far
diff --git a/src/registry.c b/src/registry.c
index d223cd6f1..ed9be9848 100644
--- a/src/registry.c
+++ b/src/registry.c
@@ -10,11 +10,11 @@
// REGISTRY concurrency locking
static inline void registry_lock(void) {
- pthread_mutex_lock(&registry.lock);
+ netdata_mutex_lock(&registry.lock);
}
static inline void registry_unlock(void) {
- pthread_mutex_unlock(&registry.lock);
+ netdata_mutex_unlock(&registry.lock);
}
@@ -41,19 +41,19 @@ static inline void registry_set_person_cookie(struct web_client *w, REGISTRY_PER
// ----------------------------------------------------------------------------
// JSON GENERATION
-static inline void registry_json_header(struct web_client *w, const char *action, const char *status) {
+static inline void registry_json_header(RRDHOST *host, struct web_client *w, const char *action, const char *status) {
buffer_flush(w->response.data);
w->response.data->contenttype = CT_APPLICATION_JSON;
buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
- action, status, registry.hostname, registry.machine_guid);
+ action, status, (host == localhost)?registry.hostname:host->hostname, host->machine_guid);
}
static inline void registry_json_footer(struct web_client *w) {
buffer_strcat(w->response.data, "\n}\n");
}
-static inline int registry_json_disabled(struct web_client *w, const char *action) {
- registry_json_header(w, action, REGISTRY_STATUS_DISABLED);
+static inline int registry_json_disabled(RRDHOST *host, struct web_client *w, const char *action) {
+ registry_json_header(host, w, action, REGISTRY_STATUS_DISABLED);
buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
registry.registry_to_announce);
@@ -127,8 +127,8 @@ static inline int registry_person_url_callback_verify_machine_exists(void *entry
// ----------------------------------------------------------------------------
// public HELLO request
-int registry_request_hello_json(struct web_client *w) {
- registry_json_header(w, "hello", REGISTRY_STATUS_OK);
+int registry_request_hello_json(RRDHOST *host, struct web_client *w) {
+ registry_json_header(host, w, "hello", REGISTRY_STATUS_OK);
buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
registry.registry_to_announce);
@@ -143,9 +143,9 @@ int registry_request_hello_json(struct web_client *w) {
#define REGISTRY_VERIFY_COOKIES_GUID "give-me-back-this-cookie-now--please"
// the main method for registering an access
-int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
+int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
if(unlikely(!registry.enabled))
- return registry_json_disabled(w, "access");
+ return registry_json_disabled(host, w, "access");
// ------------------------------------------------------------------------
// verify the browser supports cookies
@@ -167,7 +167,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
REGISTRY_PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when);
if(!p) {
- registry_json_header(w, "access", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "access", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 412;
@@ -177,7 +177,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
registry_set_person_cookie(w, p);
// generate the response
- registry_json_header(w, "access", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "access", REGISTRY_STATUS_OK);
buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
@@ -193,22 +193,22 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
// public DELETE request
// the main method for deleting a URL from a person
-int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
+int registry_request_delete_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
if(!registry.enabled)
- return registry_json_disabled(w, "delete");
+ return registry_json_disabled(host, w, "delete");
registry_lock();
REGISTRY_PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
if(!p) {
- registry_json_header(w, "delete", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "delete", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 412;
}
// generate the response
- registry_json_header(w, "delete", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "delete", REGISTRY_STATUS_OK);
registry_json_footer(w);
registry_unlock();
return 200;
@@ -218,21 +218,21 @@ int registry_request_delete_json(struct web_client *w, char *person_guid, char *
// public SEARCH request
// the main method for searching the URLs of a netdata
-int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
+int registry_request_search_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
if(!registry.enabled)
- return registry_json_disabled(w, "search");
+ return registry_json_disabled(host, w, "search");
registry_lock();
REGISTRY_MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
if(!m) {
- registry_json_header(w, "search", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "search", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 404;
}
- registry_json_header(w, "search", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "search", REGISTRY_STATUS_OK);
buffer_strcat(w->response.data, ",\n\t\"urls\": [");
struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
@@ -248,9 +248,9 @@ int registry_request_search_json(struct web_client *w, char *person_guid, char *
// SWITCH REQUEST
// the main method for switching user identity
-int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
+int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
if(!registry.enabled)
- return registry_json_disabled(w, "switch");
+ return registry_json_disabled(host, w, "switch");
(void)url;
(void)when;
@@ -259,7 +259,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
REGISTRY_PERSON *op = registry_person_find(person_guid);
if(!op) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 430;
@@ -267,7 +267,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
REGISTRY_PERSON *np = registry_person_find(new_person_guid);
if(!np) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 431;
@@ -275,7 +275,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
REGISTRY_MACHINE *m = registry_machine_find(machine_guid);
if(!m) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 432;
@@ -286,7 +286,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
// verify the old person has access to this machine
avl_traverse(&op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
if(!data.count) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 433;
@@ -296,7 +296,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
data.count = 0;
avl_traverse(&np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
if(!data.count) {
- registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
registry_unlock();
return 434;
@@ -307,7 +307,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
registry_set_person_cookie(w, np);
// generate the response
- registry_json_header(w, "switch", REGISTRY_STATUS_OK);
+ registry_json_header(host, w, "switch", REGISTRY_STATUS_OK);
buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid);
registry_json_footer(w);
@@ -323,11 +323,13 @@ void registry_statistics(void) {
static RRDSET *sts = NULL, *stc = NULL, *stm = NULL;
- if(!sts) sts = rrdset_find("netdata.registry_sessions");
+ if(!sts) sts = rrdset_find_localhost("netdata.registry_sessions");
if(!sts) {
- sts = rrdset_create("netdata", "registry_sessions", NULL, "registry", NULL, "NetData Registry Sessions", "session", 131000, rrd_update_every, RRDSET_TYPE_LINE);
+ sts = rrdset_create_localhost("netdata", "registry_sessions", NULL, "registry", NULL
+ , "NetData Registry Sessions", "session", 131000, localhost->rrd_update_every
+ , RRDSET_TYPE_LINE);
- rrddim_add(sts, "sessions", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ rrddim_add(sts, "sessions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(sts);
@@ -336,15 +338,16 @@ void registry_statistics(void) {
// ------------------------------------------------------------------------
- if(!stc) stc = rrdset_find("netdata.registry_entries");
+ if(!stc) stc = rrdset_find_localhost("netdata.registry_entries");
if(!stc) {
- stc = rrdset_create("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries", "entries", 131100, rrd_update_every, RRDSET_TYPE_LINE);
-
- rrddim_add(stc, "persons", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "machines", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "persons_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(stc, "machines_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ stc = rrdset_create_localhost("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries"
+ , "entries", 131100, localhost->rrd_update_every, RRDSET_TYPE_LINE);
+
+ rrddim_add(stc, "persons", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "machines", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "persons_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stc, "machines_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(stc);
@@ -357,15 +360,16 @@ void registry_statistics(void) {
// ------------------------------------------------------------------------
- if(!stm) stm = rrdset_find("netdata.registry_mem");
+ if(!stm) stm = rrdset_find_localhost("netdata.registry_mem");
if(!stm) {
- stm = rrdset_create("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB", 131300, rrd_update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(stm, "persons", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "machines", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
- rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+ stm = rrdset_create_localhost("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB"
+ , 131300, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+
+ rrddim_add(stm, "persons", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "machines", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(stm);
diff --git a/src/registry.h b/src/registry.h
index 4947486c4..2c4592b92 100644
--- a/src/registry.h
+++ b/src/registry.h
@@ -60,13 +60,16 @@ extern int registry_init(void);
extern void registry_free(void);
// HTTP requests handled by the registry
-extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
-extern int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
-extern int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
-extern int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when);
-extern int registry_request_hello_json(struct web_client *w);
+extern int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
+extern int registry_request_delete_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
+extern int registry_request_search_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
+extern int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when);
+extern int registry_request_hello_json(RRDHOST *host, struct web_client *w);
// update the registry monitoring charts
extern void registry_statistics(void);
+extern char *registry_get_this_machine_guid(void);
+extern int regenerate_guid(const char *guid, char *result);
+
#endif /* NETDATA_REGISTRY_H */
diff --git a/src/registry_init.c b/src/registry_init.c
index fb61acd08..2a41d36ee 100644
--- a/src/registry_init.c
+++ b/src/registry_init.c
@@ -4,45 +4,52 @@ int registry_init(void) {
char filename[FILENAME_MAX + 1];
// registry enabled?
- registry.enabled = config_get_boolean("registry", "enabled", 0);
+ if(web_server_mode != WEB_SERVER_MODE_NONE) {
+ registry.enabled = config_get_boolean(CONFIG_SECTION_REGISTRY, "enabled", 0);
+ }
+ else {
+ info("Registry is disabled - use the central netdata");
+ config_set_boolean(CONFIG_SECTION_REGISTRY, "enabled", 0);
+ registry.enabled = 0;
+ }
// pathnames
- registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR "/registry");
+ snprintfz(filename, FILENAME_MAX, "%s/registry", netdata_configured_varlib_dir);
+ registry.pathname = config_get(CONFIG_SECTION_REGISTRY, "registry db directory", filename);
if(mkdir(registry.pathname, 0770) == -1 && errno != EEXIST)
fatal("Cannot create directory '%s'.", registry.pathname);
// filenames
snprintfz(filename, FILENAME_MAX, "%s/netdata.public.unique.id", registry.pathname);
- registry.machine_guid_filename = config_get("registry", "netdata unique id file", filename);
- registry_get_this_machine_guid();
+ registry.machine_guid_filename = config_get(CONFIG_SECTION_REGISTRY, "netdata unique id file", filename);
snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname);
- registry.db_filename = config_get("registry", "registry db file", filename);
+ registry.db_filename = config_get(CONFIG_SECTION_REGISTRY, "registry db file", filename);
snprintfz(filename, FILENAME_MAX, "%s/registry-log.db", registry.pathname);
- registry.log_filename = config_get("registry", "registry log file", filename);
+ registry.log_filename = config_get(CONFIG_SECTION_REGISTRY, "registry log file", filename);
// configuration options
- registry.save_registry_every_entries = (unsigned long long)config_get_number("registry", "registry save db every new entries", 1000000);
- registry.persons_expiration = config_get_number("registry", "registry expire idle persons days", 365) * 86400;
- registry.registry_domain = config_get("registry", "registry domain", "");
- registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
- registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", localhost.hostname));
- registry.verify_cookies_redirects = config_get_boolean("registry", "verify browser cookies support", 1);
+ registry.save_registry_every_entries = (unsigned long long)config_get_number(CONFIG_SECTION_REGISTRY, "registry save db every new entries", 1000000);
+ registry.persons_expiration = config_get_number(CONFIG_SECTION_REGISTRY, "registry expire idle persons days", 365) * 86400;
+ registry.registry_domain = config_get(CONFIG_SECTION_REGISTRY, "registry domain", "");
+ registry.registry_to_announce = config_get(CONFIG_SECTION_REGISTRY, "registry to announce", "https://registry.my-netdata.io");
+ registry.hostname = config_get(CONFIG_SECTION_REGISTRY, "registry hostname", config_get(CONFIG_SECTION_GLOBAL, "hostname", "localhost"));
+ registry.verify_cookies_redirects = config_get_boolean(CONFIG_SECTION_REGISTRY, "verify browser cookies support", 1);
setenv("NETDATA_REGISTRY_HOSTNAME", registry.hostname, 1);
setenv("NETDATA_REGISTRY_URL", registry.registry_to_announce, 1);
- registry.max_url_length = (size_t)config_get_number("registry", "max URL length", 1024);
+ registry.max_url_length = (size_t)config_get_number(CONFIG_SECTION_REGISTRY, "max URL length", 1024);
if(registry.max_url_length < 10) {
registry.max_url_length = 10;
- config_set_number("registry", "max URL length", (long long)registry.max_url_length);
+ config_set_number(CONFIG_SECTION_REGISTRY, "max URL length", (long long)registry.max_url_length);
}
- registry.max_name_length = (size_t)config_get_number("registry", "max URL name length", 50);
+ registry.max_name_length = (size_t)config_get_number(CONFIG_SECTION_REGISTRY, "max URL name length", 50);
if(registry.max_name_length < 10) {
registry.max_name_length = 10;
- config_set_number("registry", "max URL name length", (long long)registry.max_name_length);
+ config_set_number(CONFIG_SECTION_REGISTRY, "max URL name length", (long long)registry.max_name_length);
}
// initialize entries counters
@@ -61,7 +68,7 @@ int registry_init(void) {
registry.machines_urls_memory = 0;
// initialize locks
- pthread_mutex_init(&registry.lock, NULL);
+ netdata_mutex_init(&registry.lock);
// create dictionaries
registry.persons = dictionary_create(DICTIONARY_FLAGS);
diff --git a/src/registry_internals.c b/src/registry_internals.c
index d32d549e2..9ec91ba40 100644
--- a/src/registry_internals.c
+++ b/src/registry_internals.c
@@ -7,7 +7,7 @@ struct registry registry;
// parse a GUID and re-generated to be always lower case
// this is used as a protection against the variations of GUIDs
-int registry_regenerate_guid(const char *guid, char *result) {
+int regenerate_guid(const char *guid, char *result) {
uuid_t uuid;
if(unlikely(uuid_parse(guid, uuid) == -1)) {
info("Registry: GUID '%s' is not a valid GUID.", guid);
@@ -18,7 +18,7 @@ int registry_regenerate_guid(const char *guid, char *result) {
#ifdef NETDATA_INTERNAL_CHECKS
if(strcmp(guid, result))
- info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
+ info("GUID '%s' and re-generated GUID '%s' differ!", guid, result);
#endif /* NETDATA_INTERNAL_CHECKS */
}
@@ -96,14 +96,14 @@ REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_gu
url = registry_fix_url(url, NULL);
// make sure the person GUID is valid
- if(registry_regenerate_guid(person_guid, pbuf) == -1) {
+ if(regenerate_guid(person_guid, pbuf) == -1) {
info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
return NULL;
}
person_guid = pbuf;
// make sure the machine GUID is valid
- if(registry_regenerate_guid(machine_guid, mbuf) == -1) {
+ if(regenerate_guid(machine_guid, mbuf) == -1) {
info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
return NULL;
}
@@ -226,7 +226,7 @@ REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid
if(!pu || !p || !m) return NULL;
// make sure the machine GUID is valid
- if(registry_regenerate_guid(request_machine, mbuf) == -1) {
+ if(regenerate_guid(request_machine, mbuf) == -1) {
info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
return NULL;
}
@@ -275,8 +275,10 @@ static inline int is_machine_guid_blacklisted(const char *guid) {
}
char *registry_get_this_machine_guid(void) {
- if(likely(registry.machine_guid[0]))
- return registry.machine_guid;
+ static char guid[GUID_LEN + 1] = "";
+
+ if(likely(guid[0]))
+ return guid;
// read it from disk
int fd = open(registry.machine_guid_filename, O_RDONLY);
@@ -286,38 +288,38 @@ char *registry_get_this_machine_guid(void) {
error("Failed to read machine GUID from '%s'", registry.machine_guid_filename);
else {
buf[GUID_LEN] = '\0';
- if(registry_regenerate_guid(buf, registry.machine_guid) == -1) {
+ if(regenerate_guid(buf, guid) == -1) {
error("Failed to validate machine GUID '%s' from '%s'. Ignoring it - this might mean this netdata will appear as duplicate in the registry.",
buf, registry.machine_guid_filename);
- registry.machine_guid[0] = '\0';
+ guid[0] = '\0';
}
- else if(is_machine_guid_blacklisted(registry.machine_guid))
- registry.machine_guid[0] = '\0';
+ else if(is_machine_guid_blacklisted(guid))
+ guid[0] = '\0';
}
close(fd);
}
// generate a new one?
- if(!registry.machine_guid[0]) {
+ if(!guid[0]) {
uuid_t uuid;
uuid_generate_time(uuid);
- uuid_unparse_lower(uuid, registry.machine_guid);
- registry.machine_guid[GUID_LEN] = '\0';
+ uuid_unparse_lower(uuid, guid);
+ guid[GUID_LEN] = '\0';
// save it
fd = open(registry.machine_guid_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
if(fd == -1)
fatal("Cannot create unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
- if(write(fd, registry.machine_guid, GUID_LEN) != GUID_LEN)
+ if(write(fd, guid, GUID_LEN) != GUID_LEN)
fatal("Cannot write the unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
close(fd);
}
- setenv("NETDATA_REGISTRY_UNIQUE_ID", registry.machine_guid, 1);
+ setenv("NETDATA_REGISTRY_UNIQUE_ID", guid, 1);
- return registry.machine_guid;
+ return guid;
}
diff --git a/src/registry_internals.h b/src/registry_internals.h
index 9c0b74452..433f04a66 100644
--- a/src/registry_internals.h
+++ b/src/registry_internals.h
@@ -14,8 +14,6 @@
struct registry {
int enabled;
- char machine_guid[GUID_LEN + 1];
-
// entries counters / statistics
unsigned long long persons_count;
unsigned long long machines_count;
@@ -58,10 +56,10 @@ struct registry {
avl_tree registry_urls_root_index;
- pthread_mutex_t lock;
+ netdata_mutex_t lock;
};
-extern int registry_regenerate_guid(const char *guid, char *result);
+extern int regenerate_guid(const char *guid, char *result);
#include "registry_url.h"
#include "registry_machine.h"
@@ -70,8 +68,6 @@ extern int registry_regenerate_guid(const char *guid, char *result);
extern struct registry registry;
-extern char *registry_get_this_machine_guid(void);
-
// REGISTRY LOW-LEVEL REQUESTS (in registry-internals.c)
extern REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when);
extern REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
diff --git a/src/registry_machine.c b/src/registry_machine.c
index 3510736df..6dc8200d3 100644
--- a/src/registry_machine.c
+++ b/src/registry_machine.c
@@ -58,7 +58,7 @@ REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
if(likely(machine_guid && *machine_guid)) {
// validate it is a GUID
char buf[GUID_LEN + 1];
- if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
+ if(unlikely(regenerate_guid(machine_guid, buf) == -1))
info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
else {
machine_guid = buf;
diff --git a/src/registry_person.c b/src/registry_person.c
index 5f9099c9a..409c76925 100644
--- a/src/registry_person.c
+++ b/src/registry_person.c
@@ -183,7 +183,7 @@ REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
if(person_guid && *person_guid) {
char buf[GUID_LEN + 1];
// validate it is a GUID
- if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
+ if(unlikely(regenerate_guid(person_guid, buf) == -1))
info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
else {
person_guid = buf;
diff --git a/src/rrd.c b/src/rrd.c
index bd0175efc..a9ff6243d 100644
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -1,7 +1,6 @@
+#define NETDATA_RRD_INTERNALS 1
#include "common.h"
-#define RRD_DEFAULT_GAP_INTERPOLATIONS 1
-
// ----------------------------------------------------------------------------
// globals
@@ -12,402 +11,124 @@
int rrd_delete_unupdated_dimensions = 0;
*/
-int rrd_update_every = UPDATE_EVERY;
-int rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
-int rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
+int default_rrd_update_every = UPDATE_EVERY;
+int default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
+RRD_MEMORY_MODE default_rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
-static int rrdset_compare(void* a, void* b);
-static int rrdset_compare_name(void* a, void* b);
-static int rrdfamily_compare(void *a, void *b);
// ----------------------------------------------------------------------------
-// RRDHOST
-
-RRDHOST localhost = {
- .hostname = "localhost",
- .rrdset_root = NULL,
- .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
- .rrdset_root_index = {
- { NULL, rrdset_compare },
- AVL_LOCK_INITIALIZER
- },
- .rrdset_root_index_name = {
- { NULL, rrdset_compare_name },
- AVL_LOCK_INITIALIZER
- },
- .rrdfamily_root_index = {
- { NULL, rrdfamily_compare },
- AVL_LOCK_INITIALIZER
- },
- .variables_root_index = {
- { NULL, rrdvar_compare },
- AVL_LOCK_INITIALIZER
- },
- .health_log = {
- .next_log_id = 1,
- .next_alarm_id = 1,
- .count = 0,
- .max = 1000,
- .alarms = NULL,
- .alarm_log_rwlock = PTHREAD_RWLOCK_INITIALIZER
- }
-};
-
-void rrdhost_init(char *hostname) {
- localhost.hostname = hostname;
- localhost.health_log.next_log_id =
- localhost.health_log.next_alarm_id = now_realtime_sec();
-}
-
-void rrdhost_rwlock(RRDHOST *host) {
- pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
-}
-
-void rrdhost_rdlock(RRDHOST *host) {
- pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
-}
-
-void rrdhost_unlock(RRDHOST *host) {
- pthread_rwlock_unlock(&host->rrdset_root_rwlock);
-}
-
-void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
- int ret = pthread_rwlock_trywrlock(&host->rrdset_root_rwlock);
-
- if(ret == 0)
- fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
-}
-
-void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
- int ret = pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock);
-
- if(ret == 0)
- fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
-}
-
-// ----------------------------------------------------------------------------
-// RRDFAMILY index
-
-static int rrdfamily_compare(void *a, void *b) {
- if(((RRDFAMILY *)a)->hash_family < ((RRDFAMILY *)b)->hash_family) return -1;
- else if(((RRDFAMILY *)a)->hash_family > ((RRDFAMILY *)b)->hash_family) return 1;
- else return strcmp(((RRDFAMILY *)a)->family, ((RRDFAMILY *)b)->family);
-}
-
-#define rrdfamily_index_add(host, rc) (RRDFAMILY *)avl_insert_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
-#define rrdfamily_index_del(host, rc) (RRDFAMILY *)avl_remove_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
-
-static RRDFAMILY *rrdfamily_index_find(RRDHOST *host, const char *id, uint32_t hash) {
- RRDFAMILY tmp;
- tmp.family = id;
- tmp.hash_family = (hash)?hash:simple_hash(tmp.family);
-
- return (RRDFAMILY *)avl_search_lock(&(host->rrdfamily_root_index), (avl *) &tmp);
-}
-
-RRDFAMILY *rrdfamily_create(const char *id) {
- RRDFAMILY *rc = rrdfamily_index_find(&localhost, id, 0);
- if(!rc) {
- rc = callocz(1, sizeof(RRDFAMILY));
+// RRD - memory modes
- rc->family = strdupz(id);
- rc->hash_family = simple_hash(rc->family);
-
- // initialize the variables index
- avl_init_lock(&rc->variables_root_index, rrdvar_compare);
-
- RRDFAMILY *ret = rrdfamily_index_add(&localhost, rc);
- if(ret != rc)
- fatal("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE");
- }
-
- rc->use_count++;
- return rc;
-}
+inline const char *rrd_memory_mode_name(RRD_MEMORY_MODE id) {
+ switch(id) {
+ case RRD_MEMORY_MODE_RAM:
+ return RRD_MEMORY_MODE_RAM_NAME;
-void rrdfamily_free(RRDFAMILY *rc) {
- rc->use_count--;
- if(!rc->use_count) {
- RRDFAMILY *ret = rrdfamily_index_del(&localhost, rc);
- if(ret != rc)
- fatal("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE");
+ case RRD_MEMORY_MODE_MAP:
+ return RRD_MEMORY_MODE_MAP_NAME;
- if(rc->variables_root_index.avl_tree.root != NULL)
- fatal("RRDFAMILY: INTERNAL ERROR: Variables index of RRDFAMILY '%s' that is freed, is not empty.", rc->family);
+ case RRD_MEMORY_MODE_NONE:
+ return RRD_MEMORY_MODE_NONE_NAME;
- freez((void *)rc->family);
- freez(rc);
+ case RRD_MEMORY_MODE_SAVE:
+ default:
+ return RRD_MEMORY_MODE_SAVE_NAME;
}
}
-// ----------------------------------------------------------------------------
-// RRDSET index
+RRD_MEMORY_MODE rrd_memory_mode_id(const char *name) {
+ if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
+ return RRD_MEMORY_MODE_RAM;
+ else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
+ return RRD_MEMORY_MODE_MAP;
+ else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_NONE_NAME)))
+ return RRD_MEMORY_MODE_NONE;
-static int rrdset_compare(void* a, void* b) {
- if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
- else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
- else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
+ return RRD_MEMORY_MODE_SAVE;
}
-#define rrdset_index_add(host, st) (RRDSET *)avl_insert_lock(&((host)->rrdset_root_index), (avl *)(st))
-#define rrdset_index_del(host, st) (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index), (avl *)(st))
-
-static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
- RRDSET tmp;
- strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
- tmp.hash = (hash)?hash:simple_hash(tmp.id);
-
- return (RRDSET *)avl_search_lock(&(host->rrdset_root_index), (avl *) &tmp);
-}
// ----------------------------------------------------------------------------
-// RRDSET name index
+// RRD - algorithms types
-#define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
+RRD_ALGORITHM rrd_algorithm_id(const char *name) {
+ if(strcmp(name, RRD_ALGORITHM_INCREMENTAL_NAME) == 0)
+ return RRD_ALGORITHM_INCREMENTAL;
-static int rrdset_compare_name(void* a, void* b) {
- RRDSET *A = rrdset_from_avlname(a);
- RRDSET *B = rrdset_from_avlname(b);
+ else if(strcmp(name, RRD_ALGORITHM_ABSOLUTE_NAME) == 0)
+ return RRD_ALGORITHM_ABSOLUTE;
- // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
+ else if(strcmp(name, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME) == 0)
+ return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL;
- if(A->hash_name < B->hash_name) return -1;
- else if(A->hash_name > B->hash_name) return 1;
- else return strcmp(A->name, B->name);
-}
+ else if(strcmp(name, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME) == 0)
+ return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL;
-RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
- void *result;
- // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
- result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
- if(result) return rrdset_from_avlname(result);
- return NULL;
+ else
+ return RRD_ALGORITHM_ABSOLUTE;
}
-RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
- void *result;
- // fprintf(stderr, "DELETING: %s (name: %s)\n", st->id, st->name);
- result = (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index_name), (avl *)(&st->avlname));
- if(result) return rrdset_from_avlname(result);
- return NULL;
-}
+const char *rrd_algorithm_name(RRD_ALGORITHM algorithm) {
+ switch(algorithm) {
+ case RRD_ALGORITHM_ABSOLUTE:
+ default:
+ return RRD_ALGORITHM_ABSOLUTE_NAME;
-static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
- void *result = NULL;
- RRDSET tmp;
- tmp.name = name;
- tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
+ case RRD_ALGORITHM_INCREMENTAL:
+ return RRD_ALGORITHM_INCREMENTAL_NAME;
- // fprintf(stderr, "SEARCHING: %s\n", name);
- result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
- if(result) {
- RRDSET *st = rrdset_from_avlname(result);
- if(strcmp(st->magic, RRDSET_MAGIC))
- error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME;
- // fprintf(stderr, "FOUND: %s\n", name);
- return rrdset_from_avlname(result);
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME;
}
- // fprintf(stderr, "NOT FOUND: %s\n", name);
- return NULL;
}
// ----------------------------------------------------------------------------
-// RRDDIM index
-
-static int rrddim_compare(void* a, void* b) {
- if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
- else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
- else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
-}
-
-#define rrddim_index_add(st, rd) (RRDDIM *)avl_insert_lock(&((st)->dimensions_index), (avl *)(rd))
-#define rrddim_index_del(st,rd ) (RRDDIM *)avl_remove_lock(&((st)->dimensions_index), (avl *)(rd))
+// RRD - chart types
-static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
- RRDDIM tmp;
- strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
- tmp.hash = (hash)?hash:simple_hash(tmp.id);
+inline RRDSET_TYPE rrdset_type_id(const char *name) {
+ if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0))
+ return RRDSET_TYPE_AREA;
- return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
-}
-
-// ----------------------------------------------------------------------------
-// chart types
+ else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0))
+ return RRDSET_TYPE_STACKED;
-int rrdset_type_id(const char *name)
-{
- if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0)) return RRDSET_TYPE_AREA;
- else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0)) return RRDSET_TYPE_STACKED;
- else if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0)) return RRDSET_TYPE_LINE;
- return RRDSET_TYPE_LINE;
+ else // if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0))
+ return RRDSET_TYPE_LINE;
}
-const char *rrdset_type_name(int chart_type)
-{
- static char line[] = RRDSET_TYPE_LINE_NAME;
- static char area[] = RRDSET_TYPE_AREA_NAME;
- static char stacked[] = RRDSET_TYPE_STACKED_NAME;
-
+const char *rrdset_type_name(RRDSET_TYPE chart_type) {
switch(chart_type) {
case RRDSET_TYPE_LINE:
- return line;
+ default:
+ return RRDSET_TYPE_LINE_NAME;
case RRDSET_TYPE_AREA:
- return area;
+ return RRDSET_TYPE_AREA_NAME;
case RRDSET_TYPE_STACKED:
- return stacked;
+ return RRDSET_TYPE_STACKED_NAME;
}
- return line;
-}
-
-// ----------------------------------------------------------------------------
-// load / save
-
-const char *rrd_memory_mode_name(int id)
-{
- static const char ram[] = RRD_MEMORY_MODE_RAM_NAME;
- static const char map[] = RRD_MEMORY_MODE_MAP_NAME;
- static const char save[] = RRD_MEMORY_MODE_SAVE_NAME;
-
- switch(id) {
- case RRD_MEMORY_MODE_RAM:
- return ram;
-
- case RRD_MEMORY_MODE_MAP:
- return map;
-
- case RRD_MEMORY_MODE_SAVE:
- default:
- return save;
- }
-
- return save;
-}
-
-int rrd_memory_mode_id(const char *name)
-{
- if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
- return RRD_MEMORY_MODE_RAM;
- else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
- return RRD_MEMORY_MODE_MAP;
-
- return RRD_MEMORY_MODE_SAVE;
}
-// ----------------------------------------------------------------------------
-// algorithms types
-
-int rrddim_algorithm_id(const char *name)
-{
- if(strcmp(name, RRDDIM_INCREMENTAL_NAME) == 0) return RRDDIM_INCREMENTAL;
- if(strcmp(name, RRDDIM_ABSOLUTE_NAME) == 0) return RRDDIM_ABSOLUTE;
- if(strcmp(name, RRDDIM_PCENT_OVER_ROW_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_ROW_TOTAL;
- if(strcmp(name, RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_DIFF_TOTAL;
- return RRDDIM_ABSOLUTE;
-}
-
-const char *rrddim_algorithm_name(int chart_type)
-{
- static char absolute[] = RRDDIM_ABSOLUTE_NAME;
- static char incremental[] = RRDDIM_INCREMENTAL_NAME;
- static char percentage_of_absolute_row[] = RRDDIM_PCENT_OVER_ROW_TOTAL_NAME;
- static char percentage_of_incremental_row[] = RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME;
-
- switch(chart_type) {
- case RRDDIM_ABSOLUTE:
- return absolute;
-
- case RRDDIM_INCREMENTAL:
- return incremental;
-
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- return percentage_of_absolute_row;
-
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- return percentage_of_incremental_row;
- }
- return absolute;
-}
// ----------------------------------------------------------------------------
-// chart names
+// RRD - cache directory
-char *rrdset_strncpyz_name(char *to, const char *from, size_t length)
-{
- char c, *p = to;
-
- while (length-- && (c = *from++)) {
- if(c != '.' && !isalnum(c))
- c = '_';
-
- *p++ = c;
- }
-
- *p = '\0';
-
- return to;
-}
-
-void rrdset_set_name(RRDSET *st, const char *name)
-{
- if(unlikely(st->name && !strcmp(st->name, name)))
- return;
-
- debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
-
- char b[CONFIG_MAX_VALUE + 1];
- char n[RRD_ID_LENGTH_MAX + 1];
-
- snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
- rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
-
- if(st->name) {
- rrdset_index_del_name(&localhost, st);
- st->name = config_set_default(st->id, "name", b);
- st->hash_name = simple_hash(st->name);
- rrdsetvar_rename_all(st);
- }
- else {
- st->name = config_get(st->id, "name", b);
- st->hash_name = simple_hash(st->name);
- }
-
- pthread_rwlock_wrlock(&st->rwlock);
- RRDDIM *rd;
- for(rd = st->dimensions; rd ;rd = rd->next)
- rrddimvar_rename_all(rd);
- pthread_rwlock_unlock(&st->rwlock);
-
- if(unlikely(rrdset_index_add_name(&localhost, st) != st))
- error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name);
-}
-
-// ----------------------------------------------------------------------------
-// cache directory
-
-char *rrdset_cache_dir(const char *id)
-{
+char *rrdset_cache_dir(RRDHOST *host, const char *id, const char *config_section) {
char *ret = NULL;
- static char *cache_dir = NULL;
- if(!cache_dir) {
- cache_dir = config_get("global", "cache directory", CACHE_DIR);
- int r = mkdir(cache_dir, 0755);
- if(r != 0 && errno != EEXIST)
- error("Cannot create directory '%s'", cache_dir);
- }
-
char b[FILENAME_MAX + 1];
char n[FILENAME_MAX + 1];
rrdset_strncpyz_name(b, id, FILENAME_MAX);
- snprintfz(n, FILENAME_MAX, "%s/%s", cache_dir, b);
- ret = config_get(id, "cache directory", n);
+ snprintfz(n, FILENAME_MAX, "%s/%s", host->cache_dir, b);
+ ret = config_get(config_section, "cache directory", n);
- if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_MAP || host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
int r = mkdir(ret, 0775);
if(r != 0 && errno != EEXIST)
error("Cannot create directory '%s'", ret);
@@ -415,1236 +136,3 @@ char *rrdset_cache_dir(const char *id)
return ret;
}
-
-// ----------------------------------------------------------------------------
-// core functions
-
-void rrdset_reset(RRDSET *st)
-{
- debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
-
- st->last_collected_time.tv_sec = 0;
- st->last_collected_time.tv_usec = 0;
- st->last_updated.tv_sec = 0;
- st->last_updated.tv_usec = 0;
- st->current_entry = 0;
- st->counter = 0;
- st->counter_done = 0;
-
- RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- rd->last_collected_time.tv_sec = 0;
- rd->last_collected_time.tv_usec = 0;
- rd->counter = 0;
- memset(rd->values, 0, rd->entries * sizeof(storage_number));
- }
-}
-static inline long align_entries_to_pagesize(long entries) {
- if(entries < 5) entries = 5;
- if(entries > RRD_HISTORY_ENTRIES_MAX) entries = RRD_HISTORY_ENTRIES_MAX;
-
-#ifdef NETDATA_LOG_ALLOCATIONS
- long page = (size_t)sysconf(_SC_PAGESIZE);
-
- long size = sizeof(RRDDIM) + entries * sizeof(storage_number);
- if(size % page) {
- size -= (size % page);
- size += page;
-
- long n = (size - sizeof(RRDDIM)) / sizeof(storage_number);
- return n;
- }
-
- return entries;
-#else
- return entries;
-#endif
-}
-
-static inline void timeval_align(struct timeval *tv, int update_every) {
- tv->tv_sec -= tv->tv_sec % update_every;
- tv->tv_usec = 500000;
-}
-
-RRDSET *rrdset_create(const char *type, const char *id, const char *name, const char *family, const char *context, const char *title, const char *units, long priority, int update_every, int chart_type)
-{
- if(!type || !type[0]) {
- fatal("Cannot create rrd stats without a type.");
- return NULL;
- }
-
- if(!id || !id[0]) {
- fatal("Cannot create rrd stats without an id.");
- return NULL;
- }
-
- char fullid[RRD_ID_LENGTH_MAX + 1];
- char fullfilename[FILENAME_MAX + 1];
-
- snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
-
- RRDSET *st = rrdset_find(fullid);
- if(st) {
- error("Cannot create rrd stats for '%s', it already exists.", fullid);
- return st;
- }
-
- long rentries = config_get_number(fullid, "history", rrd_default_history_entries);
- long entries = align_entries_to_pagesize(rentries);
- if(entries != rentries) entries = config_set_number(fullid, "history", entries);
-
- int enabled = config_get_boolean(fullid, "enabled", 1);
- if(!enabled) entries = 5;
-
- unsigned long size = sizeof(RRDSET);
- char *cache_dir = rrdset_cache_dir(fullid);
-
- debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
-
- snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
- if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
- if(st) {
- if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
- errno = 0;
- info("Initializing file %s.", fullfilename);
- memset(st, 0, size);
- }
- else if(strcmp(st->id, fullid) != 0) {
- errno = 0;
- error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
- // munmap(st, size);
- // st = NULL;
- memset(st, 0, size);
- }
- else if(st->memsize != size || st->entries != entries) {
- errno = 0;
- error("File %s does not have the desired size. Clearing it.", fullfilename);
- memset(st, 0, size);
- }
- else if(st->update_every != update_every) {
- errno = 0;
- error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
- memset(st, 0, size);
- }
- else if((now_realtime_sec() - st->last_updated.tv_sec) > update_every * entries) {
- errno = 0;
- error("File %s is too old. Clearing it.", fullfilename);
- memset(st, 0, size);
- }
-
- // make sure the database is aligned
- if(st->last_updated.tv_sec)
- timeval_align(&st->last_updated, update_every);
- }
-
- if(st) {
- st->name = NULL;
- st->type = NULL;
- st->family = NULL;
- st->context = NULL;
- st->title = NULL;
- st->units = NULL;
- st->dimensions = NULL;
- st->next = NULL;
- st->mapped = rrd_memory_mode;
- st->variables = NULL;
- st->alarms = NULL;
- memset(&st->rwlock, 0, sizeof(pthread_rwlock_t));
- memset(&st->avl, 0, sizeof(avl));
- memset(&st->avlname, 0, sizeof(avl));
- memset(&st->variables_root_index, 0, sizeof(avl_tree_lock));
- memset(&st->dimensions_index, 0, sizeof(avl_tree_lock));
- }
- else {
- st = callocz(1, size);
- st->mapped = RRD_MEMORY_MODE_RAM;
- }
-
- st->memsize = size;
- st->entries = entries;
- st->update_every = update_every;
-
- if(st->current_entry >= st->entries) st->current_entry = 0;
-
- strcpy(st->cache_filename, fullfilename);
- strcpy(st->magic, RRDSET_MAGIC);
-
- strcpy(st->id, fullid);
- st->hash = simple_hash(st->id);
-
- st->cache_dir = cache_dir;
-
- st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
- st->type = config_get(st->id, "type", type);
- st->family = config_get(st->id, "family", family?family:st->type);
- st->units = config_get(st->id, "units", units?units:"");
-
- st->context = config_get(st->id, "context", context?context:st->id);
- st->hash_context = simple_hash(st->context);
-
- st->priority = config_get_number(st->id, "priority", priority);
- st->enabled = enabled;
-
- st->isdetail = 0;
- st->debug = 0;
-
- // if(!strcmp(st->id, "disk_util.dm-0")) {
- // st->debug = 1;
- // error("enabled debugging for '%s'", st->id);
- // }
- // else error("not enabled debugging for '%s'", st->id);
-
- st->green = NAN;
- st->red = NAN;
-
- st->last_collected_time.tv_sec = 0;
- st->last_collected_time.tv_usec = 0;
- st->counter_done = 0;
-
- st->gap_when_lost_iterations_above = (int) (
- config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
-
- avl_init_lock(&st->dimensions_index, rrddim_compare);
- avl_init_lock(&st->variables_root_index, rrdvar_compare);
-
- pthread_rwlock_init(&st->rwlock, NULL);
- rrdhost_rwlock(&localhost);
-
- if(name && *name) rrdset_set_name(st, name);
- else rrdset_set_name(st, id);
-
- {
- char varvalue[CONFIG_MAX_VALUE + 1];
- char varvalue2[CONFIG_MAX_VALUE + 1];
- snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
- json_escape_string(varvalue2, varvalue, sizeof(varvalue2));
- st->title = config_get(st->id, "title", varvalue2);
- }
-
- st->rrdfamily = rrdfamily_create(st->family);
- st->rrdhost = &localhost;
-
- st->next = localhost.rrdset_root;
- localhost.rrdset_root = st;
-
- if(health_enabled) {
- rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0);
- rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, 0);
- rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, 0);
- rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, 0);
- rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, 0);
- }
-
- if(unlikely(rrdset_index_add(&localhost, st) != st))
- error("RRDSET: INTERNAL ERROR: attempt to index duplicate chart '%s'", st->id);
-
- rrdsetcalc_link_matching(st);
- rrdcalctemplate_link_matching(st);
-
- rrdhost_unlock(&localhost);
-
- return(st);
-}
-
-RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier, long divisor, int algorithm)
-{
- RRDDIM *rd = rrddim_find(st, id);
- if(rd) {
- debug(D_RRD_CALLS, "Cannot create rrd dimension '%s/%s', it already exists.", st->id, name?name:"<NONAME>");
- return rd;
- }
-
- char filename[FILENAME_MAX + 1];
- char fullfilename[FILENAME_MAX + 1];
-
- char varname[CONFIG_MAX_NAME + 1];
- unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
-
- debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
-
- rrdset_strncpyz_name(filename, id, FILENAME_MAX);
- snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
-
- if(rrd_memory_mode != RRD_MEMORY_MODE_RAM)
- rd = (RRDDIM *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 1);
-
- if(rd) {
- struct timeval now;
- now_realtime_timeval(&now);
-
- if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
- errno = 0;
- info("Initializing file %s.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->memsize != size) {
- errno = 0;
- error("File %s does not have the desired size. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->multiplier != multiplier) {
- errno = 0;
- error("File %s does not have the same multiplier. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->divisor != divisor) {
- errno = 0;
- error("File %s does not have the same divisor. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->algorithm != algorithm) {
- errno = 0;
- error("File %s does not have the same algorithm. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(rd->update_every != st->update_every) {
- errno = 0;
- error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(dt_usec(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * USEC_PER_SEC)) {
- errno = 0;
- error("File %s is too old. Clearing it.", fullfilename);
- memset(rd, 0, size);
- }
- else if(strcmp(rd->id, id) != 0) {
- errno = 0;
- error("File %s contents are not for dimension %s. Clearing it.", fullfilename, id);
- // munmap(rd, size);
- // rd = NULL;
- memset(rd, 0, size);
- }
- }
-
- if(rd) {
- // we have a file mapped for rd
- rd->mapped = rrd_memory_mode;
- rd->flags = 0x00000000;
- rd->variables = NULL;
- rd->next = NULL;
- rd->name = NULL;
- memset(&rd->avl, 0, sizeof(avl));
- }
- else {
- // if we didn't manage to get a mmap'd dimension, just create one
-
- rd = callocz(1, size);
- rd->mapped = RRD_MEMORY_MODE_RAM;
- }
- rd->memsize = size;
-
- strcpy(rd->magic, RRDDIMENSION_MAGIC);
- strcpy(rd->cache_filename, fullfilename);
- strncpyz(rd->id, id, RRD_ID_LENGTH_MAX);
- rd->hash = simple_hash(rd->id);
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
- rd->name = config_get(st->id, varname, (name && *name)?name:rd->id);
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
- rd->algorithm = rrddim_algorithm_id(config_get(st->id, varname, rrddim_algorithm_name(algorithm)));
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
- rd->multiplier = config_get_number(st->id, varname, multiplier);
-
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
- rd->divisor = config_get_number(st->id, varname, divisor);
- if(!rd->divisor) rd->divisor = 1;
-
- rd->entries = st->entries;
- rd->update_every = st->update_every;
-
- // prevent incremental calculation spikes
- rd->counter = 0;
- rd->updated = 0;
- rd->calculated_value = 0;
- rd->last_calculated_value = 0;
- rd->collected_value = 0;
- rd->last_collected_value = 0;
- rd->collected_volume = 0;
- rd->stored_volume = 0;
- rd->last_stored_value = 0;
- rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
- rd->last_collected_time.tv_sec = 0;
- rd->last_collected_time.tv_usec = 0;
- rd->rrdset = st;
-
- // append this dimension
- pthread_rwlock_wrlock(&st->rwlock);
- if(!st->dimensions)
- st->dimensions = rd;
- else {
- RRDDIM *td = st->dimensions;
- for(; td->next; td = td->next) ;
- td->next = rd;
- }
-
- if(health_enabled) {
- rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, 0);
- rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, 0);
- rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, 0);
- }
-
- pthread_rwlock_unlock(&st->rwlock);
-
- if(unlikely(rrddim_index_add(st, rd) != rd))
- error("RRDDIM: INTERNAL ERROR: attempt to index duplicate dimension '%s' on chart '%s'", rd->id, st->id);
-
- return(rd);
-}
-
-void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name)
-{
- if(unlikely(rd->name && !strcmp(rd->name, name)))
- return;
-
- debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", st->name, rd->name, st->name, name);
-
- char varname[CONFIG_MAX_NAME + 1];
- snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
- rd->name = config_set_default(st->id, varname, name);
-
- rrddimvar_rename_all(rd);
-}
-
-void rrddim_free(RRDSET *st, RRDDIM *rd)
-{
- debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
-
- if(rd == st->dimensions)
- st->dimensions = rd->next;
- else {
- RRDDIM *i;
- for (i = st->dimensions; i && i->next != rd; i = i->next) ;
-
- if (i && i->next == rd)
- i->next = rd->next;
- else
- error("Request to free dimension '%s.%s' but it is not linked.", st->id, rd->name);
- }
- rd->next = NULL;
-
- while(rd->variables)
- rrddimvar_free(rd->variables);
-
- if(unlikely(rrddim_index_del(st, rd) != rd))
- error("RRDDIM: INTERNAL ERROR: attempt to remove from index dimension '%s' on chart '%s', removed a different dimension.", rd->id, st->id);
-
- // free(rd->annotations);
- if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
- debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
- savememory(rd->cache_filename, rd, rd->memsize);
-
- debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
- munmap(rd, rd->memsize);
- }
- else if(rd->mapped == RRD_MEMORY_MODE_MAP) {
- debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
- munmap(rd, rd->memsize);
- }
- else {
- debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
- freez(rd);
- }
-}
-
-void rrdset_free_all(void)
-{
- info("Freeing all memory...");
-
- rrdhost_rwlock(&localhost);
-
- RRDSET *st;
- for(st = localhost.rrdset_root; st ;) {
- RRDSET *next = st->next;
-
- pthread_rwlock_wrlock(&st->rwlock);
-
- while(st->variables)
- rrdsetvar_free(st->variables);
-
- while(st->alarms)
- rrdsetcalc_unlink(st->alarms);
-
- while(st->dimensions)
- rrddim_free(st, st->dimensions);
-
- if(unlikely(rrdset_index_del(&localhost, st) != st))
- error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
-
- rrdset_index_del_name(&localhost, st);
-
- st->rrdfamily->use_count--;
- if(!st->rrdfamily->use_count)
- rrdfamily_free(st->rrdfamily);
-
- pthread_rwlock_unlock(&st->rwlock);
-
- if(st->mapped == RRD_MEMORY_MODE_SAVE || st->mapped == RRD_MEMORY_MODE_MAP) {
- debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
- munmap(st, st->memsize);
- }
- else
- freez(st);
-
- st = next;
- }
- localhost.rrdset_root = NULL;
-
- rrdhost_unlock(&localhost);
-
- info("Memory cleanup completed...");
-}
-
-void rrdset_save_all(void) {
- info("Saving database...");
-
- RRDSET *st;
- RRDDIM *rd;
-
- // we get an write lock
- // to ensure only one thread is saving the database
- rrdhost_rwlock(&localhost);
-
- for(st = localhost.rrdset_root; st ; st = st->next) {
- pthread_rwlock_rdlock(&st->rwlock);
-
- if(st->mapped == RRD_MEMORY_MODE_SAVE) {
- debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
- savememory(st->cache_filename, st, st->memsize);
- }
-
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(likely(rd->mapped == RRD_MEMORY_MODE_SAVE)) {
- debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
- savememory(rd->cache_filename, rd, rd->memsize);
- }
- }
-
- pthread_rwlock_unlock(&st->rwlock);
- }
-
- rrdhost_unlock(&localhost);
-}
-
-
-RRDSET *rrdset_find(const char *id)
-{
- debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
-
- RRDSET *st = rrdset_index_find(&localhost, id, 0);
- return(st);
-}
-
-RRDSET *rrdset_find_bytype(const char *type, const char *id)
-{
- debug(D_RRD_CALLS, "rrdset_find_bytype() for chart %s.%s", type, id);
-
- char buf[RRD_ID_LENGTH_MAX + 1];
-
- strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
- strcat(buf, ".");
- int len = (int) strlen(buf);
- strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
-
- return(rrdset_find(buf));
-}
-
-RRDSET *rrdset_find_byname(const char *name)
-{
- debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
-
- RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
- return(st);
-}
-
-RRDDIM *rrddim_find(RRDSET *st, const char *id)
-{
- debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
-
- return rrddim_index_find(st, id, 0);
-}
-
-int rrddim_hide(RRDSET *st, const char *id)
-{
- debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
-
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
- return 1;
- }
-
- rd->flags |= RRDDIM_FLAG_HIDDEN;
- return 0;
-}
-
-int rrddim_unhide(RRDSET *st, const char *id)
-{
- debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
-
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
- return 1;
- }
-
- if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
- return 0;
-}
-
-collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
-{
- debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
-
- now_realtime_timeval(&rd->last_collected_time);
- rd->collected_value = value;
- rd->updated = 1;
- rd->counter++;
-
- // fprintf(stderr, "%s.%s %llu " COLLECTED_NUMBER_FORMAT " dt %0.6f" " rate " CALCULATED_NUMBER_FORMAT "\n", st->name, rd->name, st->usec_since_last_update, value, (float)((double)st->usec_since_last_update / (double)1000000), (calculated_number)((value - rd->last_collected_value) * (calculated_number)rd->multiplier / (calculated_number)rd->divisor * 1000000.0 / (calculated_number)st->usec_since_last_update));
-
- return rd->last_collected_value;
-}
-
-collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
-{
- RRDDIM *rd = rrddim_find(st, id);
- if(unlikely(!rd)) {
- error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
- return 0;
- }
-
- return rrddim_set_by_pointer(st, rd, value);
-}
-
-void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds)
-{
- if(unlikely(!st->last_collected_time.tv_sec || !microseconds)) {
- // the first entry
- microseconds = st->update_every * USEC_PER_SEC;
- }
- st->usec_since_last_update = microseconds;
-}
-
-void rrdset_next_usec(RRDSET *st, usec_t microseconds)
-{
- struct timeval now;
- now_realtime_timeval(&now);
-
- if(unlikely(!st->last_collected_time.tv_sec)) {
- // the first entry
- microseconds = st->update_every * USEC_PER_SEC;
- }
- else if(unlikely(!microseconds)) {
- // no dt given by the plugin
- microseconds = dt_usec(&now, &st->last_collected_time);
- }
- else {
- // microseconds has the time since the last collection
- usec_t now_usec = timeval_usec(&now);
- usec_t last_usec = timeval_usec(&st->last_collected_time);
- usec_t since_last_usec = dt_usec(&now, &st->last_collected_time);
-
- // verify the microseconds given is good
- if(unlikely(microseconds > since_last_usec)) {
- debug(D_RRD_CALLS, "dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - since_last_usec, st->name, st->id);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(last_usec + microseconds > now_usec + 1000))
- error("dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - since_last_usec, st->name, st->id);
-#endif
-
- microseconds = since_last_usec;
- }
- else if(unlikely(microseconds < since_last_usec * 0.8)) {
- debug(D_RRD_CALLS, "dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, since_last_usec, st->name, st->id);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- error("dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, since_last_usec, st->name, st->id);
-#endif
- microseconds = since_last_usec;
- }
- }
- debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
- st->usec_since_last_update = microseconds;
-}
-
-usec_t rrdset_done(RRDSET *st)
-{
- if(unlikely(netdata_exit)) return 0;
-
- debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
-
- RRDDIM *rd;
-
- int
- pthreadoldcancelstate; // store the old cancelable pthread state, to restore it at the end
-
- char
- store_this_entry = 1, // boolean: 1 = store this entry, 0 = don't store this entry
- first_entry = 0; // boolean: 1 = this is the first entry seen for this chart, 0 = all other entries
-
- unsigned int
- stored_entries = 0; // the number of entries we have stored in the db, during this call to rrdset_done()
-
- usec_t
- last_collect_ut, // the timestamp in microseconds, of the last collected value
- now_collect_ut, // the timestamp in microseconds, of this collected value (this is NOW)
- last_stored_ut, // the timestamp in microseconds, of the last stored entry in the db
- next_store_ut, // the timestamp in microseconds, of the next entry to store in the db
- update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds
-
- if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
- error("Cannot set pthread cancel state to DISABLE.");
-
- // a read lock is OK here
- pthread_rwlock_rdlock(&st->rwlock);
-
-/*
- // enable the chart, if it was disabled
- if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
- st->enabled = 1;
-*/
-
- // check if the chart has a long time to be updated
- if(unlikely(st->usec_since_last_update > st->entries * update_every_ut)) {
- info("%s: took too long to be updated (%0.3Lf secs). Resetting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
- rrdset_reset(st);
- st->usec_since_last_update = update_every_ut;
- first_entry = 1;
- }
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
-
- // set last_collected_time
- if(unlikely(!st->last_collected_time.tv_sec)) {
- // it is the first entry
- // set the last_collected_time to now
- now_realtime_timeval(&st->last_collected_time);
- timeval_align(&st->last_collected_time, st->update_every);
-
- last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - update_every_ut;
-
- // the first entry should not be stored
- store_this_entry = 0;
- first_entry = 1;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
- }
- else {
- // it is not the first entry
- // calculate the proper last_collected_time, using usec_since_last_update
- last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
- usec_t ut = last_collect_ut + st->usec_since_last_update;
- st->last_collected_time.tv_sec = (time_t) (ut / USEC_PER_SEC);
- st->last_collected_time.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
- }
-
- // if this set has not been updated in the past
- // we fake the last_update time to be = now - usec_since_last_update
- if(unlikely(!st->last_updated.tv_sec)) {
- // it has never been updated before
- // set a fake last_updated, in the past using usec_since_last_update
- usec_t ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - st->usec_since_last_update;
- st->last_updated.tv_sec = (time_t) (ut / USEC_PER_SEC);
- st->last_updated.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
-
- // the first entry should not be stored
- store_this_entry = 0;
- first_entry = 1;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
- }
-
- // check if we will re-write the entire data set
- if(unlikely(dt_usec(&st->last_collected_time, &st->last_updated) > st->entries * update_every_ut)) {
- info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Resetting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
- rrdset_reset(st);
-
- st->usec_since_last_update = update_every_ut;
-
- now_realtime_timeval(&st->last_collected_time);
- timeval_align(&st->last_collected_time, st->update_every);
-
- usec_t ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - st->usec_since_last_update;
- st->last_updated.tv_sec = (time_t) (ut / USEC_PER_SEC);
- st->last_updated.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
-
- // the first entry should not be stored
- store_this_entry = 0;
- first_entry = 1;
- }
-
- // these are the 3 variables that will help us in interpolation
- // last_stored_ut = the last time we added a value to the storage
- // now_collect_ut = the time the current value has been collected
- // next_store_ut = the time of the next interpolation point
- last_stored_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec;
- now_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
- next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC;
-
- if(unlikely(st->debug)) {
- debug(D_RRD_STATS, "%s: last_collect_ut = %0.3Lf (last collection time)", st->name, (long double)last_collect_ut/1000000.0);
- debug(D_RRD_STATS, "%s: now_collect_ut = %0.3Lf (current collection time)", st->name, (long double)now_collect_ut/1000000.0);
- debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
- debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
- }
-
- if(unlikely(!st->counter_done)) {
- store_this_entry = 0;
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
- }
- st->counter_done++;
-
- // calculate totals and count the dimensions
- int dimensions;
- st->collected_total = 0;
- for( rd = st->dimensions, dimensions = 0 ; rd ; rd = rd->next, dimensions++ )
- if(likely(rd->updated)) st->collected_total += rd->collected_value;
-
- uint32_t storage_flags = SN_EXISTS;
-
- // process all dimensions to calculate their values
- // based on the collected figures only
- // at this stage we do not interpolate anything
- for( rd = st->dimensions ; rd ; rd = rd->next ) {
-
- if(unlikely(!rd->updated)) {
- rd->calculated_value = 0;
- continue;
- }
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
- " last_collected_value = " COLLECTED_NUMBER_FORMAT
- " collected_value = " COLLECTED_NUMBER_FORMAT
- " last_calculated_value = " CALCULATED_NUMBER_FORMAT
- " calculated_value = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->last_collected_value
- , rd->collected_value
- , rd->last_calculated_value
- , rd->calculated_value
- );
-
- switch(rd->algorithm) {
- case RRDDIM_ABSOLUTE:
- rd->calculated_value = (calculated_number)rd->collected_value
- * (calculated_number)rd->multiplier
- / (calculated_number)rd->divisor;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
- CALCULATED_NUMBER_FORMAT " = "
- COLLECTED_NUMBER_FORMAT
- " * " CALCULATED_NUMBER_FORMAT
- " / " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value
- , (calculated_number)rd->multiplier
- , (calculated_number)rd->divisor
- );
- break;
-
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- if(unlikely(!st->collected_total))
- rd->calculated_value = 0;
- else
- // the percentage of the current value
- // over the total of all dimensions
- rd->calculated_value =
- (calculated_number)100
- * (calculated_number)rd->collected_value
- / (calculated_number)st->collected_total;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
- CALCULATED_NUMBER_FORMAT " = 100"
- " * " COLLECTED_NUMBER_FORMAT
- " / " COLLECTED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value
- , st->collected_total
- );
- break;
-
- case RRDDIM_INCREMENTAL:
- if(unlikely(rd->counter <= 1)) {
- rd->calculated_value = 0;
- continue;
- }
-
- // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
- // to reset the calculation (it will give zero as the calculation for this second)
- if(unlikely(rd->last_collected_value > rd->collected_value)) {
- debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
- , st->name, rd->name
- , rd->last_collected_value
- , rd->collected_value);
- if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
- rd->last_collected_value = rd->collected_value;
- }
-
- rd->calculated_value +=
- (calculated_number)(rd->collected_value - rd->last_collected_value)
- * (calculated_number)rd->multiplier
- / (calculated_number)rd->divisor;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
- CALCULATED_NUMBER_FORMAT " = ("
- COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
- ")"
- " * " CALCULATED_NUMBER_FORMAT
- " / " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value, rd->last_collected_value
- , (calculated_number)rd->multiplier
- , (calculated_number)rd->divisor
- );
- break;
-
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- if(unlikely(rd->counter <= 1)) {
- rd->calculated_value = 0;
- continue;
- }
-
- // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
- // to reset the calculation (it will give zero as the calculation for this second)
- if(unlikely(rd->last_collected_value > rd->collected_value)) {
- debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
- , st->name, rd->name
- , rd->last_collected_value
- , rd->collected_value);
- if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
- rd->last_collected_value = rd->collected_value;
- }
-
- // the percentage of the current increment
- // over the increment of all dimensions together
- if(unlikely(st->collected_total == st->last_collected_total))
- rd->calculated_value = 0;
- else
- rd->calculated_value =
- (calculated_number)100
- * (calculated_number)(rd->collected_value - rd->last_collected_value)
- / (calculated_number)(st->collected_total - st->last_collected_total);
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
- CALCULATED_NUMBER_FORMAT " = 100"
- " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
- " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
- , st->id, rd->name
- , rd->calculated_value
- , rd->collected_value, rd->last_collected_value
- , st->collected_total, st->last_collected_total
- );
- break;
-
- default:
- // make the default zero, to make sure
- // it gets noticed when we add new types
- rd->calculated_value = 0;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC "
- CALCULATED_NUMBER_FORMAT " = 0"
- , st->id, rd->name
- , rd->calculated_value
- );
- break;
- }
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
- " last_collected_value = " COLLECTED_NUMBER_FORMAT
- " collected_value = " COLLECTED_NUMBER_FORMAT
- " last_calculated_value = " CALCULATED_NUMBER_FORMAT
- " calculated_value = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->last_collected_value
- , rd->collected_value
- , rd->last_calculated_value
- , rd->calculated_value
- );
-
- }
-
- // at this point we have all the calculated values ready
- // it is now time to interpolate values on a second boundary
-
- if(unlikely(now_collect_ut < next_store_ut)) {
- // this is collected in the same interpolation point
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
-#ifdef NETDATA_INTERNAL_CHECKS
- info("%s is collected in the same interpolation point: short by %llu microseconds", st->name, next_store_ut - now_collect_ut);
-#endif
- }
-
- usec_t first_ut = last_stored_ut;
- long long iterations = (now_collect_ut - last_stored_ut) / (update_every_ut);
- if((now_collect_ut % (update_every_ut)) == 0) iterations++;
-
- for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
-#ifdef NETDATA_INTERNAL_CHECKS
- if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_stored_ut = %llu, next_store_ut = %llu, now_collect_ut = %llu", st->name, first_ut, last_stored_ut, next_store_ut, now_collect_ut); }
-#endif
-
- if(unlikely(st->debug)) {
- debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
- debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
- }
-
- st->last_updated.tv_sec = (time_t) (next_store_ut / USEC_PER_SEC);
- st->last_updated.tv_usec = 0;
-
- for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
- calculated_number new_value;
-
- switch(rd->algorithm) {
- case RRDDIM_INCREMENTAL:
- new_value = (calculated_number)
- ( rd->calculated_value
- * (calculated_number)(next_store_ut - last_collect_ut)
- / (calculated_number)(now_collect_ut - last_collect_ut)
- );
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC2 INC "
- CALCULATED_NUMBER_FORMAT " = "
- CALCULATED_NUMBER_FORMAT
- " * %llu"
- " / %llu"
- , st->id, rd->name
- , new_value
- , rd->calculated_value
- , (next_store_ut - last_stored_ut)
- , (now_collect_ut - last_stored_ut)
- );
-
- rd->calculated_value -= new_value;
- new_value += rd->last_calculated_value;
- rd->last_calculated_value = 0;
- new_value /= (calculated_number)st->update_every;
-
- if(unlikely(next_store_ut - last_stored_ut < update_every_ut)) {
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: COLLECTION POINT IS SHORT " CALCULATED_NUMBER_FORMAT " - EXTRAPOLATING",
- st->id, rd->name
- , (calculated_number)(next_store_ut - last_stored_ut)
- );
- new_value = new_value * (calculated_number)(st->update_every * 1000000) / (calculated_number)(next_store_ut - last_stored_ut);
- }
- break;
-
- case RRDDIM_ABSOLUTE:
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- default:
- if(iterations == 1) {
- // this is the last iteration
- // do not interpolate
- // just show the calculated value
-
- new_value = rd->calculated_value;
- }
- else {
- // we have missed an update
- // interpolate in the middle values
-
- new_value = (calculated_number)
- ( ( (rd->calculated_value - rd->last_calculated_value)
- * (calculated_number)(next_store_ut - last_collect_ut)
- / (calculated_number)(now_collect_ut - last_collect_ut)
- )
- + rd->last_calculated_value
- );
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
- CALCULATED_NUMBER_FORMAT " = ((("
- "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
- " * %llu"
- " / %llu) + " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , new_value
- , rd->calculated_value, rd->last_calculated_value
- , (next_store_ut - first_ut)
- , (now_collect_ut - first_ut), rd->last_calculated_value
- );
- }
- break;
- }
-
- if(unlikely(!store_this_entry)) {
- rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
- continue;
- }
-
- if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
- rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
- rd->last_stored_value = new_value;
-
- if(unlikely(st->debug))
- debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
- CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , st->current_entry
- , unpack_storage_number(rd->values[st->current_entry]), new_value
- );
- }
- else {
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
- , st->id, rd->name
- , st->current_entry
- );
- rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
- rd->last_stored_value = NAN;
- }
-
- stored_entries++;
-
- if(unlikely(st->debug)) {
- calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
- calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
- calculated_number accuracy = accuracy_loss(t1, t2);
- debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
- , st->id, rd->name
- , st->current_entry
- , t2
- , get_storage_number_flags(rd->values[st->current_entry])
- , t1
- , accuracy
- , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
- );
-
- rd->collected_volume += t1;
- rd->stored_volume += t2;
- accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
- debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
- , st->id, rd->name
- , st->current_entry
- , rd->stored_volume
- , rd->collected_volume
- , accuracy
- , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
- );
-
- }
- }
- // reset the storage flags for the next point, if any;
- storage_flags = SN_EXISTS;
-
- st->counter++;
- st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
- last_stored_ut = next_store_ut;
- }
-
- st->last_collected_total = st->collected_total;
-
- for( rd = st->dimensions; rd ; rd = rd->next ) {
- if(unlikely(!rd->updated)) continue;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
- rd->last_collected_value = rd->collected_value;
-
- switch(rd->algorithm) {
- case RRDDIM_INCREMENTAL:
- if(unlikely(!first_entry)) {
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value + rd->calculated_value, rd->calculated_value);
- rd->last_calculated_value += rd->calculated_value;
- }
- else {
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS THE FIRST POINT", st->name);
- }
- break;
-
- case RRDDIM_ABSOLUTE:
- case RRDDIM_PCENT_OVER_ROW_TOTAL:
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
- rd->last_calculated_value = rd->calculated_value;
- break;
- }
-
- rd->calculated_value = 0;
- rd->collected_value = 0;
- rd->updated = 0;
-
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
- " last_collected_value = " COLLECTED_NUMBER_FORMAT
- " collected_value = " COLLECTED_NUMBER_FORMAT
- " last_calculated_value = " CALCULATED_NUMBER_FORMAT
- " calculated_value = " CALCULATED_NUMBER_FORMAT
- , st->id, rd->name
- , rd->last_collected_value
- , rd->collected_value
- , rd->last_calculated_value
- , rd->calculated_value
- );
- }
-
- // ALL DONE ABOUT THE DATA UPDATE
- // --------------------------------------------------------------------
-
-/*
- // find if there are any obsolete dimensions (not updated recently)
- if(unlikely(rrd_delete_unupdated_dimensions)) {
-
- for( rd = st->dimensions; likely(rd) ; rd = rd->next )
- if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
- break;
-
- if(unlikely(rd)) {
- RRDDIM *last;
- // there is dimension to free
- // upgrade our read lock to a write lock
- pthread_rwlock_unlock(&st->rwlock);
- pthread_rwlock_wrlock(&st->rwlock);
-
- for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
- // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
-
- if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
- info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
-
- if(unlikely(!last)) {
- st->dimensions = rd->next;
- rd->next = NULL;
- rrddim_free(st, rd);
- rd = st->dimensions;
- continue;
- }
- else {
- last->next = rd->next;
- rd->next = NULL;
- rrddim_free(st, rd);
- rd = last->next;
- continue;
- }
- }
-
- last = rd;
- rd = rd->next;
- }
-
- if(unlikely(!st->dimensions)) {
- info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
- st->enabled = 0;
- }
- }
- }
-*/
-
- pthread_rwlock_unlock(&st->rwlock);
-
- if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
- error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
-
- return(st->usec_since_last_update);
-}
diff --git a/src/rrd.h b/src/rrd.h
index dbaf98650..2f4f2127f 100644
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -3,20 +3,17 @@
#define UPDATE_EVERY 1
#define UPDATE_EVERY_MAX 3600
-extern int rrd_update_every;
#define RRD_DEFAULT_HISTORY_ENTRIES 3600
#define RRD_HISTORY_ENTRIES_MAX (86400*10)
-extern int rrd_default_history_entries;
-// time in seconds to delete unupdated dimensions
-// set to zero to disable this feature
-extern int rrd_delete_unupdated_dimensions;
+extern int default_rrd_update_every;
+extern int default_rrd_history_entries;
-#define RRD_ID_LENGTH_MAX 400
+#define RRD_ID_LENGTH_MAX 200
-#define RRDSET_MAGIC "NETDATA RRD SET FILE V018"
-#define RRDDIMENSION_MAGIC "NETDATA RRD DIMENSION FILE V018"
+#define RRDSET_MAGIC "NETDATA RRD SET FILE V019"
+#define RRDDIMENSION_MAGIC "NETDATA RRD DIMENSION FILE V019"
typedef long long total_number;
#define TOTAL_NUMBER_FORMAT "%lld"
@@ -24,59 +21,61 @@ typedef long long total_number;
// ----------------------------------------------------------------------------
// chart types
+typedef enum rrdset_type {
+ RRDSET_TYPE_LINE = 0,
+ RRDSET_TYPE_AREA = 1,
+ RRDSET_TYPE_STACKED = 2
+} RRDSET_TYPE;
+
#define RRDSET_TYPE_LINE_NAME "line"
#define RRDSET_TYPE_AREA_NAME "area"
#define RRDSET_TYPE_STACKED_NAME "stacked"
-#define RRDSET_TYPE_LINE 0
-#define RRDSET_TYPE_AREA 1
-#define RRDSET_TYPE_STACKED 2
-
-int rrdset_type_id(const char *name);
-const char *rrdset_type_name(int chart_type);
+RRDSET_TYPE rrdset_type_id(const char *name);
+const char *rrdset_type_name(RRDSET_TYPE chart_type);
// ----------------------------------------------------------------------------
// memory mode
+typedef enum rrd_memory_mode {
+ RRD_MEMORY_MODE_NONE = 0,
+ RRD_MEMORY_MODE_RAM = 1,
+ RRD_MEMORY_MODE_MAP = 2,
+ RRD_MEMORY_MODE_SAVE = 3
+} RRD_MEMORY_MODE;
+
+#define RRD_MEMORY_MODE_NONE_NAME "none"
#define RRD_MEMORY_MODE_RAM_NAME "ram"
#define RRD_MEMORY_MODE_MAP_NAME "map"
#define RRD_MEMORY_MODE_SAVE_NAME "save"
-#define RRD_MEMORY_MODE_RAM 0
-#define RRD_MEMORY_MODE_MAP 1
-#define RRD_MEMORY_MODE_SAVE 2
-
-extern int rrd_memory_mode;
+extern RRD_MEMORY_MODE default_rrd_memory_mode;
-extern const char *rrd_memory_mode_name(int id);
-extern int rrd_memory_mode_id(const char *name);
+extern const char *rrd_memory_mode_name(RRD_MEMORY_MODE id);
+extern RRD_MEMORY_MODE rrd_memory_mode_id(const char *name);
// ----------------------------------------------------------------------------
// algorithms types
-#define RRDDIM_ABSOLUTE_NAME "absolute"
-#define RRDDIM_INCREMENTAL_NAME "incremental"
-#define RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
-#define RRDDIM_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
+typedef enum rrd_algorithm {
+ RRD_ALGORITHM_ABSOLUTE = 0,
+ RRD_ALGORITHM_INCREMENTAL = 1,
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL = 2,
+ RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL = 3
+} RRD_ALGORITHM;
-#define RRDDIM_ABSOLUTE 0
-#define RRDDIM_INCREMENTAL 1
-#define RRDDIM_PCENT_OVER_DIFF_TOTAL 2
-#define RRDDIM_PCENT_OVER_ROW_TOTAL 3
-
-extern int rrddim_algorithm_id(const char *name);
-extern const char *rrddim_algorithm_name(int chart_type);
-
-// ----------------------------------------------------------------------------
-// flags
+#define RRD_ALGORITHM_ABSOLUTE_NAME "absolute"
+#define RRD_ALGORITHM_INCREMENTAL_NAME "incremental"
+#define RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
+#define RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
-#define RRDDIM_FLAG_HIDDEN 0x00000001 // this dimension will not be offered to callers
-#define RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS 0x00000002 // do not offer RESET or OVERFLOW info to callers
+extern RRD_ALGORITHM rrd_algorithm_id(const char *name);
+extern const char *rrd_algorithm_name(RRD_ALGORITHM algorithm);
// ----------------------------------------------------------------------------
-// RRD CONTEXT
+// RRD FAMILY
struct rrdfamily {
avl avl;
@@ -90,8 +89,25 @@ struct rrdfamily {
};
typedef struct rrdfamily RRDFAMILY;
+
+// ----------------------------------------------------------------------------
+// flags
+// use this for configuration flags, not for state control
+// flags are set/unset in a manner that is not thread safe
+// and may lead to missing information.
+
+typedef enum rrddim_flags {
+ RRDDIM_FLAG_HIDDEN = 1 << 0, // this dimension will not be offered to callers
+ RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS = 1 << 1 // do not offer RESET or OVERFLOW info to callers
+} RRDDIM_FLAGS;
+
+#define rrddim_flag_check(rd, flag) ((rd)->flags & flag)
+#define rrddim_flag_set(rd, flag) (rd)->flags |= flag
+#define rrddim_flag_clear(rd, flag) (rd)->flags &= ~flag
+
+
// ----------------------------------------------------------------------------
-// RRD DIMENSION
+// RRD DIMENSION - this is a metric
struct rrddim {
// ------------------------------------------------------------------------
@@ -102,18 +118,20 @@ struct rrddim {
// ------------------------------------------------------------------------
// the dimension definition
- char id[RRD_ID_LENGTH_MAX + 1]; // the id of this dimension (for internal identification)
-
+ const char *id; // the id of this dimension (for internal identification)
const char *name; // the name of this dimension (as presented to user)
// this is a pointer to the config structure
// since the config always has a higher priority
// (the user overwrites the name of the charts)
+ // DO NOT FREE THIS - IT IS ALLOCATED IN CONFIG
+
+ RRD_ALGORITHM algorithm; // the algorithm that is applied to add new collected values
+ RRD_MEMORY_MODE rrd_memory_mode; // the memory mode for this dimension
- int algorithm; // the algorithm that is applied to add new collected values
- long multiplier; // the multiplier of the collected values
- long divisor; // the divider of the collected values
+ collected_number multiplier; // the multiplier of the collected values
+ collected_number divisor; // the divider of the collected values
- int mapped; // if set to non zero, this dimension is mapped to a file
+ uint32_t flags; // configuration flags for the dimension
// ------------------------------------------------------------------------
// members for temporary data we need for calculations
@@ -122,17 +140,15 @@ struct rrddim {
// instead of strcmp() every item in the binary index
// we first compare the hashes
- // FIXME
- // we need the hash_name too!
+ uint32_t hash_name; // a simple hash of the name
- uint32_t flags;
+ char *cache_filename; // the filename we load/save from/to this set
- char cache_filename[FILENAME_MAX+1]; // the filename we load/save from/to this set
+ size_t collections_counter; // the number of times we added values to this rrdim
+ size_t unused[10];
- unsigned long counter; // the number of times we added values to this rrdim
-
- int updated; // set to 0 after each calculation, to 1 after each collected value
- // we use this to detect that a dimension is not updated
+ int updated:1; // 1 when the dimension has been updated since the last processing
+ int exposed:1; // 1 when set what have sent this dimension to the central netdata
struct timeval last_collected_time; // when was this dimension last updated
// this is actual date time we updated the last_collected_value
@@ -163,7 +179,7 @@ struct rrddim {
int update_every; // every how many seconds is this updated
- unsigned long memsize; // the memory allocated for this dimension
+ size_t memsize; // the memory allocated for this dimension
char magic[sizeof(RRDDIMENSION_MAGIC) + 1]; // a string to be saved, used to identify our data file
@@ -176,9 +192,34 @@ struct rrddim {
};
typedef struct rrddim RRDDIM;
+// ----------------------------------------------------------------------------
+// these loop macros make sure the linked list is accessed with the right lock
+
+#define rrddim_foreach_read(rd, st) \
+ for(rd = st->dimensions, rrdset_check_rdlock(st); rd ; rd = rd->next)
+
+#define rrddim_foreach_write(rd, st) \
+ for(rd = st->dimensions, rrdset_check_wrlock(st); rd ; rd = rd->next)
+
// ----------------------------------------------------------------------------
-// RRDSET
+// RRDSET - this is a chart
+
+// use this for configuration flags, not for state control
+// flags are set/unset in a manner that is not thread safe
+// and may lead to missing information.
+
+typedef enum rrdset_flags {
+ RRDSET_FLAG_ENABLED = 1 << 0, // enables or disables a chart
+ RRDSET_FLAG_DETAIL = 1 << 1, // if set, the data set should be considered as a detail of another
+ // (the master data set should be the one that has the same family and is not detail)
+ RRDSET_FLAG_DEBUG = 1 << 2, // enables or disables debugging for a chart
+ RRDSET_FLAG_OBSOLETE = 1 << 3 // this is marked by the collector/module as obsolete
+} RRDSET_FLAGS;
+
+#define rrdset_flag_check(st, flag) ((st)->flags & flag)
+#define rrdset_flag_set(st, flag) (st)->flags |= flag
+#define rrdset_flag_clear(st, flag) (st)->flags &= ~flag
struct rrdset {
// ------------------------------------------------------------------------
@@ -197,6 +238,8 @@ struct rrdset {
// since the config always has a higher priority
// (the user overwrites the name of the charts)
+ char *config_section; // the config section for the chart
+
char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
char *family; // grouping sets under the same family
char *title; // title shown to user
@@ -205,7 +248,7 @@ struct rrdset {
char *context; // the template of this data set
uint32_t hash_context;
- int chart_type;
+ RRDSET_TYPE chart_type;
int update_every; // every how many seconds is this updated?
@@ -214,30 +257,29 @@ struct rrdset {
long current_entry; // the entry that is currently being updated
// it goes around in a round-robin fashion
- int enabled;
+ uint32_t flags; // configuration flags
int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored
// netdata will interpolate values for gaps lower than this
long priority;
- int isdetail; // if set, the data set should be considered as a detail of another
- // (the master data set should be the one that has the same family and is not detail)
// ------------------------------------------------------------------------
// members for temporary data we need for calculations
- int mapped; // if set to 1, this is memory mapped
-
- int debug;
+ RRD_MEMORY_MODE rrd_memory_mode; // if set to 1, this is memory mapped
char *cache_dir; // the directory to store dimensions
char cache_filename[FILENAME_MAX+1]; // the filename to store this set
- pthread_rwlock_t rwlock;
+ netdata_rwlock_t rrdset_rwlock; // protects dimensions linked list
+
+ size_t counter; // the number of times we added values to this database
+ size_t counter_done; // the number of times rrdset_done() has been called
- unsigned long counter; // the number of times we added values to this rrd
- unsigned long counter_done; // the number of times we added values to this rrd
+ time_t last_accessed_time; // the last time this RRDSET has been accessed
+ size_t unused[9];
uint32_t hash; // a simple hash on the id, to speed up searching
// we first compare hashes, and only if the hashes are equal we do string comparisons
@@ -283,83 +325,248 @@ struct rrdset {
};
typedef struct rrdset RRDSET;
+#define rrdset_rdlock(st) netdata_rwlock_rdlock(&((st)->rrdset_rwlock))
+#define rrdset_wrlock(st) netdata_rwlock_wrlock(&((st)->rrdset_rwlock))
+#define rrdset_unlock(st) netdata_rwlock_unlock(&((st)->rrdset_rwlock))
+
+
+// ----------------------------------------------------------------------------
+// these loop macros make sure the linked list is accessed with the right lock
+
+#define rrdset_foreach_read(st, host) \
+ for(st = host->rrdset_root, rrdhost_check_rdlock(host); st ; st = st->next)
+
+#define rrdset_foreach_write(st, host) \
+ for(st = host->rrdset_root, rrdhost_check_wrlock(host); st ; st = st->next)
+
+
+// ----------------------------------------------------------------------------
+// RRDHOST flags
+// use this for configuration flags, not for state control
+// flags are set/unset in a manner that is not thread safe
+// and may lead to missing information.
+
+typedef enum rrdhost_flags {
+ RRDHOST_ORPHAN = 1 << 0, // this host is orphan
+ RRDHOST_DELETE_OBSOLETE_FILES = 1 << 1, // delete files of obsolete charts
+ RRDHOST_DELETE_ORPHAN_FILES = 1 << 2 // delete the entire host when orphan
+} RRDHOST_FLAGS;
+
+#define rrdhost_flag_check(host, flag) ((host)->flags & flag)
+#define rrdhost_flag_set(host, flag) (host)->flags |= flag
+#define rrdhost_flag_clear(host, flag) (host)->flags &= ~flag
+
// ----------------------------------------------------------------------------
// RRD HOST
struct rrdhost {
- avl avl;
+ avl avl; // the index of hosts
- char *hostname;
+ // ------------------------------------------------------------------------
+ // host information
- RRDSET *rrdset_root;
- pthread_rwlock_t rrdset_root_rwlock;
+ char *hostname; // the hostname of this host
+ uint32_t hash_hostname; // the hostname hash
- avl_tree_lock rrdset_root_index;
- avl_tree_lock rrdset_root_index_name;
+ char machine_guid[GUID_LEN + 1]; // the unique ID of this host
+ uint32_t hash_machine_guid; // the hash of the unique ID
- avl_tree_lock rrdfamily_root_index;
- avl_tree_lock variables_root_index;
+ char *os; // the O/S type of the host
+
+ uint32_t flags; // flags about this RRDHOST
+
+ int rrd_update_every; // the update frequency of the host
+ long rrd_history_entries; // the number of history entries for the host's charts
+ RRD_MEMORY_MODE rrd_memory_mode; // the memory more for the charts of this host
+
+ char *cache_dir; // the directory to save RRD cache files
+ char *varlib_dir; // the directory to save health log
+
+
+ // ------------------------------------------------------------------------
+ // streaming of data to remote hosts - rrdpush
+
+ int rrdpush_enabled:1; // 1 when this host sends metrics to another netdata
+ char *rrdpush_destination; // where to send metrics to
+ char *rrdpush_api_key; // the api key at the receiving netdata
+ volatile int rrdpush_connected:1; // 1 when the sender is ready to push metrics
+ volatile int rrdpush_spawn:1; // 1 when the sender thread has been spawn
+ volatile int rrdpush_error_shown:1; // 1 when we have logged a communication error
+ int rrdpush_socket; // the fd of the socket to the remote host, or -1
+ pthread_t rrdpush_thread; // the sender thread
+ netdata_mutex_t rrdpush_mutex; // exclusive access to rrdpush_buffer
+ int rrdpush_pipe[2]; // collector to sender thread communication
+ BUFFER *rrdpush_buffer; // collector fills it, sender sends them
+
+
+ // ------------------------------------------------------------------------
+ // streaming of data from remote hosts - rrdpush
+
+ volatile size_t connected_senders; // when remote hosts are streaming to this
+ // host, this is the counter of connected clients
+
+ time_t senders_disconnected_time; // the time the last sender was disconnected
+
+ // ------------------------------------------------------------------------
+ // health monitoring options
+
+ int health_enabled:1; // 1 when this host has health enabled
+ time_t health_delay_up_to; // a timestamp to delay alarms processing up to
+ char *health_default_exec; // the full path of the alarms notifications program
+ char *health_default_recipient; // the default recipient for all alarms
+ char *health_log_filename; // the alarms event log filename
+ size_t health_log_entries_written; // the number of alarm events writtern to the alarms event log
+ FILE *health_log_fp; // the FILE pointer to the open alarms event log file
// all RRDCALCs are primarily allocated and linked here
// RRDCALCs may be linked to charts at any point
// (charts may or may not exist when these are loaded)
RRDCALC *alarms;
- ALARM_LOG health_log;
+ ALARM_LOG health_log; // alarms historical events (event log)
+
+ // templates of alarms
+ // these are used to create alarms when charts
+ // are created or renamed, that match them
RRDCALCTEMPLATE *templates;
+
+
+ // ------------------------------------------------------------------------
+ // the charts of the host
+
+ RRDSET *rrdset_root; // the host charts
+
+
+ // ------------------------------------------------------------------------
+ // locks
+
+ netdata_rwlock_t rrdhost_rwlock; // lock for this RRDHOST (protects rrdset_root linked list)
+
+ avl_tree_lock rrdset_root_index; // the host's charts index (by id)
+ avl_tree_lock rrdset_root_index_name; // the host's charts index (by name)
+
+ avl_tree_lock rrdfamily_root_index; // the host's chart families index
+ avl_tree_lock variables_root_index; // the host's chart variables index
+
+ struct rrdhost *next;
};
typedef struct rrdhost RRDHOST;
-extern RRDHOST localhost;
-extern void rrdhost_init(char *hostname);
+extern RRDHOST *localhost;
+
+#define rrdhost_rdlock(host) netdata_rwlock_rdlock(&((host)->rrdhost_rwlock))
+#define rrdhost_wrlock(host) netdata_rwlock_wrlock(&((host)->rrdhost_rwlock))
+#define rrdhost_unlock(host) netdata_rwlock_unlock(&((host)->rrdhost_rwlock))
+
+// ----------------------------------------------------------------------------
+// these loop macros make sure the linked list is accessed with the right lock
+
+#define rrdhost_foreach_read(var) \
+ for(var = localhost, rrd_check_rdlock(); var ; var = var->next)
+
+#define rrdhost_foreach_write(var) \
+ for(var = localhost, rrd_check_wrlock(); var ; var = var->next)
+
+
+// ----------------------------------------------------------------------------
+// global lock for all RRDHOSTs
+
+extern netdata_rwlock_t rrd_rwlock;
+
+#define rrd_rdlock() netdata_rwlock_rdlock(&rrd_rwlock)
+#define rrd_wrlock() netdata_rwlock_wrlock(&rrd_rwlock)
+#define rrd_unlock() netdata_rwlock_unlock(&rrd_rwlock)
+
+// ----------------------------------------------------------------------------
+
+extern size_t rrd_hosts_available;
+extern time_t rrdhost_free_orphan_time;
+
+extern void rrd_init(char *hostname);
+
+extern RRDHOST *rrdhost_find_by_hostname(const char *hostname, uint32_t hash);
+extern RRDHOST *rrdhost_find_by_guid(const char *guid, uint32_t hash);
+
+extern RRDHOST *rrdhost_find_or_create(
+ const char *hostname
+ , const char *guid
+ , const char *os
+ , int update_every
+ , long history
+ , RRD_MEMORY_MODE mode
+ , int health_enabled
+ , int rrdpush_enabled
+ , char *rrdpush_destination
+ , char *rrdpush_api_key
+);
+
+#if defined(NETDATA_INTERNAL_CHECKS) && defined(NETDATA_VERIFY_LOCKS)
+extern void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line);
+extern void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line);
+extern void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line);
+extern void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line);
+extern void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line);
+extern void __rrd_check_wrlock(const char *file, const char *function, const unsigned long line);
+
+#define rrdhost_check_rdlock(host) __rrdhost_check_rdlock(host, __FILE__, __FUNCTION__, __LINE__)
+#define rrdhost_check_wrlock(host) __rrdhost_check_wrlock(host, __FILE__, __FUNCTION__, __LINE__)
+#define rrdset_check_rdlock(st) __rrdset_check_rdlock(st, __FILE__, __FUNCTION__, __LINE__)
+#define rrdset_check_wrlock(st) __rrdset_check_wrlock(st, __FILE__, __FUNCTION__, __LINE__)
+#define rrd_check_rdlock() __rrd_check_rdlock(__FILE__, __FUNCTION__, __LINE__)
+#define rrd_check_wrlock() __rrd_check_wrlock(__FILE__, __FUNCTION__, __LINE__)
-#ifdef NETDATA_INTERNAL_CHECKS
-#define rrdhost_check_wrlock(host) rrdhost_check_wrlock_int(host, __FILE__, __FUNCTION__, __LINE__)
-#define rrdhost_check_rdlock(host) rrdhost_check_rdlock_int(host, __FILE__, __FUNCTION__, __LINE__)
#else
#define rrdhost_check_rdlock(host) (void)0
#define rrdhost_check_wrlock(host) (void)0
+#define rrdset_check_rdlock(host) (void)0
+#define rrdset_check_wrlock(host) (void)0
+#define rrd_check_rdlock() (void)0
+#define rrd_check_wrlock() (void)0
#endif
-extern void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
-extern void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
-
-extern void rrdhost_rwlock(RRDHOST *host);
-extern void rrdhost_rdlock(RRDHOST *host);
-extern void rrdhost_unlock(RRDHOST *host);
-
// ----------------------------------------------------------------------------
-// RRD SET functions
+// RRDSET functions
-extern char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
extern void rrdset_set_name(RRDSET *st, const char *name);
-extern char *rrdset_cache_dir(const char *id);
+extern RRDSET *rrdset_create(RRDHOST *host
+ , const char *type
+ , const char *id
+ , const char *name
+ , const char *family
+ , const char *context
+ , const char *title
+ , const char *units
+ , long priority
+ , int update_every
+ , RRDSET_TYPE chart_type);
-extern void rrdset_reset(RRDSET *st);
+#define rrdset_create_localhost(type, id, name, family, context, title, units, priority, update_every, chart_type) rrdset_create(localhost, type, id, name, family, context, title, units, priority, update_every, chart_type)
-extern RRDSET *rrdset_create(const char *type
- , const char *id
- , const char *name
- , const char *family
- , const char *context
- , const char *title
- , const char *units
- , long priority
- , int update_every
- , int chart_type);
+extern void rrdhost_free_all(void);
+extern void rrdhost_save_all(void);
+
+extern void rrdhost_cleanup_orphan(RRDHOST *protected);
+extern void rrdhost_free(RRDHOST *host);
+extern void rrdhost_save(RRDHOST *host);
+extern void rrdhost_delete(RRDHOST *host);
+
+extern RRDSET *rrdset_find(RRDHOST *host, const char *id);
+#define rrdset_find_localhost(id) rrdset_find(localhost, id)
-extern void rrdset_free_all(void);
-extern void rrdset_save_all(void);
+extern RRDSET *rrdset_find_bytype(RRDHOST *host, const char *type, const char *id);
+#define rrdset_find_bytype_localhost(type, id) rrdset_find_bytype(localhost, type, id)
-extern RRDSET *rrdset_find(const char *id);
-extern RRDSET *rrdset_find_bytype(const char *type, const char *id);
-extern RRDSET *rrdset_find_byname(const char *name);
+extern RRDSET *rrdset_find_byname(RRDHOST *host, const char *name);
+#define rrdset_find_byname_localhost(name) rrdset_find_byname(localhost, name)
extern void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds);
extern void rrdset_next_usec(RRDSET *st, usec_t microseconds);
#define rrdset_next(st) rrdset_next_usec(st, 0ULL)
-extern usec_t rrdset_done(RRDSET *st);
+extern void rrdset_done(RRDSET *st);
+
+// checks if the RRDSET should be offered to viewers
+#define rrdset_is_available_for_viewers(st) (rrdset_flag_check(st, RRDSET_FLAG_ENABLED) && !rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE) && (st)->dimensions)
// get the total duration in seconds of the round robin database
#define rrdset_duration(st) ((time_t)( (((st)->counter >= ((unsigned long)(st)->entries))?(unsigned long)(st)->entries:(st)->counter) * (st)->update_every ))
@@ -397,11 +604,9 @@ extern usec_t rrdset_done(RRDSET *st);
// ----------------------------------------------------------------------------
// RRD DIMENSION functions
-extern RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier, long divisor, int algorithm);
+extern RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm);
extern void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name);
-extern void rrddim_free(RRDSET *st, RRDDIM *rd);
-
extern RRDDIM *rrddim_find(RRDSET *st, const char *id);
extern int rrddim_hide(RRDSET *st, const char *id);
@@ -410,4 +615,41 @@ extern int rrddim_unhide(RRDSET *st, const char *id);
extern collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
extern collected_number rrddim_set(RRDSET *st, const char *id, collected_number value);
+extern long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries);
+
+
+// ----------------------------------------------------------------------------
+// RRD internal functions
+
+#ifdef NETDATA_RRD_INTERNALS
+
+extern avl_tree_lock rrdhost_root_index;
+
+extern char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
+extern char *rrdset_cache_dir(RRDHOST *host, const char *id, const char *config_section);
+
+extern void rrddim_free(RRDSET *st, RRDDIM *rd);
+
+extern int rrddim_compare(void* a, void* b);
+extern int rrdset_compare(void* a, void* b);
+extern int rrdset_compare_name(void* a, void* b);
+extern int rrdfamily_compare(void *a, void *b);
+
+extern RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id);
+extern void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc);
+
+#define rrdset_index_add(host, st) (RRDSET *)avl_insert_lock(&((host)->rrdset_root_index), (avl *)(st))
+#define rrdset_index_del(host, st) (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index), (avl *)(st))
+extern RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st);
+
+extern void rrdset_free(RRDSET *st);
+extern void rrdset_reset(RRDSET *st);
+extern void rrdset_save(RRDSET *st);
+extern void rrdset_delete(RRDSET *st);
+
+extern void rrdhost_cleanup_obsolete(RRDHOST *host);
+
+#endif /* NETDATA_RRD_INTERNALS */
+
+
#endif /* NETDATA_RRD_H */
diff --git a/src/rrd2json.c b/src/rrd2json.c
index 067475006..4d853930c 100644
--- a/src/rrd2json.c
+++ b/src/rrd2json.c
@@ -2,7 +2,7 @@
void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memory_used)
{
- pthread_rwlock_rdlock(&st->rwlock);
+ rrdset_rdlock(st);
buffer_sprintf(wb,
"\t\t{\n"
@@ -29,7 +29,7 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions
, st->context
, st->title
, st->priority
- , st->enabled?"true":"false"
+ , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?"true":"false"
, st->units
, st->name
, rrdset_type_name(st->chart_type)
@@ -43,8 +43,8 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions
size_t dimensions = 0;
RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(rd->flags & RRDDIM_FLAG_HIDDEN) continue;
+ rrddim_foreach_read(rd, st) {
+ if(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) continue;
memory += rd->memsize;
@@ -71,58 +71,99 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions
"\n\t\t}"
);
- pthread_rwlock_unlock(&st->rwlock);
+ rrdset_unlock(st);
}
void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
rrd_stats_api_v1_chart_with_data(st, wb, NULL, NULL);
}
-void rrd_stats_api_v1_charts(BUFFER *wb)
-{
+void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) {
+ static char *custom_dashboard_info_js_filename = NULL;
size_t c, dimensions = 0, memory = 0, alarms = 0;
RRDSET *st;
+ time_t now = now_realtime_sec();
+
+ if(unlikely(!custom_dashboard_info_js_filename))
+ custom_dashboard_info_js_filename = config_get(CONFIG_SECTION_WEB, "custom dashboard_info.js", "");
+
buffer_sprintf(wb, "{\n"
"\t\"hostname\": \"%s\""
+ ",\n\t\"version\": \"%s\""
+ ",\n\t\"os\": \"%s\""
",\n\t\"update_every\": %d"
- ",\n\t\"history\": %d"
+ ",\n\t\"history\": %ld"
+ ",\n\t\"custom_info\": \"%s\""
",\n\t\"charts\": {"
- , localhost.hostname
- , rrd_update_every
- , rrd_default_history_entries
+ , host->hostname
+ , program_version
+ , host->os
+ , host->rrd_update_every
+ , host->rrd_history_entries
+ , custom_dashboard_info_js_filename
);
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
- for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
- if(st->enabled && st->dimensions) {
+ c = 0;
+ rrdhost_rdlock(host);
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
if(c) buffer_strcat(wb, ",");
buffer_strcat(wb, "\n\t\t\"");
buffer_strcat(wb, st->id);
buffer_strcat(wb, "\": ");
rrd_stats_api_v1_chart_with_data(st, wb, &dimensions, &memory);
+
c++;
+ st->last_accessed_time = now;
}
}
RRDCALC *rc;
- for(rc = localhost.alarms; rc ; rc = rc->next) {
+ for(rc = host->alarms; rc ; rc = rc->next) {
if(rc->rrdset)
alarms++;
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+ rrdhost_unlock(host);
buffer_sprintf(wb, "\n\t}"
",\n\t\"charts_count\": %zu"
",\n\t\"dimensions_count\": %zu"
",\n\t\"alarms_count\": %zu"
",\n\t\"rrd_memory_bytes\": %zu"
- "\n}\n"
+ ",\n\t\"hosts_count\": %zu"
+ ",\n\t\"hosts\": ["
, c
, dimensions
, alarms
, memory
+ , rrd_hosts_available
);
+
+ if(unlikely(rrd_hosts_available > 1)) {
+ rrd_rdlock();
+ RRDHOST *h;
+ rrdhost_foreach_read(h) {
+ buffer_sprintf(wb,
+ "%s\n\t\t{"
+ "\n\t\t\t\"hostname\": \"%s\""
+ "\n\t\t}"
+ , (h != localhost) ? "," : ""
+ , h->hostname
+ );
+ }
+ rrd_unlock();
+ }
+ else {
+ buffer_sprintf(wb,
+ "\n\t\t{"
+ "\n\t\t\t\"hostname\": \"%s\""
+ "\n\t\t}"
+ , host->hostname
+ );
+ }
+
+ buffer_sprintf(wb, "\n\t]\n}\n");
}
// ----------------------------------------------------------------------------
@@ -145,35 +186,34 @@ static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable)
#define PROMETHEUS_ELEMENT_MAX 256
-void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb)
-{
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
+void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
- char host[PROMETHEUS_ELEMENT_MAX + 1];
- prometheus_name_copy(host, config_get("global", "hostname", "localhost"), PROMETHEUS_ELEMENT_MAX);
+ char hostname[PROMETHEUS_ELEMENT_MAX + 1];
+ prometheus_name_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
// for each chart
RRDSET *st;
- for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdset_foreach_read(st, host) {
char chart[PROMETHEUS_ELEMENT_MAX + 1];
prometheus_name_copy(chart, st->id, PROMETHEUS_ELEMENT_MAX);
buffer_strcat(wb, "\n");
- if(st->enabled && st->dimensions) {
- pthread_rwlock_rdlock(&st->rwlock);
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
// for each dimension
RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(rd->counter) {
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
char dimension[PROMETHEUS_ELEMENT_MAX + 1];
prometheus_name_copy(dimension, rd->id, PROMETHEUS_ELEMENT_MAX);
// buffer_sprintf(wb, "# HELP %s.%s %s\n", st->id, rd->id, st->units);
switch(rd->algorithm) {
- case RRDDIM_INCREMENTAL:
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
+ case RRD_ALGORITHM_INCREMENTAL:
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
buffer_sprintf(wb, "# TYPE %s_%s counter\n", chart, dimension);
break;
@@ -183,21 +223,20 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb)
}
// calculated_number n = (calculated_number)rd->last_collected_value * (calculated_number)(abs(rd->multiplier)) / (calculated_number)(abs(rd->divisor));
- // buffer_sprintf(wb, "%s.%s " CALCULATED_NUMBER_FORMAT " %llu\n", st->id, rd->id, n,
- // (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000)));
+ // buffer_sprintf(wb, "%s.%s " CALCULATED_NUMBER_FORMAT " %llu\n", st->id, rd->id, n, timeval_msec(&rd->last_collected_time));
buffer_sprintf(wb, "%s_%s{instance=\"%s\"} " COLLECTED_NUMBER_FORMAT " %llu\n",
- chart, dimension, host, rd->last_collected_value,
- (unsigned long long)((rd->last_collected_time.tv_sec * 1000) + (rd->last_collected_time.tv_usec / 1000)));
+ chart, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time)
+ );
}
}
- pthread_rwlock_unlock(&st->rwlock);
+ rrdset_unlock(st);
}
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+ rrdhost_unlock(host);
}
// ----------------------------------------------------------------------------
@@ -220,28 +259,24 @@ static inline size_t shell_name_copy(char *d, const char *s, size_t usable) {
#define SHELL_ELEMENT_MAX 100
-void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
-{
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
-
- char host[SHELL_ELEMENT_MAX + 1];
- shell_name_copy(host, config_get("global", "hostname", "localhost"), SHELL_ELEMENT_MAX);
+void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
// for each chart
RRDSET *st;
- for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdset_foreach_read(st, host) {
calculated_number total = 0.0;
char chart[SHELL_ELEMENT_MAX + 1];
shell_name_copy(chart, st->id, SHELL_ELEMENT_MAX);
buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name);
- if(st->enabled && st->dimensions) {
- pthread_rwlock_rdlock(&st->rwlock);
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
// for each dimension
RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
- if(rd->counter) {
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
char dimension[SHELL_ELEMENT_MAX + 1];
shell_name_copy(dimension, rd->id, SHELL_ELEMENT_MAX);
@@ -252,7 +287,7 @@ void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
else {
if(rd->multiplier < 0 || rd->divisor < 0) n = -n;
n = roundl(n);
- if(!(rd->flags & RRDDIM_FLAG_HIDDEN)) total += n;
+ if(!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) total += n;
buffer_sprintf(wb, "NETDATA_%s_%s=\"%0.0Lf\" # %s\n", chart, dimension, n, st->units);
}
}
@@ -260,14 +295,14 @@ void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
total = roundl(total);
buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"%0.0Lf\" # %s\n", chart, total, st->units);
- pthread_rwlock_unlock(&st->rwlock);
+ rrdset_unlock(st);
}
}
buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n");
RRDCALC *rc;
- for(rc = localhost.alarms; rc ;rc = rc->next) {
+ for(rc = host->alarms; rc ;rc = rc->next) {
if(!rc->rrdset) continue;
char chart[SHELL_ELEMENT_MAX + 1];
@@ -288,159 +323,76 @@ void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb)
buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status));
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+ rrdhost_unlock(host);
}
// ----------------------------------------------------------------------------
-unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
-{
- time_t now = now_realtime_sec();
+void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
- pthread_rwlock_rdlock(&st->rwlock);
+ buffer_strcat(wb, "{");
- buffer_sprintf(wb,
- "\t\t{\n"
- "\t\t\t\"id\": \"%s\",\n"
- "\t\t\t\"name\": \"%s\",\n"
- "\t\t\t\"type\": \"%s\",\n"
- "\t\t\t\"family\": \"%s\",\n"
- "\t\t\t\"context\": \"%s\",\n"
- "\t\t\t\"title\": \"%s\",\n"
- "\t\t\t\"priority\": %ld,\n"
- "\t\t\t\"enabled\": %d,\n"
- "\t\t\t\"units\": \"%s\",\n"
- "\t\t\t\"url\": \"/data/%s/%s\",\n"
- "\t\t\t\"chart_type\": \"%s\",\n"
- "\t\t\t\"counter\": %lu,\n"
- "\t\t\t\"entries\": %ld,\n"
- "\t\t\t\"first_entry_t\": %ld,\n"
- "\t\t\t\"last_entry\": %lu,\n"
- "\t\t\t\"last_entry_t\": %ld,\n"
- "\t\t\t\"last_entry_secs_ago\": %ld,\n"
- "\t\t\t\"update_every\": %d,\n"
- "\t\t\t\"isdetail\": %d,\n"
- "\t\t\t\"usec_since_last_update\": %llu,\n"
- "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
- "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
- "\t\t\t\"dimensions\": [\n"
- , st->id
- , st->name
- , st->type
- , st->family
- , st->context
- , st->title
- , st->priority
- , st->enabled
- , st->units
- , st->name, options?options:""
- , rrdset_type_name(st->chart_type)
- , st->counter
- , st->entries
- , rrdset_first_entry_t(st)
- , rrdset_last_slot(st)
- , rrdset_last_entry_t(st)
- , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
- , st->update_every
- , st->isdetail
- , st->usec_since_last_update
- , st->collected_total
- , st->last_collected_total
- );
-
- unsigned long memory = st->memsize;
-
- RRDDIM *rd;
- for(rd = st->dimensions; rd ; rd = rd->next) {
-
- memory += rd->memsize;
+ size_t chart_counter = 0;
+ size_t dimension_counter = 0;
- buffer_sprintf(wb,
- "\t\t\t\t{\n"
- "\t\t\t\t\t\"id\": \"%s\",\n"
- "\t\t\t\t\t\"name\": \"%s\",\n"
- "\t\t\t\t\t\"entries\": %ld,\n"
- "\t\t\t\t\t\"isHidden\": %d,\n"
- "\t\t\t\t\t\"algorithm\": \"%s\",\n"
- "\t\t\t\t\t\"multiplier\": %ld,\n"
- "\t\t\t\t\t\"divisor\": %ld,\n"
- "\t\t\t\t\t\"last_entry_t\": %ld,\n"
- "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
- "\t\t\t\t\t\"memory\": %lu\n"
- "\t\t\t\t}%s\n"
- , rd->id
- , rd->name
- , rd->entries
- , (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0
- , rrddim_algorithm_name(rd->algorithm)
- , rd->multiplier
- , rd->divisor
- , rd->last_collected_time.tv_sec
- , rd->collected_value
- , rd->calculated_value
- , rd->last_collected_value
- , rd->last_calculated_value
- , rd->memsize
- , rd->next?",":""
+ // for each chart
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
+
+ buffer_sprintf(wb, "%s\n"
+ "\t\"%s\": {\n"
+ "\t\t\"name\":\"%s\",\n"
+ "\t\t\"context\":\"%s\",\n"
+ "\t\t\"units\":\"%s\",\n"
+ "\t\t\"last_updated\": %ld,\n"
+ "\t\t\"dimensions\": {"
+ , chart_counter?",":""
+ , st->id
+ , st->name
+ , st->context
+ , st->units
+ , rrdset_last_entry_t(st)
);
- }
-
- buffer_sprintf(wb,
- "\t\t\t],\n"
- "\t\t\t\"memory\" : %lu\n"
- "\t\t}"
- , memory
- );
- pthread_rwlock_unlock(&st->rwlock);
- return memory;
-}
+ chart_counter++;
+ dimension_counter = 0;
-#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
-#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
+ // for each dimension
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
+
+ buffer_sprintf(wb, "%s\n"
+ "\t\t\t\"%s\": {\n"
+ "\t\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\t\"value\": "
+ , dimension_counter?",":""
+ , rd->id
+ , rd->name
+ );
-void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb)
-{
- buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
- rrd_stats_one_json(st, options, wb);
- buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
-}
+ if(isnan(rd->last_stored_value))
+ buffer_strcat(wb, "null");
+ else
+ buffer_sprintf(wb, CALCULATED_NUMBER_FORMAT, rd->last_stored_value);
-void rrd_stats_all_json(BUFFER *wb)
-{
- unsigned long memory = 0;
- long c;
- RRDSET *st;
+ buffer_strcat(wb, "\n\t\t\t}");
- buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+ dimension_counter++;
+ }
+ }
- pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
- for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
- if(st->enabled && st->dimensions) {
- if(c) buffer_strcat(wb, ",\n");
- memory += rrd_stats_one_json(st, NULL, wb);
- c++;
+ buffer_strcat(wb, "\n\t\t}\n\t}");
+ rrdset_unlock(st);
}
}
- pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
-
- buffer_sprintf(wb, "\n\t],\n"
- "\t\"hostname\": \"%s\",\n"
- "\t\"update_every\": %d,\n"
- "\t\"history\": %d,\n"
- "\t\"memory\": %lu\n"
- "}\n"
- , localhost.hostname
- , rrd_update_every
- , rrd_default_history_entries
- , memory
- );
-}
-
+ buffer_strcat(wb, "\n}");
+ rrdhost_unlock(host);
+}
// ----------------------------------------------------------------------------
@@ -449,6 +401,7 @@ void rrd_stats_all_json(BUFFER *wb)
#define RRDR_RESET 0x02 // the dimension contains / the value is reset
#define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
#define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
+#define RRDR_SELECTED 0x10 // the dimension is selected
// RRDR result options
#define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
@@ -541,13 +494,16 @@ static void rrdr_dump(RRDR *r)
}
*/
-void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
-{
+void rrdr_disable_not_selected_dimensions(RRDR *r, uint32_t options, const char *dims) {
+ rrdset_check_rdlock(r->st);
+
+ if(unlikely(!dims || !*dims)) return;
+
char b[strlen(dims) + 1];
char *o = b, *tok;
strcpy(o, dims);
- long c;
+ long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
RRDDIM *d;
// disable all of them
@@ -561,16 +517,38 @@ void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
// find it and enable it
for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
- if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || !strcmp(d->name, tok))) {
- r->od[c] &= ~RRDR_HIDDEN;
+ if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || (hash == d->hash_name && !strcmp(d->name, tok)))) {
+
+ if(likely(r->od[c] & RRDR_HIDDEN)) {
+ r->od[c] |= RRDR_SELECTED;
+ r->od[c] &= ~RRDR_HIDDEN;
+ dims_selected++;
+ }
// since the user needs this dimension
// make it appear as NONZERO, to return it
// even if the dimension has only zeros
- r->od[c] |= RRDR_NONZERO;
+ // unless option non_zero is set
+ if(likely(!(options & RRDR_OPTION_NONZERO)))
+ r->od[c] |= RRDR_NONZERO;
+
+ // count the visible dimensions
+ if(likely(r->od[c] & RRDR_NONZERO))
+ dims_not_hidden_not_zero++;
}
}
}
+
+ // check if all dimensions are hidden
+ if(unlikely(!dims_not_hidden_not_zero && dims_selected)) {
+ // there are a few selected dimensions
+ // but they are all zero
+ // enable the selected ones
+ // to avoid returning an empty chart
+ for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
+ if(unlikely(r->od[c] & RRDR_SELECTED))
+ r->od[c] |= RRDR_NONZERO;
+ }
}
void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
@@ -624,6 +602,8 @@ void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
{
+ rrdset_check_rdlock(r->st);
+
(void)dims;
if(options & RRDR_OPTION_NONZERO) {
@@ -659,6 +639,8 @@ uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
{
+ rrdset_check_rdlock(r->st);
+
long rows = rrdr_rows(r);
long c, i;
RRDDIM *rd;
@@ -840,6 +822,8 @@ void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t option
static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
{
+ rrdset_check_rdlock(r->st);
+
//info("RRD2JSON(): %s: BEGIN", r->st->id);
int row_annotations = 0, dates, dates_with_new = 0;
char kq[2] = "", // key quote
@@ -893,14 +877,14 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
else {
kq[0] = '"';
sq[0] = '"';
- if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
- dates = JSON_DATES_TIMESTAMP;
- dates_with_new = 0;
- }
- else {
+ if(options & RRDR_OPTION_GOOGLE_JSON) {
dates = JSON_DATES_JS;
dates_with_new = 1;
}
+ else {
+ dates = JSON_DATES_TIMESTAMP;
+ dates_with_new = 0;
+ }
if( options & RRDR_OPTION_OBJECTSROWS )
strcpy(pre_date, " { ");
else
@@ -1066,6 +1050,8 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
{
+ rrdset_check_rdlock(r->st);
+
//info("RRD2CSV(): %s: BEGIN", r->st->id);
long c, i;
RRDDIM *d;
@@ -1171,6 +1157,8 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
}
inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
+ rrdset_check_rdlock(r->st);
+
long c;
RRDDIM *d;
@@ -1321,7 +1309,7 @@ inline static void rrdr_lock_rrdset(RRDR *r) {
return;
}
- pthread_rwlock_rdlock(&r->st->rwlock);
+ rrdset_rdlock(r->st);
r->has_st_lock = 1;
}
@@ -1332,7 +1320,7 @@ inline static void rrdr_unlock_rrdset(RRDR *r) {
}
if(likely(r->has_st_lock)) {
- pthread_rwlock_unlock(&r->st->rwlock);
+ rrdset_unlock(r->st);
r->has_st_lock = 0;
}
}
@@ -1371,7 +1359,7 @@ static RRDR *rrdr_create(RRDSET *st, long n)
rrdr_lock_rrdset(r);
RRDDIM *rd;
- for(rd = st->dimensions ; rd ; rd = rd->next) r->d++;
+ rrddim_foreach_read(rd, st) r->d++;
r->n = n;
@@ -1383,8 +1371,10 @@ static RRDR *rrdr_create(RRDSET *st, long n)
// set the hidden flag on hidden dimensions
int c;
for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
- if(unlikely(rd->flags & RRDDIM_FLAG_HIDDEN)) r->od[c] = RRDR_HIDDEN;
- else r->od[c] = 0;
+ if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)))
+ r->od[c] = RRDR_HIDDEN;
+ else
+ r->od[c] = 0;
}
r->c = -1;
@@ -1396,7 +1386,7 @@ static RRDR *rrdr_create(RRDSET *st, long n)
RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
{
- int debug = st->debug;
+ int debug = rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?1:0;
int absolute_period_requested = -1;
time_t first_entry_t = rrdset_first_entry_t(st);
@@ -1572,6 +1562,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
// initialize them
RRDDIM *rd;
long c;
+ rrdset_check_rdlock(st);
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
last_values[c] = 0;
group_values[c] = (group_method == GROUP_MAX || group_method == GROUP_MIN)?NAN:0;
@@ -1600,7 +1591,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
);
r->group = group;
- r->update_every = group * st->update_every;
+ r->update_every = (int)group * st->update_every;
r->before = now;
r->after = now;
@@ -1752,8 +1743,20 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
return r;
}
-int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *db_after, time_t *db_before, int *value_is_null)
-{
+int rrdset2value_api_v1(
+ RRDSET *st
+ , BUFFER *wb
+ , calculated_number *n
+ , const char *dimensions
+ , long points
+ , long long after
+ , long long before
+ , int group_method
+ , uint32_t options
+ , time_t *db_after
+ , time_t *db_before
+ , int *value_is_null
+) {
RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
if(!r) {
if(value_is_null) *value_is_null = 1;
@@ -1778,7 +1781,7 @@ int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensio
options = rrdr_check_options(r, options, dimensions);
if(dimensions)
- rrdr_disable_not_selected_dimensions(r, dimensions);
+ rrdr_disable_not_selected_dimensions(r, options, dimensions);
if(db_after) *db_after = r->after;
if(db_before) *db_before = r->before;
@@ -1790,8 +1793,20 @@ int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensio
return 200;
}
-int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp)
-{
+int rrdset2anything_api_v1(
+ RRDSET *st
+ , BUFFER *wb
+ , BUFFER *dimensions
+ , uint32_t format
+ , long points
+ , long long after
+ , long long before
+ , int group_method
+ , uint32_t options
+ , time_t *latest_timestamp
+) {
+ st->last_accessed_time = now_realtime_sec();
+
RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
if(!r) {
buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
@@ -1806,7 +1821,7 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
if(dimensions)
- rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
+ rrdr_disable_not_selected_dimensions(r, options, buffer_tostring(dimensions));
if(latest_timestamp && rrdr_rows(r) > 0)
*latest_timestamp = r->before;
@@ -1963,325 +1978,3 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
rrdr_free(r);
return 200;
}
-
-time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long points, long group, int group_method, time_t after, time_t before, int only_non_zero)
-{
- int c;
- pthread_rwlock_rdlock(&st->rwlock);
-
-
- // -------------------------------------------------------------------------
- // switch from JSON to google JSON
-
- char kq[2] = "\"";
- char sq[2] = "\"";
- switch(type) {
- case DATASOURCE_DATATABLE_JSON:
- case DATASOURCE_DATATABLE_JSONP:
- kq[0] = '\0';
- sq[0] = '\'';
- break;
-
- case DATASOURCE_JSON:
- default:
- break;
- }
-
-
- // -------------------------------------------------------------------------
- // validate the parameters
-
- if(points < 1) points = 1;
- if(group < 1) group = 1;
-
- if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
- if(after == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
-
- // ---
-
- // our return value (the last timestamp printed)
- // this is required to detect re-transmit in google JSONP
- time_t last_timestamp = 0;
-
-
- // -------------------------------------------------------------------------
- // find how many dimensions we have
-
- int dimensions = 0;
- RRDDIM *rd;
- for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
- if(!dimensions) {
- pthread_rwlock_unlock(&st->rwlock);
- buffer_strcat(wb, "No dimensions yet.");
- return 0;
- }
-
-
- // -------------------------------------------------------------------------
- // prepare various strings, to speed up the loop
-
- char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
- char normal_annotation[201]; snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
- char pre_date[51]; snprintfz(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
- char post_date[21]; snprintfz(post_date, 20, "%s}", sq);
- char pre_value[21]; snprintfz(pre_value, 20, ",{%sv%s:", kq, kq);
- char post_value[21]; strcpy(post_value, "}");
-
-
- // -------------------------------------------------------------------------
- // checks for debugging
-
- if(st->debug) {
- debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
- , st->id
- , rrdset_first_entry_t(st)
- , rrdset_last_entry_t(st)
- , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
- , after
- , before
- , before - after
- , points
- , group
- );
-
- if(before < after)
- debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
-
- if((before - after) > st->entries * st->update_every)
- debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
- }
-
-
- // -------------------------------------------------------------------------
- // temp arrays for keeping values per dimension
-
- calculated_number group_values[dimensions]; // keep sums when grouping
- int print_hidden[dimensions]; // keep hidden flags
- int found_non_zero[dimensions];
- int found_non_existing[dimensions];
-
- // initialize them
- for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- group_values[c] = 0;
- print_hidden[c] = (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0;
- found_non_zero[c] = 0;
- found_non_existing[c] = 0;
- }
-
-
- // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
- // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
- // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
-
- // -------------------------------------------------------------------------
- // remove dimensions that contain only zeros
-
- int max_loop = 1;
- if(only_non_zero) max_loop = 2;
-
- for(; max_loop ; max_loop--) {
-
- // -------------------------------------------------------------------------
- // print the JSON header
-
- buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
- buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
- buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
- buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-
- // print the header for each dimension
- // and update the print_hidden array for the dimensions that should be hidden
- int pc = 0;
- for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- if(!print_hidden[c]) {
- pc++;
- buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
- }
- }
- if(!pc) {
- buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
- }
-
- // print the begin of row data
- buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
-
-
- // -------------------------------------------------------------------------
- // the main loop
-
- int annotate_reset = 0;
- int annotation_count = 0;
-
- long t = rrdset_time2slot(st, before),
- stop_at_t = rrdset_time2slot(st, after),
- stop_now = 0;
-
- t -= t % group;
-
- time_t now = rrdset_slot2time(st, t),
- dt = st->update_every;
-
- long count = 0, printed = 0, group_count = 0;
- last_timestamp = 0;
-
- if(st->debug) debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
- , st->id
- , (uint32_t)after
- , (uint32_t)before
- , points
- , group
- , st->current_entry
- , (uint32_t)rrdset_first_entry_t(st)
- , (uint32_t)rrdset_last_entry_t(st)
- , t
- , stop_at_t
- );
-
- long counter = 0;
- for(; !stop_now ; now -= dt, t--, counter++) {
- if(t < 0) t = st->entries - 1;
- if(t == stop_at_t) stop_now = counter;
-
- int print_this = 0;
-
- if(st->debug) debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
- , st->id
- , t
- , count + 1
- , group_count + 1
- , printed
- , now
- , (group_count + 1 == group)?"PRINT":" - "
- , (now >= after && now <= before)?"RANGE":" - "
- );
-
-
- // make sure we return data in the proper time range
- if(now > before) continue;
- if(now < after) break;
-
- //if(rrdset_slot2time(st, t) != now)
- // error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
-
- count++;
- group_count++;
-
- // check if we have to print this now
- if(group_count == group) {
- if(printed >= points) {
- // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
- break;
- }
-
- // generate the local date time
- struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
- if(!tm) { error("localtime() failed."); continue; }
- if(now > last_timestamp) last_timestamp = now;
-
- if(printed) buffer_strcat(wb, "]},\n");
- buffer_strcat(wb, pre_date);
- buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
- buffer_strcat(wb, post_date);
-
- print_this = 1;
- }
-
- // do the calculations
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- storage_number n = rd->values[t];
- calculated_number value = unpack_storage_number(n);
-
- if(!does_storage_number_exist(n)) {
- value = 0.0;
- found_non_existing[c]++;
- }
- if(did_storage_number_reset(n)) annotate_reset = 1;
-
- switch(group_method) {
- case GROUP_MAX:
- if(abs(value) > abs(group_values[c])) group_values[c] = value;
- break;
-
- case GROUP_SUM:
- group_values[c] += value;
- break;
-
- default:
- case GROUP_AVERAGE:
- group_values[c] += value;
- if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
- break;
- }
- }
-
- if(print_this) {
- if(annotate_reset) {
- annotation_count++;
- buffer_strcat(wb, overflow_annotation);
- annotate_reset = 0;
- }
- else
- buffer_strcat(wb, normal_annotation);
-
- pc = 0;
- for(c = 0 ; c < dimensions ; c++) {
- if(found_non_existing[c] == group_count) {
- // all entries are non-existing
- pc++;
- buffer_strcat(wb, pre_value);
- buffer_strcat(wb, "null");
- buffer_strcat(wb, post_value);
- }
- else if(!print_hidden[c]) {
- pc++;
- buffer_strcat(wb, pre_value);
- buffer_rrd_value(wb, group_values[c]);
- buffer_strcat(wb, post_value);
-
- if(group_values[c]) found_non_zero[c]++;
- }
-
- // reset them for the next loop
- group_values[c] = 0;
- found_non_existing[c] = 0;
- }
-
- // if all dimensions are hidden, print a null
- if(!pc) {
- buffer_strcat(wb, pre_value);
- buffer_strcat(wb, "null");
- buffer_strcat(wb, post_value);
- }
-
- printed++;
- group_count = 0;
- }
- }
-
- if(printed) buffer_strcat(wb, "]}");
- buffer_strcat(wb, "\n ]\n}\n");
-
- if(only_non_zero && max_loop > 1) {
- int changed = 0;
- for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
- group_values[c] = 0;
- found_non_existing[c] = 0;
-
- if(!print_hidden[c] && !found_non_zero[c]) {
- changed = 1;
- print_hidden[c] = 1;
- }
- }
-
- if(changed) buffer_flush(wb);
- else break;
- }
- else break;
-
- } // max_loop
-
- debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %lu bytes", st->name, wb->len);
-
- pthread_rwlock_unlock(&st->rwlock);
- return last_timestamp;
-}
diff --git a/src/rrd2json.h b/src/rrd2json.h
index 7b1401970..f2f03c640 100644
--- a/src/rrd2json.h
+++ b/src/rrd2json.h
@@ -33,9 +33,11 @@
#define ALLMETRICS_FORMAT_SHELL "shell"
#define ALLMETRICS_FORMAT_PROMETHEUS "prometheus"
+#define ALLMETRICS_FORMAT_JSON "json"
#define ALLMETRICS_SHELL 1
#define ALLMETRICS_PROMETHEUS 2
+#define ALLMETRICS_JSON 3
#define GROUP_UNDEFINED 0
#define GROUP_AVERAGE 1
@@ -59,20 +61,17 @@
#define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes
extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
-extern void rrd_stats_api_v1_charts(BUFFER *wb);
-
-extern void rrd_stats_api_v1_charts_allmetrics_shell(BUFFER *wb);
-extern void rrd_stats_api_v1_charts_allmetrics_prometheus(BUFFER *wb);
-
-extern unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb);
-
-extern void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb);
-
-extern void rrd_stats_all_json(BUFFER *wb);
-
-extern time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long entries_to_show, long group, int group_method, time_t after, time_t before, int only_non_zero);
-
-extern int rrd2format(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp);
-extern int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *db_before, time_t *db_after, int *value_is_null);
+extern void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb);
+
+extern void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb);
+extern void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb);
+extern void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb);
+
+extern int rrdset2anything_api_v1(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points
+ , long long after, long long before, int group_method, uint32_t options
+ , time_t *latest_timestamp);
+extern int rrdset2value_api_v1(RRDSET *st, BUFFER *wb, calculated_number *n, const char *dimensions, long points
+ , long long after, long long before, int group_method, uint32_t options
+ , time_t *db_before, time_t *db_after, int *value_is_null);
#endif /* NETDATA_RRD2JSON_H */
diff --git a/src/rrd2json_api_old.c b/src/rrd2json_api_old.c
new file mode 100644
index 000000000..6710f31cf
--- /dev/null
+++ b/src/rrd2json_api_old.c
@@ -0,0 +1,487 @@
+#include "common.h"
+
+unsigned long rrdset_info2json_api_old(RRDSET *st, char *options, BUFFER *wb) {
+ time_t now = now_realtime_sec();
+
+ rrdset_rdlock(st);
+
+ st->last_accessed_time = now;
+
+ buffer_sprintf(wb,
+ "\t\t{\n"
+ "\t\t\t\"id\": \"%s\",\n"
+ "\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\"type\": \"%s\",\n"
+ "\t\t\t\"family\": \"%s\",\n"
+ "\t\t\t\"context\": \"%s\",\n"
+ "\t\t\t\"title\": \"%s\",\n"
+ "\t\t\t\"priority\": %ld,\n"
+ "\t\t\t\"enabled\": %d,\n"
+ "\t\t\t\"units\": \"%s\",\n"
+ "\t\t\t\"url\": \"/data/%s/%s\",\n"
+ "\t\t\t\"chart_type\": \"%s\",\n"
+ "\t\t\t\"counter\": %lu,\n"
+ "\t\t\t\"entries\": %ld,\n"
+ "\t\t\t\"first_entry_t\": %ld,\n"
+ "\t\t\t\"last_entry\": %lu,\n"
+ "\t\t\t\"last_entry_t\": %ld,\n"
+ "\t\t\t\"last_entry_secs_ago\": %ld,\n"
+ "\t\t\t\"update_every\": %d,\n"
+ "\t\t\t\"isdetail\": %d,\n"
+ "\t\t\t\"usec_since_last_update\": %llu,\n"
+ "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
+ "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
+ "\t\t\t\"dimensions\": [\n"
+ , st->id
+ , st->name
+ , st->type
+ , st->family
+ , st->context
+ , st->title
+ , st->priority
+ , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?1:0
+ , st->units
+ , st->name, options?options:""
+ , rrdset_type_name(st->chart_type)
+ , st->counter
+ , st->entries
+ , rrdset_first_entry_t(st)
+ , rrdset_last_slot(st)
+ , rrdset_last_entry_t(st)
+ , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
+ , st->update_every
+ , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?1:0
+ , st->usec_since_last_update
+ , st->collected_total
+ , st->last_collected_total
+ );
+
+ unsigned long memory = st->memsize;
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+
+ memory += rd->memsize;
+
+ buffer_sprintf(wb,
+ "\t\t\t\t{\n"
+ "\t\t\t\t\t\"id\": \"%s\",\n"
+ "\t\t\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\t\t\"entries\": %ld,\n"
+ "\t\t\t\t\t\"isHidden\": %d,\n"
+ "\t\t\t\t\t\"algorithm\": \"%s\",\n"
+ "\t\t\t\t\t\"multiplier\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"divisor\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"last_entry_t\": %ld,\n"
+ "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
+ "\t\t\t\t\t\"memory\": %lu\n"
+ "\t\t\t\t}%s\n"
+ , rd->id
+ , rd->name
+ , rd->entries
+ , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?1:0
+ , rrd_algorithm_name(rd->algorithm)
+ , rd->multiplier
+ , rd->divisor
+ , rd->last_collected_time.tv_sec
+ , rd->collected_value
+ , rd->calculated_value
+ , rd->last_collected_value
+ , rd->last_calculated_value
+ , rd->memsize
+ , rd->next?",":""
+ );
+ }
+
+ buffer_sprintf(wb,
+ "\t\t\t],\n"
+ "\t\t\t\"memory\" : %lu\n"
+ "\t\t}"
+ , memory
+ );
+
+ rrdset_unlock(st);
+ return memory;
+}
+
+#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
+#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
+
+void rrd_graph2json_api_old(RRDSET *st, char *options, BUFFER *wb)
+{
+ buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+ rrdset_info2json_api_old(st, options, wb);
+ buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
+}
+
+void rrd_all2json_api_old(RRDHOST *host, BUFFER *wb)
+{
+ unsigned long memory = 0;
+ long c = 0;
+ RRDSET *st;
+
+ time_t now = now_realtime_sec();
+
+ buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+
+ rrdhost_rdlock(host);
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
+ if(c) buffer_strcat(wb, ",\n");
+ memory += rrdset_info2json_api_old(st, NULL, wb);
+
+ c++;
+ st->last_accessed_time = now;
+ }
+ }
+ rrdhost_unlock(host);
+
+ buffer_sprintf(wb, "\n\t],\n"
+ "\t\"hostname\": \"%s\",\n"
+ "\t\"update_every\": %d,\n"
+ "\t\"history\": %ld,\n"
+ "\t\"memory\": %lu\n"
+ "}\n"
+ , host->hostname
+ , host->rrd_update_every
+ , host->rrd_history_entries
+ , memory
+ );
+}
+
+time_t rrdset2json_api_old(
+ int type
+ , RRDSET *st
+ , BUFFER *wb
+ , long points
+ , long group
+ , int group_method
+ , time_t after
+ , time_t before
+ , int only_non_zero
+) {
+ int c;
+ rrdset_rdlock(st);
+
+ st->last_accessed_time = now_realtime_sec();
+
+ // -------------------------------------------------------------------------
+ // switch from JSON to google JSON
+
+ char kq[2] = "\"";
+ char sq[2] = "\"";
+ switch(type) {
+ case DATASOURCE_DATATABLE_JSON:
+ case DATASOURCE_DATATABLE_JSONP:
+ kq[0] = '\0';
+ sq[0] = '\'';
+ break;
+
+ case DATASOURCE_JSON:
+ default:
+ break;
+ }
+
+
+ // -------------------------------------------------------------------------
+ // validate the parameters
+
+ if(points < 1) points = 1;
+ if(group < 1) group = 1;
+
+ if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
+ if(after == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
+
+ // ---
+
+ // our return value (the last timestamp printed)
+ // this is required to detect re-transmit in google JSONP
+ time_t last_timestamp = 0;
+
+
+ // -------------------------------------------------------------------------
+ // find how many dimensions we have
+
+ int dimensions = 0;
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) dimensions++;
+ if(!dimensions) {
+ rrdset_unlock(st);
+ buffer_strcat(wb, "No dimensions yet.");
+ return 0;
+ }
+
+
+ // -------------------------------------------------------------------------
+ // prepare various strings, to speed up the loop
+
+ char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
+ char normal_annotation[201]; snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
+ char pre_date[51]; snprintfz(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
+ char post_date[21]; snprintfz(post_date, 20, "%s}", sq);
+ char pre_value[21]; snprintfz(pre_value, 20, ",{%sv%s:", kq, kq);
+ char post_value[21]; strcpy(post_value, "}");
+
+
+ // -------------------------------------------------------------------------
+ // checks for debugging
+
+ if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)) {
+ debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
+ , st->id
+ , rrdset_first_entry_t(st)
+ , rrdset_last_entry_t(st)
+ , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
+ , after
+ , before
+ , before - after
+ , points
+ , group
+ );
+
+ if(before < after)
+ debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
+
+ if((before - after) > st->entries * st->update_every)
+ debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
+ }
+
+
+ // -------------------------------------------------------------------------
+ // temp arrays for keeping values per dimension
+
+ calculated_number group_values[dimensions]; // keep sums when grouping
+ int print_hidden[dimensions]; // keep hidden flags
+ int found_non_zero[dimensions];
+ int found_non_existing[dimensions];
+
+ // initialize them
+ for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ group_values[c] = 0;
+ print_hidden[c] = rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?1:0;
+ found_non_zero[c] = 0;
+ found_non_existing[c] = 0;
+ }
+
+
+ // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
+ // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
+ // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
+
+ // -------------------------------------------------------------------------
+ // remove dimensions that contain only zeros
+
+ int max_loop = 1;
+ if(only_non_zero) max_loop = 2;
+
+ for(; max_loop ; max_loop--) {
+
+ // -------------------------------------------------------------------------
+ // print the JSON header
+
+ buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
+ buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+ buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+ buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+
+ // print the header for each dimension
+ // and update the print_hidden array for the dimensions that should be hidden
+ int pc = 0;
+ for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ if(!print_hidden[c]) {
+ pc++;
+ buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+ }
+ }
+ if(!pc) {
+ buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
+ }
+
+ // print the begin of row data
+ buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
+
+
+ // -------------------------------------------------------------------------
+ // the main loop
+
+ int annotate_reset = 0;
+ int annotation_count = 0;
+
+ long t = rrdset_time2slot(st, before),
+ stop_at_t = rrdset_time2slot(st, after),
+ stop_now = 0;
+
+ t -= t % group;
+
+ time_t now = rrdset_slot2time(st, t),
+ dt = st->update_every;
+
+ long count = 0, printed = 0, group_count = 0;
+ last_timestamp = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
+ , st->id
+ , (uint32_t)after
+ , (uint32_t)before
+ , points
+ , group
+ , st->current_entry
+ , (uint32_t)rrdset_first_entry_t(st)
+ , (uint32_t)rrdset_last_entry_t(st)
+ , t
+ , stop_at_t
+ );
+
+ long counter = 0;
+ for(; !stop_now ; now -= dt, t--, counter++) {
+ if(t < 0) t = st->entries - 1;
+ if(t == stop_at_t) stop_now = counter;
+
+ int print_this = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
+ , st->id
+ , t
+ , count + 1
+ , group_count + 1
+ , printed
+ , now
+ , (group_count + 1 == group)?"PRINT":" - "
+ , (now >= after && now <= before)?"RANGE":" - "
+ );
+
+
+ // make sure we return data in the proper time range
+ if(now > before) continue;
+ if(now < after) break;
+
+ //if(rrdset_slot2time(st, t) != now)
+ // error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
+
+ count++;
+ group_count++;
+
+ // check if we have to print this now
+ if(group_count == group) {
+ if(printed >= points) {
+ // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
+ break;
+ }
+
+ // generate the local date time
+ struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
+ if(!tm) { error("localtime() failed."); continue; }
+ if(now > last_timestamp) last_timestamp = now;
+
+ if(printed) buffer_strcat(wb, "]},\n");
+ buffer_strcat(wb, pre_date);
+ buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ buffer_strcat(wb, post_date);
+
+ print_this = 1;
+ }
+
+ // do the calculations
+ for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ storage_number n = rd->values[t];
+ calculated_number value = unpack_storage_number(n);
+
+ if(!does_storage_number_exist(n)) {
+ value = 0.0;
+ found_non_existing[c]++;
+ }
+ if(did_storage_number_reset(n)) annotate_reset = 1;
+
+ switch(group_method) {
+ case GROUP_MAX:
+ if(abs(value) > abs(group_values[c])) group_values[c] = value;
+ break;
+
+ case GROUP_SUM:
+ group_values[c] += value;
+ break;
+
+ default:
+ case GROUP_AVERAGE:
+ group_values[c] += value;
+ if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
+ break;
+ }
+ }
+
+ if(print_this) {
+ if(annotate_reset) {
+ annotation_count++;
+ buffer_strcat(wb, overflow_annotation);
+ annotate_reset = 0;
+ }
+ else
+ buffer_strcat(wb, normal_annotation);
+
+ pc = 0;
+ for(c = 0 ; c < dimensions ; c++) {
+ if(found_non_existing[c] == group_count) {
+ // all entries are non-existing
+ pc++;
+ buffer_strcat(wb, pre_value);
+ buffer_strcat(wb, "null");
+ buffer_strcat(wb, post_value);
+ }
+ else if(!print_hidden[c]) {
+ pc++;
+ buffer_strcat(wb, pre_value);
+ buffer_rrd_value(wb, group_values[c]);
+ buffer_strcat(wb, post_value);
+
+ if(group_values[c]) found_non_zero[c]++;
+ }
+
+ // reset them for the next loop
+ group_values[c] = 0;
+ found_non_existing[c] = 0;
+ }
+
+ // if all dimensions are hidden, print a null
+ if(!pc) {
+ buffer_strcat(wb, pre_value);
+ buffer_strcat(wb, "null");
+ buffer_strcat(wb, post_value);
+ }
+
+ printed++;
+ group_count = 0;
+ }
+ }
+
+ if(printed) buffer_strcat(wb, "]}");
+ buffer_strcat(wb, "\n ]\n}\n");
+
+ if(only_non_zero && max_loop > 1) {
+ int changed = 0;
+ for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+ group_values[c] = 0;
+ found_non_existing[c] = 0;
+
+ if(!print_hidden[c] && !found_non_zero[c]) {
+ changed = 1;
+ print_hidden[c] = 1;
+ }
+ }
+
+ if(changed) buffer_flush(wb);
+ else break;
+ }
+ else break;
+
+ } // max_loop
+
+ debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %zu bytes", st->name, wb->len);
+
+ rrdset_unlock(st);
+ return last_timestamp;
+}
diff --git a/src/rrd2json_api_old.h b/src/rrd2json_api_old.h
new file mode 100644
index 000000000..f8c63814f
--- /dev/null
+++ b/src/rrd2json_api_old.h
@@ -0,0 +1,14 @@
+#ifndef NETDATA_RRD2JSON_API_OLD_H
+#define NETDATA_RRD2JSON_API_OLD_H
+
+extern unsigned long rrdset_info2json_api_old(RRDSET *st, char *options, BUFFER *wb);
+
+extern void rrd_graph2json_api_old(RRDSET *st, char *options, BUFFER *wb);
+
+extern void rrd_all2json_api_old(RRDHOST *host, BUFFER *wb);
+
+extern time_t rrdset2json_api_old(int type, RRDSET *st, BUFFER *wb, long entries_to_show, long group, int group_method
+ , time_t after, time_t before, int only_non_zero);
+
+
+#endif //NETDATA_RRD2JSON_API_OLD_H
diff --git a/src/rrdcalc.c b/src/rrdcalc.c
new file mode 100644
index 000000000..1f1845409
--- /dev/null
+++ b/src/rrdcalc.c
@@ -0,0 +1,415 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDCALC management
+
+inline const char *rrdcalc_status2string(int status) {
+ switch(status) {
+ case RRDCALC_STATUS_REMOVED:
+ return "REMOVED";
+
+ case RRDCALC_STATUS_UNDEFINED:
+ return "UNDEFINED";
+
+ case RRDCALC_STATUS_UNINITIALIZED:
+ return "UNINITIALIZED";
+
+ case RRDCALC_STATUS_CLEAR:
+ return "CLEAR";
+
+ case RRDCALC_STATUS_RAISED:
+ return "RAISED";
+
+ case RRDCALC_STATUS_WARNING:
+ return "WARNING";
+
+ case RRDCALC_STATUS_CRITICAL:
+ return "CRITICAL";
+
+ default:
+ error("Unknown alarm status %d", status);
+ return "UNKNOWN";
+ }
+}
+
+static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
+ debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
+
+ rc->last_status_change = now_realtime_sec();
+ rc->rrdset = st;
+
+ rc->rrdset_next = st->alarms;
+ rc->rrdset_prev = NULL;
+
+ if(rc->rrdset_next)
+ rc->rrdset_next->rrdset_prev = rc;
+
+ st->alarms = rc;
+
+ if(rc->update_every < rc->rrdset->update_every) {
+ error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
+ rc->update_every = rc->rrdset->update_every;
+ }
+
+ if(!isnan(rc->green) && isnan(st->green)) {
+ debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
+ st->green = rc->green;
+ }
+
+ if(!isnan(rc->red) && isnan(st->red)) {
+ debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
+ st->red = rc->red;
+ }
+
+ rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
+ rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+ char fullname[RRDVAR_MAX_LENGTH + 1];
+ snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
+ rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+ snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
+ rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+ if(!rc->units) rc->units = strdupz(st->units);
+
+ {
+ time_t now = now_realtime_sec();
+ health_alarm_log(
+ st->rrdhost,
+ rc->id,
+ rc->next_event_id++,
+ now,
+ rc->name,
+ rc->rrdset->id,
+ rc->rrdset->family,
+ rc->exec,
+ rc->recipient,
+ now - rc->last_status_change,
+ rc->old_value,
+ rc->value,
+ rc->status,
+ RRDCALC_STATUS_UNINITIALIZED,
+ rc->source,
+ rc->units,
+ rc->info,
+ 0,
+ 0
+ );
+ }
+}
+
+static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
+ if( (rc->hash_chart == st->hash && !strcmp(rc->chart, st->id)) ||
+ (rc->hash_chart == st->hash_name && !strcmp(rc->chart, st->name)))
+ return 1;
+
+ return 0;
+}
+
+// this has to be called while the RRDHOST is locked
+inline void rrdsetcalc_link_matching(RRDSET *st) {
+ // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
+
+ RRDCALC *rc;
+ for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
+ if(unlikely(rc->rrdset))
+ continue;
+
+ if(unlikely(rrdcalc_is_matching_this_rrdset(rc, st)))
+ rrdsetcalc_link(st, rc);
+ }
+}
+
+// this has to be called while the RRDHOST is locked
+inline void rrdsetcalc_unlink(RRDCALC *rc) {
+ RRDSET *st = rc->rrdset;
+
+ if(!st) {
+ debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
+ error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
+ return;
+ }
+
+ {
+ time_t now = now_realtime_sec();
+ health_alarm_log(
+ st->rrdhost,
+ rc->id,
+ rc->next_event_id++,
+ now,
+ rc->name,
+ rc->rrdset->id,
+ rc->rrdset->family,
+ rc->exec,
+ rc->recipient,
+ now - rc->last_status_change,
+ rc->old_value,
+ rc->value,
+ rc->status,
+ RRDCALC_STATUS_REMOVED,
+ rc->source,
+ rc->units,
+ rc->info,
+ 0,
+ 0
+ );
+ }
+
+ RRDHOST *host = st->rrdhost;
+
+ debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
+
+ // unlink it
+ if(rc->rrdset_prev)
+ rc->rrdset_prev->rrdset_next = rc->rrdset_next;
+
+ if(rc->rrdset_next)
+ rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
+
+ if(st->alarms == rc)
+ st->alarms = rc->rrdset_next;
+
+ rc->rrdset_prev = rc->rrdset_next = NULL;
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
+ rc->local = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family);
+ rc->family = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
+ rc->hostid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
+ rc->hostname = NULL;
+
+ rc->rrdset = NULL;
+
+ // RRDCALC will remain in RRDHOST
+ // so that if the matching chart is found in the future
+ // it will be applied automatically
+}
+
+RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
+ RRDCALC *rc;
+ uint32_t hash = simple_hash(name);
+
+ for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
+ if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
+ return rc;
+ }
+
+ return NULL;
+}
+
+inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
+ RRDCALC *rc;
+
+ if(unlikely(!chart)) {
+ error("attempt to find RRDCALC '%s' without giving a chart name", name);
+ return 1;
+ }
+
+ if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
+ if(unlikely(!hash_name)) hash_name = simple_hash(name);
+
+ // make sure it does not already exist
+ for(rc = host->alarms; rc ; rc = rc->next) {
+ if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
+ debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
+ error("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
+ if(chart && name) {
+ uint32_t hash_chart = simple_hash(chart);
+ uint32_t hash_name = simple_hash(name);
+
+ // re-use old IDs, by looking them up in the alarm log
+ ALARM_ENTRY *ae;
+ for(ae = host->health_log.alarms; ae ;ae = ae->next) {
+ if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
+ if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
+ return ae->alarm_id;
+ }
+ }
+ }
+
+ return host->health_log.next_alarm_id++;
+}
+
+inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
+ rrdhost_check_rdlock(host);
+
+ if(rc->calculation) {
+ rc->calculation->status = &rc->status;
+ rc->calculation->this = &rc->value;
+ rc->calculation->after = &rc->db_after;
+ rc->calculation->before = &rc->db_before;
+ rc->calculation->rrdcalc = rc;
+ }
+
+ if(rc->warning) {
+ rc->warning->status = &rc->status;
+ rc->warning->this = &rc->value;
+ rc->warning->after = &rc->db_after;
+ rc->warning->before = &rc->db_before;
+ rc->warning->rrdcalc = rc;
+ }
+
+ if(rc->critical) {
+ rc->critical->status = &rc->status;
+ rc->critical->this = &rc->value;
+ rc->critical->after = &rc->db_after;
+ rc->critical->before = &rc->db_before;
+ rc->critical->rrdcalc = rc;
+ }
+
+ // link it to the host
+ if(likely(host->alarms)) {
+ // append it
+ RRDCALC *t;
+ for(t = host->alarms; t && t->next ; t = t->next) ;
+ t->next = rc;
+ }
+ else {
+ host->alarms = rc;
+ }
+
+ // link it to its chart
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ if(rrdcalc_is_matching_this_rrdset(rc, st)) {
+ rrdsetcalc_link(st, rc);
+ break;
+ }
+ }
+}
+
+inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
+
+ debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
+
+ if(rrdcalc_exists(host, chart, rt->name, 0, 0))
+ return NULL;
+
+ RRDCALC *rc = callocz(1, sizeof(RRDCALC));
+ rc->next_event_id = 1;
+ rc->id = rrdcalc_get_unique_id(host, chart, rt->name, &rc->next_event_id);
+ rc->name = strdupz(rt->name);
+ rc->hash = simple_hash(rc->name);
+ rc->chart = strdupz(chart);
+ rc->hash_chart = simple_hash(rc->chart);
+
+ if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
+
+ rc->green = rt->green;
+ rc->red = rt->red;
+ rc->value = NAN;
+ rc->old_value = NAN;
+
+ rc->delay_up_duration = rt->delay_up_duration;
+ rc->delay_down_duration = rt->delay_down_duration;
+ rc->delay_max_duration = rt->delay_max_duration;
+ rc->delay_multiplier = rt->delay_multiplier;
+
+ rc->group = rt->group;
+ rc->after = rt->after;
+ rc->before = rt->before;
+ rc->update_every = rt->update_every;
+ rc->options = rt->options;
+
+ if(rt->exec) rc->exec = strdupz(rt->exec);
+ if(rt->recipient) rc->recipient = strdupz(rt->recipient);
+ if(rt->source) rc->source = strdupz(rt->source);
+ if(rt->units) rc->units = strdupz(rt->units);
+ if(rt->info) rc->info = strdupz(rt->info);
+
+ if(rt->calculation) {
+ rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
+ if(!rc->calculation)
+ error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
+ }
+ if(rt->warning) {
+ rc->warning = expression_parse(rt->warning->source, NULL, NULL);
+ if(!rc->warning)
+ error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
+ }
+ if(rt->critical) {
+ rc->critical = expression_parse(rt->critical->source, NULL, NULL);
+ if(!rc->critical)
+ error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
+ }
+
+ debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
+ (rc->chart)?rc->chart:"NOCHART",
+ rc->name,
+ (rc->exec)?rc->exec:"DEFAULT",
+ (rc->recipient)?rc->recipient:"DEFAULT",
+ rc->green,
+ rc->red,
+ rc->group,
+ rc->after,
+ rc->before,
+ rc->options,
+ (rc->dimensions)?rc->dimensions:"NONE",
+ rc->update_every,
+ (rc->calculation)?rc->calculation->parsed_as:"NONE",
+ (rc->warning)?rc->warning->parsed_as:"NONE",
+ (rc->critical)?rc->critical->parsed_as:"NONE",
+ rc->source,
+ rc->delay_up_duration,
+ rc->delay_down_duration,
+ rc->delay_max_duration,
+ rc->delay_multiplier
+ );
+
+ rrdcalc_create_part2(host, rc);
+ return rc;
+}
+
+void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
+ if(!rc) return;
+
+ debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
+
+ // unlink it from RRDSET
+ if(rc->rrdset) rrdsetcalc_unlink(rc);
+
+ // unlink it from RRDHOST
+ if(unlikely(rc == host->alarms))
+ host->alarms = rc->next;
+
+ else {
+ RRDCALC *t;
+ for(t = host->alarms; t && t->next != rc; t = t->next) ;
+ if(t) {
+ t->next = rc->next;
+ rc->next = NULL;
+ }
+ else
+ error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
+ }
+
+ expression_free(rc->calculation);
+ expression_free(rc->warning);
+ expression_free(rc->critical);
+
+ freez(rc->name);
+ freez(rc->chart);
+ freez(rc->family);
+ freez(rc->dimensions);
+ freez(rc->exec);
+ freez(rc->recipient);
+ freez(rc->source);
+ freez(rc->units);
+ freez(rc->info);
+ freez(rc);
+}
diff --git a/src/rrdcalctemplate.c b/src/rrdcalctemplate.c
new file mode 100644
index 000000000..2c5e2bd16
--- /dev/null
+++ b/src/rrdcalctemplate.c
@@ -0,0 +1,62 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDCALCTEMPLATE management
+
+void rrdcalctemplate_link_matching(RRDSET *st) {
+ RRDCALCTEMPLATE *rt;
+
+ for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
+ if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)
+ && (!rt->family_pattern || simple_pattern_matches(rt->family_pattern, st->family))) {
+ RRDCALC *rc = rrdcalc_create(st->rrdhost, rt, st->id);
+ if(unlikely(!rc))
+ error("Health tried to create alarm from template '%s', but it failed", rt->name);
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ else if(rc->rrdset != st)
+ error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
+#endif
+ }
+ }
+}
+
+inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
+ if(unlikely(!rt)) return;
+
+ debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
+
+ if(host->templates == rt) {
+ host->templates = rt->next;
+ }
+ else {
+ RRDCALCTEMPLATE *t;
+ for (t = host->templates; t && t->next != rt; t = t->next ) ;
+ if(t) {
+ t->next = rt->next;
+ rt->next = NULL;
+ }
+ else
+ error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
+ }
+
+ expression_free(rt->calculation);
+ expression_free(rt->warning);
+ expression_free(rt->critical);
+
+ freez(rt->family_match);
+ simple_pattern_free(rt->family_pattern);
+
+ freez(rt->name);
+ freez(rt->exec);
+ freez(rt->recipient);
+ freez(rt->context);
+ freez(rt->source);
+ freez(rt->units);
+ freez(rt->info);
+ freez(rt->dimensions);
+ freez(rt);
+}
+
+
diff --git a/src/rrddim.c b/src/rrddim.c
new file mode 100644
index 000000000..54a17522f
--- /dev/null
+++ b/src/rrddim.c
@@ -0,0 +1,313 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDDIM index
+
+int rrddim_compare(void* a, void* b) {
+ if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
+ else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
+ else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
+}
+
+#define rrddim_index_add(st, rd) (RRDDIM *)avl_insert_lock(&((st)->dimensions_index), (avl *)(rd))
+#define rrddim_index_del(st,rd ) (RRDDIM *)avl_remove_lock(&((st)->dimensions_index), (avl *)(rd))
+
+static inline RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
+ RRDDIM tmp = {
+ .id = id,
+ .hash = (hash)?hash:simple_hash(id)
+ };
+ return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM - find a dimension
+
+inline RRDDIM *rrddim_find(RRDSET *st, const char *id) {
+ debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
+
+ return rrddim_index_find(st, id, 0);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM rename a dimension
+
+inline void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name) {
+ if(unlikely(!strcmp(rd->name, name)))
+ return;
+
+ debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", st->name, rd->name, st->name, name);
+
+ char varname[CONFIG_MAX_NAME + 1];
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
+ rd->name = config_set_default(st->config_section, varname, name);
+ rd->hash_name = simple_hash(rd->name);
+
+ rrddimvar_rename_all(rd);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM create a dimension
+
+RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm) {
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(rd)) {
+ debug(D_RRD_CALLS, "Cannot create rrd dimension '%s/%s', it already exists.", st->id, name?name:"<NONAME>");
+ return rd;
+ }
+
+ char filename[FILENAME_MAX + 1];
+ char fullfilename[FILENAME_MAX + 1];
+
+ char varname[CONFIG_MAX_NAME + 1];
+ unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
+
+ debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
+
+ rrdset_strncpyz_name(filename, id, FILENAME_MAX);
+ snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ rd = (RRDDIM *)mymmap(fullfilename, size, ((st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 1);
+ if(likely(rd)) {
+ // we have a file mapped for rd
+
+ memset(&rd->avl, 0, sizeof(avl));
+ rd->id = NULL;
+ rd->name = NULL;
+ rd->cache_filename = NULL;
+ rd->variables = NULL;
+ rd->next = NULL;
+ rd->rrdset = NULL;
+
+ struct timeval now;
+ now_realtime_timeval(&now);
+
+ if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
+ errno = 0;
+ info("Initializing file %s.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->memsize != size) {
+ errno = 0;
+ error("File %s does not have the desired size. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->multiplier != multiplier) {
+ errno = 0;
+ error("File %s does not have the same multiplier. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->divisor != divisor) {
+ errno = 0;
+ error("File %s does not have the same divisor. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(rd->update_every != st->update_every) {
+ errno = 0;
+ error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+ else if(dt_usec(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * USEC_PER_SEC)) {
+ errno = 0;
+ error("File %s is too old. Clearing it.", fullfilename);
+ memset(rd, 0, size);
+ }
+
+ if(rd->algorithm && rd->algorithm != algorithm)
+ error("File %s does not have the expected algorithm (expected %u '%s', found %u '%s'). Previous values may be wrong."
+ , fullfilename, algorithm, rrd_algorithm_name(algorithm), rd->algorithm,
+ rrd_algorithm_name(rd->algorithm));
+
+ // make sure we have the right memory mode
+ // even if we cleared the memory
+ rd->rrd_memory_mode = st->rrd_memory_mode;
+ }
+ }
+
+ if(unlikely(!rd)) {
+ // if we didn't manage to get a mmap'd dimension, just create one
+ rd = callocz(1, size);
+ rd->rrd_memory_mode = (st->rrd_memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_RAM;
+ }
+
+ rd->memsize = size;
+
+ strcpy(rd->magic, RRDDIMENSION_MAGIC);
+
+ rd->id = strdupz(id);
+ rd->hash = simple_hash(rd->id);
+
+ rd->cache_filename = strdupz(fullfilename);
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
+ rd->name = config_get(st->config_section, varname, (name && *name)?name:rd->id);
+ rd->hash_name = simple_hash(rd->name);
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
+ rd->algorithm = rrd_algorithm_id(config_get(st->config_section, varname, rrd_algorithm_name(algorithm)));
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
+ rd->multiplier = config_get_number(st->config_section, varname, multiplier);
+
+ snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
+ rd->divisor = config_get_number(st->config_section, varname, divisor);
+ if(!rd->divisor) rd->divisor = 1;
+
+ rd->entries = st->entries;
+ rd->update_every = st->update_every;
+
+ // prevent incremental calculation spikes
+ rd->collections_counter = 0;
+ rd->updated = 0;
+ rd->flags = 0x00000000;
+
+ rd->calculated_value = 0;
+ rd->last_calculated_value = 0;
+ rd->collected_value = 0;
+ rd->last_collected_value = 0;
+ rd->collected_volume = 0;
+ rd->stored_volume = 0;
+ rd->last_stored_value = 0;
+ rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+ rd->last_collected_time.tv_sec = 0;
+ rd->last_collected_time.tv_usec = 0;
+ rd->rrdset = st;
+
+ // append this dimension
+ rrdset_wrlock(st);
+ if(!st->dimensions)
+ st->dimensions = rd;
+ else {
+ RRDDIM *td = st->dimensions;
+ for(; td->next; td = td->next) ;
+ td->next = rd;
+ }
+
+ if(st->rrdhost->health_enabled) {
+ rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, 0);
+ rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, 0);
+ rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, 0);
+ }
+
+ rrdset_unlock(st);
+
+ if(unlikely(rrddim_index_add(st, rd) != rd))
+ error("RRDDIM: INTERNAL ERROR: attempt to index duplicate dimension '%s' on chart '%s'", rd->id, st->id);
+
+ return(rd);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM remove / free a dimension
+
+void rrddim_free(RRDSET *st, RRDDIM *rd)
+{
+ debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
+
+ if(rd == st->dimensions)
+ st->dimensions = rd->next;
+ else {
+ RRDDIM *i;
+ for (i = st->dimensions; i && i->next != rd; i = i->next) ;
+
+ if (i && i->next == rd)
+ i->next = rd->next;
+ else
+ error("Request to free dimension '%s.%s' but it is not linked.", st->id, rd->name);
+ }
+ rd->next = NULL;
+
+ while(rd->variables)
+ rrddimvar_free(rd->variables);
+
+ if(unlikely(rrddim_index_del(st, rd) != rd))
+ error("RRDDIM: INTERNAL ERROR: attempt to remove from index dimension '%s' on chart '%s', removed a different dimension.", rd->id, st->id);
+
+ // free(rd->annotations);
+
+ switch(rd->rrd_memory_mode) {
+ case RRD_MEMORY_MODE_SAVE:
+ debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ savememory(rd->cache_filename, rd, rd->memsize);
+ // continue to map mode - no break;
+
+ case RRD_MEMORY_MODE_MAP:
+ debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
+ freez((void *)rd->id);
+ freez(rd->cache_filename);
+ munmap(rd, rd->memsize);
+ break;
+
+ case RRD_MEMORY_MODE_NONE:
+ case RRD_MEMORY_MODE_RAM:
+ debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
+ freez((void *)rd->id);
+ freez(rd->cache_filename);
+ freez(rd);
+ break;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM - set dimension options
+
+int rrddim_hide(RRDSET *st, const char *id) {
+ debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
+
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+ return 1;
+ }
+
+ rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
+ return 0;
+}
+
+int rrddim_unhide(RRDSET *st, const char *id) {
+ debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
+
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+ return 1;
+ }
+
+ rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
+ return 0;
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDDIM - collect values for a dimension
+
+inline collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value) {
+ debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
+
+ now_realtime_timeval(&rd->last_collected_time);
+ rd->collected_value = value;
+ rd->updated = 1;
+
+ rd->collections_counter++;
+
+ // fprintf(stderr, "%s.%s %llu " COLLECTED_NUMBER_FORMAT " dt %0.6f" " rate " CALCULATED_NUMBER_FORMAT "\n", st->name, rd->name, st->usec_since_last_update, value, (float)((double)st->usec_since_last_update / (double)1000000), (calculated_number)((value - rd->last_collected_value) * (calculated_number)rd->multiplier / (calculated_number)rd->divisor * 1000000.0 / (calculated_number)st->usec_since_last_update));
+
+ return rd->last_collected_value;
+}
+
+collected_number rrddim_set(RRDSET *st, const char *id, collected_number value) {
+ RRDDIM *rd = rrddim_find(st, id);
+ if(unlikely(!rd)) {
+ error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+ return 0;
+ }
+
+ return rrddim_set_by_pointer(st, rd, value);
+}
diff --git a/src/rrddimvar.c b/src/rrddimvar.c
new file mode 100644
index 000000000..f6eb6d8ef
--- /dev/null
+++ b/src/rrddimvar.c
@@ -0,0 +1,210 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDDIMVAR management
+// DIMENSION VARIABLES
+
+#define RRDDIMVAR_ID_MAX 1024
+
+static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+
+ // CHART VARIABLES FOR THIS DIMENSION
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id);
+ rs->var_local_id = NULL;
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name);
+ rs->var_local_name = NULL;
+
+ // FAMILY VARIABLES FOR THIS DIMENSION
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id);
+ rs->var_family_id = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
+ rs->var_family_name = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid);
+ rs->var_family_contextid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname);
+ rs->var_family_contextname = NULL;
+
+ // HOST VARIABLES FOR THIS DIMENSION
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid);
+ rs->var_host_chartidid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname);
+ rs->var_host_chartidname = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid);
+ rs->var_host_chartnameid = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename);
+ rs->var_host_chartnamename = NULL;
+
+ // KEYS
+
+ freez(rs->key_id);
+ rs->key_id = NULL;
+
+ freez(rs->key_name);
+ rs->key_name = NULL;
+
+ freez(rs->key_fullidid);
+ rs->key_fullidid = NULL;
+
+ freez(rs->key_fullidname);
+ rs->key_fullidname = NULL;
+
+ freez(rs->key_contextid);
+ rs->key_contextid = NULL;
+
+ freez(rs->key_contextname);
+ rs->key_contextname = NULL;
+
+ freez(rs->key_fullnameid);
+ rs->key_fullnameid = NULL;
+
+ freez(rs->key_fullnamename);
+ rs->key_fullnamename = NULL;
+}
+
+static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
+ rrddimvar_free_variables(rs);
+
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+
+ char buffer[RRDDIMVAR_ID_MAX + 1];
+
+ // KEYS
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
+ rs->key_id = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
+ rs->key_name = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
+ rs->key_fullidid = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
+ rs->key_fullidname = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
+ rs->key_contextid = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
+ rs->key_contextname = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
+ rs->key_fullnameid = strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
+ rs->key_fullnamename = strdupz(buffer);
+
+ // CHART VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $id
+ // - $name
+
+ rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value);
+ rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value);
+
+ // FAMILY VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $id (only the first, when multiple overlap)
+ // - $name (only the first, when multiple overlap)
+ // - $chart-context.id
+ // - $chart-context.name
+
+ rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value);
+ rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value);
+ rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value);
+ rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value);
+
+ // HOST VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $chart-id.id
+ // - $chart-id.name
+ // - $chart-name.id
+ // - $chart-name.name
+
+ rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value);
+ rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value);
+ rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value);
+ rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value);
+}
+
+RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
+ RRDSET *st = rd->rrdset;
+
+ debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", st->id, st->name, rd->id, (prefix)?prefix:"", rd->name, (suffix)?suffix:"");
+
+ if(!prefix) prefix = "";
+ if(!suffix) suffix = "";
+
+ RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
+
+ rs->prefix = strdupz(prefix);
+ rs->suffix = strdupz(suffix);
+
+ rs->type = type;
+ rs->value = value;
+ rs->options = options;
+ rs->rrddim = rd;
+
+ rs->next = rd->variables;
+ rd->variables = rs;
+
+ rrddimvar_create_variables(rs);
+
+ return rs;
+}
+
+void rrddimvar_rename_all(RRDDIM *rd) {
+ RRDSET *st = rd->rrdset;
+ debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+
+ RRDDIMVAR *rs, *next = rd->variables;
+ while((rs = next)) {
+ next = rs->next;
+ rrddimvar_create_variables(rs);
+ }
+}
+
+void rrddimvar_free(RRDDIMVAR *rs) {
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+ debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", st->id, st->name, rd->id, rd->name, rs->prefix, rs->suffix);
+
+ rrddimvar_free_variables(rs);
+
+ if(rd->variables == rs) {
+ debug(D_VARIABLES, "RRDDIMSET removing first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+ rd->variables = rs->next;
+ }
+ else {
+ debug(D_VARIABLES, "RRDDIMSET removing non-first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+ RRDDIMVAR *t;
+ for (t = rd->variables; t && t->next != rs; t = t->next) ;
+ if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
+ else t->next = rs->next;
+ }
+
+ freez(rs->prefix);
+ freez(rs->suffix);
+ freez(rs);
+}
+
diff --git a/src/rrdfamily.c b/src/rrdfamily.c
new file mode 100644
index 000000000..fc203e915
--- /dev/null
+++ b/src/rrdfamily.c
@@ -0,0 +1,58 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDFAMILY index
+
+int rrdfamily_compare(void *a, void *b) {
+ if(((RRDFAMILY *)a)->hash_family < ((RRDFAMILY *)b)->hash_family) return -1;
+ else if(((RRDFAMILY *)a)->hash_family > ((RRDFAMILY *)b)->hash_family) return 1;
+ else return strcmp(((RRDFAMILY *)a)->family, ((RRDFAMILY *)b)->family);
+}
+
+#define rrdfamily_index_add(host, rc) (RRDFAMILY *)avl_insert_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
+#define rrdfamily_index_del(host, rc) (RRDFAMILY *)avl_remove_lock(&((host)->rrdfamily_root_index), (avl *)(rc))
+
+static RRDFAMILY *rrdfamily_index_find(RRDHOST *host, const char *id, uint32_t hash) {
+ RRDFAMILY tmp;
+ tmp.family = id;
+ tmp.hash_family = (hash)?hash:simple_hash(tmp.family);
+
+ return (RRDFAMILY *)avl_search_lock(&(host->rrdfamily_root_index), (avl *) &tmp);
+}
+
+RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id) {
+ RRDFAMILY *rc = rrdfamily_index_find(host, id, 0);
+ if(!rc) {
+ rc = callocz(1, sizeof(RRDFAMILY));
+
+ rc->family = strdupz(id);
+ rc->hash_family = simple_hash(rc->family);
+
+ // initialize the variables index
+ avl_init_lock(&rc->variables_root_index, rrdvar_compare);
+
+ RRDFAMILY *ret = rrdfamily_index_add(host, rc);
+ if(ret != rc)
+ fatal("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE");
+ }
+
+ rc->use_count++;
+ return rc;
+}
+
+void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc) {
+ rc->use_count--;
+ if(!rc->use_count) {
+ RRDFAMILY *ret = rrdfamily_index_del(host, rc);
+ if(ret != rc)
+ fatal("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE");
+
+ if(rc->variables_root_index.avl_tree.root != NULL)
+ fatal("RRDFAMILY: INTERNAL ERROR: Variables index of RRDFAMILY '%s' that is freed, is not empty.", rc->family);
+
+ freez((void *)rc->family);
+ freez(rc);
+ }
+}
+
diff --git a/src/rrdhost.c b/src/rrdhost.c
new file mode 100644
index 000000000..a2310330d
--- /dev/null
+++ b/src/rrdhost.c
@@ -0,0 +1,583 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+RRDHOST *localhost = NULL;
+size_t rrd_hosts_available = 0;
+netdata_rwlock_t rrd_rwlock = NETDATA_RWLOCK_INITIALIZER;
+
+time_t rrdset_free_obsolete_time = 3600;
+time_t rrdhost_free_orphan_time = 3600;
+
+// ----------------------------------------------------------------------------
+// RRDHOST index
+
+int rrdhost_compare(void* a, void* b) {
+ if(((RRDHOST *)a)->hash_machine_guid < ((RRDHOST *)b)->hash_machine_guid) return -1;
+ else if(((RRDHOST *)a)->hash_machine_guid > ((RRDHOST *)b)->hash_machine_guid) return 1;
+ else return strcmp(((RRDHOST *)a)->machine_guid, ((RRDHOST *)b)->machine_guid);
+}
+
+avl_tree_lock rrdhost_root_index = {
+ .avl_tree = { NULL, rrdhost_compare },
+ .rwlock = AVL_LOCK_INITIALIZER
+};
+
+RRDHOST *rrdhost_find_by_guid(const char *guid, uint32_t hash) {
+ debug(D_RRDHOST, "Searching in index for host with guid '%s'", guid);
+
+ RRDHOST tmp;
+ strncpyz(tmp.machine_guid, guid, GUID_LEN);
+ tmp.hash_machine_guid = (hash)?hash:simple_hash(tmp.machine_guid);
+
+ return (RRDHOST *)avl_search_lock(&(rrdhost_root_index), (avl *) &tmp);
+}
+
+RRDHOST *rrdhost_find_by_hostname(const char *hostname, uint32_t hash) {
+ if(unlikely(!strcmp(hostname, "localhost")))
+ return localhost;
+
+ if(unlikely(!hash)) hash = simple_hash(hostname);
+
+ rrd_rdlock();
+ RRDHOST *host;
+ rrdhost_foreach_read(host) {
+ if(unlikely((hash == host->hash_hostname && !strcmp(hostname, host->hostname)))) {
+ rrd_unlock();
+ return host;
+ }
+ }
+ rrd_unlock();
+
+ return NULL;
+}
+
+#define rrdhost_index_add(rrdhost) (RRDHOST *)avl_insert_lock(&(rrdhost_root_index), (avl *)(rrdhost))
+#define rrdhost_index_del(rrdhost) (RRDHOST *)avl_remove_lock(&(rrdhost_root_index), (avl *)(rrdhost))
+
+
+// ----------------------------------------------------------------------------
+// RRDHOST - internal helpers
+
+static inline void rrdhost_init_hostname(RRDHOST *host, const char *hostname) {
+ freez(host->hostname);
+ host->hostname = strdupz(hostname);
+ host->hash_hostname = simple_hash(host->hostname);
+}
+
+static inline void rrdhost_init_os(RRDHOST *host, const char *os) {
+ freez(host->os);
+ host->os = strdupz(os?os:"unknown");
+}
+
+static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_guid) {
+ strncpy(host->machine_guid, machine_guid, GUID_LEN);
+ host->machine_guid[GUID_LEN] = '\0';
+ host->hash_machine_guid = simple_hash(host->machine_guid);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDHOST - add a host
+
+RRDHOST *rrdhost_create(const char *hostname,
+ const char *guid,
+ const char *os,
+ int update_every,
+ long entries,
+ RRD_MEMORY_MODE memory_mode,
+ int health_enabled,
+ int rrdpush_enabled,
+ char *rrdpush_destination,
+ char *rrdpush_api_key,
+ int is_localhost
+) {
+ debug(D_RRDHOST, "Host '%s': adding with guid '%s'", hostname, guid);
+
+ rrd_check_wrlock();
+
+ RRDHOST *host = callocz(1, sizeof(RRDHOST));
+
+ host->rrd_update_every = (update_every > 0)?update_every:1;
+ host->rrd_history_entries = align_entries_to_pagesize(memory_mode, entries);
+ host->rrd_memory_mode = memory_mode;
+ host->health_enabled = (memory_mode == RRD_MEMORY_MODE_NONE)? 0 : health_enabled;
+ host->rrdpush_enabled = (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key);
+ host->rrdpush_destination = (host->rrdpush_enabled)?strdupz(rrdpush_destination):NULL;
+ host->rrdpush_api_key = (host->rrdpush_enabled)?strdupz(rrdpush_api_key):NULL;
+
+ host->rrdpush_pipe[0] = -1;
+ host->rrdpush_pipe[1] = -1;
+ host->rrdpush_socket = -1;
+
+ netdata_mutex_init(&host->rrdpush_mutex);
+ netdata_rwlock_init(&host->rrdhost_rwlock);
+
+ rrdhost_init_hostname(host, hostname);
+ rrdhost_init_machine_guid(host, guid);
+ rrdhost_init_os(host, os);
+
+ avl_init_lock(&(host->rrdset_root_index), rrdset_compare);
+ avl_init_lock(&(host->rrdset_root_index_name), rrdset_compare_name);
+ avl_init_lock(&(host->rrdfamily_root_index), rrdfamily_compare);
+ avl_init_lock(&(host->variables_root_index), rrdvar_compare);
+
+ if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete obsolete charts files", 1))
+ rrdhost_flag_set(host, RRDHOST_DELETE_OBSOLETE_FILES);
+
+ if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete orphan hosts files", 1) && !is_localhost)
+ rrdhost_flag_set(host, RRDHOST_DELETE_ORPHAN_FILES);
+
+
+ // ------------------------------------------------------------------------
+ // initialize health variables
+
+ host->health_log.next_log_id = 1;
+ host->health_log.next_alarm_id = 1;
+ host->health_log.max = 1000;
+ host->health_log.next_log_id =
+ host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
+
+ long n = config_get_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", host->health_log.max);
+ if(n < 10) {
+ error("Host '%s': health configuration has invalid max log entries %ld. Using default %u", host->hostname, n, host->health_log.max);
+ config_set_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", (long)host->health_log.max);
+ }
+ else
+ host->health_log.max = (unsigned int)n;
+
+ netdata_rwlock_init(&host->health_log.alarm_log_rwlock);
+
+ char filename[FILENAME_MAX + 1];
+
+ if(is_localhost) {
+
+ host->cache_dir = strdupz(netdata_configured_cache_dir);
+ host->varlib_dir = strdupz(netdata_configured_varlib_dir);
+
+ }
+ else {
+ // this is not localhost - append our GUID to localhost path
+
+ snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_cache_dir, host->machine_guid);
+ host->cache_dir = strdupz(filename);
+
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_MAP || host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ int r = mkdir(host->cache_dir, 0775);
+ if(r != 0 && errno != EEXIST)
+ error("Host '%s': cannot create directory '%s'", host->hostname, host->cache_dir);
+ }
+
+ snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_varlib_dir, host->machine_guid);
+ host->varlib_dir = strdupz(filename);
+
+ if(host->health_enabled) {
+ int r = mkdir(host->varlib_dir, 0775);
+ if(r != 0 && errno != EEXIST)
+ error("Host '%s': cannot create directory '%s'", host->hostname, host->varlib_dir);
+ }
+
+ }
+
+ if(host->health_enabled) {
+ snprintfz(filename, FILENAME_MAX, "%s/health", host->varlib_dir);
+ int r = mkdir(filename, 0775);
+ if(r != 0 && errno != EEXIST)
+ error("Host '%s': cannot create directory '%s'", host->hostname, filename);
+ }
+
+ snprintfz(filename, FILENAME_MAX, "%s/health/health-log.db", host->varlib_dir);
+ host->health_log_filename = strdupz(filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_plugins_dir);
+ host->health_default_exec = strdupz(config_get(CONFIG_SECTION_HEALTH, "script to execute on alarm", filename));
+ host->health_default_recipient = strdup("root");
+
+
+ // ------------------------------------------------------------------------
+ // load health configuration
+
+ if(host->health_enabled) {
+ health_alarm_log_load(host);
+ health_alarm_log_open(host);
+
+ rrdhost_wrlock(host);
+ health_readdir(host, health_config_dir());
+ rrdhost_unlock(host);
+ }
+
+
+ // ------------------------------------------------------------------------
+ // link it and add it to the index
+
+ if(is_localhost) {
+ host->next = localhost;
+ localhost = host;
+ }
+ else {
+ if(localhost) {
+ host->next = localhost->next;
+ localhost->next = host;
+ }
+ else localhost = host;
+ }
+
+ RRDHOST *t = rrdhost_index_add(host);
+
+ if(t != host) {
+ error("Host '%s': cannot add host with machine guid '%s' to index. It already exists as host '%s' with machine guid '%s'.", host->hostname, host->machine_guid, t->hostname, t->machine_guid);
+ rrdhost_free(host);
+ host = NULL;
+ }
+ else {
+ info("Host '%s' with guid '%s' initialized"
+ ", os %s"
+ ", update every %d"
+ ", memory mode %s"
+ ", history entries %ld"
+ ", streaming %s"
+ " (to '%s' with api key '%s')"
+ ", health %s"
+ ", cache_dir '%s'"
+ ", varlib_dir '%s'"
+ ", health_log '%s'"
+ ", alarms default handler '%s'"
+ ", alarms default recipient '%s'"
+ , host->hostname
+ , host->machine_guid
+ , host->os
+ , host->rrd_update_every
+ , rrd_memory_mode_name(host->rrd_memory_mode)
+ , host->rrd_history_entries
+ , host->rrdpush_enabled?"enabled":"disabled"
+ , host->rrdpush_destination?host->rrdpush_destination:""
+ , host->rrdpush_api_key?host->rrdpush_api_key:""
+ , host->health_enabled?"enabled":"disabled"
+ , host->cache_dir
+ , host->varlib_dir
+ , host->health_log_filename
+ , host->health_default_exec
+ , host->health_default_recipient
+ );
+ }
+
+ rrd_hosts_available++;
+
+ return host;
+}
+
+RRDHOST *rrdhost_find_or_create(
+ const char *hostname
+ , const char *guid
+ , const char *os
+ , int update_every
+ , long history
+ , RRD_MEMORY_MODE mode
+ , int health_enabled
+ , int rrdpush_enabled
+ , char *rrdpush_destination
+ , char *rrdpush_api_key
+) {
+ debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
+
+ rrd_wrlock();
+ RRDHOST *host = rrdhost_find_by_guid(guid, 0);
+ if(!host) {
+ host = rrdhost_create(
+ hostname
+ , guid
+ , os
+ , update_every
+ , history
+ , mode
+ , health_enabled
+ , rrdpush_enabled
+ , rrdpush_destination
+ , rrdpush_api_key
+ , 0
+ );
+ }
+ else {
+ host->health_enabled = health_enabled;
+
+ if(strcmp(host->hostname, hostname)) {
+ char *t = host->hostname;
+ host->hostname = strdupz(hostname);
+ host->hash_hostname = simple_hash(host->hostname);
+ freez(t);
+ }
+
+ if(host->rrd_update_every != update_every)
+ error("Host '%s' has an update frequency of %d seconds, but the wanted one is %d seconds.", host->hostname, host->rrd_update_every, update_every);
+
+ if(host->rrd_history_entries != history)
+ error("Host '%s' has history of %ld entries, but the wanted one is %ld entries.", host->hostname, host->rrd_history_entries, history);
+
+ if(host->rrd_memory_mode != mode)
+ error("Host '%s' has memory mode '%s', but the wanted one is '%s'.", host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
+ }
+ rrd_unlock();
+
+ rrdhost_cleanup_orphan(host);
+
+ return host;
+}
+
+static inline int rrdhost_should_be_deleted(RRDHOST *host, RRDHOST *protected, time_t now) {
+ if(host != protected
+ && host != localhost
+ && !host->connected_senders
+ && host->senders_disconnected_time
+ && host->senders_disconnected_time + rrdhost_free_orphan_time < now)
+ return 1;
+
+ return 0;
+}
+
+void rrdhost_cleanup_orphan(RRDHOST *protected) {
+ time_t now = now_realtime_sec();
+
+ rrd_wrlock();
+
+ RRDHOST *host;
+
+restart_after_removal:
+ rrdhost_foreach_write(host) {
+ if(rrdhost_should_be_deleted(host, protected, now)) {
+ info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", host->hostname, host->machine_guid);
+
+ if(rrdset_flag_check(host, RRDHOST_ORPHAN))
+ rrdhost_delete(host);
+ else
+ rrdhost_save(host);
+
+ rrdhost_free(host);
+ goto restart_after_removal;
+ }
+ }
+
+ rrd_unlock();
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST global / startup initialization
+
+void rrd_init(char *hostname) {
+ rrdset_free_obsolete_time = config_get_number(CONFIG_SECTION_GLOBAL, "cleanup obsolete charts after seconds", rrdset_free_obsolete_time);
+
+ health_init();
+ registry_init();
+ rrdpush_init();
+
+ debug(D_RRDHOST, "Initializing localhost with hostname '%s'", hostname);
+ rrd_wrlock();
+ localhost = rrdhost_create(
+ hostname
+ , registry_get_this_machine_guid()
+ , os_type
+ , default_rrd_update_every
+ , default_rrd_history_entries
+ , default_rrd_memory_mode
+ , default_health_enabled
+ , default_rrdpush_enabled
+ , default_rrdpush_destination
+ , default_rrdpush_api_key
+ , 1
+ );
+ rrd_unlock();
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - lock validations
+// there are only used when NETDATA_INTERNAL_CHECKS is set
+
+void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking read lock on host '%s'", host->hostname);
+
+ int ret = netdata_rwlock_trywrlock(&host->rrdhost_rwlock);
+ if(ret == 0)
+ fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
+}
+
+void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking write lock on host '%s'", host->hostname);
+
+ int ret = netdata_rwlock_tryrdlock(&host->rrdhost_rwlock);
+ if(ret == 0)
+ fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
+}
+
+void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking read lock on all RRDs");
+
+ int ret = netdata_rwlock_trywrlock(&rrd_rwlock);
+ if(ret == 0)
+ fatal("RRDs should be read-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
+}
+
+void __rrd_check_wrlock(const char *file, const char *function, const unsigned long line) {
+ debug(D_RRDHOST, "Checking write lock on all RRDs");
+
+ int ret = netdata_rwlock_tryrdlock(&rrd_rwlock);
+ if(ret == 0)
+ fatal("RRDs should be write-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - free
+
+void rrdhost_free(RRDHOST *host) {
+ if(!host) return;
+
+ info("Freeing all memory for host '%s'...", host->hostname);
+
+ rrd_check_wrlock(); // make sure the RRDs are write locked
+
+ // stop a possibly running thread
+ rrdpush_sender_thread_stop(host);
+
+ rrdhost_wrlock(host); // lock this RRDHOST
+
+ // ------------------------------------------------------------------------
+ // release its children resources
+
+ while(host->rrdset_root) rrdset_free(host->rrdset_root);
+
+ while(host->alarms) rrdcalc_free(host, host->alarms);
+ while(host->templates) rrdcalctemplate_free(host, host->templates);
+ health_alarm_log_free(host);
+
+
+ // ------------------------------------------------------------------------
+ // remove it from the indexes
+
+ if(rrdhost_index_del(host) != host)
+ error("RRDHOST '%s' removed from index, deleted the wrong entry.", host->hostname);
+
+
+ // ------------------------------------------------------------------------
+ // unlink it from the host
+
+ if(host == localhost) {
+ localhost = host->next;
+ }
+ else {
+ // find the previous one
+ RRDHOST *h;
+ for(h = localhost; h && h->next != host ; h = h->next) ;
+
+ // bypass it
+ if(h) h->next = host->next;
+ else error("Request to free RRDHOST '%s': cannot find it", host->hostname);
+ }
+
+ // ------------------------------------------------------------------------
+ // free it
+
+ freez(host->os);
+ freez(host->cache_dir);
+ freez(host->varlib_dir);
+ freez(host->rrdpush_api_key);
+ freez(host->rrdpush_destination);
+ freez(host->health_default_exec);
+ freez(host->health_default_recipient);
+ freez(host->health_log_filename);
+ freez(host->hostname);
+ rrdhost_unlock(host);
+ netdata_rwlock_destroy(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_destroy(&host->rrdhost_rwlock);
+ freez(host);
+
+ rrd_hosts_available--;
+}
+
+void rrdhost_free_all(void) {
+ rrd_wrlock();
+ while(localhost) rrdhost_free(localhost);
+ rrd_unlock();
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - save
+
+void rrdhost_save(RRDHOST *host) {
+ if(!host) return;
+
+ info("Saving database of host '%s'...", host->hostname);
+
+ RRDSET *st;
+
+ // we get a write lock
+ // to ensure only one thread is saving the database
+ rrdhost_wrlock(host);
+
+ rrdset_foreach_write(st, host) {
+ rrdset_rdlock(st);
+ rrdset_save(st);
+ rrdset_unlock(st);
+ }
+
+ rrdhost_unlock(host);
+}
+
+// ----------------------------------------------------------------------------
+// RRDHOST - delete files
+
+void rrdhost_delete(RRDHOST *host) {
+ if(!host) return;
+
+ info("Deleting database of host '%s'...", host->hostname);
+
+ RRDSET *st;
+
+ // we get a write lock
+ // to ensure only one thread is saving the database
+ rrdhost_wrlock(host);
+
+ rrdset_foreach_write(st, host) {
+ rrdset_rdlock(st);
+ rrdset_delete(st);
+ rrdset_unlock(st);
+ }
+
+ rrdhost_unlock(host);
+}
+
+void rrdhost_save_all(void) {
+ info("Saving database [%zu hosts(s)]...", rrd_hosts_available);
+
+ rrd_rdlock();
+
+ RRDHOST *host;
+ rrdhost_foreach_read(host)
+ rrdhost_save(host);
+
+ rrd_unlock();
+}
+
+void rrdhost_cleanup_obsolete(RRDHOST *host) {
+ time_t now = now_realtime_sec();
+
+ RRDSET *st;
+
+restart_after_removal:
+ rrdset_foreach_write(st, host) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)
+ && st->last_accessed_time + rrdset_free_obsolete_time < now
+ && st->last_updated.tv_sec + rrdset_free_obsolete_time < now
+ && st->last_collected_time.tv_sec + rrdset_free_obsolete_time < now
+ )) {
+
+ rrdset_rdlock(st);
+
+ if(rrdhost_flag_check(host, RRDHOST_DELETE_OBSOLETE_FILES))
+ rrdset_delete(st);
+ else
+ rrdset_save(st);
+
+ rrdset_unlock(st);
+
+ rrdset_free(st);
+ goto restart_after_removal;
+ }
+ }
+}
diff --git a/src/rrdpush.c b/src/rrdpush.c
new file mode 100644
index 000000000..72e6d8a73
--- /dev/null
+++ b/src/rrdpush.c
@@ -0,0 +1,761 @@
+#include "common.h"
+
+/*
+ * rrdpush
+ *
+ * 3 threads are involved for all stream operations
+ *
+ * 1. a random data collection thread, calling rrdset_done_push()
+ * this is called for each chart.
+ *
+ * the output of this work is kept in a BUFFER in RRDHOST
+ * the sender thread is signalled via a pipe (also in RRDHOST)
+ *
+ * 2. a sender thread running at the sending netdata
+ * this is spawned automatically on the first chart to be pushed
+ *
+ * It tries to push the metrics to the remote netdata, as fast
+ * as possible (i.e. immediately after they are collected).
+ *
+ * 3. a receiver thread, running at the receiving netdata
+ * this is spawned automatically when the sender connects to
+ * the receiver.
+ *
+ */
+
+#define START_STREAMING_PROMPT "Hit me baby, push them over..."
+
+int default_rrdpush_enabled = 0;
+char *default_rrdpush_destination = NULL;
+char *default_rrdpush_api_key = NULL;
+
+int rrdpush_init() {
+ default_rrdpush_enabled = appconfig_get_boolean(&stream_config, CONFIG_SECTION_STREAM, "enabled", default_rrdpush_enabled);
+ default_rrdpush_destination = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "destination", "");
+ default_rrdpush_api_key = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "api key", "");
+ rrdhost_free_orphan_time = config_get_number(CONFIG_SECTION_GLOBAL, "cleanup orphan hosts after seconds", rrdhost_free_orphan_time);
+
+ if(default_rrdpush_enabled && (!default_rrdpush_destination || !*default_rrdpush_destination || !default_rrdpush_api_key || !*default_rrdpush_api_key)) {
+ error("STREAM [send]: cannot enable sending thread - information is missing.");
+ default_rrdpush_enabled = 0;
+ }
+
+ return default_rrdpush_enabled;
+}
+
+#define CONNECTED_TO_SIZE 100
+
+// data collection happens from multiple threads
+// each of these threads calls rrdset_done()
+// which in turn calls rrdset_done_push()
+// which uses this pipe to notify the streaming thread
+// that there are more data ready to be sent
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+// to have the remote netdata re-sync the charts
+// to its current clock, we send for this many
+// iterations a BEGIN line without microseconds
+// this is for the first iterations of each chart
+static unsigned int remote_clock_resync_iterations = 60;
+
+#define rrdpush_lock(host) netdata_mutex_lock(&((host)->rrdpush_mutex))
+#define rrdpush_unlock(host) netdata_mutex_unlock(&((host)->rrdpush_mutex))
+
+// checks if the current chart definition has been sent
+static inline int need_to_send_chart_definition(RRDSET *st) {
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st)
+ if(!rd->exposed)
+ return 1;
+
+ return 0;
+}
+
+// sends the current chart definition
+static inline void send_chart_definition(RRDSET *st) {
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "CHART '%s' '%s' '%s' '%s' '%s' '%s' '%s' %ld %d\n"
+ , st->id
+ , st->name
+ , st->title
+ , st->units
+ , st->family
+ , st->context
+ , rrdset_type_name(st->chart_type)
+ , st->priority
+ , st->update_every
+ );
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "DIMENSION '%s' '%s' '%s' " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " '%s %s'\n"
+ , rd->id
+ , rd->name
+ , rrd_algorithm_name(rd->algorithm)
+ , rd->multiplier
+ , rd->divisor
+ , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?"hidden":""
+ , rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)?"noreset":""
+ );
+ rd->exposed = 1;
+ }
+}
+
+// sends the current chart dimensions
+static inline void send_chart_metrics(RRDSET *st) {
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "BEGIN %s %llu\n", st->id, (st->counter_done > remote_clock_resync_iterations)?st->usec_since_last_update:0);
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ if(rd->updated && rd->exposed)
+ buffer_sprintf(st->rrdhost->rrdpush_buffer, "SET %s = " COLLECTED_NUMBER_FORMAT "\n"
+ , rd->id
+ , rd->collected_value
+ );
+ }
+
+ buffer_strcat(st->rrdhost->rrdpush_buffer, "END\n");
+}
+
+void rrdpush_sender_thread_spawn(RRDHOST *host);
+
+void rrdset_done_push(RRDSET *st) {
+ RRDHOST *host = st->rrdhost;
+
+ if(unlikely(!rrdset_flag_check(st, RRDSET_FLAG_ENABLED)))
+ return;
+
+ rrdpush_lock(host);
+
+ if(unlikely(host->rrdpush_enabled && !host->rrdpush_spawn))
+ rrdpush_sender_thread_spawn(host);
+
+ if(unlikely(!host->rrdpush_buffer || !host->rrdpush_connected)) {
+ if(unlikely(!host->rrdpush_error_shown))
+ error("STREAM %s [send]: not ready - discarding collected metrics.", host->hostname);
+
+ host->rrdpush_error_shown = 1;
+
+ rrdpush_unlock(host);
+ return;
+ }
+ else if(unlikely(host->rrdpush_error_shown)) {
+ info("STREAM %s [send]: ready - sending metrics...", host->hostname);
+ host->rrdpush_error_shown = 0;
+ }
+
+ if(need_to_send_chart_definition(st))
+ send_chart_definition(st);
+
+ send_chart_metrics(st);
+
+ // signal the sender there are more data
+ if(write(host->rrdpush_pipe[PIPE_WRITE], " ", 1) == -1)
+ error("STREAM %s [send]: cannot write to internal pipe", host->hostname);
+
+ rrdpush_unlock(host);
+}
+
+// ----------------------------------------------------------------------------
+// rrdpush sender thread
+
+// resets all the chart, so that their definitions
+// will be resent to the central netdata
+static void rrdpush_sender_thread_reset_all_charts(RRDHOST *host) {
+ rrdhost_rdlock(host);
+
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+
+ // make it re-align the current time
+ // on the remote host
+ st->counter_done = 0;
+
+ rrdset_rdlock(st);
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st)
+ rd->exposed = 0;
+
+ rrdset_unlock(st);
+ }
+
+ rrdhost_unlock(host);
+}
+
+static inline void rrdpush_sender_thread_data_flush(RRDHOST *host) {
+ rrdpush_lock(host);
+
+ if(buffer_strlen(host->rrdpush_buffer))
+ error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", host->hostname, buffer_strlen(host->rrdpush_buffer));
+
+ buffer_flush(host->rrdpush_buffer);
+
+ rrdpush_sender_thread_reset_all_charts(host);
+
+ rrdpush_unlock(host);
+}
+
+static void rrdpush_sender_thread_cleanup_locked_all(RRDHOST *host) {
+ host->rrdpush_connected = 0;
+
+ if(host->rrdpush_socket != -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+
+ // close the pipe
+ if(host->rrdpush_pipe[PIPE_READ] != -1) {
+ close(host->rrdpush_pipe[PIPE_READ]);
+ host->rrdpush_pipe[PIPE_READ] = -1;
+ }
+
+ if(host->rrdpush_pipe[PIPE_WRITE] != -1) {
+ close(host->rrdpush_pipe[PIPE_WRITE]);
+ host->rrdpush_pipe[PIPE_WRITE] = -1;
+ }
+
+ buffer_free(host->rrdpush_buffer);
+ host->rrdpush_buffer = NULL;
+
+ host->rrdpush_spawn = 0;
+
+ rrdhost_flag_set(host, RRDHOST_ORPHAN);
+}
+
+void rrdpush_sender_thread_stop(RRDHOST *host) {
+ rrdpush_lock(host);
+ rrdhost_wrlock(host);
+
+ if(host->rrdpush_spawn) {
+ info("STREAM %s [send]: stopping sending thread...", host->hostname);
+ pthread_cancel(host->rrdpush_thread);
+ rrdpush_sender_thread_cleanup_locked_all(host);
+ }
+
+ rrdhost_unlock(host);
+ rrdpush_unlock(host);
+}
+
+void *rrdpush_sender_thread(void *ptr) {
+ RRDHOST *host = (RRDHOST *)ptr;
+
+ info("STREAM %s [send]: thread created (task id %d)", host->hostname, gettid());
+
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel type to DEFERRED.", host->hostname);
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname);
+
+ int timeout = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "timeout seconds", 60);
+ int default_port = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "default port", 19999);
+ size_t max_size = (size_t)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "buffer size bytes", 1024 * 1024);
+ unsigned int reconnect_delay = (unsigned int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "reconnect delay seconds", 5);
+ remote_clock_resync_iterations = (unsigned int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "initial clock resync iterations", remote_clock_resync_iterations);
+ char connected_to[CONNECTED_TO_SIZE + 1] = "";
+
+ if(!host->rrdpush_enabled || !host->rrdpush_destination || !*host->rrdpush_destination || !host->rrdpush_api_key || !*host->rrdpush_api_key)
+ goto cleanup;
+
+ // initialize rrdpush globals
+ host->rrdpush_buffer = buffer_create(1);
+ host->rrdpush_connected = 0;
+ if(pipe(host->rrdpush_pipe) == -1) fatal("STREAM %s [send]: cannot create required pipe.", host->hostname);
+
+ // initialize local variables
+ size_t begin = 0;
+ size_t reconnects_counter = 0;
+ size_t sent_bytes = 0;
+ size_t sent_connection = 0;
+
+ struct timeval tv = {
+ .tv_sec = timeout,
+ .tv_usec = 0
+ };
+
+ struct pollfd fds[2], *ifd, *ofd;
+ nfds_t fdmax;
+
+ ifd = &fds[0];
+ ofd = &fds[1];
+
+ for(; host->rrdpush_enabled && !netdata_exit ;) {
+
+ if(unlikely(host->rrdpush_socket == -1)) {
+ // stop appending data into rrdpush_buffer
+ // they will be lost, so there is no point to do it
+ host->rrdpush_connected = 0;
+
+ info("STREAM %s [send to %s]: connecting...", host->hostname, host->rrdpush_destination);
+ host->rrdpush_socket = connect_to_one_of(host->rrdpush_destination, default_port, &tv, &reconnects_counter, connected_to, CONNECTED_TO_SIZE);
+
+ if(unlikely(host->rrdpush_socket == -1)) {
+ error("STREAM %s [send to %s]: failed to connect", host->hostname, host->rrdpush_destination);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ info("STREAM %s [send to %s]: initializing communication...", host->hostname, connected_to);
+
+ char http[1000 + 1];
+ snprintfz(http, 1000,
+ "STREAM key=%s&hostname=%s&machine_guid=%s&os=%s&update_every=%d HTTP/1.1\r\n"
+ "User-Agent: netdata-push-service/%s\r\n"
+ "Accept: */*\r\n\r\n"
+ , host->rrdpush_api_key
+ , host->hostname
+ , host->machine_guid
+ , host->os
+ , default_rrd_update_every
+ , program_version
+ );
+
+ if(send_timeout(host->rrdpush_socket, http, strlen(http), 0, timeout) == -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ error("STREAM %s [send to %s]: failed to send http header to netdata", host->hostname, connected_to);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, connected_to);
+
+ if(recv_timeout(host->rrdpush_socket, http, 1000, 0, timeout) == -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ error("STREAM %s [send to %s]: failed to initialize communication", host->hostname, connected_to);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ if(strncmp(http, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT))) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ error("STREAM %s [send to %s]: server is not replying properly.", host->hostname, connected_to);
+ sleep(reconnect_delay);
+ continue;
+ }
+
+ info("STREAM %s [send to %s]: established communication - sending metrics...", host->hostname, connected_to);
+
+ if(fcntl(host->rrdpush_socket, F_SETFL, O_NONBLOCK) < 0)
+ error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", host->hostname, connected_to);
+
+ rrdpush_sender_thread_data_flush(host);
+ sent_connection = 0;
+
+ // allow appending data into rrdpush_buffer
+ host->rrdpush_connected = 1;
+ }
+
+ ifd->fd = host->rrdpush_pipe[PIPE_READ];
+ ifd->events = POLLIN;
+ ifd->revents = 0;
+
+ ofd->fd = host->rrdpush_socket;
+ ofd->revents = 0;
+ if(begin < buffer_strlen(host->rrdpush_buffer)) {
+ ofd->events = POLLOUT;
+ fdmax = 2;
+ }
+ else {
+ ofd->events = 0;
+ fdmax = 1;
+ }
+
+ if(netdata_exit) break;
+ int retval = poll(fds, fdmax, timeout * 1000);
+ if(netdata_exit) break;
+
+ if(unlikely(retval == -1)) {
+ if(errno == EAGAIN || errno == EINTR)
+ continue;
+
+ error("STREAM %s [send to %s]: failed to poll().", host->hostname, connected_to);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ break;
+ }
+ else if(unlikely(!retval)) {
+ // timeout
+ continue;
+ }
+
+ if(ifd->revents & POLLIN) {
+ char buffer[1000 + 1];
+ if(read(host->rrdpush_pipe[PIPE_READ], buffer, 1000) == -1)
+ error("STREAM %s [send to %s]: cannot read from internal pipe.", host->hostname, connected_to);
+ }
+
+ if(ofd->revents & POLLOUT && begin < buffer_strlen(host->rrdpush_buffer)) {
+
+ // BEGIN RRDPUSH LOCKED SESSION
+
+ // during this session, data collectors
+ // will not be able to append data to our buffer
+ // but the socket is in non-blocking mode
+ // so, we will not block at send()
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname);
+
+ rrdpush_lock(host);
+
+ ssize_t ret = send(host->rrdpush_socket, &host->rrdpush_buffer->buffer[begin], buffer_strlen(host->rrdpush_buffer) - begin, MSG_DONTWAIT);
+ if(ret == -1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection);
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+ }
+ else {
+ sent_connection += ret;
+ sent_bytes += ret;
+ begin += ret;
+ if(begin == buffer_strlen(host->rrdpush_buffer)) {
+ // we send it all
+
+ buffer_flush(host->rrdpush_buffer);
+ begin = 0;
+ }
+ }
+
+ rrdpush_unlock(host);
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname);
+
+ // END RRDPUSH LOCKED SESSION
+ }
+
+ // protection from overflow
+ if(host->rrdpush_buffer->len > max_size) {
+ errno = 0;
+ error("STREAM %s [send to %s]: too many data pending - buffer is %zu bytes long, %zu unsent - we have sent %zu bytes in total, %zu on this connection. Closing connection to flush the data.", host->hostname, connected_to, host->rrdpush_buffer->len, host->rrdpush_buffer->len - begin, sent_bytes, sent_connection);
+ if(host->rrdpush_socket != -1) {
+ close(host->rrdpush_socket);
+ host->rrdpush_socket = -1;
+ }
+ }
+ }
+
+cleanup:
+ debug(D_WEB_CLIENT, "STREAM %s [send]: sending thread exits.", host->hostname);
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname);
+
+ rrdpush_lock(host);
+ rrdhost_wrlock(host);
+ rrdpush_sender_thread_cleanup_locked_all(host);
+ rrdhost_unlock(host);
+ rrdpush_unlock(host);
+
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname);
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// rrdpush receiver thread
+
+int rrdpush_receive(int fd, const char *key, const char *hostname, const char *machine_guid, const char *os, int update_every, char *client_ip, char *client_port) {
+ RRDHOST *host;
+ int history = default_rrd_history_entries;
+ RRD_MEMORY_MODE mode = default_rrd_memory_mode;
+ int health_enabled = default_health_enabled;
+ int rrdpush_enabled = default_rrdpush_enabled;
+ char *rrdpush_destination = default_rrdpush_destination;
+ char *rrdpush_api_key = default_rrdpush_api_key;
+ time_t alarms_delay = 60;
+
+ update_every = (int)appconfig_get_number(&stream_config, machine_guid, "update every", update_every);
+ if(update_every < 0) update_every = 1;
+
+ history = (int)appconfig_get_number(&stream_config, key, "default history", history);
+ history = (int)appconfig_get_number(&stream_config, machine_guid, "history", history);
+ if(history < 5) history = 5;
+
+ mode = rrd_memory_mode_id(appconfig_get(&stream_config, key, "default memory mode", rrd_memory_mode_name(mode)));
+ mode = rrd_memory_mode_id(appconfig_get(&stream_config, machine_guid, "memory mode", rrd_memory_mode_name(mode)));
+
+ health_enabled = appconfig_get_boolean_ondemand(&stream_config, key, "health enabled by default", health_enabled);
+ health_enabled = appconfig_get_boolean_ondemand(&stream_config, machine_guid, "health enabled", health_enabled);
+
+ alarms_delay = appconfig_get_number(&stream_config, key, "default postpone alarms on connect seconds", alarms_delay);
+ alarms_delay = appconfig_get_number(&stream_config, machine_guid, "postpone alarms on connect seconds", alarms_delay);
+
+ rrdpush_enabled = appconfig_get_boolean(&stream_config, key, "default proxy enabled", rrdpush_enabled);
+ rrdpush_enabled = appconfig_get_boolean(&stream_config, machine_guid, "proxy enabled", rrdpush_enabled);
+
+ rrdpush_destination = appconfig_get(&stream_config, key, "default proxy destination", rrdpush_destination);
+ rrdpush_destination = appconfig_get(&stream_config, machine_guid, "proxy destination", rrdpush_destination);
+
+ rrdpush_api_key = appconfig_get(&stream_config, key, "default proxy api key", rrdpush_api_key);
+ rrdpush_api_key = appconfig_get(&stream_config, machine_guid, "proxy api key", rrdpush_api_key);
+
+ if(!strcmp(machine_guid, "localhost"))
+ host = localhost;
+ else
+ host = rrdhost_find_or_create(
+ hostname
+ , machine_guid
+ , os
+ , update_every
+ , history
+ , mode
+ , (health_enabled != CONFIG_BOOLEAN_NO)
+ , (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key)
+ , rrdpush_destination
+ , rrdpush_api_key
+ );
+
+ if(!host) {
+ close(fd);
+ error("STREAM %s [receive from [%s]:%s]: failed to find/create host structure.", hostname, client_ip, client_port);
+ return 1;
+ }
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ info("STREAM %s [receive from [%s]:%s]: client willing to stream metrics for host '%s' with machine_guid '%s': update every = %d, history = %ld, memory mode = %s, health %s"
+ , hostname
+ , client_ip
+ , client_port
+ , host->hostname
+ , host->machine_guid
+ , host->rrd_update_every
+ , host->rrd_history_entries
+ , rrd_memory_mode_name(host->rrd_memory_mode)
+ , (health_enabled == CONFIG_BOOLEAN_NO)?"disabled":((health_enabled == CONFIG_BOOLEAN_YES)?"enabled":"auto")
+ );
+#endif // NETDATA_INTERNAL_CHECKS
+
+ struct plugind cd = {
+ .enabled = 1,
+ .update_every = default_rrd_update_every,
+ .pid = 0,
+ .serial_failures = 0,
+ .successful_collections = 0,
+ .obsolete = 0,
+ .started_t = now_realtime_sec(),
+ .next = NULL,
+ };
+
+ // put the client IP and port into the buffers used by plugins.d
+ snprintfz(cd.id, CONFIG_MAX_NAME, "%s:%s", client_ip, client_port);
+ snprintfz(cd.filename, FILENAME_MAX, "%s:%s", client_ip, client_port);
+ snprintfz(cd.fullfilename, FILENAME_MAX, "%s:%s", client_ip, client_port);
+ snprintfz(cd.cmd, PLUGINSD_CMD_MAX, "%s:%s", client_ip, client_port);
+
+ info("STREAM %s [receive from [%s]:%s]: initializing communication...", host->hostname, client_ip, client_port);
+ if(send_timeout(fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
+ error("STREAM %s [receive from [%s]:%s]: cannot send ready command.", host->hostname, client_ip, client_port);
+ close(fd);
+ return 0;
+ }
+
+ // remove the non-blocking flag from the socket
+ if(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK) == -1)
+ error("STREAM %s [receive from [%s]:%s]: cannot remove the non-blocking flag from socket %d", host->hostname, client_ip, client_port, fd);
+
+ // convert the socket to a FILE *
+ FILE *fp = fdopen(fd, "r");
+ if(!fp) {
+ error("STREAM %s [receive from [%s]:%s]: failed to get a FILE for FD %d.", host->hostname, client_ip, client_port, fd);
+ close(fd);
+ return 0;
+ }
+
+ rrdhost_wrlock(host);
+ host->connected_senders++;
+ if(health_enabled != CONFIG_BOOLEAN_NO)
+ host->health_delay_up_to = now_realtime_sec() + alarms_delay;
+ rrdhost_unlock(host);
+
+ // call the plugins.d processor to receive the metrics
+ info("STREAM %s [receive from [%s]:%s]: receiving metrics...", host->hostname, client_ip, client_port);
+ size_t count = pluginsd_process(host, &cd, fp, 1);
+ error("STREAM %s [receive from [%s]:%s]: disconnected (completed updates %zu).", host->hostname, client_ip, client_port, count);
+
+ rrdhost_wrlock(host);
+ host->senders_disconnected_time = now_realtime_sec();
+ host->connected_senders--;
+ if(!host->connected_senders) {
+ if(health_enabled == CONFIG_BOOLEAN_AUTO)
+ host->health_enabled = 0;
+ }
+ rrdhost_unlock(host);
+
+ rrdpush_sender_thread_stop(host);
+
+ // cleanup
+ fclose(fp);
+
+ return (int)count;
+}
+
+struct rrdpush_thread {
+ int fd;
+ char *key;
+ char *hostname;
+ char *machine_guid;
+ char *os;
+ char *client_ip;
+ char *client_port;
+ int update_every;
+};
+
+void *rrdpush_receiver_thread(void *ptr) {
+ struct rrdpush_thread *rpt = (struct rrdpush_thread *)ptr;
+
+ if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+ error("STREAM %s [receive]: cannot set pthread cancel type to DEFERRED.", rpt->hostname);
+
+ if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+ error("STREAM %s [receive]: cannot set pthread cancel state to ENABLE.", rpt->hostname);
+
+
+ info("STREAM %s [%s]:%s: receive thread created (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
+ rrdpush_receive(rpt->fd, rpt->key, rpt->hostname, rpt->machine_guid, rpt->os, rpt->update_every, rpt->client_ip, rpt->client_port);
+ info("STREAM %s [receive from [%s]:%s]: receive thread ended (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
+
+ freez(rpt->key);
+ freez(rpt->hostname);
+ freez(rpt->machine_guid);
+ freez(rpt->os);
+ freez(rpt->client_ip);
+ freez(rpt->client_port);
+ freez(rpt);
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void rrdpush_sender_thread_spawn(RRDHOST *host) {
+ rrdhost_wrlock(host);
+
+ if(!host->rrdpush_spawn) {
+ if(pthread_create(&host->rrdpush_thread, NULL, rrdpush_sender_thread, (void *) host))
+ error("STREAM %s [send]: failed to create new thread for client.", host->hostname);
+
+ else if(pthread_detach(host->rrdpush_thread))
+ error("STREAM %s [send]: cannot request detach newly created thread.", host->hostname);
+
+ rrdhost_flag_clear(host, RRDHOST_ORPHAN);
+ host->rrdpush_spawn = 1;
+ }
+
+ rrdhost_unlock(host);
+}
+
+int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url) {
+ (void)host;
+
+ info("STREAM [receive from [%s]:%s]: new client connection.", w->client_ip, w->client_port);
+
+ char *key = NULL, *hostname = NULL, *machine_guid = NULL, *os = "unknown";
+ int update_every = default_rrd_update_every;
+ char buf[GUID_LEN + 1];
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ if(!strcmp(name, "key"))
+ key = value;
+ else if(!strcmp(name, "hostname"))
+ hostname = value;
+ else if(!strcmp(name, "machine_guid"))
+ machine_guid = value;
+ else if(!strcmp(name, "update_every"))
+ update_every = (int)strtoul(value, NULL, 0);
+ else if(!strcmp(name, "os"))
+ os = value;
+ }
+
+ if(!key || !*key) {
+ error("STREAM [receive from [%s]:%s]: request without an API key. Forbidding access.", w->client_ip, w->client_port);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "You need an API key for this request.");
+ return 401;
+ }
+
+ if(!hostname || !*hostname) {
+ error("STREAM [receive from [%s]:%s]: request without a hostname. Forbidding access.", w->client_ip, w->client_port);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "You need to send a hostname too.");
+ return 400;
+ }
+
+ if(!machine_guid || !*machine_guid) {
+ error("STREAM [receive from [%s]:%s]: request without a machine GUID. Forbidding access.", w->client_ip, w->client_port);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "You need to send a machine GUID too.");
+ return 400;
+ }
+
+ if(regenerate_guid(key, buf) == -1) {
+ error("STREAM [receive from [%s]:%s]: API key '%s' is not valid GUID. Forbidding access.", w->client_ip, w->client_port, key);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your API key is invalid.");
+ return 401;
+ }
+
+ if(regenerate_guid(machine_guid, buf) == -1) {
+ error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not GUID. Forbidding access.", w->client_ip, w->client_port, key);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your machine GUID is invalid.");
+ return 404;
+ }
+
+ if(!appconfig_get_boolean(&stream_config, key, "enabled", 0)) {
+ error("STREAM [receive from [%s]:%s]: API key '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your API key is not permitted access.");
+ return 401;
+ }
+
+ if(!appconfig_get_boolean(&stream_config, machine_guid, "enabled", 1)) {
+ error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid);
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your machine guide is not permitted access.");
+ return 404;
+ }
+
+ struct rrdpush_thread *rpt = mallocz(sizeof(struct rrdpush_thread));
+ rpt->fd = w->ifd;
+ rpt->key = strdupz(key);
+ rpt->hostname = strdupz(hostname);
+ rpt->machine_guid = strdupz(machine_guid);
+ rpt->os = strdupz(os);
+ rpt->client_ip = strdupz(w->client_ip);
+ rpt->client_port = strdupz(w->client_port);
+ rpt->update_every = update_every;
+ pthread_t thread;
+
+ debug(D_SYSTEM, "STREAM [receive from [%s]:%s]: starting receiving thread.", w->client_ip, w->client_port);
+
+ if(pthread_create(&thread, NULL, rrdpush_receiver_thread, (void *)rpt))
+ error("STREAM [receive from [%s]:%s]: failed to create new thread for client.", w->client_ip, w->client_port);
+
+ else if(pthread_detach(thread))
+ error("STREAM [receive from [%s]:%s]: cannot request detach newly created thread.", w->client_ip, w->client_port);
+
+ // prevent the caller from closing the streaming socket
+ if(w->ifd == w->ofd)
+ w->ifd = w->ofd = -1;
+ else
+ w->ifd = -1;
+
+ buffer_flush(w->response.data);
+ return 200;
+}
diff --git a/src/rrdpush.h b/src/rrdpush.h
new file mode 100644
index 000000000..dddbe758b
--- /dev/null
+++ b/src/rrdpush.h
@@ -0,0 +1,15 @@
+#ifndef NETDATA_RRDPUSH_H
+#define NETDATA_RRDPUSH_H
+
+extern int default_rrdpush_enabled;
+extern char *default_rrdpush_destination;
+extern char *default_rrdpush_api_key;
+
+extern int rrdpush_init();
+extern void rrdset_done_push(RRDSET *st);
+extern void *rrdpush_sender_thread(void *ptr);
+
+extern int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url);
+extern void rrdpush_sender_thread_stop(RRDHOST *host);
+
+#endif //NETDATA_RRDPUSH_H
diff --git a/src/rrdset.c b/src/rrdset.c
new file mode 100644
index 000000000..c847b9690
--- /dev/null
+++ b/src/rrdset.c
@@ -0,0 +1,1310 @@
+#define NETDATA_RRD_INTERNALS 1
+#include "common.h"
+
+#define RRD_DEFAULT_GAP_INTERPOLATIONS 1
+
+void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRD_CALLS, "Checking read lock on chart '%s'", st->id);
+
+ int ret = netdata_rwlock_trywrlock(&st->rrdset_rwlock);
+ if(ret == 0)
+ fatal("RRDSET '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
+}
+
+void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
+ debug(D_RRD_CALLS, "Checking write lock on chart '%s'", st->id);
+
+ int ret = netdata_rwlock_tryrdlock(&st->rrdset_rwlock);
+ if(ret == 0)
+ fatal("RRDSET '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET index
+
+int rrdset_compare(void* a, void* b) {
+ if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
+ else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
+ else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
+}
+
+static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
+ RRDSET tmp;
+ strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
+ tmp.hash = (hash)?hash:simple_hash(tmp.id);
+
+ return (RRDSET *)avl_search_lock(&(host->rrdset_root_index), (avl *) &tmp);
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET name index
+
+#define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
+
+int rrdset_compare_name(void* a, void* b) {
+ RRDSET *A = rrdset_from_avlname(a);
+ RRDSET *B = rrdset_from_avlname(b);
+
+ // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
+
+ if(A->hash_name < B->hash_name) return -1;
+ else if(A->hash_name > B->hash_name) return 1;
+ else return strcmp(A->name, B->name);
+}
+
+RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
+ void *result;
+ // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
+ result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
+ if(result) return rrdset_from_avlname(result);
+ return NULL;
+}
+
+RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
+ void *result;
+ // fprintf(stderr, "DELETING: %s (name: %s)\n", st->id, st->name);
+ result = (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index_name), (avl *)(&st->avlname));
+ if(result) return rrdset_from_avlname(result);
+ return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - find charts
+
+static inline RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
+ void *result = NULL;
+ RRDSET tmp;
+ tmp.name = name;
+ tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
+
+ // fprintf(stderr, "SEARCHING: %s\n", name);
+ result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
+ if(result) {
+ RRDSET *st = rrdset_from_avlname(result);
+ if(strcmp(st->magic, RRDSET_MAGIC))
+ error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
+
+ // fprintf(stderr, "FOUND: %s\n", name);
+ return rrdset_from_avlname(result);
+ }
+ // fprintf(stderr, "NOT FOUND: %s\n", name);
+ return NULL;
+}
+
+inline RRDSET *rrdset_find(RRDHOST *host, const char *id) {
+ debug(D_RRD_CALLS, "rrdset_find() for chart '%s' in host '%s'", id, host->hostname);
+ RRDSET *st = rrdset_index_find(host, id, 0);
+ return(st);
+}
+
+inline RRDSET *rrdset_find_bytype(RRDHOST *host, const char *type, const char *id) {
+ debug(D_RRD_CALLS, "rrdset_find_bytype() for chart '%s.%s' in host '%s'", type, id, host->hostname);
+
+ char buf[RRD_ID_LENGTH_MAX + 1];
+ strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
+ strcat(buf, ".");
+ int len = (int) strlen(buf);
+ strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
+
+ return(rrdset_find(host, buf));
+}
+
+inline RRDSET *rrdset_find_byname(RRDHOST *host, const char *name) {
+ debug(D_RRD_CALLS, "rrdset_find_byname() for chart '%s' in host '%s'", name, host->hostname);
+ RRDSET *st = rrdset_index_find_name(host, name, 0);
+ return(st);
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - rename charts
+
+char *rrdset_strncpyz_name(char *to, const char *from, size_t length) {
+ char c, *p = to;
+
+ while (length-- && (c = *from++)) {
+ if(c != '.' && !isalnum(c))
+ c = '_';
+
+ *p++ = c;
+ }
+
+ *p = '\0';
+
+ return to;
+}
+
+void rrdset_set_name(RRDSET *st, const char *name) {
+ if(unlikely(st->name && !strcmp(st->name, name)))
+ return;
+
+ debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
+
+ char b[CONFIG_MAX_VALUE + 1];
+ char n[RRD_ID_LENGTH_MAX + 1];
+
+ snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
+ rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
+
+ if(st->name) {
+ rrdset_index_del_name(st->rrdhost, st);
+ st->name = config_set_default(st->config_section, "name", b);
+ st->hash_name = simple_hash(st->name);
+ rrdsetvar_rename_all(st);
+ }
+ else {
+ st->name = config_get(st->config_section, "name", b);
+ st->hash_name = simple_hash(st->name);
+ }
+
+ rrdset_wrlock(st);
+ RRDDIM *rd;
+ rrddim_foreach_write(rd, st)
+ rrddimvar_rename_all(rd);
+ rrdset_unlock(st);
+
+ if(unlikely(rrdset_index_add_name(st->rrdhost, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - reset a chart
+
+void rrdset_reset(RRDSET *st) {
+ debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
+
+ st->last_collected_time.tv_sec = 0;
+ st->last_collected_time.tv_usec = 0;
+ st->last_updated.tv_sec = 0;
+ st->last_updated.tv_usec = 0;
+ st->current_entry = 0;
+ st->counter = 0;
+ st->counter_done = 0;
+
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ rd->last_collected_time.tv_sec = 0;
+ rd->last_collected_time.tv_usec = 0;
+ rd->collections_counter = 0;
+ memset(rd->values, 0, rd->entries * sizeof(storage_number));
+ }
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - helpers for rrdset_create()
+
+inline long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries) {
+ if(unlikely(entries < 5)) entries = 5;
+ if(unlikely(entries > RRD_HISTORY_ENTRIES_MAX)) entries = RRD_HISTORY_ENTRIES_MAX;
+
+ if(unlikely(mode == RRD_MEMORY_MODE_NONE || mode == RRD_MEMORY_MODE_RAM))
+ return entries;
+
+ long page = (size_t)sysconf(_SC_PAGESIZE);
+ long size = sizeof(RRDDIM) + entries * sizeof(storage_number);
+ if(unlikely(size % page)) {
+ size -= (size % page);
+ size += page;
+
+ long n = (size - sizeof(RRDDIM)) / sizeof(storage_number);
+ return n;
+ }
+
+ return entries;
+}
+
+static inline void last_collected_time_align(struct timeval *tv, int update_every) {
+ tv->tv_sec -= tv->tv_sec % update_every;
+ tv->tv_usec = 500000;
+}
+
+static inline void last_updated_time_align(struct timeval *tv, int update_every) {
+ tv->tv_sec -= tv->tv_sec % update_every;
+ tv->tv_usec = 0;
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - free a chart
+
+void rrdset_free(RRDSET *st) {
+ if(unlikely(!st)) return;
+
+ rrdhost_check_wrlock(st->rrdhost); // make sure we have a write lock on the host
+ rrdset_wrlock(st); // lock this RRDSET
+
+ // info("Removing chart '%s' ('%s')", st->id, st->name);
+
+ // ------------------------------------------------------------------------
+ // remove it from the indexes
+
+ if(unlikely(rrdset_index_del(st->rrdhost, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
+
+ rrdset_index_del_name(st->rrdhost, st);
+
+ // ------------------------------------------------------------------------
+ // free its children structures
+
+ while(st->variables) rrdsetvar_free(st->variables);
+ while(st->alarms) rrdsetcalc_unlink(st->alarms);
+ while(st->dimensions) rrddim_free(st, st->dimensions);
+
+ rrdfamily_free(st->rrdhost, st->rrdfamily);
+
+ // ------------------------------------------------------------------------
+ // unlink it from the host
+
+ if(st == st->rrdhost->rrdset_root) {
+ st->rrdhost->rrdset_root = st->next;
+ }
+ else {
+ // find the previous one
+ RRDSET *s;
+ for(s = st->rrdhost->rrdset_root; s && s->next != st ; s = s->next) ;
+
+ // bypass it
+ if(s) s->next = st->next;
+ else error("Request to free RRDSET '%s': cannot find it under host '%s'", st->id, st->rrdhost->hostname);
+ }
+
+ rrdset_unlock(st);
+
+ // ------------------------------------------------------------------------
+ // free it
+
+ netdata_rwlock_destroy(&st->rrdset_rwlock);
+
+ // free directly allocated members
+ freez(st->config_section);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
+ munmap(st, st->memsize);
+ }
+ else
+ freez(st);
+}
+
+void rrdset_save(RRDSET *st) {
+ RRDDIM *rd;
+
+ rrdset_check_rdlock(st);
+
+ // info("Saving chart '%s' ('%s')", st->id, st->name);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ debug(D_RRD_STATS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
+ savememory(st->cache_filename, st, st->memsize);
+ }
+
+ rrddim_foreach_read(rd, st) {
+ if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
+ debug(D_RRD_STATS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ savememory(rd->cache_filename, rd, rd->memsize);
+ }
+ }
+}
+
+void rrdset_delete(RRDSET *st) {
+ RRDDIM *rd;
+
+ rrdset_check_rdlock(st);
+
+ // info("Deleting chart '%s' ('%s')", st->id, st->name);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ debug(D_RRD_STATS, "Deleting stats '%s' to '%s'.", st->name, st->cache_filename);
+ unlink(st->cache_filename);
+ }
+
+ rrddim_foreach_read(rd, st) {
+ if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
+ debug(D_RRD_STATS, "Deleting dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ unlink(rd->cache_filename);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// RRDSET - create a chart
+
+static inline RRDSET *rrdset_find_on_create(RRDHOST *host, const char *fullid) {
+ RRDSET *st = rrdset_find(host, fullid);
+ if(unlikely(st)) {
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+ debug(D_RRD_CALLS, "RRDSET '%s', already exists.", fullid);
+ return st;
+ }
+
+ return NULL;
+}
+
+RRDSET *rrdset_create(
+ RRDHOST *host
+ , const char *type
+ , const char *id
+ , const char *name
+ , const char *family
+ , const char *context
+ , const char *title
+ , const char *units
+ , long priority
+ , int update_every
+ , RRDSET_TYPE chart_type
+) {
+ if(!type || !type[0]) {
+ fatal("Cannot create rrd stats without a type.");
+ return NULL;
+ }
+
+ if(!id || !id[0]) {
+ fatal("Cannot create rrd stats without an id.");
+ return NULL;
+ }
+
+ // ------------------------------------------------------------------------
+ // check if it already exists
+
+ char fullid[RRD_ID_LENGTH_MAX + 1];
+ snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
+
+ RRDSET *st = rrdset_find_on_create(host, fullid);
+ if(st) return st;
+
+ rrdhost_wrlock(host);
+
+ st = rrdset_find_on_create(host, fullid);
+ if(st) {
+ rrdhost_unlock(host);
+ return st;
+ }
+
+ char fullfilename[FILENAME_MAX + 1];
+
+ // ------------------------------------------------------------------------
+ // compose the config_section for this chart
+
+ char config_section[RRD_ID_LENGTH_MAX + 1];
+ if(host == localhost)
+ strcpy(config_section, fullid);
+ else
+ snprintfz(config_section, RRD_ID_LENGTH_MAX, "%s/%s", host->machine_guid, fullid);
+
+ // ------------------------------------------------------------------------
+ // get the options from the config, we need to create it
+
+ long rentries = config_get_number(config_section, "history", host->rrd_history_entries);
+ long entries = align_entries_to_pagesize(host->rrd_memory_mode, rentries);
+ if(entries != rentries) entries = config_set_number(config_section, "history", entries);
+
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE && entries != rentries)
+ entries = config_set_number(config_section, "history", 10);
+
+ int enabled = config_get_boolean(config_section, "enabled", 1);
+ if(!enabled) entries = 5;
+
+ unsigned long size = sizeof(RRDSET);
+ char *cache_dir = rrdset_cache_dir(host, fullid, config_section);
+
+ time_t now = now_realtime_sec();
+
+ // ------------------------------------------------------------------------
+ // load it or allocate it
+
+ debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
+
+ snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || host->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ st = (RRDSET *) mymmap(fullfilename, size, ((host->rrd_memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 0);
+ if(st) {
+ memset(&st->avl, 0, sizeof(avl));
+ memset(&st->avlname, 0, sizeof(avl));
+ memset(&st->variables_root_index, 0, sizeof(avl_tree_lock));
+ memset(&st->dimensions_index, 0, sizeof(avl_tree_lock));
+ memset(&st->rrdset_rwlock, 0, sizeof(netdata_rwlock_t));
+
+ st->name = NULL;
+ st->type = NULL;
+ st->family = NULL;
+ st->context = NULL;
+ st->title = NULL;
+ st->units = NULL;
+ st->dimensions = NULL;
+ st->next = NULL;
+ st->variables = NULL;
+ st->alarms = NULL;
+ st->flags = 0x00000000;
+
+ if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
+ errno = 0;
+ info("Initializing file %s.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if(strcmp(st->id, fullid) != 0) {
+ errno = 0;
+ error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
+ // munmap(st, size);
+ // st = NULL;
+ memset(st, 0, size);
+ }
+ else if(st->memsize != size || st->entries != entries) {
+ errno = 0;
+ error("File %s does not have the desired size. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if(st->update_every != update_every) {
+ errno = 0;
+ error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if((now - st->last_updated.tv_sec) > update_every * entries) {
+ errno = 0;
+ error("File %s is too old. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+ else if(st->last_updated.tv_sec > now + update_every) {
+ errno = 0;
+ error("File %s refers to the future. Clearing it.", fullfilename);
+ memset(st, 0, size);
+ }
+
+ // make sure the database is aligned
+ if(st->last_updated.tv_sec)
+ last_updated_time_align(&st->last_updated, update_every);
+
+
+ // make sure we have the right memory mode
+ // even if we cleared the memory
+ st->rrd_memory_mode = host->rrd_memory_mode;
+ }
+ }
+
+ if(unlikely(!st)) {
+ st = callocz(1, size);
+ st->rrd_memory_mode = (host->rrd_memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_RAM;
+ }
+
+ st->config_section = strdup(config_section);
+ st->rrdhost = host;
+ st->memsize = size;
+ st->entries = entries;
+ st->update_every = update_every;
+
+ if(st->current_entry >= st->entries) st->current_entry = 0;
+
+ strcpy(st->cache_filename, fullfilename);
+ strcpy(st->magic, RRDSET_MAGIC);
+
+ strcpy(st->id, fullid);
+ st->hash = simple_hash(st->id);
+
+ st->cache_dir = cache_dir;
+
+ st->chart_type = rrdset_type_id(config_get(st->config_section, "chart type", rrdset_type_name(chart_type)));
+ st->type = config_get(st->config_section, "type", type);
+ st->family = config_get(st->config_section, "family", family?family:st->type);
+ st->units = config_get(st->config_section, "units", units?units:"");
+
+ st->context = config_get(st->config_section, "context", context?context:st->id);
+ st->hash_context = simple_hash(st->context);
+
+ st->priority = config_get_number(st->config_section, "priority", priority);
+ if(enabled)
+ rrdset_flag_set(st, RRDSET_FLAG_ENABLED);
+ else
+ rrdset_flag_clear(st, RRDSET_FLAG_ENABLED);
+
+ rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
+ rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+
+ // if(!strcmp(st->id, "disk_util.dm-0")) {
+ // st->debug = 1;
+ // error("enabled debugging for '%s'", st->id);
+ // }
+ // else error("not enabled debugging for '%s'", st->id);
+
+ st->green = NAN;
+ st->red = NAN;
+
+ st->last_collected_time.tv_sec = 0;
+ st->last_collected_time.tv_usec = 0;
+ st->counter_done = 0;
+
+ st->gap_when_lost_iterations_above = (int) (
+ config_get_number(st->config_section, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
+
+ avl_init_lock(&st->dimensions_index, rrddim_compare);
+ avl_init_lock(&st->variables_root_index, rrdvar_compare);
+
+ netdata_rwlock_init(&st->rrdset_rwlock);
+
+ if(name && *name) rrdset_set_name(st, name);
+ else rrdset_set_name(st, id);
+
+ {
+ char varvalue[CONFIG_MAX_VALUE + 1];
+ char varvalue2[CONFIG_MAX_VALUE + 1];
+ snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
+ json_escape_string(varvalue2, varvalue, sizeof(varvalue2));
+ st->title = config_get(st->config_section, "title", varvalue2);
+ }
+
+ st->rrdfamily = rrdfamily_create(host, st->family);
+
+ st->next = host->rrdset_root;
+ host->rrdset_root = st;
+
+ if(host->health_enabled) {
+ rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0);
+ rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, 0);
+ rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, 0);
+ rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, 0);
+ rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, 0);
+ }
+
+ if(unlikely(rrdset_index_add(host, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempt to index duplicate chart '%s'", st->id);
+
+ rrdsetcalc_link_matching(st);
+ rrdcalctemplate_link_matching(st);
+
+ rrdhost_cleanup_obsolete(host);
+
+ rrdhost_unlock(host);
+
+ return(st);
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - data collection iteration control
+
+inline void rrdset_next_usec_unfiltered(RRDSET *st, usec_t microseconds) {
+
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // the first entry
+ microseconds = st->update_every * USEC_PER_SEC;
+ }
+ else if(unlikely(!microseconds)) {
+ // no dt given by the plugin
+ struct timeval now;
+ now_realtime_timeval(&now);
+ microseconds = dt_usec(&now, &st->last_collected_time);
+ }
+
+ st->usec_since_last_update = microseconds;
+}
+
+inline void rrdset_next_usec(RRDSET *st, usec_t microseconds) {
+ struct timeval now;
+ now_realtime_timeval(&now);
+
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // the first entry
+ microseconds = st->update_every * USEC_PER_SEC;
+ }
+ else if(unlikely(!microseconds)) {
+ // no dt given by the plugin
+ microseconds = dt_usec(&now, &st->last_collected_time);
+ }
+ else {
+ // microseconds has the time since the last collection
+//#ifdef NETDATA_INTERNAL_CHECKS
+// usec_t now_usec = timeval_usec(&now);
+// usec_t last_usec = timeval_usec(&st->last_collected_time);
+//#endif
+ susec_t since_last_usec = dt_usec_signed(&now, &st->last_collected_time);
+
+ if(unlikely(since_last_usec < 0)) {
+ // oops! the database is in the future
+ error("Database for chart '%s' on host '%s' is %lld microseconds in the future. Adjusting it to current time.", st->id, st->rrdhost->hostname, -since_last_usec);
+
+ st->last_collected_time.tv_sec = now.tv_sec - st->update_every;
+ st->last_collected_time.tv_usec = now.tv_usec;
+ last_collected_time_align(&st->last_collected_time, st->update_every);
+
+ st->last_updated.tv_sec = now.tv_sec - st->update_every;
+ st->last_updated.tv_usec = now.tv_usec;
+ last_updated_time_align(&st->last_updated, st->update_every);
+
+ microseconds = st->update_every * USEC_PER_SEC;
+ since_last_usec = st->update_every * USEC_PER_SEC;
+ }
+
+ // verify the microseconds given is good
+ if(unlikely(microseconds > (usec_t)since_last_usec)) {
+ debug(D_RRD_CALLS, "dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - (usec_t)since_last_usec, st->name, st->id);
+
+//#ifdef NETDATA_INTERNAL_CHECKS
+// if(unlikely(last_usec + microseconds > now_usec + 1000))
+// error("dt %llu usec given is too big - it leads %llu usec to the future, for chart '%s' (%s).", microseconds, microseconds - (usec_t)since_last_usec, st->name, st->id);
+//#endif
+
+ microseconds = (usec_t)since_last_usec;
+ }
+ else if(unlikely(microseconds < (usec_t)since_last_usec * 0.8)) {
+ debug(D_RRD_CALLS, "dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, (usec_t)since_last_usec, st->name, st->id);
+
+//#ifdef NETDATA_INTERNAL_CHECKS
+// error("dt %llu usec given is too small - expected %llu usec up to -20%%, for chart '%s' (%s).", microseconds, (usec_t)since_last_usec, st->name, st->id);
+//#endif
+ microseconds = (usec_t)since_last_usec;
+ }
+ }
+ debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
+
+ st->usec_since_last_update = microseconds;
+}
+
+
+// ----------------------------------------------------------------------------
+// RRDSET - process the collected values for all dimensions of a chart
+
+static inline void rrdset_init_last_collected_time(RRDSET *st) {
+ now_realtime_timeval(&st->last_collected_time);
+ last_collected_time_align(&st->last_collected_time, st->update_every);
+}
+
+static inline usec_t rrdset_update_last_collected_time(RRDSET *st) {
+ usec_t last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
+ usec_t ut = last_collect_ut + st->usec_since_last_update;
+ st->last_collected_time.tv_sec = (time_t) (ut / USEC_PER_SEC);
+ st->last_collected_time.tv_usec = (suseconds_t) (ut % USEC_PER_SEC);
+ return last_collect_ut;
+}
+
+static inline void rrdset_init_last_updated_time(RRDSET *st) {
+ // copy the last collected time to last updated time
+ st->last_updated.tv_sec = st->last_collected_time.tv_sec;
+ st->last_updated.tv_usec = st->last_collected_time.tv_usec;
+ last_updated_time_align(&st->last_updated, st->update_every);
+}
+
+static inline void rrdset_done_push_exclusive(RRDSET *st) {
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // it is the first entry
+ // set the last_collected_time to now
+ rrdset_init_last_collected_time(st);
+ }
+ else {
+ // it is not the first entry
+ // calculate the proper last_collected_time, using usec_since_last_update
+ rrdset_update_last_collected_time(st);
+ }
+
+ st->counter_done++;
+
+ rrdset_rdlock(st);
+ rrdset_done_push(st);
+ rrdset_unlock(st);
+}
+
+void rrdset_done(RRDSET *st) {
+ if(unlikely(netdata_exit)) return;
+
+ if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
+ if(unlikely(st->rrdhost->rrdpush_enabled))
+ rrdset_done_push_exclusive(st);
+
+ return;
+ }
+
+ debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
+
+ RRDDIM *rd;
+
+ int
+ pthreadoldcancelstate; // store the old cancelable pthread state, to restore it at the end
+
+ char
+ store_this_entry = 1, // boolean: 1 = store this entry, 0 = don't store this entry
+ first_entry = 0; // boolean: 1 = this is the first entry seen for this chart, 0 = all other entries
+
+ unsigned int
+ stored_entries = 0; // the number of entries we have stored in the db, during this call to rrdset_done()
+
+ usec_t
+ last_collect_ut, // the timestamp in microseconds, of the last collected value
+ now_collect_ut, // the timestamp in microseconds, of this collected value (this is NOW)
+ last_stored_ut, // the timestamp in microseconds, of the last stored entry in the db
+ next_store_ut, // the timestamp in microseconds, of the next entry to store in the db
+ update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds
+
+ if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
+ error("Cannot set pthread cancel state to DISABLE.");
+
+ // a read lock is OK here
+ rrdset_rdlock(st);
+
+/*
+ // enable the chart, if it was disabled
+ if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
+ st->enabled = 1;
+*/
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))) {
+ error("Chart '%s' has the OBSOLETE flag set, but it is collected.", st->id);
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+ }
+
+ // check if the chart has a long time to be updated
+ if(unlikely(st->usec_since_last_update > st->entries * update_every_ut)) {
+ info("%s: took too long to be updated (%0.3Lf secs). Resetting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
+ rrdset_reset(st);
+ st->usec_since_last_update = update_every_ut;
+ first_entry = 1;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
+
+ // set last_collected_time
+ if(unlikely(!st->last_collected_time.tv_sec)) {
+ // it is the first entry
+ // set the last_collected_time to now
+ rrdset_init_last_collected_time(st);
+
+ last_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec - update_every_ut;
+
+ // the first entry should not be stored
+ store_this_entry = 0;
+ first_entry = 1;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
+ }
+ else {
+ // it is not the first entry
+ // calculate the proper last_collected_time, using usec_since_last_update
+ last_collect_ut = rrdset_update_last_collected_time(st);
+ }
+
+ // if this set has not been updated in the past
+ // we fake the last_update time to be = now - usec_since_last_update
+ if(unlikely(!st->last_updated.tv_sec)) {
+ // it has never been updated before
+ // set a fake last_updated, in the past using usec_since_last_update
+ rrdset_init_last_updated_time(st);
+
+ // the first entry should not be stored
+ store_this_entry = 0;
+ first_entry = 1;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: initializing last_updated to last_collected_time - %llu microseconds. Will not store the next entry.", st->name, st->usec_since_last_update);
+ }
+
+ // check if we will re-write the entire data set
+ if(unlikely(dt_usec(&st->last_collected_time, &st->last_updated) > st->entries * update_every_ut)) {
+ info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Resetting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
+ rrdset_reset(st);
+ rrdset_init_last_updated_time(st);
+
+ st->usec_since_last_update = update_every_ut;
+
+ // the first entry should not be stored
+ store_this_entry = 0;
+ first_entry = 1;
+ }
+
+ // these are the 3 variables that will help us in interpolation
+ // last_stored_ut = the last time we added a value to the storage
+ // now_collect_ut = the time the current value has been collected
+ // next_store_ut = the time of the next interpolation point
+ last_stored_ut = st->last_updated.tv_sec * USEC_PER_SEC + st->last_updated.tv_usec;
+ now_collect_ut = st->last_collected_time.tv_sec * USEC_PER_SEC + st->last_collected_time.tv_usec;
+ next_store_ut = (st->last_updated.tv_sec + st->update_every) * USEC_PER_SEC;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) {
+ debug(D_RRD_STATS, "%s: last_collect_ut = %0.3Lf (last collection time)", st->name, (long double)last_collect_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: now_collect_ut = %0.3Lf (current collection time)", st->name, (long double)now_collect_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
+ }
+
+ if(unlikely(!st->counter_done)) {
+ store_this_entry = 0;
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
+ }
+ st->counter_done++;
+
+ if(unlikely(st->rrdhost->rrdpush_enabled))
+ rrdset_done_push(st);
+
+ // calculate totals and count the dimensions
+ int dimensions = 0;
+ st->collected_total = 0;
+ rrddim_foreach_read(rd, st) {
+ dimensions++;
+ if(likely(rd->updated))
+ st->collected_total += rd->collected_value;
+ }
+
+ uint32_t storage_flags = SN_EXISTS;
+
+ // process all dimensions to calculate their values
+ // based on the collected figures only
+ // at this stage we do not interpolate anything
+ rrddim_foreach_read(rd, st) {
+
+ if(unlikely(!rd->updated)) {
+ rd->calculated_value = 0;
+ continue;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: START "
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
+ " collected_value = " COLLECTED_NUMBER_FORMAT
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->last_collected_value
+ , rd->collected_value
+ , rd->last_calculated_value
+ , rd->calculated_value
+ );
+
+ switch(rd->algorithm) {
+ case RRD_ALGORITHM_ABSOLUTE:
+ rd->calculated_value = (calculated_number)rd->collected_value
+ * (calculated_number)rd->multiplier
+ / (calculated_number)rd->divisor;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
+ CALCULATED_NUMBER_FORMAT " = "
+ COLLECTED_NUMBER_FORMAT
+ " * " CALCULATED_NUMBER_FORMAT
+ " / " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value
+ , (calculated_number)rd->multiplier
+ , (calculated_number)rd->divisor
+ );
+ break;
+
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ if(unlikely(!st->collected_total))
+ rd->calculated_value = 0;
+ else
+ // the percentage of the current value
+ // over the total of all dimensions
+ rd->calculated_value =
+ (calculated_number)100
+ * (calculated_number)rd->collected_value
+ / (calculated_number)st->collected_total;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
+ CALCULATED_NUMBER_FORMAT " = 100"
+ " * " COLLECTED_NUMBER_FORMAT
+ " / " COLLECTED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value
+ , st->collected_total
+ );
+ break;
+
+ case RRD_ALGORITHM_INCREMENTAL:
+ if(unlikely(rd->collections_counter <= 1)) {
+ rd->calculated_value = 0;
+ continue;
+ }
+
+ // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
+ // to reset the calculation (it will give zero as the calculation for this second)
+ if(unlikely(rd->last_collected_value > rd->collected_value)) {
+ debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+ , st->name, rd->name
+ , rd->last_collected_value
+ , rd->collected_value);
+
+ if(!(rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)))
+ storage_flags = SN_EXISTS_RESET;
+
+ rd->last_collected_value = rd->collected_value;
+ }
+
+ rd->calculated_value +=
+ (calculated_number)(rd->collected_value - rd->last_collected_value)
+ * (calculated_number)rd->multiplier
+ / (calculated_number)rd->divisor;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
+ CALCULATED_NUMBER_FORMAT " = ("
+ COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
+ ")"
+ " * " CALCULATED_NUMBER_FORMAT
+ " / " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value, rd->last_collected_value
+ , (calculated_number)rd->multiplier
+ , (calculated_number)rd->divisor
+ );
+ break;
+
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ if(unlikely(rd->collections_counter <= 1)) {
+ rd->calculated_value = 0;
+ continue;
+ }
+
+ // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
+ // to reset the calculation (it will give zero as the calculation for this second)
+ if(unlikely(rd->last_collected_value > rd->collected_value)) {
+ debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+ , st->name, rd->name
+ , rd->last_collected_value
+ , rd->collected_value);
+
+ if(!(rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)))
+ storage_flags = SN_EXISTS_RESET;
+
+ rd->last_collected_value = rd->collected_value;
+ }
+
+ // the percentage of the current increment
+ // over the increment of all dimensions together
+ if(unlikely(st->collected_total == st->last_collected_total))
+ rd->calculated_value = 0;
+ else
+ rd->calculated_value =
+ (calculated_number)100
+ * (calculated_number)(rd->collected_value - rd->last_collected_value)
+ / (calculated_number)(st->collected_total - st->last_collected_total);
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
+ CALCULATED_NUMBER_FORMAT " = 100"
+ " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+ " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+ , st->id, rd->name
+ , rd->calculated_value
+ , rd->collected_value, rd->last_collected_value
+ , st->collected_total, st->last_collected_total
+ );
+ break;
+
+ default:
+ // make the default zero, to make sure
+ // it gets noticed when we add new types
+ rd->calculated_value = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC "
+ CALCULATED_NUMBER_FORMAT " = 0"
+ , st->id, rd->name
+ , rd->calculated_value
+ );
+ break;
+ }
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: PHASE2 "
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
+ " collected_value = " COLLECTED_NUMBER_FORMAT
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->last_collected_value
+ , rd->collected_value
+ , rd->last_calculated_value
+ , rd->calculated_value
+ );
+
+ }
+
+ // at this point we have all the calculated values ready
+ // it is now time to interpolate values on a second boundary
+
+ if(unlikely(now_collect_ut < next_store_ut)) {
+ // this is collected in the same interpolation point
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
+
+//#ifdef NETDATA_INTERNAL_CHECKS
+// info("%s is collected in the same interpolation point: short by %llu microseconds", st->name, next_store_ut - now_collect_ut);
+//#endif
+ }
+
+ usec_t first_ut = last_stored_ut;
+ long long iterations = (now_collect_ut - last_stored_ut) / (update_every_ut);
+ if((now_collect_ut % (update_every_ut)) == 0) iterations++;
+
+ for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
+//#ifdef NETDATA_INTERNAL_CHECKS
+// if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_stored_ut = %llu, next_store_ut = %llu, now_collect_ut = %llu", st->name, first_ut, last_stored_ut, next_store_ut, now_collect_ut); }
+//#endif
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) {
+ debug(D_RRD_STATS, "%s: last_stored_ut = %0.3Lf (last updated time)", st->name, (long double)last_stored_ut/1000000.0);
+ debug(D_RRD_STATS, "%s: next_store_ut = %0.3Lf (next interpolation point)", st->name, (long double)next_store_ut/1000000.0);
+ }
+
+ st->last_updated.tv_sec = (time_t) (next_store_ut / USEC_PER_SEC);
+ st->last_updated.tv_usec = 0;
+
+ rrddim_foreach_read(rd, st) {
+ calculated_number new_value;
+
+ switch(rd->algorithm) {
+ case RRD_ALGORITHM_INCREMENTAL:
+ new_value = (calculated_number)
+ ( rd->calculated_value
+ * (calculated_number)(next_store_ut - last_collect_ut)
+ / (calculated_number)(now_collect_ut - last_collect_ut)
+ );
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC2 INC "
+ CALCULATED_NUMBER_FORMAT " = "
+ CALCULATED_NUMBER_FORMAT
+ " * %llu"
+ " / %llu"
+ , st->id, rd->name
+ , new_value
+ , rd->calculated_value
+ , (next_store_ut - last_stored_ut)
+ , (now_collect_ut - last_stored_ut)
+ );
+
+ rd->calculated_value -= new_value;
+ new_value += rd->last_calculated_value;
+ rd->last_calculated_value = 0;
+ new_value /= (calculated_number)st->update_every;
+
+ if(unlikely(next_store_ut - last_stored_ut < update_every_ut)) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: COLLECTION POINT IS SHORT " CALCULATED_NUMBER_FORMAT " - EXTRAPOLATING",
+ st->id, rd->name
+ , (calculated_number)(next_store_ut - last_stored_ut)
+ );
+ new_value = new_value * (calculated_number)(st->update_every * 1000000) / (calculated_number)(next_store_ut - last_stored_ut);
+ }
+ break;
+
+ case RRD_ALGORITHM_ABSOLUTE:
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ default:
+ if(iterations == 1) {
+ // this is the last iteration
+ // do not interpolate
+ // just show the calculated value
+
+ new_value = rd->calculated_value;
+ }
+ else {
+ // we have missed an update
+ // interpolate in the middle values
+
+ new_value = (calculated_number)
+ ( ( (rd->calculated_value - rd->last_calculated_value)
+ * (calculated_number)(next_store_ut - last_collect_ut)
+ / (calculated_number)(now_collect_ut - last_collect_ut)
+ )
+ + rd->last_calculated_value
+ );
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
+ CALCULATED_NUMBER_FORMAT " = ((("
+ "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
+ " * %llu"
+ " / %llu) + " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , new_value
+ , rd->calculated_value, rd->last_calculated_value
+ , (next_store_ut - first_ut)
+ , (now_collect_ut - first_ut), rd->last_calculated_value
+ );
+ }
+ break;
+ }
+
+ if(unlikely(!store_this_entry)) {
+ rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+ continue;
+ }
+
+ if(likely(rd->updated && rd->collections_counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
+ rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
+ rd->last_stored_value = new_value;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
+ CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , st->current_entry
+ , unpack_storage_number(rd->values[st->current_entry]), new_value
+ );
+ }
+ else {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
+ , st->id, rd->name
+ , st->current_entry
+ );
+ rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+ rd->last_stored_value = NAN;
+ }
+
+ stored_entries++;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) {
+ calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
+ calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
+ calculated_number accuracy = accuracy_loss(t1, t2);
+ debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
+ , st->id, rd->name
+ , st->current_entry
+ , t2
+ , get_storage_number_flags(rd->values[st->current_entry])
+ , t1
+ , accuracy
+ , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
+ );
+
+ rd->collected_volume += t1;
+ rd->stored_volume += t2;
+ accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
+ debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
+ , st->id, rd->name
+ , st->current_entry
+ , rd->stored_volume
+ , rd->collected_volume
+ , accuracy
+ , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
+ );
+
+ }
+ }
+ // reset the storage flags for the next point, if any;
+ storage_flags = SN_EXISTS;
+
+ st->counter++;
+ st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
+ last_stored_ut = next_store_ut;
+ }
+
+ st->last_collected_total = st->collected_total;
+
+ rrddim_foreach_read(rd, st) {
+ if(unlikely(!rd->updated))
+ continue;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
+
+ rd->last_collected_value = rd->collected_value;
+
+ switch(rd->algorithm) {
+ case RRD_ALGORITHM_INCREMENTAL:
+ if(unlikely(!first_entry)) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value + rd->calculated_value, rd->calculated_value);
+ rd->last_calculated_value += rd->calculated_value;
+ }
+ else {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s: THIS IS THE FIRST POINT", st->name);
+ }
+ break;
+
+ case RRD_ALGORITHM_ABSOLUTE:
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
+ rd->last_calculated_value = rd->calculated_value;
+ break;
+ }
+
+ rd->calculated_value = 0;
+ rd->collected_value = 0;
+ rd->updated = 0;
+
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
+ debug(D_RRD_STATS, "%s/%s: END "
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
+ " collected_value = " COLLECTED_NUMBER_FORMAT
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
+ , st->id, rd->name
+ , rd->last_collected_value
+ , rd->collected_value
+ , rd->last_calculated_value
+ , rd->calculated_value
+ );
+ }
+
+ // ALL DONE ABOUT THE DATA UPDATE
+ // --------------------------------------------------------------------
+
+/*
+ // find if there are any obsolete dimensions (not updated recently)
+ if(unlikely(rrd_delete_unupdated_dimensions)) {
+
+ for( rd = st->dimensions; likely(rd) ; rd = rd->next )
+ if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
+ break;
+
+ if(unlikely(rd)) {
+ RRDDIM *last;
+ // there is dimension to free
+ // upgrade our read lock to a write lock
+ rrdset_unlock(st);
+ rrdset_wrlock(st);
+
+ for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
+ // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
+
+ if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
+ info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
+
+ if(unlikely(!last)) {
+ st->dimensions = rd->next;
+ rd->next = NULL;
+ rrddim_free(st, rd);
+ rd = st->dimensions;
+ continue;
+ }
+ else {
+ last->next = rd->next;
+ rd->next = NULL;
+ rrddim_free(st, rd);
+ rd = last->next;
+ continue;
+ }
+ }
+
+ last = rd;
+ rd = rd->next;
+ }
+
+ if(unlikely(!st->dimensions)) {
+ info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
+ st->enabled = 0;
+ }
+ }
+ }
+*/
+
+ rrdset_unlock(st);
+
+ if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
+ error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
+}
diff --git a/src/rrdsetvar.c b/src/rrdsetvar.c
new file mode 100644
index 000000000..03d7aeced
--- /dev/null
+++ b/src/rrdsetvar.c
@@ -0,0 +1,120 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDSETVAR management
+// CHART VARIABLES
+
+static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
+ RRDSET *st = rs->rrdset;
+
+ // CHART
+
+ rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local);
+ rs->var_local = NULL;
+
+ // FAMILY
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family);
+ rs->var_family = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host);
+ rs->var_host = NULL;
+
+ // HOST
+
+ rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
+ rs->var_family_name = NULL;
+
+ rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name);
+ rs->var_host_name = NULL;
+
+ // KEYS
+
+ freez(rs->key_fullid);
+ rs->key_fullid = NULL;
+
+ freez(rs->key_fullname);
+ rs->key_fullname = NULL;
+}
+
+static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
+ rrdsetvar_free_variables(rs);
+
+ RRDSET *st = rs->rrdset;
+
+ // KEYS
+
+ char buffer[RRDVAR_MAX_LENGTH + 1];
+ snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
+ rs->key_fullid = strdupz(buffer);
+
+ snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
+ rs->key_fullname = strdupz(buffer);
+
+ // CHART
+
+ rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
+
+ // FAMILY
+
+ rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value);
+ rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value);
+
+ // HOST
+
+ rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value);
+ rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value);
+
+}
+
+RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
+ debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
+ RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
+
+ rs->variable = strdupz(variable);
+ rs->type = type;
+ rs->value = value;
+ rs->options = options;
+ rs->rrdset = st;
+
+ rs->next = st->variables;
+ st->variables = rs;
+
+ rrdsetvar_create_variables(rs);
+
+ return rs;
+}
+
+void rrdsetvar_rename_all(RRDSET *st) {
+ debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
+
+ RRDSETVAR *rs, *next = st->variables;
+ while((rs = next)) {
+ next = rs->next;
+ rrdsetvar_create_variables(rs);
+ }
+
+ rrdsetcalc_link_matching(st);
+}
+
+void rrdsetvar_free(RRDSETVAR *rs) {
+ RRDSET *st = rs->rrdset;
+ debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
+
+ if(st->variables == rs) {
+ st->variables = rs->next;
+ }
+ else {
+ RRDSETVAR *t;
+ for (t = st->variables; t && t->next != rs; t = t->next);
+ if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
+ else t->next = rs->next;
+ }
+
+ rrdsetvar_free_variables(rs);
+
+ freez(rs->variable);
+ freez(rs);
+}
+
diff --git a/src/rrdvar.c b/src/rrdvar.c
new file mode 100644
index 000000000..2223d7c9a
--- /dev/null
+++ b/src/rrdvar.c
@@ -0,0 +1,265 @@
+#define NETDATA_HEALTH_INTERNALS
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDVAR management
+
+inline int rrdvar_fix_name(char *variable) {
+ int fixed = 0;
+ while(*variable) {
+ if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
+ *variable++ = '_';
+ fixed++;
+ }
+ else
+ variable++;
+ }
+
+ return fixed;
+}
+
+int rrdvar_compare(void* a, void* b) {
+ if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
+ else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
+ else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
+}
+
+static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
+ RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
+ if(ret != rv)
+ debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
+
+ return ret;
+}
+
+static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
+ RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
+ if(!ret)
+ error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
+
+ return ret;
+}
+
+static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
+ RRDVAR tmp;
+ tmp.name = (char *)name;
+ tmp.hash = (hash)?hash:simple_hash(tmp.name);
+
+ return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
+}
+
+inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
+ (void)host;
+
+ if(!rv) return;
+
+ if(tree) {
+ debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
+ if(unlikely(!rrdvar_index_del(tree, rv)))
+ error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
+ }
+
+ freez(rv->name);
+ freez(rv);
+}
+
+inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) {
+ char *variable = strdupz(name);
+ rrdvar_fix_name(variable);
+ uint32_t hash = simple_hash(variable);
+
+ RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
+ if(unlikely(!rv)) {
+ debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
+
+ rv = callocz(1, sizeof(RRDVAR));
+ rv->name = variable;
+ rv->hash = hash;
+ rv->type = type;
+ rv->value = value;
+
+ RRDVAR *ret = rrdvar_index_add(tree, rv);
+ if(unlikely(ret != rv)) {
+ debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
+ rrdvar_free(NULL, NULL, rv);
+ rv = NULL;
+ }
+ else
+ debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
+ }
+ else {
+ debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
+
+ // already exists
+ freez(variable);
+
+ // this is important
+ // it must return NULL - not the existing variable - or double-free will happen
+ rv = NULL;
+ }
+
+ return rv;
+}
+
+// ----------------------------------------------------------------------------
+// CUSTOM VARIABLES
+
+RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
+ calculated_number *v = callocz(1, sizeof(calculated_number));
+ *v = NAN;
+ RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v);
+ if(unlikely(!rv)) {
+ free(v);
+ error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name);
+
+ char *variable = strdupz(name);
+ rrdvar_fix_name(variable);
+ uint32_t hash = simple_hash(variable);
+
+ rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
+ }
+
+ return rv;
+}
+
+void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) {
+ char *variable = strdupz(name);
+ rrdvar_fix_name(variable);
+ uint32_t hash = simple_hash(variable);
+
+ RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
+ freez(variable);
+
+ if(!rv) {
+ error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname);
+ return;
+ }
+
+ if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) {
+ error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname);
+ return;
+ }
+
+ if(!rrdvar_index_del(&host->variables_root_index, rv)) {
+ error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname);
+ return;
+ }
+
+ freez(rv->name);
+ freez(rv->value);
+ freez(rv);
+}
+
+void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) {
+ if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED)
+ error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value);
+ else {
+ calculated_number *v = rv->value;
+ *v = value;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// RRDVAR lookup
+
+static calculated_number rrdvar2number(RRDVAR *rv) {
+ switch(rv->type) {
+ case RRDVAR_TYPE_CALCULATED_ALLOCATED:
+ case RRDVAR_TYPE_CALCULATED: {
+ calculated_number *n = (calculated_number *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_TIME_T: {
+ time_t *n = (time_t *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_COLLECTED: {
+ collected_number *n = (collected_number *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_TOTAL: {
+ total_number *n = (total_number *)rv->value;
+ return *n;
+ }
+
+ case RRDVAR_TYPE_INT: {
+ int *n = (int *)rv->value;
+ return *n;
+ }
+
+ default:
+ error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type);
+ return NAN;
+ }
+}
+
+int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
+ RRDSET *st = rc->rrdset;
+ RRDVAR *rv;
+
+ if(!st) return 0;
+
+ rv = rrdvar_index_find(&st->variables_root_index, variable, hash);
+ if(rv) {
+ *result = rrdvar2number(rv);
+ return 1;
+ }
+
+ rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash);
+ if(rv) {
+ *result = rrdvar2number(rv);
+ return 1;
+ }
+
+ rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash);
+ if(rv) {
+ *result = rrdvar2number(rv);
+ return 1;
+ }
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// RRDVAR to JSON
+
+struct variable2json_helper {
+ BUFFER *buf;
+ size_t counter;
+};
+
+static int single_variable2json(void *entry, void *data) {
+ struct variable2json_helper *helper = (struct variable2json_helper *)data;
+ RRDVAR *rv = (RRDVAR *)entry;
+ calculated_number value = rrdvar2number(rv);
+
+ if(unlikely(isnan(value) || isinf(value)))
+ buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
+ else
+ buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
+
+ helper->counter++;
+
+ return 0;
+}
+
+void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
+ struct variable2json_helper helper = {
+ .buf = buf,
+ .counter = 0
+ };
+
+ buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", st->id, st->name, st->context);
+ avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
+ helper.counter = 0;
+ avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
+ helper.counter = 0;
+ avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
+ buffer_strcat(buf, "\n\t}\n}\n");
+}
+
diff --git a/src/simple_pattern.c b/src/simple_pattern.c
index 7e4424297..f72a42d06 100644
--- a/src/simple_pattern.c
+++ b/src/simple_pattern.c
@@ -169,7 +169,7 @@ static inline int match_pattern(struct simple_pattern *m, const char *str, size_
int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) {
struct simple_pattern *m, *root = (struct simple_pattern *)list;
- if(unlikely(!root)) return 0;
+ if(unlikely(!root || !str || !*str)) return 0;
size_t len = strlen(str);
for(m = root; m ; m = m->next)
@@ -184,8 +184,8 @@ int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) {
static inline void free_pattern(struct simple_pattern *m) {
if(!m) return;
- if(m->next) free_pattern(m->next);
- if(m->child) free_pattern(m->child);
+ free_pattern(m->child);
+ free_pattern(m->next);
freez((void *)m->match);
freez(m);
}
@@ -193,5 +193,5 @@ static inline void free_pattern(struct simple_pattern *m) {
void simple_pattern_free(SIMPLE_PATTERN *list) {
if(!list) return;
- free_pattern(((struct simple_pattern *)list)->next);
+ free_pattern(((struct simple_pattern *)list));
}
diff --git a/src/socket.c b/src/socket.c
index 643811e44..400c1ef4e 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -160,8 +160,10 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(fd != -1) {
- if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)timeout, sizeof(struct timeval)) < 0)
- error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
+ if(timeout) {
+ if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0)
+ error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
+ }
if(connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
error("Failed to connect to '%s', port '%s'", hostBfr, servBfr);
@@ -177,3 +179,98 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
return fd;
}
+
+int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) {
+ int sock = -1;
+
+ const char *s = destination;
+ while(*s) {
+ const char *e = s;
+
+ // skip separators, moving both s(tart) and e(nd)
+ while(isspace(*e) || *e == ',') s = ++e;
+
+ // move e(nd) to the first separator
+ while(*e && !isspace(*e) && *e != ',') e++;
+
+ // is there anything?
+ if(!*s || s == e) break;
+
+ char buf[e - s + 1];
+ strncpyz(buf, s, e - s);
+ if(reconnects_counter) *reconnects_counter += 1;
+ sock = connect_to(buf, default_port, timeout);
+ if(sock != -1) {
+ if(connected_to && connected_to_size) {
+ strncpy(connected_to, buf, connected_to_size);
+ connected_to[connected_to_size - 1] = '\0';
+ }
+ break;
+ }
+ s = e;
+ }
+
+ return sock;
+}
+
+ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
+ for(;;) {
+ struct pollfd fd = {
+ .fd = sockfd,
+ .events = POLLIN,
+ .revents = 0
+ };
+
+ errno = 0;
+ int retval = poll(&fd, 1, timeout * 1000);
+
+ if(retval == -1) {
+ // failed
+
+ if(errno == EINTR || errno == EAGAIN)
+ continue;
+
+ return -1;
+ }
+
+ if(!retval) {
+ // timeout
+ return 0;
+ }
+
+ if(fd.events & POLLIN) break;
+ }
+
+ return recv(sockfd, buf, len, flags);
+}
+
+ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
+ for(;;) {
+ struct pollfd fd = {
+ .fd = sockfd,
+ .events = POLLOUT,
+ .revents = 0
+ };
+
+ errno = 0;
+ int retval = poll(&fd, 1, timeout * 1000);
+
+ if(retval == -1) {
+ // failed
+
+ if(errno == EINTR || errno == EAGAIN)
+ continue;
+
+ return -1;
+ }
+
+ if(!retval) {
+ // timeout
+ return 0;
+ }
+
+ if(fd.events & POLLOUT) break;
+ }
+
+ return send(sockfd, buf, len, flags);
+}
diff --git a/src/socket.h b/src/socket.h
index 791c0ce54..89c154a61 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -6,5 +6,9 @@
#define NETDATA_SOCKET_H
extern int connect_to(const char *definition, int default_port, struct timeval *timeout);
+extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size);
+
+extern ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
+extern ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
#endif //NETDATA_SOCKET_H
diff --git a/src/sys_devices_system_edac_mc.c b/src/sys_devices_system_edac_mc.c
index c764615f1..c41ad7faa 100644
--- a/src/sys_devices_system_edac_mc.c
+++ b/src/sys_devices_system_edac_mc.c
@@ -23,7 +23,7 @@ static struct mc *mc_root = NULL;
static void find_all_mc() {
char name[FILENAME_MAX + 1];
- snprintfz(name, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/devices/system/edac/mc");
+ snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/edac/mc");
char *dirname = config_get("plugin:proc:/sys/devices/system/edac/mc", "directory to monitor", name);
DIR *dir = opendir(dirname);
@@ -76,11 +76,11 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
struct mc *m;
if(unlikely(do_ce == -1)) {
- do_ce = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory correctable errors", CONFIG_ONDEMAND_ONDEMAND);
- do_ue = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory uncorrectable errors", CONFIG_ONDEMAND_ONDEMAND);
+ do_ce = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory correctable errors", CONFIG_BOOLEAN_AUTO);
+ do_ue = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory uncorrectable errors", CONFIG_BOOLEAN_AUTO);
}
- if(do_ce != CONFIG_ONDEMAND_NO) {
+ if(do_ce != CONFIG_BOOLEAN_NO) {
for(m = mc_root; m; m = m->next) {
if(m->ce_count_filename) {
m->ce_updated = 0;
@@ -102,7 +102,7 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
}
}
- if(do_ue != CONFIG_ONDEMAND_NO) {
+ if(do_ue != CONFIG_BOOLEAN_NO) {
for(m = mc_root; m; m = m->next) {
if(m->ue_count_filename) {
m->ue_updated = 0;
@@ -126,20 +126,20 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ce == CONFIG_ONDEMAND_YES || (do_ce == CONFIG_ONDEMAND_ONDEMAND && ce_sum > 0)) {
- do_ce = CONFIG_ONDEMAND_YES;
+ if(do_ce == CONFIG_BOOLEAN_YES || (do_ce == CONFIG_BOOLEAN_AUTO && ce_sum > 0)) {
+ do_ce = CONFIG_BOOLEAN_YES;
static RRDSET *ce_st = NULL;
if(unlikely(!ce_st)) {
- ce_st = rrdset_find("mem.ecc_ce");
+ ce_st = rrdset_find_localhost("mem.ecc_ce");
if(unlikely(!ce_st))
- ce_st = rrdset_create("mem", "ecc_ce", NULL, "ecc", NULL, "ECC Memory Correctable Errors", "errors",
- 6600, update_every, RRDSET_TYPE_LINE);
+ ce_st = rrdset_create_localhost("mem", "ecc_ce", NULL, "ecc", NULL, "ECC Memory Correctable Errors"
+ , "errors", 6600, update_every, RRDSET_TYPE_LINE);
for(m = mc_root; m; m = m->next)
if(m->ce_count_filename)
- m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(ce_st);
@@ -153,21 +153,21 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- if(do_ue == CONFIG_ONDEMAND_YES || (do_ue == CONFIG_ONDEMAND_ONDEMAND && ue_sum > 0)) {
- do_ue = CONFIG_ONDEMAND_YES;
+ if(do_ue == CONFIG_BOOLEAN_YES || (do_ue == CONFIG_BOOLEAN_AUTO && ue_sum > 0)) {
+ do_ue = CONFIG_BOOLEAN_YES;
static RRDSET *ue_st = NULL;
if(unlikely(!ue_st)) {
- ue_st = rrdset_find("mem.ecc_ue");
+ ue_st = rrdset_find_localhost("mem.ecc_ue");
if(unlikely(!ue_st))
- ue_st = rrdset_create("mem", "ecc_ue", NULL, "ecc", NULL, "ECC Memory Uncorrectable Errors", "errors",
- 6610, update_every, RRDSET_TYPE_LINE);
+ ue_st = rrdset_create_localhost("mem", "ecc_ue", NULL, "ecc", NULL, "ECC Memory Uncorrectable Errors"
+ , "errors", 6610, update_every, RRDSET_TYPE_LINE);
for(m = mc_root; m; m = m->next)
if(m->ue_count_filename)
- m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+ m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(ue_st);
diff --git a/src/sys_devices_system_node.c b/src/sys_devices_system_node.c
index 18c3fcd3a..a7690e7b7 100644
--- a/src/sys_devices_system_node.c
+++ b/src/sys_devices_system_node.c
@@ -12,7 +12,7 @@ static struct node *numa_root = NULL;
static int find_all_nodes() {
int numa_node_count = 0;
char name[FILENAME_MAX + 1];
- snprintfz(name, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/devices/system/node");
+ snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/node");
char *dirname = config_get("plugin:proc:/sys/devices/system/node", "directory to monitor", name);
DIR *dir = opendir(dirname);
@@ -60,26 +60,34 @@ static int find_all_nodes() {
int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
(void)dt;
- static int numa_node_count = 0;
+ static uint32_t hash_local_node = 0, hash_numa_foreign = 0, hash_interleave_hit = 0, hash_other_node = 0, hash_numa_hit = 0, hash_numa_miss = 0;
+ static int do_numastat = -1, numa_node_count = 0;
+ struct node *m;
if(unlikely(numa_root == NULL)) {
- numa_node_count = find_all_nodes(update_every);
+ numa_node_count = find_all_nodes();
if(unlikely(numa_root == NULL))
return 1;
}
- static int do_numastat = -1;
- struct node *m;
-
if(unlikely(do_numastat == -1)) {
- do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_ONDEMAND_ONDEMAND);
+ do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_BOOLEAN_AUTO);
+
+ hash_local_node = simple_hash("local_node");
+ hash_numa_foreign = simple_hash("numa_foreign");
+ hash_interleave_hit = simple_hash("interleave_hit");
+ hash_other_node = simple_hash("other_node");
+ hash_numa_hit = simple_hash("numa_hit");
+ hash_numa_miss = simple_hash("numa_miss");
}
- if(do_numastat == CONFIG_ONDEMAND_YES || (do_numastat == CONFIG_ONDEMAND_ONDEMAND && numa_node_count >= 2)) {
+ if(do_numastat == CONFIG_BOOLEAN_YES || (do_numastat == CONFIG_BOOLEAN_AUTO && numa_node_count >= 2)) {
for(m = numa_root; m; m = m->next) {
if(m->numastat_filename) {
+
if(unlikely(!m->numastat_ff)) {
m->numastat_ff = procfile_open(m->numastat_filename, " ", PROCFILE_FLAG_DEFAULT);
+
if(unlikely(!m->numastat_ff))
continue;
}
@@ -88,37 +96,61 @@ int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
if(unlikely(!m->numastat_ff || procfile_lines(m->numastat_ff) < 1 || procfile_linewords(m->numastat_ff, 0) < 1))
continue;
- procfile *ff = m->numastat_ff;
-
- RRDSET *st = m->numastat_st;
- if(unlikely(!st)) {
- st = rrdset_create("mem", m->name, NULL, "numa", NULL, "NUMA events", "events/s", 1000, update_every, RRDSET_TYPE_LINE);
- st->isdetail = 1;
+ if(unlikely(!m->numastat_st)) {
+ m->numastat_st = rrdset_create_localhost(
+ "mem"
+ , m->name
+ , NULL
+ , "numa"
+ , NULL
+ , "NUMA events"
+ , "events/s"
+ , 1000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_flag_set(m->numastat_st, RRDSET_FLAG_DETAIL);
+
+ rrddim_add(m->numastat_st, "numa_hit", "hit", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "numa_miss", "miss", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "local_node", "local", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "numa_foreign", "foreign", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "interleave_hit", "interleave", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(m->numastat_st, "other_node", "other", 1, 1, RRD_ALGORITHM_INCREMENTAL);
- rrddim_add(st, "local_node", "local", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "numa_foreign", "foreign", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "interleave_hit", "interleave", 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(st, "other_node", "other", 1, 1, RRDDIM_INCREMENTAL);
-
- m->numastat_st = st;
}
- else rrdset_next(st);
+ else rrdset_next(m->numastat_st);
- uint32_t lines = procfile_lines(ff), l;
+ size_t lines = procfile_lines(m->numastat_ff), l;
for(l = 0; l < lines; l++) {
- uint32_t words = procfile_linewords(ff, l);
+ size_t words = procfile_linewords(m->numastat_ff, l);
+
if(unlikely(words < 2)) {
- if(unlikely(words)) error("Cannot read %s numastat line %u. Expected 2 params, read %u.", m->name, l, words);
+ if(unlikely(words))
+ error("Cannot read %s numastat line %zu. Expected 2 params, read %zu.", m->name, l, words);
continue;
}
- char *name = procfile_lineword(ff, l, 0);
- char *value = procfile_lineword(ff, l, 1);
- if (unlikely(!name || !*name || !value || !*value)) continue;
+ char *name = procfile_lineword(m->numastat_ff, l, 0);
+ char *value = procfile_lineword(m->numastat_ff, l, 1);
- rrddim_set(st, name, strtoull(value, NULL, 10));
+ if (unlikely(!name || !*name || !value || !*value))
+ continue;
+
+ uint32_t hash = simple_hash(name);
+ if(likely(
+ (hash == hash_numa_hit && !strcmp(name, "numa_hit"))
+ || (hash == hash_numa_miss && !strcmp(name, "numa_miss"))
+ || (hash == hash_local_node && !strcmp(name, "local_node"))
+ || (hash == hash_numa_foreign && !strcmp(name, "numa_foreign"))
+ || (hash == hash_interleave_hit && !strcmp(name, "interleave_hit"))
+ || (hash == hash_other_node && !strcmp(name, "other_node"))
+ ))
+ rrddim_set(m->numastat_st, name, (collected_number)str2kernel_uint_t(value));
}
- rrdset_done(st);
+
+ rrdset_done(m->numastat_st);
}
}
}
diff --git a/src/sys_fs_cgroup.c b/src/sys_fs_cgroup.c
index 2b7254f47..8f31527de 100644
--- a/src/sys_fs_cgroup.c
+++ b/src/sys_fs_cgroup.c
@@ -8,22 +8,22 @@
static long system_page_size = 4096; // system will be queried via sysconf() in configuration()
-static int cgroup_enable_cpuacct_stat = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_memory = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_detailed_memory = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_memory_failcnt = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_swap = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_io = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_ops = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_throttle_io = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_throttle_ops = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_merged_ops = CONFIG_ONDEMAND_ONDEMAND;
-static int cgroup_enable_blkio_queued_ops = CONFIG_ONDEMAND_ONDEMAND;
-
-static int cgroup_enable_systemd_services = CONFIG_ONDEMAND_YES;
-static int cgroup_enable_systemd_services_detailed_memory = CONFIG_ONDEMAND_NO;
-static int cgroup_used_memory_without_cache = CONFIG_ONDEMAND_YES;
+static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_memory = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_detailed_memory = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_swap = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_io = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_ops = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_throttle_io = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_throttle_ops = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_merged_ops = CONFIG_BOOLEAN_AUTO;
+static int cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_AUTO;
+
+static int cgroup_enable_systemd_services = CONFIG_BOOLEAN_YES;
+static int cgroup_enable_systemd_services_detailed_memory = CONFIG_BOOLEAN_NO;
+static int cgroup_used_memory_without_cache = CONFIG_BOOLEAN_YES;
static int cgroup_search_in_devices = 1;
@@ -49,7 +49,9 @@ static SIMPLE_PATTERN *enabled_cgroup_paths = NULL;
static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
-static char *cgroups_rename_script = PLUGINS_DIR "/cgroup-name.sh";
+static char *cgroups_rename_script = NULL;
+
+static int cgroups_check = 0;
static uint32_t Read_hash = 0;
static uint32_t Write_hash = 0;
@@ -64,9 +66,9 @@ void read_cgroup_plugin_configuration() {
user_hash = simple_hash("user");
system_hash = simple_hash("system");
- cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", rrd_update_every);
- if(cgroup_update_every < rrd_update_every)
- cgroup_update_every = rrd_update_every;
+ cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", localhost->rrd_update_every);
+ if(cgroup_update_every < localhost->rrd_update_every)
+ cgroup_update_every = localhost->rrd_update_every;
cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every * cgroup_update_every);
if(cgroup_check_for_new_every < cgroup_update_every)
@@ -105,7 +107,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/cpuacct";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
@@ -115,7 +117,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/blkio";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
@@ -125,7 +127,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/memory";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
@@ -135,7 +137,7 @@ void read_cgroup_plugin_configuration() {
s = "/sys/fs/cgroup/devices";
}
else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
cgroup_root_max = (int)config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
@@ -145,6 +147,8 @@ void read_cgroup_plugin_configuration() {
enabled_cgroup_patterns = simple_pattern_create(
config_get("plugin:cgroups", "enable by default cgroups matching",
+ " /system.slice/docker-*.scope "
+ " /qemu.slice/*.scope " // #1949
" !*.mount "
" !*.partition "
" !*.scope "
@@ -156,18 +160,18 @@ void read_cgroup_plugin_configuration() {
" !/docker "
" !/libvirt "
" !/lxc "
- " !/lxc/*/ns " // #1397
+ " !/lxc/*/ns " // #1397
" !/machine "
" !/qemu "
" !/system "
" !/systemd "
" !/user "
- " * " // enable anything else
+ " * " // enable anything else
), SIMPLE_PATTERN_EXACT);
enabled_cgroup_paths = simple_pattern_create(
config_get("plugin:cgroups", "search for cgroups in subpaths matching",
- " !*-qemu " // #345
+ " !*-qemu " // #345
" !/init.scope "
" !/system "
" !/systemd "
@@ -176,10 +180,14 @@ void read_cgroup_plugin_configuration() {
" * "
), SIMPLE_PATTERN_EXACT);
- cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", cgroups_rename_script);
+ snprintfz(filename, FILENAME_MAX, "%s/cgroup-name.sh", netdata_configured_plugins_dir);
+ cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", filename);
enabled_cgroup_renames = simple_pattern_create(
config_get("plugin:cgroups", "run script to rename cgroups matching",
+ " /qemu.slice/*.scope " // #1949
+ " *docker* "
+ " *lxc* "
" !/ "
" !*.mount "
" !*.partition "
@@ -207,7 +215,7 @@ void read_cgroup_plugin_configuration() {
struct blkio {
int updated;
- int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
int delay_counter;
char *filename;
@@ -232,10 +240,10 @@ struct memory {
int updated_msw_usage_in_bytes;
int updated_failcnt;
- int enabled_detailed; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
- int enabled_usage_in_bytes; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
- int enabled_msw_usage_in_bytes; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
- int enabled_failcnt; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled_detailed; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
+ int enabled_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
+ int enabled_msw_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
+ int enabled_failcnt; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
int delay_counter_detailed;
int delay_counter_failcnt;
@@ -294,7 +302,7 @@ struct memory {
// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
struct cpuacct_stat {
int updated;
- int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
char *filename;
@@ -305,7 +313,7 @@ struct cpuacct_stat {
// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
struct cpuacct_usage {
int updated;
- int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
+ int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
char *filename;
@@ -403,12 +411,14 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
cp->updated = 0;
+ cgroups_check = 1;
return;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
cp->updated = 0;
+ cgroups_check = 1;
return;
}
@@ -433,8 +443,8 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
cp->updated = 1;
- if(unlikely(cp->enabled == CONFIG_ONDEMAND_ONDEMAND && (cp->user || cp->system)))
- cp->enabled = CONFIG_ONDEMAND_YES;
+ if(unlikely(cp->enabled == CONFIG_BOOLEAN_AUTO && (cp->user || cp->system)))
+ cp->enabled = CONFIG_BOOLEAN_YES;
}
}
@@ -445,12 +455,14 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
ca->updated = 0;
+ cgroups_check = 1;
return;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
ca->updated = 0;
+ cgroups_check = 1;
return;
}
@@ -462,8 +474,8 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
unsigned long i = procfile_linewords(ff, 0);
if(unlikely(i == 0)) {
- return;
ca->updated = 0;
+ return;
}
// we may have 1 more CPU reported
@@ -488,15 +500,15 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
ca->updated = 1;
- if(unlikely(ca->enabled == CONFIG_ONDEMAND_ONDEMAND && total))
- ca->enabled = CONFIG_ONDEMAND_YES;
+ if(unlikely(ca->enabled == CONFIG_BOOLEAN_AUTO && total))
+ ca->enabled = CONFIG_BOOLEAN_YES;
}
}
static inline void cgroup_read_blkio(struct blkio *io) {
static procfile *ff = NULL;
- if(unlikely(io->enabled == CONFIG_ONDEMAND_ONDEMAND && io->delay_counter > 0)) {
+ if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO && io->delay_counter > 0)) {
io->delay_counter--;
return;
}
@@ -505,12 +517,14 @@ static inline void cgroup_read_blkio(struct blkio *io) {
ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
io->updated = 0;
+ cgroups_check = 1;
return;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
io->updated = 0;
+ cgroups_check = 1;
return;
}
@@ -554,9 +568,9 @@ static inline void cgroup_read_blkio(struct blkio *io) {
io->updated = 1;
- if(unlikely(io->enabled == CONFIG_ONDEMAND_ONDEMAND)) {
+ if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO)) {
if(unlikely(io->Read || io->Write))
- io->enabled = CONFIG_ONDEMAND_YES;
+ io->enabled = CONFIG_BOOLEAN_YES;
else
io->delay_counter = cgroup_recheck_zero_blkio_every_iterations;
}
@@ -568,7 +582,7 @@ static inline void cgroup_read_memory(struct memory *mem) {
// read detailed ram usage
if(likely(mem->filename_detailed)) {
- if(unlikely(mem->enabled_detailed == CONFIG_ONDEMAND_ONDEMAND && mem->delay_counter_detailed > 0)) {
+ if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO && mem->delay_counter_detailed > 0)) {
mem->delay_counter_detailed--;
goto memory_next;
}
@@ -576,12 +590,14 @@ static inline void cgroup_read_memory(struct memory *mem) {
ff = procfile_reopen(ff, mem->filename_detailed, NULL, PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
mem->updated_detailed = 0;
+ cgroups_check = 1;
goto memory_next;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
mem->updated_detailed = 0;
+ cgroups_check = 1;
goto memory_next;
}
@@ -627,9 +643,9 @@ static inline void cgroup_read_memory(struct memory *mem) {
mem->updated_detailed = 1;
- if(unlikely(mem->enabled_detailed == CONFIG_ONDEMAND_ONDEMAND)) {
+ if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO)) {
if(mem->cache || mem->dirty || mem->rss || mem->rss_huge || mem->mapped_file || mem->writeback || mem->swap || mem->pgpgin || mem->pgpgout || mem->pgfault || mem->pgmajfault)
- mem->enabled_detailed = CONFIG_ONDEMAND_YES;
+ mem->enabled_detailed = CONFIG_BOOLEAN_YES;
else
mem->delay_counter_detailed = cgroup_recheck_zero_mem_detailed_every_iterations;
}
@@ -640,30 +656,30 @@ memory_next:
// read usage_in_bytes
if(likely(mem->filename_usage_in_bytes)) {
mem->updated_usage_in_bytes = !read_single_number_file(mem->filename_usage_in_bytes, &mem->usage_in_bytes);
- if(unlikely(mem->updated_usage_in_bytes && mem->enabled_usage_in_bytes == CONFIG_ONDEMAND_ONDEMAND && mem->usage_in_bytes))
- mem->enabled_usage_in_bytes = CONFIG_ONDEMAND_YES;
+ if(unlikely(mem->updated_usage_in_bytes && mem->enabled_usage_in_bytes == CONFIG_BOOLEAN_AUTO && mem->usage_in_bytes))
+ mem->enabled_usage_in_bytes = CONFIG_BOOLEAN_YES;
}
// read msw_usage_in_bytes
if(likely(mem->filename_msw_usage_in_bytes)) {
mem->updated_msw_usage_in_bytes = !read_single_number_file(mem->filename_msw_usage_in_bytes, &mem->msw_usage_in_bytes);
- if(unlikely(mem->updated_msw_usage_in_bytes && mem->enabled_msw_usage_in_bytes == CONFIG_ONDEMAND_ONDEMAND && mem->msw_usage_in_bytes))
- mem->enabled_msw_usage_in_bytes = CONFIG_ONDEMAND_YES;
+ if(unlikely(mem->updated_msw_usage_in_bytes && mem->enabled_msw_usage_in_bytes == CONFIG_BOOLEAN_AUTO && mem->msw_usage_in_bytes))
+ mem->enabled_msw_usage_in_bytes = CONFIG_BOOLEAN_YES;
}
// read failcnt
if(likely(mem->filename_failcnt)) {
- if(unlikely(mem->enabled_failcnt == CONFIG_ONDEMAND_ONDEMAND && mem->delay_counter_failcnt > 0)) {
+ if(unlikely(mem->enabled_failcnt == CONFIG_BOOLEAN_AUTO && mem->delay_counter_failcnt > 0)) {
mem->updated_failcnt = 0;
mem->delay_counter_failcnt--;
}
else {
mem->updated_failcnt = !read_single_number_file(mem->filename_failcnt, &mem->failcnt);
- if(unlikely(mem->updated_failcnt && mem->enabled_failcnt == CONFIG_ONDEMAND_ONDEMAND)) {
+ if(unlikely(mem->updated_failcnt && mem->enabled_failcnt == CONFIG_BOOLEAN_AUTO)) {
if(unlikely(!mem->failcnt))
mem->delay_counter_failcnt = cgroup_recheck_zero_mem_failcnt_every_iterations;
else
- mem->enabled_failcnt = CONFIG_ONDEMAND_YES;
+ mem->enabled_failcnt = CONFIG_BOOLEAN_YES;
}
}
}
@@ -877,6 +893,21 @@ static inline struct cgroup *cgroup_add(const char *id) {
static inline void cgroup_free(struct cgroup *cg) {
debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
+ if(cg->st_cpu) rrdset_flag_set(cg->st_cpu, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_cpu_per_core) rrdset_flag_set(cg->st_cpu_per_core, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem) rrdset_flag_set(cg->st_mem, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_writeback) rrdset_flag_set(cg->st_writeback, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem_activity) rrdset_flag_set(cg->st_mem_activity, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_pgfaults) rrdset_flag_set(cg->st_pgfaults, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem_usage) rrdset_flag_set(cg->st_mem_usage, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_mem_failcnt) rrdset_flag_set(cg->st_mem_failcnt, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_io) rrdset_flag_set(cg->st_io, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_serviced_ops) rrdset_flag_set(cg->st_serviced_ops, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_throttle_io) rrdset_flag_set(cg->st_throttle_io, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_throttle_serviced_ops) rrdset_flag_set(cg->st_throttle_serviced_ops, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_queued_ops) rrdset_flag_set(cg->st_queued_ops, RRDSET_FLAG_OBSOLETE);
+ if(cg->st_merged_ops) rrdset_flag_set(cg->st_merged_ops, RRDSET_FLAG_OBSOLETE);
+
freez(cg->cpuacct_usage.cpu_percpu);
freez(cg->cpuacct_stat.filename);
@@ -1070,7 +1101,7 @@ static inline void find_all_cgroups() {
if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
if(find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
cgroup_enable_cpuacct_stat =
- cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_NO;
+ cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
error("disabled CGROUP cpu statistics.");
}
}
@@ -1082,7 +1113,7 @@ static inline void find_all_cgroups() {
cgroup_enable_blkio_throttle_io =
cgroup_enable_blkio_throttle_ops =
cgroup_enable_blkio_merged_ops =
- cgroup_enable_blkio_queued_ops = CONFIG_ONDEMAND_NO;
+ cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_NO;
error("disabled CGROUP blkio statistics.");
}
}
@@ -1092,7 +1123,7 @@ static inline void find_all_cgroups() {
cgroup_enable_memory =
cgroup_enable_detailed_memory =
cgroup_enable_swap =
- cgroup_enable_memory_failcnt = CONFIG_ONDEMAND_NO;
+ cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_NO;
error("disabled CGROUP memory statistics.");
}
}
@@ -1146,7 +1177,7 @@ static inline void find_all_cgroups() {
snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
if(likely(stat(filename, &buf) != -1)) {
cg->memory.filename_detailed = strdupz(filename);
- cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_ONDEMAND_YES)?CONFIG_ONDEMAND_YES:CONFIG_ONDEMAND_ONDEMAND;
+ cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_AUTO;
debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_detailed);
}
else
@@ -1262,18 +1293,19 @@ static inline void find_all_cgroups() {
#define CHART_TITLE_MAX 300
-void update_services_charts(int update_every,
- int do_cpu,
- int do_mem_usage,
- int do_mem_detailed,
- int do_mem_failcnt,
- int do_swap_usage,
- int do_io,
- int do_io_ops,
- int do_throttle_io,
- int do_throttle_ops,
- int do_queued_ops,
- int do_merged_ops
+void update_systemd_services_charts(
+ int update_every
+ , int do_cpu
+ , int do_mem_usage
+ , int do_mem_detailed
+ , int do_mem_failcnt
+ , int do_swap_usage
+ , int do_io
+ , int do_io_ops
+ , int do_throttle_io
+ , int do_throttle_ops
+ , int do_queued_ops
+ , int do_merged_ops
) {
static RRDSET
*st_cpu = NULL,
@@ -1309,12 +1341,21 @@ void update_services_charts(int update_every,
if(likely(do_cpu)) {
if(unlikely(!st_cpu)) {
char title[CHART_TITLE_MAX + 1];
+ snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
+
+ st_cpu = rrdset_create_localhost(
+ "services"
+ , "cpu"
+ , NULL
+ , "cpu"
+ , "services.cpu"
+ , title
+ , "%"
+ , CHART_PRIORITY_SYSTEMD_SERVICES
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
- st_cpu = rrdset_find_bytype("services", "cpu");
- if(likely(!st_cpu)) {
- snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
- st_cpu = rrdset_create("services", "cpu", NULL, "cpu", "services.cpu", title, "%", CHART_PRIORITY_SYSTEMD_SERVICES, update_every, RRDSET_TYPE_STACKED);
- }
}
else
rrdset_next(st_cpu);
@@ -1322,9 +1363,21 @@ void update_services_charts(int update_every,
if(likely(do_mem_usage)) {
if(unlikely(!st_mem_usage)) {
- st_mem_usage = rrdset_find_bytype("services", "mem_usage");
- if(likely(!st_mem_usage))
- st_mem_usage = rrdset_create("services", "mem_usage", NULL, "mem", "services.mem_usage", (cgroup_used_memory_without_cache)?"Systemd Services Used Memory without Cache":"Systemd Services Used Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 10, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_usage = rrdset_create_localhost(
+ "services"
+ , "mem_usage"
+ , NULL
+ , "mem"
+ , "services.mem_usage"
+ , (cgroup_used_memory_without_cache) ? "Systemd Services Used Memory without Cache"
+ : "Systemd Services Used Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 10
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_usage);
@@ -1332,65 +1385,152 @@ void update_services_charts(int update_every,
if(likely(do_mem_detailed)) {
if(unlikely(!st_mem_detailed_rss)) {
- st_mem_detailed_rss = rrdset_find_bytype("services", "mem_rss");
- if(likely(!st_mem_detailed_rss))
- st_mem_detailed_rss = rrdset_create("services", "mem_rss", NULL, "mem", "services.mem_rss", "Systemd Services RSS Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 20, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_rss = rrdset_create_localhost(
+ "services"
+ , "mem_rss"
+ , NULL
+ , "mem"
+ , "services.mem_rss"
+ , "Systemd Services RSS Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 20
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_rss);
if(unlikely(!st_mem_detailed_mapped)) {
- st_mem_detailed_mapped = rrdset_find_bytype("services", "mem_mapped");
- if(likely(!st_mem_detailed_mapped))
- st_mem_detailed_mapped = rrdset_create("services", "mem_mapped", NULL, "mem", "services.mem_mapped", "Systemd Services Mapped Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 30, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_mapped = rrdset_create_localhost(
+ "services"
+ , "mem_mapped"
+ , NULL
+ , "mem"
+ , "services.mem_mapped"
+ , "Systemd Services Mapped Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 30
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_mapped);
if(unlikely(!st_mem_detailed_cache)) {
- st_mem_detailed_cache = rrdset_find_bytype("services", "mem_cache");
- if(likely(!st_mem_detailed_cache))
- st_mem_detailed_cache = rrdset_create("services", "mem_cache", NULL, "mem", "services.mem_cache", "Systemd Services Cache Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 40, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_cache = rrdset_create_localhost(
+ "services"
+ , "mem_cache"
+ , NULL
+ , "mem"
+ , "services.mem_cache"
+ , "Systemd Services Cache Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 40
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_cache);
if(unlikely(!st_mem_detailed_writeback)) {
- st_mem_detailed_writeback = rrdset_find_bytype("services", "mem_writeback");
- if(likely(!st_mem_detailed_writeback))
- st_mem_detailed_writeback = rrdset_create("services", "mem_writeback", NULL, "mem", "services.mem_writeback", "Systemd Services Writeback Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 50, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_writeback = rrdset_create_localhost(
+ "services"
+ , "mem_writeback"
+ , NULL
+ , "mem"
+ , "services.mem_writeback"
+ , "Systemd Services Writeback Memory"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 50
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_writeback);
if(unlikely(!st_mem_detailed_pgfault)) {
- st_mem_detailed_pgfault = rrdset_find_bytype("services", "mem_pgfault");
- if(likely(!st_mem_detailed_pgfault))
- st_mem_detailed_pgfault = rrdset_create("services", "mem_pgfault", NULL, "mem", "services.mem_pgfault", "Systemd Services Memory Minor Page Faults", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 60, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgfault = rrdset_create_localhost(
+ "services"
+ , "mem_pgfault"
+ , NULL
+ , "mem"
+ , "services.mem_pgfault"
+ , "Systemd Services Memory Minor Page Faults"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 60
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
}
else
rrdset_next(st_mem_detailed_pgfault);
if(unlikely(!st_mem_detailed_pgmajfault)) {
- st_mem_detailed_pgmajfault = rrdset_find_bytype("services", "mem_pgmajfault");
- if(likely(!st_mem_detailed_pgmajfault))
- st_mem_detailed_pgmajfault = rrdset_create("services", "mem_pgmajfault", NULL, "mem", "services.mem_pgmajfault", "Systemd Services Memory Major Page Faults", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 70, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgmajfault = rrdset_create_localhost(
+ "services"
+ , "mem_pgmajfault"
+ , NULL
+ , "mem"
+ , "services.mem_pgmajfault"
+ , "Systemd Services Memory Major Page Faults"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 70
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_pgmajfault);
if(unlikely(!st_mem_detailed_pgpgin)) {
- st_mem_detailed_pgpgin = rrdset_find_bytype("services", "mem_pgpgin");
- if(likely(!st_mem_detailed_pgpgin))
- st_mem_detailed_pgpgin = rrdset_create("services", "mem_pgpgin", NULL, "mem", "services.mem_pgpgin", "Systemd Services Memory Charging Activity", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 80, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgpgin = rrdset_create_localhost(
+ "services"
+ , "mem_pgpgin"
+ , NULL
+ , "mem"
+ , "services.mem_pgpgin"
+ , "Systemd Services Memory Charging Activity"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 80
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_pgpgin);
if(unlikely(!st_mem_detailed_pgpgout)) {
- st_mem_detailed_pgpgout = rrdset_find_bytype("services", "mem_pgpgout");
- if(likely(!st_mem_detailed_pgpgout))
- st_mem_detailed_pgpgout = rrdset_create("services", "mem_pgpgout", NULL, "mem", "services.mem_pgpgout", "Systemd Services Memory Uncharging Activity", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 90, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_detailed_pgpgout = rrdset_create_localhost(
+ "services"
+ , "mem_pgpgout"
+ , NULL
+ , "mem"
+ , "services.mem_pgpgout"
+ , "Systemd Services Memory Uncharging Activity"
+ , "MB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 90
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_detailed_pgpgout);
@@ -1398,9 +1538,20 @@ void update_services_charts(int update_every,
if(likely(do_mem_failcnt)) {
if(unlikely(!st_mem_failcnt)) {
- st_mem_failcnt = rrdset_find_bytype("services", "mem_failcnt");
- if(likely(!st_mem_failcnt))
- st_mem_failcnt = rrdset_create("services", "mem_failcnt", NULL, "mem", "services.mem_failcnt", "Systemd Services Memory Limit Failures", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 110, update_every, RRDSET_TYPE_STACKED);
+
+ st_mem_failcnt = rrdset_create_localhost(
+ "services"
+ , "mem_failcnt"
+ , NULL
+ , "mem"
+ , "services.mem_failcnt"
+ , "Systemd Services Memory Limit Failures"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 110
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_mem_failcnt);
@@ -1408,9 +1559,20 @@ void update_services_charts(int update_every,
if(likely(do_swap_usage)) {
if(unlikely(!st_swap_usage)) {
- st_swap_usage = rrdset_find_bytype("services", "swap_usage");
- if(likely(!st_swap_usage))
- st_swap_usage = rrdset_create("services", "swap_usage", NULL, "swap", "services.swap_usage", "Systemd Services Swap Memory Used", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 100, update_every, RRDSET_TYPE_STACKED);
+
+ st_swap_usage = rrdset_create_localhost(
+ "services"
+ , "swap_usage"
+ , NULL
+ , "swap"
+ , "services.swap_usage"
+ , "Systemd Services Swap Memory Used"
+ , "MB"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 100
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_swap_usage);
@@ -1418,17 +1580,39 @@ void update_services_charts(int update_every,
if(likely(do_io)) {
if(unlikely(!st_io_read)) {
- st_io_read = rrdset_find_bytype("services", "io_read");
- if(likely(!st_io_read))
- st_io_read = rrdset_create("services", "io_read", NULL, "disk", "services.io_read", "Systemd Services Disk Read Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 120, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_read = rrdset_create_localhost(
+ "services"
+ , "io_read"
+ , NULL
+ , "disk"
+ , "services.io_read"
+ , "Systemd Services Disk Read Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 120
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_read);
if(unlikely(!st_io_write)) {
- st_io_write = rrdset_find_bytype("services", "io_write");
- if(likely(!st_io_write))
- st_io_write = rrdset_create("services", "io_write", NULL, "disk", "services.io_write", "Systemd Services Disk Write Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 130, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_write = rrdset_create_localhost(
+ "services"
+ , "io_write"
+ , NULL
+ , "disk"
+ , "services.io_write"
+ , "Systemd Services Disk Write Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 130
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_write);
@@ -1436,17 +1620,39 @@ void update_services_charts(int update_every,
if(likely(do_io_ops)) {
if(unlikely(!st_io_serviced_read)) {
- st_io_serviced_read = rrdset_find_bytype("services", "io_ops_read");
- if(likely(!st_io_serviced_read))
- st_io_serviced_read = rrdset_create("services", "io_ops_read", NULL, "disk", "services.io_ops_read", "Systemd Services Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 140, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_serviced_read = rrdset_create_localhost(
+ "services"
+ , "io_ops_read"
+ , NULL
+ , "disk"
+ , "services.io_ops_read"
+ , "Systemd Services Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 140
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_serviced_read);
if(unlikely(!st_io_serviced_write)) {
- st_io_serviced_write = rrdset_find_bytype("services", "io_ops_write");
- if(likely(!st_io_serviced_write))
- st_io_serviced_write = rrdset_create("services", "io_ops_write", NULL, "disk", "services.io_ops_write", "Systemd Services Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 150, update_every, RRDSET_TYPE_STACKED);
+
+ st_io_serviced_write = rrdset_create_localhost(
+ "services"
+ , "io_ops_write"
+ , NULL
+ , "disk"
+ , "services.io_ops_write"
+ , "Systemd Services Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 150
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_io_serviced_write);
@@ -1454,17 +1660,39 @@ void update_services_charts(int update_every,
if(likely(do_throttle_io)) {
if(unlikely(!st_throttle_io_read)) {
- st_throttle_io_read = rrdset_find_bytype("services", "throttle_io_read");
- if(likely(!st_throttle_io_read))
- st_throttle_io_read = rrdset_create("services", "throttle_io_read", NULL, "disk", "services.throttle_io_read", "Systemd Services Throttle Disk Read Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 160, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_io_read = rrdset_create_localhost(
+ "services"
+ , "throttle_io_read"
+ , NULL
+ , "disk"
+ , "services.throttle_io_read"
+ , "Systemd Services Throttle Disk Read Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 160
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_io_read);
if(unlikely(!st_throttle_io_write)) {
- st_throttle_io_write = rrdset_find_bytype("services", "throttle_io_write");
- if(likely(!st_throttle_io_write))
- st_throttle_io_write = rrdset_create("services", "throttle_io_write", NULL, "disk", "services.throttle_io_write", "Systemd Services Throttle Disk Write Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 170, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_io_write = rrdset_create_localhost(
+ "services"
+ , "throttle_io_write"
+ , NULL
+ , "disk"
+ , "services.throttle_io_write"
+ , "Systemd Services Throttle Disk Write Bandwidth"
+ , "KB/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 170
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_io_write);
@@ -1472,17 +1700,39 @@ void update_services_charts(int update_every,
if(likely(do_throttle_ops)) {
if(unlikely(!st_throttle_ops_read)) {
- st_throttle_ops_read = rrdset_find_bytype("services", "throttle_io_ops_read");
- if(likely(!st_throttle_ops_read))
- st_throttle_ops_read = rrdset_create("services", "throttle_io_ops_read", NULL, "disk", "services.throttle_io_ops_read", "Systemd Services Throttle Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 180, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_ops_read = rrdset_create_localhost(
+ "services"
+ , "throttle_io_ops_read"
+ , NULL
+ , "disk"
+ , "services.throttle_io_ops_read"
+ , "Systemd Services Throttle Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 180
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_ops_read);
if(unlikely(!st_throttle_ops_write)) {
- st_throttle_ops_write = rrdset_find_bytype("services", "throttle_io_ops_write");
- if(likely(!st_throttle_ops_write))
- st_throttle_ops_write = rrdset_create("services", "throttle_io_ops_write", NULL, "disk", "services.throttle_io_ops_write", "Systemd Services Throttle Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 190, update_every, RRDSET_TYPE_STACKED);
+
+ st_throttle_ops_write = rrdset_create_localhost(
+ "services"
+ , "throttle_io_ops_write"
+ , NULL
+ , "disk"
+ , "services.throttle_io_ops_write"
+ , "Systemd Services Throttle Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 190
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_throttle_ops_write);
@@ -1490,17 +1740,39 @@ void update_services_charts(int update_every,
if(likely(do_queued_ops)) {
if(unlikely(!st_queued_ops_read)) {
- st_queued_ops_read = rrdset_find_bytype("services", "queued_io_ops_read");
- if(likely(!st_queued_ops_read))
- st_queued_ops_read = rrdset_create("services", "queued_io_ops_read", NULL, "disk", "services.queued_io_ops_read", "Systemd Services Queued Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 200, update_every, RRDSET_TYPE_STACKED);
+
+ st_queued_ops_read = rrdset_create_localhost(
+ "services"
+ , "queued_io_ops_read"
+ , NULL
+ , "disk"
+ , "services.queued_io_ops_read"
+ , "Systemd Services Queued Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 200
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_queued_ops_read);
if(unlikely(!st_queued_ops_write)) {
- st_queued_ops_write = rrdset_find_bytype("services", "queued_io_ops_write");
- if(likely(!st_queued_ops_write))
- st_queued_ops_write = rrdset_create("services", "queued_io_ops_write", NULL, "disk", "services.queued_io_ops_write", "Systemd Services Queued Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 210, update_every, RRDSET_TYPE_STACKED);
+
+ st_queued_ops_write = rrdset_create_localhost(
+ "services"
+ , "queued_io_ops_write"
+ , NULL
+ , "disk"
+ , "services.queued_io_ops_write"
+ , "Systemd Services Queued Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 210
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_queued_ops_write);
@@ -1508,17 +1780,39 @@ void update_services_charts(int update_every,
if(likely(do_merged_ops)) {
if(unlikely(!st_merged_ops_read)) {
- st_merged_ops_read = rrdset_find_bytype("services", "merged_io_ops_read");
- if(likely(!st_merged_ops_read))
- st_merged_ops_read = rrdset_create("services", "merged_io_ops_read", NULL, "disk", "services.merged_io_ops_read", "Systemd Services Merged Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 220, update_every, RRDSET_TYPE_STACKED);
+
+ st_merged_ops_read = rrdset_create_localhost(
+ "services"
+ , "merged_io_ops_read"
+ , NULL
+ , "disk"
+ , "services.merged_io_ops_read"
+ , "Systemd Services Merged Disk Read Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 220
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_merged_ops_read);
if(unlikely(!st_merged_ops_write)) {
- st_merged_ops_write = rrdset_find_bytype("services", "merged_io_ops_write");
- if(likely(!st_merged_ops_write))
- st_merged_ops_write = rrdset_create("services", "merged_io_ops_write", NULL, "disk", "services.merged_io_ops_write", "Systemd Services Merged Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 230, update_every, RRDSET_TYPE_STACKED);
+
+ st_merged_ops_write = rrdset_create_localhost(
+ "services"
+ , "merged_io_ops_write"
+ , NULL
+ , "disk"
+ , "services.merged_io_ops_write"
+ , "Systemd Services Merged Disk Write Operations"
+ , "operations/s"
+ , CHART_PRIORITY_SYSTEMD_SERVICES + 230
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
}
else
rrdset_next(st_merged_ops_write);
@@ -1532,134 +1826,142 @@ void update_services_charts(int update_every,
if(likely(do_cpu && cg->cpuacct_stat.updated)) {
if(unlikely(!cg->rd_cpu))
- cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRDDIM_INCREMENTAL);
+ cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
}
if(likely(do_mem_usage && cg->memory.updated_usage_in_bytes)) {
if(unlikely(!cg->rd_mem_usage))
- cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_set_by_pointer(st_mem_usage, cg->rd_mem_usage, cg->memory.usage_in_bytes - ((cgroup_used_memory_without_cache)?cg->memory.cache:0));
}
if(likely(do_mem_detailed && cg->memory.updated_detailed)) {
if(unlikely(!cg->rd_mem_detailed_rss))
- cg->rd_mem_detailed_rss = rrddim_add(st_mem_detailed_rss, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_rss = rrddim_add(st_mem_detailed_rss, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_rss, cg->rd_mem_detailed_rss, cg->memory.rss + cg->memory.rss_huge);
if(unlikely(!cg->rd_mem_detailed_mapped))
- cg->rd_mem_detailed_mapped = rrddim_add(st_mem_detailed_mapped, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_mapped = rrddim_add(st_mem_detailed_mapped, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_mapped, cg->rd_mem_detailed_mapped, cg->memory.mapped_file);
if(unlikely(!cg->rd_mem_detailed_cache))
- cg->rd_mem_detailed_cache = rrddim_add(st_mem_detailed_cache, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_cache = rrddim_add(st_mem_detailed_cache, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_cache, cg->rd_mem_detailed_cache, cg->memory.cache);
if(unlikely(!cg->rd_mem_detailed_writeback))
- cg->rd_mem_detailed_writeback = rrddim_add(st_mem_detailed_writeback, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_mem_detailed_writeback = rrddim_add(st_mem_detailed_writeback, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
rrddim_set_by_pointer(st_mem_detailed_writeback, cg->rd_mem_detailed_writeback, cg->memory.writeback);
if(unlikely(!cg->rd_mem_detailed_pgfault))
- cg->rd_mem_detailed_pgfault = rrddim_add(st_mem_detailed_pgfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgfault = rrddim_add(st_mem_detailed_pgfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgfault, cg->rd_mem_detailed_pgfault, cg->memory.pgfault);
if(unlikely(!cg->rd_mem_detailed_pgmajfault))
- cg->rd_mem_detailed_pgmajfault = rrddim_add(st_mem_detailed_pgmajfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgmajfault = rrddim_add(st_mem_detailed_pgmajfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgmajfault, cg->rd_mem_detailed_pgmajfault, cg->memory.pgmajfault);
if(unlikely(!cg->rd_mem_detailed_pgpgin))
- cg->rd_mem_detailed_pgpgin = rrddim_add(st_mem_detailed_pgpgin, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgpgin = rrddim_add(st_mem_detailed_pgpgin, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgpgin, cg->rd_mem_detailed_pgpgin, cg->memory.pgpgin);
if(unlikely(!cg->rd_mem_detailed_pgpgout))
- cg->rd_mem_detailed_pgpgout = rrddim_add(st_mem_detailed_pgpgout, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ cg->rd_mem_detailed_pgpgout = rrddim_add(st_mem_detailed_pgpgout, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+
rrddim_set_by_pointer(st_mem_detailed_pgpgout, cg->rd_mem_detailed_pgpgout, cg->memory.pgpgout);
}
if(likely(do_mem_failcnt && cg->memory.updated_failcnt)) {
if(unlikely(!cg->rd_mem_failcnt))
- cg->rd_mem_failcnt = rrddim_add(st_mem_failcnt, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_mem_failcnt = rrddim_add(st_mem_failcnt, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_mem_failcnt, cg->rd_mem_failcnt, cg->memory.failcnt);
}
if(likely(do_swap_usage && cg->memory.updated_msw_usage_in_bytes)) {
if(unlikely(!cg->rd_swap_usage))
- cg->rd_swap_usage = rrddim_add(st_swap_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ cg->rd_swap_usage = rrddim_add(st_swap_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_set_by_pointer(st_swap_usage, cg->rd_swap_usage, cg->memory.msw_usage_in_bytes);
}
if(likely(do_io && cg->io_service_bytes.updated)) {
if(unlikely(!cg->rd_io_service_bytes_read))
- cg->rd_io_service_bytes_read = rrddim_add(st_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_io_service_bytes_read = rrddim_add(st_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_read, cg->rd_io_service_bytes_read, cg->io_service_bytes.Read);
if(unlikely(!cg->rd_io_service_bytes_write))
- cg->rd_io_service_bytes_write = rrddim_add(st_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_io_service_bytes_write = rrddim_add(st_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_write, cg->rd_io_service_bytes_write, cg->io_service_bytes.Write);
}
if(likely(do_io_ops && cg->io_serviced.updated)) {
if(unlikely(!cg->rd_io_serviced_read))
- cg->rd_io_serviced_read = rrddim_add(st_io_serviced_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_serviced_read = rrddim_add(st_io_serviced_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_serviced_read, cg->rd_io_serviced_read, cg->io_serviced.Read);
if(unlikely(!cg->rd_io_serviced_write))
- cg->rd_io_serviced_write = rrddim_add(st_io_serviced_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_serviced_write = rrddim_add(st_io_serviced_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_io_serviced_write, cg->rd_io_serviced_write, cg->io_serviced.Write);
}
if(likely(do_throttle_io && cg->throttle_io_service_bytes.updated)) {
if(unlikely(!cg->rd_throttle_io_read))
- cg->rd_throttle_io_read = rrddim_add(st_throttle_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_read = rrddim_add(st_throttle_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_io_read, cg->rd_throttle_io_read, cg->throttle_io_service_bytes.Read);
if(unlikely(!cg->rd_throttle_io_write))
- cg->rd_throttle_io_write = rrddim_add(st_throttle_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_write = rrddim_add(st_throttle_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_io_write, cg->rd_throttle_io_write, cg->throttle_io_service_bytes.Write);
}
if(likely(do_throttle_ops && cg->throttle_io_serviced.updated)) {
if(unlikely(!cg->rd_throttle_io_serviced_read))
- cg->rd_throttle_io_serviced_read = rrddim_add(st_throttle_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_serviced_read = rrddim_add(st_throttle_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_ops_read, cg->rd_throttle_io_serviced_read, cg->throttle_io_serviced.Read);
if(unlikely(!cg->rd_throttle_io_serviced_write))
- cg->rd_throttle_io_serviced_write = rrddim_add(st_throttle_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_throttle_io_serviced_write = rrddim_add(st_throttle_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_throttle_ops_write, cg->rd_throttle_io_serviced_write, cg->throttle_io_serviced.Write);
}
if(likely(do_queued_ops && cg->io_queued.updated)) {
if(unlikely(!cg->rd_io_queued_read))
- cg->rd_io_queued_read = rrddim_add(st_queued_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_queued_read = rrddim_add(st_queued_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_queued_ops_read, cg->rd_io_queued_read, cg->io_queued.Read);
if(unlikely(!cg->rd_io_queued_write))
- cg->rd_io_queued_write = rrddim_add(st_queued_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_queued_write = rrddim_add(st_queued_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_queued_ops_write, cg->rd_io_queued_write, cg->io_queued.Write);
}
if(likely(do_merged_ops && cg->io_merged.updated)) {
if(unlikely(!cg->rd_io_merged_read))
- cg->rd_io_merged_read = rrddim_add(st_merged_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_merged_read = rrddim_add(st_merged_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_merged_ops_read, cg->rd_io_merged_read, cg->io_merged.Read);
if(unlikely(!cg->rd_io_merged_write))
- cg->rd_io_merged_write = rrddim_add(st_merged_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
+ cg->rd_io_merged_write = rrddim_add(st_merged_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_set_by_pointer(st_merged_ops_write, cg->rd_io_merged_write, cg->io_merged.Write);
}
@@ -1756,33 +2058,43 @@ void update_cgroup_charts(int update_every) {
continue;
if(likely(cgroup_enable_systemd_services && cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) {
- if(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_ONDEMAND_YES) services_do_cpu++;
+ if(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES) services_do_cpu++;
if(cgroup_enable_systemd_services_detailed_memory && cg->memory.updated_detailed && cg->memory.enabled_detailed) services_do_mem_detailed++;
- if(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_ONDEMAND_YES) services_do_mem_usage++;
- if(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_ONDEMAND_YES) services_do_mem_failcnt++;
- if(cg->memory.updated_msw_usage_in_bytes && cg->memory.enabled_msw_usage_in_bytes == CONFIG_ONDEMAND_YES) services_do_swap_usage++;
-
- if(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_ONDEMAND_YES) services_do_io++;
- if(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_ONDEMAND_YES) services_do_io_ops++;
- if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_ONDEMAND_YES) services_do_throttle_io++;
- if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_ONDEMAND_YES) services_do_throttle_ops++;
- if(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_ONDEMAND_YES) services_do_queued_ops++;
- if(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_ONDEMAND_YES) services_do_merged_ops++;
+ if(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES) services_do_mem_usage++;
+ if(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES) services_do_mem_failcnt++;
+ if(cg->memory.updated_msw_usage_in_bytes && cg->memory.enabled_msw_usage_in_bytes == CONFIG_BOOLEAN_YES) services_do_swap_usage++;
+
+ if(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES) services_do_io++;
+ if(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES) services_do_io_ops++;
+ if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES) services_do_throttle_io++;
+ if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES) services_do_throttle_ops++;
+ if(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES) services_do_queued_ops++;
+ if(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES) services_do_merged_ops++;
continue;
}
type[0] = '\0';
- if(likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_cpu)) {
- cg->st_cpu = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu");
- if(likely(!cg->st_cpu)) {
- snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
- cg->st_cpu = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", CHART_PRIORITY_CONTAINERS, update_every, RRDSET_TYPE_STACKED);
- }
- rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
+
+ cg->st_cpu = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "cpu"
+ , NULL
+ , "cpu"
+ , "cgroup.cpu"
+ , title
+ , "%"
+ , CHART_PRIORITY_CONTAINERS
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_cpu);
@@ -1792,84 +2104,128 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_cpu);
}
- if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_BOOLEAN_YES)) {
char id[RRD_ID_LENGTH_MAX + 1];
unsigned int i;
if(unlikely(!cg->st_cpu_per_core)) {
- cg->st_cpu_per_core = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu_per_core");
- if(likely(!cg->st_cpu_per_core)) {
- snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) Per Core for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
- cg->st_cpu_per_core = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", CHART_PRIORITY_CONTAINERS + 100, update_every, RRDSET_TYPE_STACKED);
- }
+ snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) Per Core for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
+
+ cg->st_cpu_per_core = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "cpu_per_core"
+ , NULL
+ , "cpu"
+ , "cgroup.cpu_per_core"
+ , title
+ , "%"
+ , CHART_PRIORITY_CONTAINERS + 100
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
for(i = 0; i < cg->cpuacct_usage.cpus; i++) {
- snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
- rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
+ snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
+ rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRD_ALGORITHM_INCREMENTAL);
}
}
else
rrdset_next(cg->st_cpu_per_core);
for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
- snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
+ snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
rrddim_set(cg->st_cpu_per_core, id, cg->cpuacct_usage.cpu_percpu[i]);
}
rrdset_done(cg->st_cpu_per_core);
}
- if(likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_mem)) {
- cg->st_mem = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem");
- if(likely(!cg->st_mem)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
- cg->st_mem = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", CHART_PRIORITY_CONTAINERS + 210, update_every, RRDSET_TYPE_STACKED);
- }
+ snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
+
+ cg->st_mem = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem"
+ , NULL
+ , "mem"
+ , "cgroup.mem"
+ , title
+ , "MB"
+ , CHART_PRIORITY_CONTAINERS + 210
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
- rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
if(cg->memory.detailed_has_swap)
- rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
+ rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_mem);
rrddim_set(cg->st_mem, "cache", cg->memory.cache);
rrddim_set(cg->st_mem, "rss", cg->memory.rss);
+
if(cg->memory.detailed_has_swap)
rrddim_set(cg->st_mem, "swap", cg->memory.swap);
+
rrddim_set(cg->st_mem, "rss_huge", cg->memory.rss_huge);
rrddim_set(cg->st_mem, "mapped_file", cg->memory.mapped_file);
rrdset_done(cg->st_mem);
if(unlikely(!cg->st_writeback)) {
- cg->st_writeback = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "writeback");
- if(likely(!cg->st_writeback)) {
- snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
- cg->st_writeback = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", CHART_PRIORITY_CONTAINERS + 300, update_every, RRDSET_TYPE_AREA);
- }
+ snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
+
+ cg->st_writeback = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "writeback"
+ , NULL
+ , "mem"
+ , "cgroup.writeback"
+ , title
+ , "MB"
+ , CHART_PRIORITY_CONTAINERS + 300
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
if(cg->memory.detailed_has_dirty)
- rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+
+ rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_writeback);
if(cg->memory.detailed_has_dirty)
rrddim_set(cg->st_writeback, "dirty", cg->memory.dirty);
+
rrddim_set(cg->st_writeback, "writeback", cg->memory.writeback);
rrdset_done(cg->st_writeback);
if(unlikely(!cg->st_mem_activity)) {
- cg->st_mem_activity = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_activity");
- if(likely(!cg->st_mem_activity)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
- cg->st_mem_activity = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s", CHART_PRIORITY_CONTAINERS + 400, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
+
+ cg->st_mem_activity = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem_activity"
+ , NULL
+ , "mem"
+ , "cgroup.mem_activity"
+ , title
+ , "MB/s"
+ , CHART_PRIORITY_CONTAINERS + 400
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_mem_activity);
@@ -1879,13 +2235,23 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_mem_activity);
if(unlikely(!cg->st_pgfaults)) {
- cg->st_pgfaults = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "pgfaults");
- if(likely(!cg->st_pgfaults)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
- cg->st_pgfaults = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", CHART_PRIORITY_CONTAINERS + 500, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
+
+ cg->st_pgfaults = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "pgfaults"
+ , NULL
+ , "mem"
+ , "cgroup.pgfaults"
+ , title
+ , "MB/s"
+ , CHART_PRIORITY_CONTAINERS + 500
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_pgfaults);
@@ -1895,15 +2261,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_pgfaults);
}
- if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_mem_usage)) {
- cg->st_mem_usage = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_usage");
- if(likely(!cg->st_mem_usage)) {
- snprintfz(title, CHART_TITLE_MAX, "Used Memory %sfor cgroup %s", (cgroup_used_memory_without_cache && cg->memory.updated_detailed)?"without Cache ":"", cg->chart_title);
- cg->st_mem_usage = rrdset_create(type, "mem_usage", NULL, "mem", "cgroup.mem_usage", title, "MB", CHART_PRIORITY_CONTAINERS + 200, update_every, RRDSET_TYPE_STACKED);
- }
- rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ snprintfz(title, CHART_TITLE_MAX, "Used Memory %sfor cgroup %s", (cgroup_used_memory_without_cache && cg->memory.updated_detailed)?"without Cache ":"", cg->chart_title);
+
+ cg->st_mem_usage = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem_usage"
+ , NULL
+ , "mem"
+ , "cgroup.mem_usage"
+ , title
+ , "MB"
+ , CHART_PRIORITY_CONTAINERS + 200
+ , update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_mem_usage);
@@ -1913,14 +2289,24 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_mem_usage);
}
- if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_mem_failcnt)) {
- cg->st_mem_failcnt = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_failcnt");
- if(likely(!cg->st_mem_failcnt)) {
- snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures for cgroup %s", cg->chart_title);
- cg->st_mem_failcnt = rrdset_create(type, "mem_failcnt", NULL, "mem", "cgroup.mem_failcnt", title, "count", CHART_PRIORITY_CONTAINERS + 250, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures for cgroup %s", cg->chart_title);
+
+ cg->st_mem_failcnt = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "mem_failcnt"
+ , NULL
+ , "mem"
+ , "cgroup.mem_failcnt"
+ , title
+ , "count"
+ , CHART_PRIORITY_CONTAINERS + 250
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_mem_failcnt);
@@ -1929,15 +2315,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_mem_failcnt);
}
- if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_io)) {
- cg->st_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "io");
- if(likely(!cg->st_io)) {
- snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
- cg->st_io = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_AREA);
- }
- rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_io = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "io"
+ , NULL
+ , "disk"
+ , "cgroup.io"
+ , title
+ , "KB/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_io);
@@ -1947,15 +2343,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_io);
}
- if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_serviced_ops)) {
- cg->st_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "serviced_ops");
- if(likely(!cg->st_serviced_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_serviced_ops = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_serviced_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "serviced_ops"
+ , NULL
+ , "disk"
+ , "cgroup.serviced_ops"
+ , title
+ , "operations/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_serviced_ops);
@@ -1965,15 +2371,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_serviced_ops);
}
- if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_throttle_io)) {
- cg->st_throttle_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_io");
- if(likely(!cg->st_throttle_io)) {
- snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
- cg->st_throttle_io = rrdset_create(type, "throttle_io", NULL, "disk", "cgroup.throttle_io", title, "KB/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_AREA);
- }
- rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_throttle_io = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "throttle_io"
+ , NULL
+ , "disk"
+ , "cgroup.throttle_io"
+ , title
+ , "KB/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_throttle_io);
@@ -1983,15 +2399,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_throttle_io);
}
- if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_throttle_serviced_ops)) {
- cg->st_throttle_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_serviced_ops");
- if(likely(!cg->st_throttle_serviced_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_throttle_serviced_ops = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_throttle_serviced_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "throttle_serviced_ops"
+ , NULL
+ , "disk"
+ , "cgroup.throttle_serviced_ops"
+ , title
+ , "operations/s"
+ , CHART_PRIORITY_CONTAINERS + 1200
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_throttle_serviced_ops);
@@ -2001,15 +2427,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_throttle_serviced_ops);
}
- if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_queued_ops)) {
- cg->st_queued_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "queued_ops");
- if(likely(!cg->st_queued_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_queued_ops = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", CHART_PRIORITY_CONTAINERS + 2000, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
- rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
+ snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_queued_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "queued_ops"
+ , NULL
+ , "disk"
+ , "cgroup.queued_ops"
+ , title
+ , "operations"
+ , CHART_PRIORITY_CONTAINERS + 2000
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
}
else
rrdset_next(cg->st_queued_ops);
@@ -2019,15 +2455,25 @@ void update_cgroup_charts(int update_every) {
rrdset_done(cg->st_queued_ops);
}
- if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_ONDEMAND_YES)) {
+ if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES)) {
if(unlikely(!cg->st_merged_ops)) {
- cg->st_merged_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "merged_ops");
- if(likely(!cg->st_merged_ops)) {
- snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
- cg->st_merged_ops = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 2100, update_every, RRDSET_TYPE_LINE);
- }
- rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
- rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+ snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
+
+ cg->st_merged_ops = rrdset_create_localhost(
+ cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
+ , "merged_ops"
+ , NULL
+ , "disk"
+ , "cgroup.merged_ops"
+ , title
+ , "operations/s"
+ , CHART_PRIORITY_CONTAINERS + 2100
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(cg->st_merged_ops);
@@ -2039,18 +2485,10 @@ void update_cgroup_charts(int update_every) {
}
if(likely(cgroup_enable_systemd_services))
- update_services_charts(update_every,
- services_do_cpu,
- services_do_mem_usage,
- services_do_mem_detailed,
- services_do_mem_failcnt,
- services_do_swap_usage,
- services_do_io,
- services_do_io_ops,
- services_do_throttle_io,
- services_do_throttle_ops,
- services_do_queued_ops,
- services_do_merged_ops
+ update_systemd_services_charts(update_every, services_do_cpu, services_do_mem_usage, services_do_mem_detailed
+ , services_do_mem_failcnt, services_do_swap_usage, services_do_io
+ , services_do_io_ops, services_do_throttle_io, services_do_throttle_ops
+ , services_do_queued_ops, services_do_merged_ops
);
debug(D_CGROUP, "done updating cgroups charts");
@@ -2079,24 +2517,21 @@ void *cgroups_main(void *ptr) {
RRDSET *stcpu_thread = NULL;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
usec_t step = cgroup_update_every * USEC_PER_SEC;
- usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_next = 0;
+ usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_dt = 0;
for(;;) {
- usec_t now = now_monotonic_usec();
- usec_t next = now - (now % step) + step;
-
- while(now < next) {
- sleep_usec(next - now);
- now = now_monotonic_usec();
- }
-
+ usec_t hb_dt = heartbeat_next(&hb, step);
if(unlikely(netdata_exit)) break;
// BEGIN -- the job to be done
- if(unlikely(now >= find_next)) {
+ find_dt += hb_dt;
+ if(unlikely(find_dt >= find_every || cgroups_check)) {
find_all_cgroups();
- find_next = now + find_every;
+ find_dt = 0;
+ cgroups_check = 0;
}
read_all_cgroups(cgroup_root);
@@ -2110,12 +2545,22 @@ void *cgroups_main(void *ptr) {
getrusage(RUSAGE_THREAD, &thread);
if(unlikely(!stcpu_thread)) {
- stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
- if(unlikely(!stcpu_thread))
- stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "cgroups", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, cgroup_update_every, RRDSET_TYPE_STACKED);
- rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
- rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+ stcpu_thread = rrdset_create_localhost(
+ "netdata"
+ , "plugin_cgroups_cpu"
+ , NULL
+ , "cgroups"
+ , NULL
+ , "NetData CGroups Plugin CPU usage"
+ , "milliseconds/s"
+ , 132000
+ , cgroup_update_every
+ , RRDSET_TYPE_STACKED
+ );
+
+ rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
+ rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
}
else
rrdset_next(stcpu_thread);
diff --git a/src/sys_kernel_mm_ksm.c b/src/sys_kernel_mm_ksm.c
index 83da74429..76d808538 100644
--- a/src/sys_kernel_mm_ksm.c
+++ b/src/sys_kernel_mm_ksm.c
@@ -20,40 +20,39 @@ KSM_NAME_VALUE values[] = {
};
int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
+ (void)dt;
static procfile *ff_pages_shared = NULL, *ff_pages_sharing = NULL, *ff_pages_unshared = NULL, *ff_pages_volatile = NULL, *ff_pages_to_scan = NULL;
static long page_size = -1;
- if(dt) {};
-
if(page_size == -1)
page_size = sysconf(_SC_PAGESIZE);
if(!ff_pages_shared) {
- snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
+ snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename));
ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
if(!ff_pages_sharing) {
- snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
+ snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename));
ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
if(!ff_pages_unshared) {
- snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
+ snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename));
ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
if(!ff_pages_volatile) {
- snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
+ snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename));
ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
if(!ff_pages_to_scan) {
- snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
+ snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename));
ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT);
}
@@ -91,15 +90,16 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
// --------------------------------------------------------------------
- st = rrdset_find("mem.ksm");
+ st = rrdset_find_localhost("mem.ksm");
if(!st) {
- st = rrdset_create("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000, update_every, RRDSET_TYPE_AREA);
-
- rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ st = rrdset_create_localhost("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000
+ , update_every, RRDSET_TYPE_AREA);
+
+ rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -110,12 +110,13 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
rrddim_set(st, "to_scan", pages_to_scan * page_size);
rrdset_done(st);
- st = rrdset_find("mem.ksm_savings");
+ st = rrdset_find_localhost("mem.ksm_savings");
if(!st) {
- st = rrdset_create("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB", 5001, update_every, RRDSET_TYPE_AREA);
+ st = rrdset_create_localhost("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB"
+ , 5001, update_every, RRDSET_TYPE_AREA);
- rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
+ rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
@@ -123,11 +124,12 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
rrddim_set(st, "offered", offered * page_size);
rrdset_done(st);
- st = rrdset_find("mem.ksm_ratios");
+ st = rrdset_find_localhost("mem.ksm_ratios");
if(!st) {
- st = rrdset_create("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness", "percentage", 5002, update_every, RRDSET_TYPE_LINE);
+ st = rrdset_create_localhost("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness"
+ , "percentage", 5002, update_every, RRDSET_TYPE_LINE);
- rrddim_add(st, "savings", NULL, 1, 10000, RRDDIM_ABSOLUTE);
+ rrddim_add(st, "savings", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
}
else rrdset_next(st);
diff --git a/src/unit_test.c b/src/unit_test.c
index 4e2f10c0a..0866d215c 100644
--- a/src/unit_test.c
+++ b/src/unit_test.c
@@ -282,7 +282,7 @@ struct test test1 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
10, // feed entries
9, // result entries
test1_feed, // feed
@@ -318,7 +318,7 @@ struct test test2 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
10, // feed entries
9, // result entries
test2_feed, // feed
@@ -353,7 +353,7 @@ struct test test3 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test3_feed, // feed
@@ -388,7 +388,7 @@ struct test test4 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test4_feed, // feed
@@ -423,7 +423,7 @@ struct test test5 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test5_feed, // feed
@@ -464,7 +464,7 @@ struct test test6 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
16, // feed entries
4, // result entries
test6_feed, // feed
@@ -499,7 +499,7 @@ struct test test7 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
18, // result entries
test7_feed, // feed
@@ -530,7 +530,7 @@ struct test test8 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
6, // feed entries
10, // result entries
test8_feed, // feed
@@ -571,7 +571,7 @@ struct test test9 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_ABSOLUTE, // algorithm
+ RRD_ALGORITHM_ABSOLUTE, // algorithm
16, // feed entries
4, // result entries
test9_feed, // feed
@@ -606,7 +606,7 @@ struct test test10 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
7, // result entries
test10_feed, // feed
@@ -649,7 +649,7 @@ struct test test11 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm
10, // feed entries
9, // result entries
test11_feed, // feed
@@ -692,7 +692,7 @@ struct test test12 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm
10, // feed entries
9, // result entries
test12_feed, // feed
@@ -727,7 +727,7 @@ struct test test13 = {
1, // update_every
1, // multiplier
1, // divisor
- RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
+ RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL, // algorithm
10, // feed entries
7, // result entries
test13_feed, // feed
@@ -762,7 +762,7 @@ struct test test14 = {
30, // update_every
8, // multiplier
1000000000, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
8, // result entries
test14_feed, // feed
@@ -794,7 +794,7 @@ struct test test14b = {
30, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
8, // result entries
test14b_feed, // feed
@@ -826,7 +826,7 @@ struct test test14c = {
30, // update_every
1, // multiplier
1, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test14c_feed, // feed
@@ -869,7 +869,7 @@ struct test test15 = {
1, // update_every
8, // multiplier
1024, // divisor
- RRDDIM_INCREMENTAL, // algorithm
+ RRD_ALGORITHM_INCREMENTAL, // algorithm
10, // feed entries
9, // result entries
test15_feed, // feed
@@ -884,21 +884,22 @@ int run_test(struct test *test)
{
fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
- rrd_memory_mode = RRD_MEMORY_MODE_RAM;
- rrd_update_every = test->update_every;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ default_rrd_update_every = test->update_every;
char name[101];
snprintfz(name, 100, "unittest-%s", test->name);
// create the chart
- RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, test->update_every, RRDSET_TYPE_LINE);
+ RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1
+ , test->update_every, RRDSET_TYPE_LINE);
RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
RRDDIM *rd2 = NULL;
if(test->feed2)
rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
- st->debug = 1;
+ rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
// feed it with the test data
time_t time_now = 0, time_start = now_realtime_sec();
@@ -977,15 +978,16 @@ int run_test(struct test *test)
static int test_variable_renames(void) {
fprintf(stderr, "Creating chart\n");
- RRDSET *st = rrdset_create("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
+ RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1
+ , RRDSET_TYPE_LINE);
fprintf(stderr, "Created chart with id '%s', name '%s'\n", st->id, st->name);
fprintf(stderr, "Creating dimension DIM1\n");
- RRDDIM *rd1 = rrddim_add(st, "DIM1", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ RRDDIM *rd1 = rrddim_add(st, "DIM1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd1->id, rd1->name);
fprintf(stderr, "Creating dimension DIM2\n");
- RRDDIM *rd2 = rrddim_add(st, "DIM2", NULL, 1, 1, RRDDIM_INCREMENTAL);
+ RRDDIM *rd2 = rrddim_add(st, "DIM2", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd2->id, rd2->name);
fprintf(stderr, "Renaming chart to CHARTNAME1\n");
@@ -1089,26 +1091,27 @@ int unit_test(long delay, long shift)
snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
//debug_flags = 0xffffffff;
- rrd_memory_mode = RRD_MEMORY_MODE_RAM;
- rrd_update_every = 1;
+ default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ default_rrd_update_every = 1;
int do_abs = 1;
int do_inc = 1;
int do_abst = 0;
int do_absi = 0;
- RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
- st->debug = 1;
+ RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1
+ , RRDSET_TYPE_LINE);
+ rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
RRDDIM *rdabs = NULL;
RRDDIM *rdinc = NULL;
RRDDIM *rdabst = NULL;
RRDDIM *rdabsi = NULL;
- if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
- if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
- if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
- if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+ if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL);
+ if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
long increment = 1000;
collected_number i = 0;
diff --git a/src/web_api_old.c b/src/web_api_old.c
new file mode 100644
index 000000000..373e7e9f8
--- /dev/null
+++ b/src/web_api_old.c
@@ -0,0 +1,237 @@
+#include "common.h"
+
+int web_client_api_old_data_request(RRDHOST *host, struct web_client *w, char *url, int datasource_type) {
+ if(!url || !*url) {
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Incomplete request.");
+ return 400;
+ }
+
+ RRDSET *st = NULL;
+
+ char *args = strchr(url, '?');
+ if(args) {
+ *args='\0';
+ args = &args[1];
+ }
+
+ // get the name of the data to show
+ char *tok = mystrsep(&url, "/");
+ if(!tok) tok = "";
+
+ // do we have such a data set?
+ if(*tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+ st = rrdset_find_byname(host, tok);
+ if(!st) st = rrdset_find(host, tok);
+ }
+
+ if(!st) {
+ // we don't have it
+ // try to send a file with that name
+ buffer_flush(w->response.data);
+ return(mysendfile(w, tok));
+ }
+
+ // we have it
+ debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
+
+ // how many entries does the client want?
+ int lines = (int)st->entries;
+ int group_count = 1;
+ time_t after = 0, before = 0;
+ int group_method = GROUP_AVERAGE;
+ int nonzero = 0;
+
+ if(url) {
+ // parse the lines required
+ tok = mystrsep(&url, "/");
+ if(tok) lines = str2i(tok);
+ if(lines < 1) lines = 1;
+ }
+ if(url) {
+ // parse the group count required
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) group_count = str2i(tok);
+ if(group_count < 1) group_count = 1;
+ //if(group_count > save_history / 20) group_count = save_history / 20;
+ }
+ if(url) {
+ // parse the grouping method required
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) {
+ if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
+ else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
+ else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
+ else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
+ }
+ }
+ if(url) {
+ // parse after time
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) after = str2ul(tok);
+ if(after < 0) after = 0;
+ }
+ if(url) {
+ // parse before time
+ tok = mystrsep(&url, "/");
+ if(tok && *tok) before = str2ul(tok);
+ if(before < 0) before = 0;
+ }
+ if(url) {
+ // parse nonzero
+ tok = mystrsep(&url, "/");
+ if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
+ }
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+
+ char *google_version = "0.6";
+ char *google_reqId = "0";
+ char *google_sig = "0";
+ char *google_out = "json";
+ char *google_responseHandler = "google.visualization.Query.setResponse";
+ char *google_outFileName = NULL;
+ time_t last_timestamp_in_data = 0;
+ if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
+
+ w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
+
+ while(args) {
+ tok = mystrsep(&args, "&");
+ if(tok && *tok) {
+ char *name = mystrsep(&tok, "=");
+ if(name && *name && strcmp(name, "tqx") == 0) {
+ char *key = mystrsep(&tok, ":");
+ char *value = mystrsep(&tok, ";");
+ if(key && value && *key && *value) {
+ if(strcmp(key, "version") == 0)
+ google_version = value;
+
+ else if(strcmp(key, "reqId") == 0)
+ google_reqId = value;
+
+ else if(strcmp(key, "sig") == 0)
+ google_sig = value;
+
+ else if(strcmp(key, "out") == 0)
+ google_out = value;
+
+ else if(strcmp(key, "responseHandler") == 0)
+ google_responseHandler = value;
+
+ else if(strcmp(key, "outFileName") == 0)
+ google_outFileName = value;
+ }
+ }
+ }
+ }
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
+ w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
+ );
+
+ if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+ last_timestamp_in_data = strtoul(google_sig, NULL, 0);
+
+ // check the client wants json
+ if(strcmp(google_out, "json") != 0) {
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
+ google_responseHandler, google_version, google_reqId, google_out);
+ return 200;
+ }
+ }
+ }
+
+ if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
+ google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
+ }
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
+ w->id, st->name, st->id, lines, group_count, group_method, after, before);
+
+ time_t timestamp_in_data = rrdset2json_api_old(datasource_type, st, w->response.data, lines, group_count
+ , group_method, (unsigned long) after, (unsigned long) before
+ , nonzero);
+
+ if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+ if(timestamp_in_data > last_timestamp_in_data)
+ buffer_strcat(w->response.data, "});");
+
+ else {
+ // the client already has the latest data
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
+ google_responseHandler, google_version, google_reqId);
+ }
+ }
+
+ return 200;
+}
+
+inline int web_client_api_old_data_request_json(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_old_data_request(host, w, url, DATASOURCE_JSON);
+}
+
+inline int web_client_api_old_data_request_jsonp(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_old_data_request(host, w, url, DATASOURCE_DATATABLE_JSONP);
+}
+
+inline int web_client_api_old_graph_request(RRDHOST *host, struct web_client *w, char *url) {
+ // get the name of the data to show
+ char *tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+
+ // do we have such a data set?
+ RRDSET *st = rrdset_find_byname(host, tok);
+ if(!st) st = rrdset_find(host, tok);
+ if(!st) {
+ // we don't have it
+ // try to send a file with that name
+ buffer_flush(w->response.data);
+ return mysendfile(w, tok);
+ }
+ st->last_accessed_time = now_realtime_sec();
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+ rrd_graph2json_api_old(st, url, w->response.data);
+ return 200;
+ }
+
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Graph name?\r\n");
+ return 400;
+}
+
+inline int web_client_api_old_list_request(RRDHOST *host, struct web_client *w, char *url) {
+ (void)url;
+
+ buffer_flush(w->response.data);
+ RRDSET *st;
+
+ rrdhost_rdlock(host);
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st))
+ buffer_sprintf(w->response.data, "%s\n", st->name);
+ }
+ rrdhost_unlock(host);
+
+ return 200;
+}
+
+inline int web_client_api_old_all_json(RRDHOST *host, struct web_client *w, char *url) {
+ (void)url;
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+ rrd_all2json_api_old(host, w->response.data);
+ return 200;
+}
diff --git a/src/web_api_old.h b/src/web_api_old.h
new file mode 100644
index 000000000..dff48c2f3
--- /dev/null
+++ b/src/web_api_old.h
@@ -0,0 +1,13 @@
+#ifndef NETDATA_WEB_API_OLD_H
+#define NETDATA_WEB_API_OLD_H
+
+#include "common.h"
+
+extern int web_client_api_old_data_request(RRDHOST *host, struct web_client *w, char *url, int datasource_type);
+extern int web_client_api_old_data_request_json(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_data_request_jsonp(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_graph_request(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_list_request(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_old_all_json(RRDHOST *host, struct web_client *w, char *url);
+
+#endif //NETDATA_WEB_API_OLD_H
diff --git a/src/web_api_v1.c b/src/web_api_v1.c
new file mode 100644
index 000000000..0acc43acb
--- /dev/null
+++ b/src/web_api_v1.c
@@ -0,0 +1,903 @@
+#include "common.h"
+
+inline int web_client_api_request_v1_data_group(char *name, int def) {
+ if(!strcmp(name, "average"))
+ return GROUP_AVERAGE;
+
+ else if(!strcmp(name, "min"))
+ return GROUP_MIN;
+
+ else if(!strcmp(name, "max"))
+ return GROUP_MAX;
+
+ else if(!strcmp(name, "sum"))
+ return GROUP_SUM;
+
+ else if(!strcmp(name, "incremental-sum"))
+ return GROUP_INCREMENTAL_SUM;
+
+ return def;
+}
+
+inline uint32_t web_client_api_request_v1_data_options(char *o) {
+ uint32_t ret = 0x00000000;
+ char *tok;
+
+ while(o && *o && (tok = mystrsep(&o, ", |"))) {
+ if(!*tok) continue;
+
+ if(!strcmp(tok, "nonzero"))
+ ret |= RRDR_OPTION_NONZERO;
+ else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
+ ret |= RRDR_OPTION_REVERSED;
+ else if(!strcmp(tok, "jsonwrap"))
+ ret |= RRDR_OPTION_JSON_WRAP;
+ else if(!strcmp(tok, "min2max"))
+ ret |= RRDR_OPTION_MIN2MAX;
+ else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
+ ret |= RRDR_OPTION_MILLISECONDS;
+ else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
+ ret |= RRDR_OPTION_ABSOLUTE;
+ else if(!strcmp(tok, "seconds"))
+ ret |= RRDR_OPTION_SECONDS;
+ else if(!strcmp(tok, "null2zero"))
+ ret |= RRDR_OPTION_NULL2ZERO;
+ else if(!strcmp(tok, "objectrows"))
+ ret |= RRDR_OPTION_OBJECTSROWS;
+ else if(!strcmp(tok, "google_json"))
+ ret |= RRDR_OPTION_GOOGLE_JSON;
+ else if(!strcmp(tok, "percentage"))
+ ret |= RRDR_OPTION_PERCENTAGE;
+ else if(!strcmp(tok, "unaligned"))
+ ret |= RRDR_OPTION_NOT_ALIGNED;
+ }
+
+ return ret;
+}
+
+inline uint32_t web_client_api_request_v1_data_format(char *name) {
+ if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
+ return DATASOURCE_DATATABLE_JSON;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
+ return DATASOURCE_DATATABLE_JSONP;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
+ return DATASOURCE_JSON;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
+ return DATASOURCE_JSONP;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
+ return DATASOURCE_SSV;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
+ return DATASOURCE_CSV;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
+ return DATASOURCE_TSV;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
+ return DATASOURCE_HTML;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
+ return DATASOURCE_JS_ARRAY;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
+ return DATASOURCE_SSV_COMMA;
+
+ else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
+ return DATASOURCE_CSV_JSON_ARRAY;
+
+ return DATASOURCE_JSON;
+}
+
+inline uint32_t web_client_api_request_v1_data_google_format(char *name) {
+ if(!strcmp(name, "json"))
+ return DATASOURCE_DATATABLE_JSONP;
+
+ else if(!strcmp(name, "html"))
+ return DATASOURCE_HTML;
+
+ else if(!strcmp(name, "csv"))
+ return DATASOURCE_CSV;
+
+ else if(!strcmp(name, "tsv-excel"))
+ return DATASOURCE_TSV;
+
+ return DATASOURCE_JSON;
+}
+
+
+inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url) {
+ int all = 0;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ if(!strcmp(value, "all")) all = 1;
+ else if(!strcmp(value, "active")) all = 0;
+ }
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ health_alarms2json(host, w->response.data, all);
+ return 200;
+}
+
+inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) {
+ uint32_t after = 0;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ if(!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0);
+ }
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ health_alarm_log2json(host, w->response.data, after);
+ return 200;
+}
+
+inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf)) {
+ int ret = 400;
+ char *chart = NULL;
+
+ buffer_flush(w->response.data);
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ //else {
+ /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
+ // goto cleanup;
+ //}
+ }
+
+ if(!chart || !*chart) {
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, chart);
+ ret = 404;
+ goto cleanup;
+ }
+
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ st->last_accessed_time = now_realtime_sec();
+ callback(st, w->response.data);
+ return 200;
+
+ cleanup:
+ return ret;
+}
+
+inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
+}
+
+inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url) {
+ (void)url;
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ rrd_stats_api_v1_charts(host, w->response.data);
+ return 200;
+}
+
+inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url) {
+ int format = ALLMETRICS_SHELL;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ if(!strcmp(name, "format")) {
+ if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
+ format = ALLMETRICS_SHELL;
+ else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
+ format = ALLMETRICS_PROMETHEUS;
+ else if(!strcmp(value, ALLMETRICS_FORMAT_JSON))
+ format = ALLMETRICS_JSON;
+ else
+ format = 0;
+ }
+ }
+
+ buffer_flush(w->response.data);
+ buffer_no_cacheable(w->response.data);
+
+ switch(format) {
+ case ALLMETRICS_JSON:
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ rrd_stats_api_v1_charts_allmetrics_json(host, w->response.data);
+ return 200;
+
+ case ALLMETRICS_SHELL:
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ rrd_stats_api_v1_charts_allmetrics_shell(host, w->response.data);
+ return 200;
+
+ case ALLMETRICS_PROMETHEUS:
+ w->response.data->contenttype = CT_PROMETHEUS;
+ rrd_stats_api_v1_charts_allmetrics_prometheus(host, w->response.data);
+ return 200;
+
+ default:
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_strcat(w->response.data, "Which format? '" ALLMETRICS_FORMAT_SHELL "', '" ALLMETRICS_FORMAT_PROMETHEUS "' and '" ALLMETRICS_FORMAT_JSON "' are currently supported.");
+ return 400;
+ }
+}
+
+inline int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, char *url) {
+ return web_client_api_request_single_chart(host, w, url, rrd_stats_api_v1_chart);
+}
+
+int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) {
+ int ret = 400;
+ buffer_flush(w->response.data);
+
+ BUFFER *dimensions = NULL;
+
+ const char *chart = NULL
+ , *before_str = NULL
+ , *after_str = NULL
+ , *points_str = NULL
+ , *multiply_str = NULL
+ , *divide_str = NULL
+ , *label = NULL
+ , *units = NULL
+ , *label_color = NULL
+ , *value_color = NULL
+ , *refresh_str = NULL
+ , *precision_str = NULL
+ , *alarm = NULL;
+
+ int group = GROUP_AVERAGE;
+ uint32_t options = 0x00000000;
+
+ while(url) {
+ char *value = mystrsep(&url, "/?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+ if(!dimensions)
+ dimensions = buffer_create(100);
+
+ buffer_strcat(dimensions, "|");
+ buffer_strcat(dimensions, value);
+ }
+ else if(!strcmp(name, "after")) after_str = value;
+ else if(!strcmp(name, "before")) before_str = value;
+ else if(!strcmp(name, "points")) points_str = value;
+ else if(!strcmp(name, "group")) {
+ group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
+ }
+ else if(!strcmp(name, "options")) {
+ options |= web_client_api_request_v1_data_options(value);
+ }
+ else if(!strcmp(name, "label")) label = value;
+ else if(!strcmp(name, "units")) units = value;
+ else if(!strcmp(name, "label_color")) label_color = value;
+ else if(!strcmp(name, "value_color")) value_color = value;
+ else if(!strcmp(name, "multiply")) multiply_str = value;
+ else if(!strcmp(name, "divide")) divide_str = value;
+ else if(!strcmp(name, "refresh")) refresh_str = value;
+ else if(!strcmp(name, "precision")) precision_str = value;
+ else if(!strcmp(name, "alarm")) alarm = value;
+ }
+
+ if(!chart || !*chart) {
+ buffer_no_cacheable(w->response.data);
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_no_cacheable(w->response.data);
+ buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
+ ret = 200;
+ goto cleanup;
+ }
+ st->last_accessed_time = now_realtime_sec();
+
+ RRDCALC *rc = NULL;
+ if(alarm) {
+ rc = rrdcalc_find(st, alarm);
+ if (!rc) {
+ buffer_no_cacheable(w->response.data);
+ buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
+ ret = 200;
+ goto cleanup;
+ }
+ }
+
+ long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1;
+ long long divide = (divide_str && *divide_str )?str2l(divide_str):1;
+ long long before = (before_str && *before_str )?str2l(before_str):0;
+ long long after = (after_str && *after_str )?str2l(after_str):-st->update_every;
+ int points = (points_str && *points_str )?str2i(points_str):1;
+ int precision = (precision_str && *precision_str)?str2i(precision_str):-1;
+
+ if(!multiply) multiply = 1;
+ if(!divide) divide = 1;
+
+ int refresh = 0;
+ if(refresh_str && *refresh_str) {
+ if(!strcmp(refresh_str, "auto")) {
+ if(rc) refresh = rc->update_every;
+ else if(options & RRDR_OPTION_NOT_ALIGNED)
+ refresh = st->update_every;
+ else {
+ refresh = (int)(before - after);
+ if(refresh < 0) refresh = -refresh;
+ }
+ }
+ else {
+ refresh = str2i(refresh_str);
+ if(refresh < 0) refresh = -refresh;
+ }
+ }
+
+ if(!label) {
+ if(alarm) {
+ char *s = (char *)alarm;
+ while(*s) {
+ if(*s == '_') *s = ' ';
+ s++;
+ }
+ label = alarm;
+ }
+ else if(dimensions) {
+ const char *dim = buffer_tostring(dimensions);
+ if(*dim == '|') dim++;
+ label = dim;
+ }
+ else
+ label = st->name;
+ }
+ if(!units) {
+ if(alarm) {
+ if(rc->units)
+ units = rc->units;
+ else
+ units = "";
+ }
+ else if(options & RRDR_OPTION_PERCENTAGE)
+ units = "%";
+ else
+ units = st->units;
+ }
+
+ debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
+ , w->id
+ , chart
+ , alarm?alarm:""
+ , (dimensions)?buffer_tostring(dimensions):""
+ , after
+ , before
+ , points
+ , group
+ , options
+ );
+
+ if(rc) {
+ if (refresh > 0) {
+ buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+ w->response.data->expires = now_realtime_sec() + refresh;
+ }
+ else buffer_no_cacheable(w->response.data);
+
+ if(!value_color) {
+ switch(rc->status) {
+ case RRDCALC_STATUS_CRITICAL:
+ value_color = "red";
+ break;
+
+ case RRDCALC_STATUS_WARNING:
+ value_color = "orange";
+ break;
+
+ case RRDCALC_STATUS_CLEAR:
+ value_color = "brightgreen";
+ break;
+
+ case RRDCALC_STATUS_UNDEFINED:
+ value_color = "lightgrey";
+ break;
+
+ case RRDCALC_STATUS_UNINITIALIZED:
+ value_color = "#000";
+ break;
+
+ default:
+ value_color = "grey";
+ break;
+ }
+ }
+
+ buffer_svg(w->response.data,
+ label,
+ (isnan(rc->value)||isinf(rc->value)) ? rc->value : rc->value * multiply / divide,
+ units,
+ label_color,
+ value_color,
+ precision);
+ ret = 200;
+ }
+ else {
+ time_t latest_timestamp = 0;
+ int value_is_null = 1;
+ calculated_number n = NAN;
+ ret = 500;
+
+ // if the collected value is too old, don't calculate its value
+ if (rrdset_last_entry_t(st) >= (now_realtime_sec() - (st->update_every * st->gap_when_lost_iterations_above)))
+ ret = rrdset2value_api_v1(st, w->response.data, &n, (dimensions) ? buffer_tostring(dimensions) : NULL
+ , points, after, before, group, options, NULL, &latest_timestamp, &value_is_null);
+
+ // if the value cannot be calculated, show empty badge
+ if (ret != 200) {
+ buffer_no_cacheable(w->response.data);
+ value_is_null = 1;
+ n = 0;
+ ret = 200;
+ }
+ else if (refresh > 0) {
+ buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+ w->response.data->expires = now_realtime_sec() + refresh;
+ }
+ else buffer_no_cacheable(w->response.data);
+
+ // render the badge
+ buffer_svg(w->response.data,
+ label,
+ (value_is_null)?NAN:(n * multiply / divide),
+ units,
+ label_color,
+ value_color,
+ precision);
+ }
+
+ cleanup:
+ buffer_free(dimensions);
+ return ret;
+}
+
+// returns the HTTP code
+inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
+ debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
+
+ int ret = 400;
+ BUFFER *dimensions = NULL;
+
+ buffer_flush(w->response.data);
+
+ char *google_version = "0.6",
+ *google_reqId = "0",
+ *google_sig = "0",
+ *google_out = "json",
+ *responseHandler = NULL,
+ *outFileName = NULL;
+
+ time_t last_timestamp_in_data = 0, google_timestamp = 0;
+
+ char *chart = NULL
+ , *before_str = NULL
+ , *after_str = NULL
+ , *points_str = NULL;
+
+ int group = GROUP_AVERAGE;
+ uint32_t format = DATASOURCE_JSON;
+ uint32_t options = 0x00000000;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if(!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+ if(!dimensions) dimensions = buffer_create(100);
+ buffer_strcat(dimensions, "|");
+ buffer_strcat(dimensions, value);
+ }
+ else if(!strcmp(name, "after")) after_str = value;
+ else if(!strcmp(name, "before")) before_str = value;
+ else if(!strcmp(name, "points")) points_str = value;
+ else if(!strcmp(name, "group")) {
+ group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
+ }
+ else if(!strcmp(name, "format")) {
+ format = web_client_api_request_v1_data_format(value);
+ }
+ else if(!strcmp(name, "options")) {
+ options |= web_client_api_request_v1_data_options(value);
+ }
+ else if(!strcmp(name, "callback")) {
+ responseHandler = value;
+ }
+ else if(!strcmp(name, "filename")) {
+ outFileName = value;
+ }
+ else if(!strcmp(name, "tqx")) {
+ // parse Google Visualization API options
+ // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
+ char *tqx_name, *tqx_value;
+
+ while(value) {
+ tqx_value = mystrsep(&value, ";");
+ if(!tqx_value || !*tqx_value) continue;
+
+ tqx_name = mystrsep(&tqx_value, ":");
+ if(!tqx_name || !*tqx_name) continue;
+ if(!tqx_value || !*tqx_value) continue;
+
+ if(!strcmp(tqx_name, "version"))
+ google_version = tqx_value;
+ else if(!strcmp(tqx_name, "reqId"))
+ google_reqId = tqx_value;
+ else if(!strcmp(tqx_name, "sig")) {
+ google_sig = tqx_value;
+ google_timestamp = strtoul(google_sig, NULL, 0);
+ }
+ else if(!strcmp(tqx_name, "out")) {
+ google_out = tqx_value;
+ format = web_client_api_request_v1_data_google_format(google_out);
+ }
+ else if(!strcmp(tqx_name, "responseHandler"))
+ responseHandler = tqx_value;
+ else if(!strcmp(tqx_name, "outFileName"))
+ outFileName = tqx_value;
+ }
+ }
+ }
+
+ if(!chart || !*chart) {
+ buffer_sprintf(w->response.data, "No chart id is given at the request.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, chart);
+ ret = 404;
+ goto cleanup;
+ }
+ st->last_accessed_time = now_realtime_sec();
+
+ long long before = (before_str && *before_str)?str2l(before_str):0;
+ long long after = (after_str && *after_str) ?str2l(after_str):0;
+ int points = (points_str && *points_str)?str2i(points_str):0;
+
+ debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
+ , w->id
+ , chart
+ , (dimensions)?buffer_tostring(dimensions):""
+ , after
+ , before
+ , points
+ , group
+ , format
+ , options
+ );
+
+ if(outFileName && *outFileName) {
+ buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
+ debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
+ }
+
+ if(format == DATASOURCE_DATATABLE_JSONP) {
+ if(responseHandler == NULL)
+ responseHandler = "google.visualization.Query.setResponse";
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
+ w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
+ );
+
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
+ responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
+ }
+ else if(format == DATASOURCE_JSONP) {
+ if(responseHandler == NULL)
+ responseHandler = "callback";
+
+ buffer_strcat(w->response.data, responseHandler);
+ buffer_strcat(w->response.data, "(");
+ }
+
+ ret = rrdset2anything_api_v1(st, w->response.data, dimensions, format, points, after, before, group, options
+ , &last_timestamp_in_data);
+
+ if(format == DATASOURCE_DATATABLE_JSONP) {
+ if(google_timestamp < last_timestamp_in_data)
+ buffer_strcat(w->response.data, "});");
+
+ else {
+ // the client already has the latest data
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data,
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
+ responseHandler, google_version, google_reqId);
+ }
+ }
+ else if(format == DATASOURCE_JSONP)
+ buffer_strcat(w->response.data, ");");
+
+ cleanup:
+ buffer_free(dimensions);
+ return ret;
+}
+
+inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
+ hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
+ hash_to = 0 /*, hash_redirects = 0 */;
+
+ if(unlikely(!hash_action)) {
+ hash_action = simple_hash("action");
+ hash_access = simple_hash("access");
+ hash_hello = simple_hash("hello");
+ hash_delete = simple_hash("delete");
+ hash_search = simple_hash("search");
+ hash_switch = simple_hash("switch");
+ hash_machine = simple_hash("machine");
+ hash_url = simple_hash("url");
+ hash_name = simple_hash("name");
+ hash_delete_url = simple_hash("delete_url");
+ hash_for = simple_hash("for");
+ hash_to = simple_hash("to");
+/*
+ hash_redirects = simple_hash("redirects");
+*/
+ }
+
+ char person_guid[GUID_LEN + 1] = "";
+
+ debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
+
+ // FIXME
+ // The browser may send multiple cookies with our id
+
+ char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
+ if(cookie)
+ strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
+
+ char action = '\0';
+ char *machine_guid = NULL,
+ *machine_url = NULL,
+ *url_name = NULL,
+ *search_machine_guid = NULL,
+ *delete_url = NULL,
+ *to_person_guid = NULL;
+/*
+ int redirects = 0;
+*/
+
+ while(url) {
+ char *value = mystrsep(&url, "?&");
+ if (!value || !*value) continue;
+
+ char *name = mystrsep(&value, "=");
+ if (!name || !*name) continue;
+ if (!value || !*value) continue;
+
+ debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
+
+ uint32_t hash = simple_hash(name);
+
+ if(hash == hash_action && !strcmp(name, "action")) {
+ uint32_t vhash = simple_hash(value);
+
+ if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
+ else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
+ else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
+ else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
+ else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
+#ifdef NETDATA_INTERNAL_CHECKS
+ else error("unknown registry action '%s'", value);
+#endif /* NETDATA_INTERNAL_CHECKS */
+ }
+/*
+ else if(hash == hash_redirects && !strcmp(name, "redirects"))
+ redirects = atoi(value);
+*/
+ else if(hash == hash_machine && !strcmp(name, "machine"))
+ machine_guid = value;
+
+ else if(hash == hash_url && !strcmp(name, "url"))
+ machine_url = value;
+
+ else if(action == 'A') {
+ if(hash == hash_name && !strcmp(name, "name"))
+ url_name = value;
+ }
+ else if(action == 'D') {
+ if(hash == hash_delete_url && !strcmp(name, "delete_url"))
+ delete_url = value;
+ }
+ else if(action == 'S') {
+ if(hash == hash_for && !strcmp(name, "for"))
+ search_machine_guid = value;
+ }
+ else if(action == 'W') {
+ if(hash == hash_to && !strcmp(name, "to"))
+ to_person_guid = value;
+ }
+#ifdef NETDATA_INTERNAL_CHECKS
+ else error("unused registry URL parameter '%s' with value '%s'", name, value);
+#endif /* NETDATA_INTERNAL_CHECKS */
+ }
+
+ if(respect_web_browser_do_not_track_policy && w->donottrack) {
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
+ return 400;
+ }
+
+ if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
+ error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Access request.");
+ return 400;
+ }
+ else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
+ error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Delete request.");
+ return 400;
+ }
+ else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
+ error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Search request.");
+ return 400;
+ }
+ else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
+ error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
+ machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry Switch request.");
+ return 400;
+ }
+
+ switch(action) {
+ case 'A':
+ w->tracking_required = 1;
+ return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
+
+ case 'D':
+ w->tracking_required = 1;
+ return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
+
+ case 'S':
+ w->tracking_required = 1;
+ return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec());
+
+ case 'W':
+ w->tracking_required = 1;
+ return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
+
+ case 'H':
+ return registry_request_hello_json(host, w);
+
+ default:
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
+ return 400;
+ }
+}
+
+inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0, hash_raw = 0;
+
+ if(unlikely(hash_data == 0)) {
+ hash_data = simple_hash("data");
+ hash_chart = simple_hash("chart");
+ hash_charts = simple_hash("charts");
+ hash_registry = simple_hash("registry");
+ hash_badge = simple_hash("badge.svg");
+ hash_alarms = simple_hash("alarms");
+ hash_alarm_log = simple_hash("alarm_log");
+ hash_alarm_variables = simple_hash("alarm_variables");
+ hash_raw = simple_hash("allmetrics");
+ }
+
+ // get the command
+ char *tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
+ uint32_t hash = simple_hash(tok);
+
+ if(hash == hash_data && !strcmp(tok, "data"))
+ return web_client_api_request_v1_data(host, w, url);
+
+ else if(hash == hash_chart && !strcmp(tok, "chart"))
+ return web_client_api_request_v1_chart(host, w, url);
+
+ else if(hash == hash_charts && !strcmp(tok, "charts"))
+ return web_client_api_request_v1_charts(host, w, url);
+
+ else if(hash == hash_registry && !strcmp(tok, "registry"))
+ return web_client_api_request_v1_registry(host, w, url);
+
+ else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
+ return web_client_api_request_v1_badge(host, w, url);
+
+ else if(hash == hash_alarms && !strcmp(tok, "alarms"))
+ return web_client_api_request_v1_alarms(host, w, url);
+
+ else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
+ return web_client_api_request_v1_alarm_log(host, w, url);
+
+ else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
+ return web_client_api_request_v1_alarm_variables(host, w, url);
+
+ else if(hash == hash_raw && !strcmp(tok, "allmetrics"))
+ return web_client_api_request_v1_allmetrics(host, w, url);
+
+ else {
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Unsupported v1 API command: ");
+ buffer_strcat_htmlescape(w->response.data, tok);
+ return 404;
+ }
+ }
+ else {
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Which API v1 command?");
+ return 400;
+ }
+}
diff --git a/src/web_api_v1.h b/src/web_api_v1.h
new file mode 100644
index 000000000..e980edb1d
--- /dev/null
+++ b/src/web_api_v1.h
@@ -0,0 +1,21 @@
+#ifndef NETDATA_WEB_API_V1_H
+#define NETDATA_WEB_API_V1_H
+
+extern int web_client_api_request_v1_data_group(char *name, int def);
+extern uint32_t web_client_api_request_v1_data_options(char *o);
+extern uint32_t web_client_api_request_v1_data_format(char *name);
+extern uint32_t web_client_api_request_v1_data_google_format(char *name);
+
+extern int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf));
+extern int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url);
+extern int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url);
+
+#endif //NETDATA_WEB_API_V1_H
diff --git a/src/web_buffer.c b/src/web_buffer.c
index 6203db0f7..9f9ceda63 100644
--- a/src/web_buffer.c
+++ b/src/web_buffer.c
@@ -359,8 +359,9 @@ BUFFER *buffer_create(size_t size)
return(b);
}
-void buffer_free(BUFFER *b)
-{
+void buffer_free(BUFFER *b) {
+ if(unlikely(!b)) return;
+
buffer_overflow_check(b);
debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
diff --git a/src/web_buffer_svg.c b/src/web_buffer_svg.c
index cac365ab1..2591799d4 100644
--- a/src/web_buffer_svg.c
+++ b/src/web_buffer_svg.c
@@ -368,10 +368,226 @@ cleanup:
return len - i;
}
-static inline const char *fix_units(const char *units) {
- if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return "";
- if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%";
- return units;
+static inline char *format_value_with_precision_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
+ if(unlikely(isnan(value) || isinf(value)))
+ value = 0.0;
+
+ char *separator = "";
+ if(unlikely(isalnum(*units)))
+ separator = " ";
+
+ if(precision < 0) {
+ int len, lstop = 0, trim_zeros = 1;
+
+ calculated_number abs = value;
+ if(isless(value, 0)) {
+ lstop = 1;
+ abs = -value;
+ }
+
+ if(isgreaterequal(abs, 1000)) {
+ len = snprintfz(value_string, value_string_len, "%0.0Lf", (long double) value);
+ trim_zeros = 0;
+ }
+ else if(isgreaterequal(abs, 10)) len = snprintfz(value_string, value_string_len, "%0.1Lf", (long double) value);
+ else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
+ else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
+ else len = snprintfz(value_string, value_string_len, "%0.4Lf", (long double) value);
+
+ if(unlikely(trim_zeros)) {
+ int l;
+ // remove trailing zeros from the decimal part
+ for(l = len - 1; l > lstop; l--) {
+ if(likely(value_string[l] == '0')) {
+ value_string[l] = '\0';
+ len--;
+ }
+
+ else if(unlikely(value_string[l] == '.')) {
+ value_string[l] = '\0';
+ len--;
+ break;
+ }
+
+ else
+ break;
+ }
+ }
+
+ if(unlikely(len <= 0)) len = 1;
+ snprintfz(&value_string[len], value_string_len - len, "%s%s", separator, units);
+ }
+ else {
+ if(precision > 50) precision = 50;
+ snprintfz(value_string, value_string_len, "%0.*Lf%s%s", precision, (long double) value, separator, units);
+ }
+
+ return value_string;
+}
+
+inline char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
+ static uint32_t
+ hash_seconds = 0,
+ hash_seconds_ago = 0,
+ hash_minutes = 0,
+ hash_minutes_ago = 0,
+ hash_hours = 0,
+ hash_hours_ago = 0,
+ hash_onoff = 0,
+ hash_updown = 0,
+ hash_okerror = 0,
+ hash_okfailed = 0,
+ hash_empty = 0,
+ hash_null = 0,
+ hash_percentage = 0,
+ hash_percent = 0,
+ hash_pcent = 0;
+
+ if(unlikely(!hash_seconds)) {
+ hash_seconds = simple_hash("seconds");
+ hash_seconds_ago = simple_hash("seconds ago");
+ hash_minutes = simple_hash("minutes");
+ hash_minutes_ago = simple_hash("minutes ago");
+ hash_hours = simple_hash("hours");
+ hash_hours_ago = simple_hash("hours ago");
+ hash_onoff = simple_hash("on/off");
+ hash_updown = simple_hash("up/down");
+ hash_okerror = simple_hash("ok/error");
+ hash_okfailed = simple_hash("ok/failed");
+ hash_empty = simple_hash("empty");
+ hash_null = simple_hash("null");
+ hash_percentage = simple_hash("percentage");
+ hash_percent = simple_hash("percent");
+ hash_pcent = simple_hash("pcent");
+ }
+
+ if(unlikely(!units)) units = "";
+
+ uint32_t hash_units = simple_hash(units);
+
+ if(unlikely((hash_units == hash_seconds && !strcmp(units, "seconds")) || (hash_units == hash_seconds_ago && !strcmp(units, "seconds ago")))) {
+ if(value == 0.0) {
+ snprintfz(value_string, value_string_len, "%s", "now");
+ return value_string;
+ }
+ else if(isnan(value) || isinf(value)) {
+ snprintfz(value_string, value_string_len, "%s", "never");
+ return value_string;
+ }
+
+ const char *suffix = (hash_units == hash_seconds_ago)?" ago":"";
+
+ size_t s = (size_t)value;
+ size_t d = s / 86400;
+ s = s % 86400;
+
+ size_t h = s / 3600;
+ s = s % 3600;
+
+ size_t m = s / 60;
+ s = s % 60;
+
+ if(d)
+ snprintfz(value_string, value_string_len, "%zu %s %02zu:%02zu:%02zu%s", d, (d == 1)?"day":"days", h, m, s, suffix);
+ else
+ snprintfz(value_string, value_string_len, "%02zu:%02zu:%02zu%s", h, m, s, suffix);
+
+ return value_string;
+ }
+
+ else if(unlikely((hash_units == hash_minutes && !strcmp(units, "minutes")) || (hash_units == hash_minutes_ago && !strcmp(units, "minutes ago")))) {
+ if(value == 0.0) {
+ snprintfz(value_string, value_string_len, "%s", "now");
+ return value_string;
+ }
+ else if(isnan(value) || isinf(value)) {
+ snprintfz(value_string, value_string_len, "%s", "never");
+ return value_string;
+ }
+
+ const char *suffix = (hash_units == hash_minutes_ago)?" ago":"";
+
+ size_t m = (size_t)value;
+ size_t d = m / (60 * 24);
+ m = m % (60 * 24);
+
+ size_t h = m / 60;
+ m = m % 60;
+
+ if(d)
+ snprintfz(value_string, value_string_len, "%zud %02zuh %02zum%s", d, h, m, suffix);
+ else
+ snprintfz(value_string, value_string_len, "%zuh %zum%s", h, m, suffix);
+
+ return value_string;
+ }
+
+ else if(unlikely((hash_units == hash_hours && !strcmp(units, "hours")) || (hash_units == hash_hours_ago && !strcmp(units, "hours ago")))) {
+ if(value == 0.0) {
+ snprintfz(value_string, value_string_len, "%s", "now");
+ return value_string;
+ }
+ else if(isnan(value) || isinf(value)) {
+ snprintfz(value_string, value_string_len, "%s", "never");
+ return value_string;
+ }
+
+ const char *suffix = (hash_units == hash_hours_ago)?" ago":"";
+
+ size_t h = (size_t)value;
+ size_t d = h / 24;
+ h = h % 24;
+
+ if(d)
+ snprintfz(value_string, value_string_len, "%zud %zuh%s", d, h, suffix);
+ else
+ snprintfz(value_string, value_string_len, "%zuh%s", h, suffix);
+
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_onoff && !strcmp(units, "on/off"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"on":"off");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_updown && !strcmp(units, "up/down"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"up":"down");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_okerror && !strcmp(units, "ok/error"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"error");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_okfailed && !strcmp(units, "ok/failed"))) {
+ snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"failed");
+ return value_string;
+ }
+
+ else if(unlikely(hash_units == hash_empty && !strcmp(units, "empty")))
+ units = "";
+
+ else if(unlikely(hash_units == hash_null && !strcmp(units, "null")))
+ units = "";
+
+ else if(unlikely(hash_units == hash_percentage && !strcmp(units, "percentage")))
+ units = "%";
+
+ else if(unlikely(hash_units == hash_percent && !strcmp(units, "percent")))
+ units = "%";
+
+ else if(unlikely(hash_units == hash_pcent && !strcmp(units, "pcent")))
+ units = "%";
+
+
+ if(unlikely(isnan(value) || isinf(value))) {
+ strcpy(value_string, "-");
+ return value_string;
+ }
+
+ return format_value_with_precision_and_unit(value_string, value_string_len, value, units, precision);
}
static inline const char *color_map(const char *color) {
@@ -391,7 +607,13 @@ static inline const char *color_map(const char *color) {
return color;
}
-static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value, int value_is_null) {
+static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value) {
+ int value_is_null = 0;
+ if(isnan(value) || isinf(value)) {
+ value = 0.0;
+ value_is_null = 1;
+ }
+
char color_buffer[256 + 1] = "";
char value_buffer[256 + 1] = "";
char comparison = '>';
@@ -501,7 +723,7 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu
// colors
#define COLOR_STRING_SIZE 100
-void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision) {
+void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision) {
char label_buffer[LABEL_STRING_SIZE + 1]
, value_color_buffer[COLOR_STRING_SIZE + 1]
, value_string[VALUE_STRING_SIZE + 1]
@@ -516,102 +738,10 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch
label_color = "#555";
if(unlikely(!value_color || !*value_color))
- value_color = (value_is_null)?"#999":"#4c1";
-
- units = fix_units(units);
- calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value, value_is_null);
-
- char *separator = "";
- if(unlikely(isalnum(*units)))
- separator = " ";
-
- if(unlikely(!strcmp(units, "seconds"))) {
- size_t s = (size_t)value;
- size_t d = s / 86400;
- s = s % 86400;
-
- size_t h = s / 3600;
- s = s % 3600;
-
- size_t m = s / 60;
- s = s % 60;
-
- if(d)
- snprintfz(value_string, VALUE_STRING_SIZE, "%zu %s %02zu:%02zu:%02zu", d, (d == 1)?"day":"days", h, m, s);
- else
- snprintfz(value_string, VALUE_STRING_SIZE, "%02zu:%02zu:%02zu", h, m, s);
- }
-
- else if(unlikely(!strcmp(units, "minutes"))) {
- size_t m = (size_t)value;
- size_t d = m / (60 * 24);
- m = m % (60 * 24);
-
- size_t h = m / 60;
- m = m % 60;
+ value_color = (isnan(value) || isinf(value))?"#999":"#4c1";
- if(d)
- snprintfz(value_string, VALUE_STRING_SIZE, "%zud %02zuh %02zum", d, h, m);
- else
- snprintfz(value_string, VALUE_STRING_SIZE, "%zuh %zum", h, m);
- }
-
- else if(unlikely(!strcmp(units, "hours"))) {
- size_t h = (size_t)value;
- size_t d = h / 24;
- h = h % 24;
-
- if(d)
- snprintfz(value_string, VALUE_STRING_SIZE, "%zud %zuh", d, h);
- else
- snprintfz(value_string, VALUE_STRING_SIZE, "%zuh", h);
- }
-
- else if(unlikely(value_is_null))
- strcpy(value_string, "-");
-
- else if(precision < 0) {
- int len, lstop = 0, trim_zeros = 1;
-
- calculated_number abs = value;
- if(isless(value, 0)) {
- lstop = 1;
- abs = -value;
- }
-
- if(isgreaterequal(abs, 1000)) { len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.0Lf", (long double)value); trim_zeros = 0; }
- else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.1Lf", (long double)value);
- else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.2Lf", (long double)value);
- else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.3Lf", (long double)value);
- else len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.4Lf", (long double)value);
-
- if(unlikely(trim_zeros)) {
- int l;
- // remove trailing zeros from the decimal part
- for(l = len - 1; l > lstop ; l--) {
- if(likely(value_string[l] == '0')) {
- value_string[l] = '\0';
- len--;
- }
-
- else if(unlikely(value_string[l] == '.')) {
- value_string[l] = '\0';
- len--;
- break;
- }
-
- else
- break;
- }
- }
-
- if(len >= 0)
- snprintfz(&value_string[len], VALUE_STRING_SIZE - len, "%s%s", separator, units);
- }
- else {
- if(precision > 50) precision = 50;
- snprintfz(value_string, VALUE_STRING_SIZE, "%0.*Lf%s%s", precision, (long double)value, separator, units);
- }
+ calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value);
+ format_value_and_unit(value_string, VALUE_STRING_SIZE, value, units, precision);
// we need to copy the label, since verdana11_width may write to it
strncpyz(label_buffer, label, LABEL_STRING_SIZE);
diff --git a/src/web_buffer_svg.h b/src/web_buffer_svg.h
index 1281847eb..49f73e445 100644
--- a/src/web_buffer_svg.h
+++ b/src/web_buffer_svg.h
@@ -1,6 +1,7 @@
#ifndef NETDATA_WEB_BUFFER_SVG_H
#define NETDATA_WEB_BUFFER_SVG_H 1
-extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision);
+extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision);
+extern char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision);
#endif /* NETDATA_WEB_BUFFER_SVG_H */
diff --git a/src/web_client.c b/src/web_client.c
index 4b6ccf646..b5b25899f 100644
--- a/src/web_client.c
+++ b/src/web_client.c
@@ -5,7 +5,8 @@
#define TOO_BIG_REQUEST 16384
int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS;
-int web_donotrack_comply = 0;
+int respect_web_browser_do_not_track_policy = 0;
+char *web_x_frame_options = NULL;
#ifdef NETDATA_WITH_ZLIB
int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRATEGY;
@@ -24,6 +25,8 @@ static inline int web_client_crock_socket(struct web_client *w) {
return -1;
}
}
+#else
+ (void)w;
#endif /* TCP_CORK */
return 0;
@@ -39,13 +42,14 @@ static inline int web_client_uncrock_socket(struct web_client *w) {
return -1;
}
}
+#else
+ (void)w;
#endif /* TCP_CORK */
return 0;
}
-struct web_client *web_client_create(int listener)
-{
+struct web_client *web_client_create(int listener) {
struct web_client *w;
w = callocz(1, sizeof(struct web_client));
@@ -222,9 +226,9 @@ struct web_client *web_client_free(struct web_client *w) {
if(w->prev) w->prev->next = w->next;
if(w->next) w->next->prev = w->prev;
- if(w->response.header_output) buffer_free(w->response.header_output);
- if(w->response.header) buffer_free(w->response.header);
- if(w->response.data) buffer_free(w->response.data);
+ buffer_free(w->response.header_output);
+ buffer_free(w->response.header);
+ buffer_free(w->response.data);
if(w->ifd != -1) close(w->ifd);
if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
freez(w);
@@ -239,7 +243,7 @@ uid_t web_files_uid(void) {
static uid_t owner_uid = 0;
if(unlikely(!web_owner)) {
- web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
+ web_owner = config_get(CONFIG_SECTION_WEB, "web files owner", config_get(CONFIG_SECTION_GLOBAL, "run as user", ""));
if(!web_owner || !*web_owner)
owner_uid = geteuid();
else {
@@ -266,7 +270,7 @@ gid_t web_files_gid(void) {
static gid_t owner_gid = 0;
if(unlikely(!web_group)) {
- web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
+ web_group = config_get(CONFIG_SECTION_WEB, "web files group", config_get(CONFIG_SECTION_WEB, "web files owner", ""));
if(!web_group || !*web_group)
owner_gid = getegid();
else {
@@ -288,14 +292,8 @@ gid_t web_files_gid(void) {
return(owner_gid);
}
-int mysendfile(struct web_client *w, char *filename)
-{
- static char *web_dir = NULL;
-
- // initialize our static data
- if(unlikely(!web_dir)) web_dir = config_get("global", "web files directory", WEB_DIR);
-
- debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, web_dir, filename);
+int mysendfile(struct web_client *w, char *filename) {
+ debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, netdata_configured_web_dir, filename);
// skip leading slashes
while (*filename == '/') filename++;
@@ -308,6 +306,7 @@ int mysendfile(struct web_client *w, char *filename)
for(s = filename; *s ;s++) {
if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_sprintf(w->response.data, "Filename contains invalid characters: ");
buffer_strcat_htmlescape(w->response.data, filename);
return 400;
@@ -317,6 +316,7 @@ int mysendfile(struct web_client *w, char *filename)
// if the filename contains a .. refuse to serve it
if(strstr(filename, "..") != 0) {
debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Relative filenames are not supported: ");
buffer_strcat_htmlescape(w->response.data, filename);
return 400;
@@ -324,12 +324,13 @@ int mysendfile(struct web_client *w, char *filename)
// access the file
char webfilename[FILENAME_MAX + 1];
- snprintfz(webfilename, FILENAME_MAX, "%s/%s", web_dir, filename);
+ snprintfz(webfilename, FILENAME_MAX, "%s/%s", netdata_configured_web_dir, filename);
// check if the file exists
struct stat stat;
if(lstat(webfilename, &stat) != 0) {
debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "File does not exist, or is not accessible: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 404;
@@ -338,6 +339,7 @@ int mysendfile(struct web_client *w, char *filename)
// check if the file is owned by expected user
if(stat.st_uid != web_files_uid()) {
error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, stat.st_uid, web_files_uid());
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Access to file is not permitted: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 403;
@@ -346,6 +348,7 @@ int mysendfile(struct web_client *w, char *filename)
// check if the file is owned by expected group
if(stat.st_gid != web_files_gid()) {
error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, stat.st_gid, web_files_gid());
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Access to file is not permitted: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 403;
@@ -358,6 +361,7 @@ int mysendfile(struct web_client *w, char *filename)
if((stat.st_mode & S_IFMT) != S_IFREG) {
error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Access to file is not permitted: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 403;
@@ -370,6 +374,7 @@ int mysendfile(struct web_client *w, char *filename)
if(errno == EBUSY || errno == EAGAIN) {
error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
buffer_strcat(w->response.data, "File is currently busy, please try again later: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
@@ -377,6 +382,7 @@ int mysendfile(struct web_client *w, char *filename)
}
else {
error("%llu: Cannot open file '%s'.", w->id, webfilename);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Cannot open file: ");
buffer_strcat_htmlescape(w->response.data, webfilename);
return 404;
@@ -536,98 +542,6 @@ void buffer_data_options2string(BUFFER *wb, uint32_t options) {
}
}
-uint32_t web_client_api_request_v1_data_options(char *o)
-{
- uint32_t ret = 0x00000000;
- char *tok;
-
- while(o && *o && (tok = mystrsep(&o, ", |"))) {
- if(!*tok) continue;
-
- if(!strcmp(tok, "nonzero"))
- ret |= RRDR_OPTION_NONZERO;
- else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
- ret |= RRDR_OPTION_REVERSED;
- else if(!strcmp(tok, "jsonwrap"))
- ret |= RRDR_OPTION_JSON_WRAP;
- else if(!strcmp(tok, "min2max"))
- ret |= RRDR_OPTION_MIN2MAX;
- else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
- ret |= RRDR_OPTION_MILLISECONDS;
- else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
- ret |= RRDR_OPTION_ABSOLUTE;
- else if(!strcmp(tok, "seconds"))
- ret |= RRDR_OPTION_SECONDS;
- else if(!strcmp(tok, "null2zero"))
- ret |= RRDR_OPTION_NULL2ZERO;
- else if(!strcmp(tok, "objectrows"))
- ret |= RRDR_OPTION_OBJECTSROWS;
- else if(!strcmp(tok, "google_json"))
- ret |= RRDR_OPTION_GOOGLE_JSON;
- else if(!strcmp(tok, "percentage"))
- ret |= RRDR_OPTION_PERCENTAGE;
- else if(!strcmp(tok, "unaligned"))
- ret |= RRDR_OPTION_NOT_ALIGNED;
- }
-
- return ret;
-}
-
-uint32_t web_client_api_request_v1_data_format(char *name)
-{
- if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
- return DATASOURCE_DATATABLE_JSON;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
- return DATASOURCE_DATATABLE_JSONP;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
- return DATASOURCE_JSON;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
- return DATASOURCE_JSONP;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
- return DATASOURCE_SSV;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
- return DATASOURCE_CSV;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
- return DATASOURCE_TSV;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
- return DATASOURCE_HTML;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
- return DATASOURCE_JS_ARRAY;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
- return DATASOURCE_SSV_COMMA;
-
- else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
- return DATASOURCE_CSV_JSON_ARRAY;
-
- return DATASOURCE_JSON;
-}
-
-uint32_t web_client_api_request_v1_data_google_format(char *name)
-{
- if(!strcmp(name, "json"))
- return DATASOURCE_DATATABLE_JSONP;
-
- else if(!strcmp(name, "html"))
- return DATASOURCE_HTML;
-
- else if(!strcmp(name, "csv"))
- return DATASOURCE_CSV;
-
- else if(!strcmp(name, "tsv-excel"))
- return DATASOURCE_TSV;
-
- return DATASOURCE_JSON;
-}
-
const char *group_method2string(int group) {
switch(group) {
case GROUP_UNDEFINED:
@@ -653,844 +567,27 @@ const char *group_method2string(int group) {
}
}
-int web_client_api_request_v1_data_group(char *name, int def)
-{
- if(!strcmp(name, "average"))
- return GROUP_AVERAGE;
-
- else if(!strcmp(name, "min"))
- return GROUP_MIN;
-
- else if(!strcmp(name, "max"))
- return GROUP_MAX;
-
- else if(!strcmp(name, "sum"))
- return GROUP_SUM;
-
- else if(!strcmp(name, "incremental-sum"))
- return GROUP_INCREMENTAL_SUM;
-
- return def;
-}
-
-int web_client_api_request_v1_alarms(struct web_client *w, char *url)
-{
- int all = 0;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- if(!strcmp(value, "all")) all = 1;
- else if(!strcmp(value, "active")) all = 0;
- }
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- health_alarms2json(&localhost, w->response.data, all);
- return 200;
-}
-
-int web_client_api_request_v1_alarm_log(struct web_client *w, char *url)
-{
- uint32_t after = 0;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- if(!strcmp(name, "after")) after = strtoul(value, NULL, 0);
- }
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- health_alarm_log2json(&localhost, w->response.data, after);
- return 200;
-}
-
-int web_client_api_request_single_chart(struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf))
-{
- int ret = 400;
- char *chart = NULL;
-
- buffer_flush(w->response.data);
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if(!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- // name and value are now the parameters
- // they are not null and not empty
-
- if(!strcmp(name, "chart")) chart = value;
- //else {
- /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
- // goto cleanup;
- //}
- }
-
- if(!chart || !*chart) {
- buffer_sprintf(w->response.data, "No chart id is given at the request.");
- goto cleanup;
- }
-
- RRDSET *st = rrdset_find(chart);
- if(!st) st = rrdset_find_byname(chart);
- if(!st) {
- buffer_strcat(w->response.data, "Chart is not found: ");
- buffer_strcat_htmlescape(w->response.data, chart);
- ret = 404;
- goto cleanup;
- }
-
- w->response.data->contenttype = CT_APPLICATION_JSON;
- callback(st, w->response.data);
- return 200;
-
- cleanup:
- return ret;
-}
-
-int web_client_api_request_v1_alarm_variables(struct web_client *w, char *url)
-{
- return web_client_api_request_single_chart(w, url, health_api_v1_chart_variables2json);
-}
-
-int web_client_api_request_v1_charts(struct web_client *w, char *url)
-{
- (void)url;
-
- buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- rrd_stats_api_v1_charts(w->response.data);
- return 200;
-}
-
-int web_client_api_request_v1_allmetrics(struct web_client *w, char *url)
-{
- int format = ALLMETRICS_SHELL;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- if(!strcmp(name, "format")) {
- if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
- format = ALLMETRICS_SHELL;
- else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
- format = ALLMETRICS_PROMETHEUS;
- else
- format = 0;
- }
- }
-
- buffer_flush(w->response.data);
- buffer_no_cacheable(w->response.data);
-
- switch(format) {
- case ALLMETRICS_SHELL:
- w->response.data->contenttype = CT_TEXT_PLAIN;
- rrd_stats_api_v1_charts_allmetrics_shell(w->response.data);
- return 200;
-
- case ALLMETRICS_PROMETHEUS:
- w->response.data->contenttype = CT_PROMETHEUS;
- rrd_stats_api_v1_charts_allmetrics_prometheus(w->response.data);
- return 200;
-
- default:
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_strcat(w->response.data, "Which format? Only '" ALLMETRICS_FORMAT_SHELL "' and '" ALLMETRICS_FORMAT_PROMETHEUS "' is currently supported.");
- return 400;
- }
-}
-
-int web_client_api_request_v1_chart(struct web_client *w, char *url)
-{
- return web_client_api_request_single_chart(w, url, rrd_stats_api_v1_chart);
-}
-
-int web_client_api_request_v1_badge(struct web_client *w, char *url) {
- int ret = 400;
- buffer_flush(w->response.data);
-
- BUFFER *dimensions = NULL;
-
- const char *chart = NULL
- , *before_str = NULL
- , *after_str = NULL
- , *points_str = NULL
- , *multiply_str = NULL
- , *divide_str = NULL
- , *label = NULL
- , *units = NULL
- , *label_color = NULL
- , *value_color = NULL
- , *refresh_str = NULL
- , *precision_str = NULL
- , *alarm = NULL;
-
- int group = GROUP_AVERAGE;
- uint32_t options = 0x00000000;
-
- while(url) {
- char *value = mystrsep(&url, "/?&");
- if(!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
-
- // name and value are now the parameters
- // they are not null and not empty
-
- if(!strcmp(name, "chart")) chart = value;
- else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
- if(!dimensions)
- dimensions = buffer_create(100);
-
- buffer_strcat(dimensions, "|");
- buffer_strcat(dimensions, value);
- }
- else if(!strcmp(name, "after")) after_str = value;
- else if(!strcmp(name, "before")) before_str = value;
- else if(!strcmp(name, "points")) points_str = value;
- else if(!strcmp(name, "group")) {
- group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
- }
- else if(!strcmp(name, "options")) {
- options |= web_client_api_request_v1_data_options(value);
- }
- else if(!strcmp(name, "label")) label = value;
- else if(!strcmp(name, "units")) units = value;
- else if(!strcmp(name, "label_color")) label_color = value;
- else if(!strcmp(name, "value_color")) value_color = value;
- else if(!strcmp(name, "multiply")) multiply_str = value;
- else if(!strcmp(name, "divide")) divide_str = value;
- else if(!strcmp(name, "refresh")) refresh_str = value;
- else if(!strcmp(name, "precision")) precision_str = value;
- else if(!strcmp(name, "alarm")) alarm = value;
- }
-
- if(!chart || !*chart) {
- buffer_no_cacheable(w->response.data);
- buffer_sprintf(w->response.data, "No chart id is given at the request.");
- goto cleanup;
- }
-
- RRDSET *st = rrdset_find(chart);
- if(!st) st = rrdset_find_byname(chart);
- if(!st) {
- buffer_no_cacheable(w->response.data);
- buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
- ret = 200;
- goto cleanup;
- }
-
- RRDCALC *rc = NULL;
- if(alarm) {
- rc = rrdcalc_find(st, alarm);
- if (!rc) {
- buffer_no_cacheable(w->response.data);
- buffer_svg(w->response.data, "alarm not found", 0, "", NULL, NULL, 1, -1);
- ret = 200;
- goto cleanup;
- }
- }
-
- long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1;
- long long divide = (divide_str && *divide_str )?str2l(divide_str):1;
- long long before = (before_str && *before_str )?str2l(before_str):0;
- long long after = (after_str && *after_str )?str2l(after_str):-st->update_every;
- int points = (points_str && *points_str )?str2i(points_str):1;
- int precision = (precision_str && *precision_str)?str2i(precision_str):-1;
-
- if(!multiply) multiply = 1;
- if(!divide) divide = 1;
-
- int refresh = 0;
- if(refresh_str && *refresh_str) {
- if(!strcmp(refresh_str, "auto")) {
- if(rc) refresh = rc->update_every;
- else if(options & RRDR_OPTION_NOT_ALIGNED)
- refresh = st->update_every;
- else {
- refresh = (int)(before - after);
- if(refresh < 0) refresh = -refresh;
- }
- }
- else {
- refresh = str2i(refresh_str);
- if(refresh < 0) refresh = -refresh;
- }
- }
-
- if(!label) {
- if(alarm) {
- char *s = (char *)alarm;
- while(*s) {
- if(*s == '_') *s = ' ';
- s++;
- }
- label = alarm;
- }
- else if(dimensions) {
- const char *dim = buffer_tostring(dimensions);
- if(*dim == '|') dim++;
- label = dim;
- }
- else
- label = st->name;
- }
- if(!units) {
- if(alarm) {
- if(rc->units)
- units = rc->units;
- else
- units = "";
- }
- else if(options & RRDR_OPTION_PERCENTAGE)
- units = "%";
- else
- units = st->units;
- }
-
- debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
- , w->id
- , chart
- , alarm?alarm:""
- , (dimensions)?buffer_tostring(dimensions):""
- , after
- , before
- , points
- , group
- , options
- );
-
- if(rc) {
- calculated_number n = rc->value;
- if(isnan(n) || isinf(n)) n = 0;
-
- if (refresh > 0) {
- buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
- w->response.data->expires = now_realtime_sec() + refresh;
- }
- else buffer_no_cacheable(w->response.data);
-
- if(!value_color) {
- switch(rc->status) {
- case RRDCALC_STATUS_CRITICAL:
- value_color = "red";
- break;
-
- case RRDCALC_STATUS_WARNING:
- value_color = "orange";
- break;
-
- case RRDCALC_STATUS_CLEAR:
- value_color = "brightgreen";
- break;
-
- case RRDCALC_STATUS_UNDEFINED:
- value_color = "lightgrey";
- break;
-
- case RRDCALC_STATUS_UNINITIALIZED:
- value_color = "#000";
- break;
-
- default:
- value_color = "grey";
- break;
- }
- }
-
- buffer_svg(w->response.data,
- label,
- rc->value * multiply / divide,
- units,
- label_color,
- value_color,
- 0,
- precision);
- ret = 200;
- }
- else {
- time_t latest_timestamp = 0;
- int value_is_null = 1;
- calculated_number n = 0;
- ret = 500;
-
- // if the collected value is too old, don't calculate its value
- if (rrdset_last_entry_t(st) >= (now_realtime_sec() - (st->update_every * st->gap_when_lost_iterations_above)))
- ret = rrd2value(st,
- w->response.data,
- &n,
- (dimensions) ? buffer_tostring(dimensions) : NULL,
- points,
- after,
- before,
- group,
- options,
- NULL,
- &latest_timestamp,
- &value_is_null);
-
- // if the value cannot be calculated, show empty badge
- if (ret != 200) {
- buffer_no_cacheable(w->response.data);
- value_is_null = 1;
- n = 0;
- ret = 200;
- }
- else if (refresh > 0) {
- buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
- w->response.data->expires = now_realtime_sec() + refresh;
- }
- else buffer_no_cacheable(w->response.data);
-
- // render the badge
- buffer_svg(w->response.data,
- label,
- n * multiply / divide,
- units,
- label_color,
- value_color,
- value_is_null,
- precision);
- }
-
-cleanup:
- if(dimensions)
- buffer_free(dimensions);
- return ret;
-}
-
-// returns the HTTP code
-int web_client_api_request_v1_data(struct web_client *w, char *url)
-{
- debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
-
- int ret = 400;
- BUFFER *dimensions = NULL;
-
- buffer_flush(w->response.data);
-
- char *google_version = "0.6",
- *google_reqId = "0",
- *google_sig = "0",
- *google_out = "json",
- *responseHandler = NULL,
- *outFileName = NULL;
-
- time_t last_timestamp_in_data = 0, google_timestamp = 0;
-
- char *chart = NULL
- , *before_str = NULL
- , *after_str = NULL
- , *points_str = NULL;
-
- int group = GROUP_AVERAGE;
- uint32_t format = DATASOURCE_JSON;
- uint32_t options = 0x00000000;
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if(!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if(!name || !*name) continue;
- if(!value || !*value) continue;
-
- debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
-
- // name and value are now the parameters
- // they are not null and not empty
-
- if(!strcmp(name, "chart")) chart = value;
- else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
- if(!dimensions) dimensions = buffer_create(100);
- buffer_strcat(dimensions, "|");
- buffer_strcat(dimensions, value);
- }
- else if(!strcmp(name, "after")) after_str = value;
- else if(!strcmp(name, "before")) before_str = value;
- else if(!strcmp(name, "points")) points_str = value;
- else if(!strcmp(name, "group")) {
- group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
- }
- else if(!strcmp(name, "format")) {
- format = web_client_api_request_v1_data_format(value);
- }
- else if(!strcmp(name, "options")) {
- options |= web_client_api_request_v1_data_options(value);
- }
- else if(!strcmp(name, "callback")) {
- responseHandler = value;
- }
- else if(!strcmp(name, "filename")) {
- outFileName = value;
- }
- else if(!strcmp(name, "tqx")) {
- // parse Google Visualization API options
- // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
- char *tqx_name, *tqx_value;
-
- while(value) {
- tqx_value = mystrsep(&value, ";");
- if(!tqx_value || !*tqx_value) continue;
-
- tqx_name = mystrsep(&tqx_value, ":");
- if(!tqx_name || !*tqx_name) continue;
- if(!tqx_value || !*tqx_value) continue;
-
- if(!strcmp(tqx_name, "version"))
- google_version = tqx_value;
- else if(!strcmp(tqx_name, "reqId"))
- google_reqId = tqx_value;
- else if(!strcmp(tqx_name, "sig")) {
- google_sig = tqx_value;
- google_timestamp = strtoul(google_sig, NULL, 0);
- }
- else if(!strcmp(tqx_name, "out")) {
- google_out = tqx_value;
- format = web_client_api_request_v1_data_google_format(google_out);
- }
- else if(!strcmp(tqx_name, "responseHandler"))
- responseHandler = tqx_value;
- else if(!strcmp(tqx_name, "outFileName"))
- outFileName = tqx_value;
- }
- }
- }
-
- if(!chart || !*chart) {
- buffer_sprintf(w->response.data, "No chart id is given at the request.");
- goto cleanup;
- }
-
- RRDSET *st = rrdset_find(chart);
- if(!st) st = rrdset_find_byname(chart);
- if(!st) {
- buffer_strcat(w->response.data, "Chart is not found: ");
- buffer_strcat_htmlescape(w->response.data, chart);
- ret = 404;
- goto cleanup;
- }
-
- long long before = (before_str && *before_str)?str2l(before_str):0;
- long long after = (after_str && *after_str) ?str2l(after_str):0;
- int points = (points_str && *points_str)?str2i(points_str):0;
-
- debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
- , w->id
- , chart
- , (dimensions)?buffer_tostring(dimensions):""
- , after
- , before
- , points
- , group
- , format
- , options
- );
-
- if(outFileName && *outFileName) {
- buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
- debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
- }
-
- if(format == DATASOURCE_DATATABLE_JSONP) {
- if(responseHandler == NULL)
- responseHandler = "google.visualization.Query.setResponse";
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
- w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
- );
-
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
- responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
- }
- else if(format == DATASOURCE_JSONP) {
- if(responseHandler == NULL)
- responseHandler = "callback";
-
- buffer_strcat(w->response.data, responseHandler);
- buffer_strcat(w->response.data, "(");
- }
-
- ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
-
- if(format == DATASOURCE_DATATABLE_JSONP) {
- if(google_timestamp < last_timestamp_in_data)
- buffer_strcat(w->response.data, "});");
-
- else {
- // the client already has the latest data
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
- responseHandler, google_version, google_reqId);
- }
- }
- else if(format == DATASOURCE_JSONP)
- buffer_strcat(w->response.data, ");");
-
-cleanup:
- if(dimensions) buffer_free(dimensions);
- return ret;
-}
-
-
-int web_client_api_request_v1_registry(struct web_client *w, char *url)
-{
- static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
- hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
- hash_to = 0 /*, hash_redirects = 0 */;
-
- if(unlikely(!hash_action)) {
- hash_action = simple_hash("action");
- hash_access = simple_hash("access");
- hash_hello = simple_hash("hello");
- hash_delete = simple_hash("delete");
- hash_search = simple_hash("search");
- hash_switch = simple_hash("switch");
- hash_machine = simple_hash("machine");
- hash_url = simple_hash("url");
- hash_name = simple_hash("name");
- hash_delete_url = simple_hash("delete_url");
- hash_for = simple_hash("for");
- hash_to = simple_hash("to");
-/*
- hash_redirects = simple_hash("redirects");
-*/
- }
-
- char person_guid[GUID_LEN + 1] = "";
-
- debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
-
- // FIXME
- // The browser may send multiple cookies with our id
-
- char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
- if(cookie)
- strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
-
- char action = '\0';
- char *machine_guid = NULL,
- *machine_url = NULL,
- *url_name = NULL,
- *search_machine_guid = NULL,
- *delete_url = NULL,
- *to_person_guid = NULL;
-/*
- int redirects = 0;
-*/
-
- while(url) {
- char *value = mystrsep(&url, "?&");
- if (!value || !*value) continue;
-
- char *name = mystrsep(&value, "=");
- if (!name || !*name) continue;
- if (!value || !*value) continue;
-
- debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
-
- uint32_t hash = simple_hash(name);
-
- if(hash == hash_action && !strcmp(name, "action")) {
- uint32_t vhash = simple_hash(value);
-
- if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
- else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
- else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
- else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
- else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
-#ifdef NETDATA_INTERNAL_CHECKS
- else error("unknown registry action '%s'", value);
-#endif /* NETDATA_INTERNAL_CHECKS */
- }
-/*
- else if(hash == hash_redirects && !strcmp(name, "redirects"))
- redirects = atoi(value);
-*/
- else if(hash == hash_machine && !strcmp(name, "machine"))
- machine_guid = value;
-
- else if(hash == hash_url && !strcmp(name, "url"))
- machine_url = value;
-
- else if(action == 'A') {
- if(hash == hash_name && !strcmp(name, "name"))
- url_name = value;
- }
- else if(action == 'D') {
- if(hash == hash_delete_url && !strcmp(name, "delete_url"))
- delete_url = value;
- }
- else if(action == 'S') {
- if(hash == hash_for && !strcmp(name, "for"))
- search_machine_guid = value;
- }
- else if(action == 'W') {
- if(hash == hash_to && !strcmp(name, "to"))
- to_person_guid = value;
- }
-#ifdef NETDATA_INTERNAL_CHECKS
- else error("unused registry URL parameter '%s' with value '%s'", name, value);
-#endif /* NETDATA_INTERNAL_CHECKS */
- }
-
- if(web_donotrack_comply && w->donottrack) {
+static inline int check_host_and_call(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) {
+ if(unlikely(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
+ buffer_strcat(w->response.data, "This host does not maintain a database");
return 400;
}
- if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
- error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Access request.");
- return 400;
- }
- else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
- error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Delete request.");
- return 400;
- }
- else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
- error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Search request.");
- return 400;
- }
- else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
- error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
- machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry Switch request.");
- return 400;
- }
-
- switch(action) {
- case 'A':
- w->tracking_required = 1;
- return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
-
- case 'D':
- w->tracking_required = 1;
- return registry_request_delete_json(w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
-
- case 'S':
- w->tracking_required = 1;
- return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec());
-
- case 'W':
- w->tracking_required = 1;
- return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
-
- case 'H':
- return registry_request_hello_json(w);
-
- default:
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
- return 400;
- }
+ return func(host, w, url);
}
-int web_client_api_request_v1(struct web_client *w, char *url) {
- static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0, hash_raw = 0;
-
- if(unlikely(hash_data == 0)) {
- hash_data = simple_hash("data");
- hash_chart = simple_hash("chart");
- hash_charts = simple_hash("charts");
- hash_registry = simple_hash("registry");
- hash_badge = simple_hash("badge.svg");
- hash_alarms = simple_hash("alarms");
- hash_alarm_log = simple_hash("alarm_log");
- hash_alarm_variables = simple_hash("alarm_variables");
- hash_raw = simple_hash("allmetrics");
- }
-
- // get the command
- char *tok = mystrsep(&url, "/?&");
- if(tok && *tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
- uint32_t hash = simple_hash(tok);
-
- if(hash == hash_data && !strcmp(tok, "data"))
- return web_client_api_request_v1_data(w, url);
-
- else if(hash == hash_chart && !strcmp(tok, "chart"))
- return web_client_api_request_v1_chart(w, url);
-
- else if(hash == hash_charts && !strcmp(tok, "charts"))
- return web_client_api_request_v1_charts(w, url);
-
- else if(hash == hash_registry && !strcmp(tok, "registry"))
- return web_client_api_request_v1_registry(w, url);
-
- else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
- return web_client_api_request_v1_badge(w, url);
-
- else if(hash == hash_alarms && !strcmp(tok, "alarms"))
- return web_client_api_request_v1_alarms(w, url);
-
- else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
- return web_client_api_request_v1_alarm_log(w, url);
-
- else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
- return web_client_api_request_v1_alarm_variables(w, url);
-
- else if(hash == hash_raw && !strcmp(tok, "allmetrics"))
- return web_client_api_request_v1_allmetrics(w, url);
-
- else {
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Unsupported v1 API command: ");
- buffer_strcat_htmlescape(w->response.data, tok);
- return 404;
- }
- }
- else {
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Which API v1 command?");
- return 400;
- }
-}
-
-int web_client_api_request(struct web_client *w, char *url)
+int web_client_api_request(RRDHOST *host, struct web_client *w, char *url)
{
// get the api version
char *tok = mystrsep(&url, "/?&");
if(tok && *tok) {
debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
if(strcmp(tok, "v1") == 0)
- return web_client_api_request_v1(w, url);
+ return web_client_api_request_v1(host, w, url);
else {
buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_TEXT_HTML;
buffer_strcat(w->response.data, "Unsupported API version: ");
buffer_strcat_htmlescape(w->response.data, tok);
return 404;
@@ -1503,179 +600,6 @@ int web_client_api_request(struct web_client *w, char *url)
}
}
-int web_client_api_old_data_request(struct web_client *w, char *url, int datasource_type)
-{
- if(!url || !*url) {
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Incomplete request.");
- return 400;
- }
-
- RRDSET *st = NULL;
-
- char *args = strchr(url, '?');
- if(args) {
- *args='\0';
- args = &args[1];
- }
-
- // get the name of the data to show
- char *tok = mystrsep(&url, "/");
- if(!tok) tok = "";
-
- // do we have such a data set?
- if(*tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
- st = rrdset_find_byname(tok);
- if(!st) st = rrdset_find(tok);
- }
-
- if(!st) {
- // we don't have it
- // try to send a file with that name
- buffer_flush(w->response.data);
- return(mysendfile(w, tok));
- }
-
- // we have it
- debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
-
- // how many entries does the client want?
- int lines = rrd_default_history_entries;
- int group_count = 1;
- time_t after = 0, before = 0;
- int group_method = GROUP_AVERAGE;
- int nonzero = 0;
-
- if(url) {
- // parse the lines required
- tok = mystrsep(&url, "/");
- if(tok) lines = str2i(tok);
- if(lines < 1) lines = 1;
- }
- if(url) {
- // parse the group count required
- tok = mystrsep(&url, "/");
- if(tok && *tok) group_count = str2i(tok);
- if(group_count < 1) group_count = 1;
- //if(group_count > save_history / 20) group_count = save_history / 20;
- }
- if(url) {
- // parse the grouping method required
- tok = mystrsep(&url, "/");
- if(tok && *tok) {
- if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
- else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
- else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
- else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
- }
- }
- if(url) {
- // parse after time
- tok = mystrsep(&url, "/");
- if(tok && *tok) after = str2ul(tok);
- if(after < 0) after = 0;
- }
- if(url) {
- // parse before time
- tok = mystrsep(&url, "/");
- if(tok && *tok) before = str2ul(tok);
- if(before < 0) before = 0;
- }
- if(url) {
- // parse nonzero
- tok = mystrsep(&url, "/");
- if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
- }
-
- w->response.data->contenttype = CT_APPLICATION_JSON;
- buffer_flush(w->response.data);
-
- char *google_version = "0.6";
- char *google_reqId = "0";
- char *google_sig = "0";
- char *google_out = "json";
- char *google_responseHandler = "google.visualization.Query.setResponse";
- char *google_outFileName = NULL;
- time_t last_timestamp_in_data = 0;
- if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
-
- w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
-
- while(args) {
- tok = mystrsep(&args, "&");
- if(tok && *tok) {
- char *name = mystrsep(&tok, "=");
- if(name && *name && strcmp(name, "tqx") == 0) {
- char *key = mystrsep(&tok, ":");
- char *value = mystrsep(&tok, ";");
- if(key && value && *key && *value) {
- if(strcmp(key, "version") == 0)
- google_version = value;
-
- else if(strcmp(key, "reqId") == 0)
- google_reqId = value;
-
- else if(strcmp(key, "sig") == 0)
- google_sig = value;
-
- else if(strcmp(key, "out") == 0)
- google_out = value;
-
- else if(strcmp(key, "responseHandler") == 0)
- google_responseHandler = value;
-
- else if(strcmp(key, "outFileName") == 0)
- google_outFileName = value;
- }
- }
- }
- }
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
- w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
- );
-
- if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
- last_timestamp_in_data = strtoul(google_sig, NULL, 0);
-
- // check the client wants json
- if(strcmp(google_out, "json") != 0) {
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
- google_responseHandler, google_version, google_reqId, google_out);
- return 200;
- }
- }
- }
-
- if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
- google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
- }
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
- w->id, st->name, st->id, lines, group_count, group_method, after, before);
-
- time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, (unsigned long)after, (unsigned long)before, nonzero);
-
- if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
- if(timestamp_in_data > last_timestamp_in_data)
- buffer_strcat(w->response.data, "});");
-
- else {
- // the client already has the latest data
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data,
- "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
- google_responseHandler, google_version, google_reqId);
- }
- }
-
- return 200;
-}
-
const char *web_content_type_to_string(uint8_t contenttype) {
switch(contenttype) {
case CT_TEXT_HTML:
@@ -1834,7 +758,7 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
if(strcasestr(v, "keep-alive"))
w->keepalive = 1;
}
- else if(web_donotrack_comply && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
+ else if(respect_web_browser_do_not_track_policy && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
if(*v == '0') w->donottrack = 0;
else if(*v == '1') w->donottrack = 1;
}
@@ -1862,7 +786,13 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
// > 0 : request is not supported
// < 0 : request is incomplete - wait for more data
-static inline int http_request_validate(struct web_client *w) {
+typedef enum http_validation {
+ HTTP_VALIDATION_OK,
+ HTTP_VALIDATION_NOT_SUPPORTED,
+ HTTP_VALIDATION_INCOMPLETE
+} HTTP_VALIDATION;
+
+static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
char *s = w->response.data->buffer, *encoded_url = NULL;
// is is a valid request?
@@ -1874,9 +804,13 @@ static inline int http_request_validate(struct web_client *w) {
encoded_url = s = &s[8];
w->mode = WEB_CLIENT_MODE_OPTIONS;
}
+ else if(!strncmp(s, "STREAM ", 7)) {
+ encoded_url = s = &s[7];
+ w->mode = WEB_CLIENT_MODE_STREAM;
+ }
else {
w->wait_receive = 0;
- return 1;
+ return HTTP_VALIDATION_NOT_SUPPORTED;
}
// find the SPACE + "HTTP/"
@@ -1892,7 +826,7 @@ static inline int http_request_validate(struct web_client *w) {
// incomplete requests
if(unlikely(!*s)) {
w->wait_receive = 1;
- return -2;
+ return HTTP_VALIDATION_INCOMPLETE;
}
// we have the end of encoded_url - remember it
@@ -1923,7 +857,7 @@ static inline int http_request_validate(struct web_client *w) {
strncpyz(w->last_url, w->decoded_url, URL_MAX);
w->wait_receive = 0;
- return 0;
+ return HTTP_VALIDATION_OK;
}
// another header line
@@ -1933,259 +867,26 @@ static inline int http_request_validate(struct web_client *w) {
// incomplete request
w->wait_receive = 1;
- return -3;
+ return HTTP_VALIDATION_INCOMPLETE;
}
-void web_client_process(struct web_client *w) {
- static uint32_t
- hash_api = 0,
- hash_netdata_conf = 0,
- hash_data = 0,
- hash_datasource = 0,
- hash_graph = 0,
- hash_list = 0,
- hash_all_json = 0;
-
-#ifdef NETDATA_INTERNAL_CHECKS
- static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
-#endif
-
- // start timing us
- now_realtime_timeval(&w->tv_in);
-
- if(unlikely(!hash_api)) {
- hash_api = simple_hash("api");
- hash_netdata_conf = simple_hash("netdata.conf");
- hash_data = simple_hash(WEB_PATH_DATA);
- hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
- hash_graph = simple_hash(WEB_PATH_GRAPH);
- hash_list = simple_hash("list");
- hash_all_json = simple_hash("all.json");
-#ifdef NETDATA_INTERNAL_CHECKS
- hash_exit = simple_hash("exit");
- hash_debug = simple_hash("debug");
- hash_mirror = simple_hash("mirror");
-#endif
- }
-
- int code = 500;
- ssize_t bytes;
-
- int what_to_do = http_request_validate(w);
-
- // wait for more data
- if(what_to_do < 0) {
- if(w->response.data->len > TOO_BIG_REQUEST) {
- strcpy(w->last_url, "too big request");
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
-
- code = 400;
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Received request is too big (%zu bytes).\r\n", w->response.data->len);
- }
- else {
- // wait for more data
- return;
- }
- }
- else if(what_to_do > 0) {
- // strcpy(w->last_url, "not a valid request");
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
-
- code = 500;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "I don't understand you...\r\n");
- }
- else { // what_to_do == 0
- if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
- code = 200;
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "OK");
- }
- else {
- char *url = w->decoded_url;
- char *tok = mystrsep(&url, "/?");
- if(tok && *tok) {
- uint32_t hash = simple_hash(tok);
- debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
-
- if(hash == hash_api && strcmp(tok, "api") == 0) {
- // the client is requesting api access
- code = web_client_api_request(w, url);
- }
- else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
-
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
- generate_config(w->response.data, 0);
- }
- else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
- // the client is requesting rrd data -- OLD API
- code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
- }
- else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
- // the client is requesting google datasource -- OLD API
- code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
- }
- else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
- // the client is requesting an rrd graph -- OLD API
-
- // get the name of the data to show
- tok = mystrsep(&url, "/?&");
- if(tok && *tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-
- // do we have such a data set?
- RRDSET *st = rrdset_find_byname(tok);
- if(!st) st = rrdset_find(tok);
- if(!st) {
- // we don't have it
- // try to send a file with that name
- buffer_flush(w->response.data);
- code = mysendfile(w, tok);
- }
- else {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
- w->response.data->contenttype = CT_APPLICATION_JSON;
- buffer_flush(w->response.data);
- rrd_stats_graph_json(st, url, w->response.data);
- }
- }
- else {
- code = 400;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Graph name?\r\n");
- }
- }
- else if(hash == hash_list && strcmp(tok, "list") == 0) {
- // OLD API
- code = 200;
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
-
- buffer_flush(w->response.data);
- RRDSET *st = localhost.rrdset_root;
-
- for ( ; st ; st = st->next )
- buffer_sprintf(w->response.data, "%s\n", st->name);
- }
- else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
- // OLD API
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
-
- w->response.data->contenttype = CT_APPLICATION_JSON;
- buffer_flush(w->response.data);
- rrd_stats_all_json(w->response.data);
- }
-#ifdef NETDATA_INTERNAL_CHECKS
- else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
- code = 200;
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
-
- if(!netdata_exit)
- buffer_strcat(w->response.data, "ok, will do...");
- else
- buffer_strcat(w->response.data, "I am doing it already");
-
- error("web request to exit received.");
- netdata_cleanup_and_exit(0);
- }
- else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
- buffer_flush(w->response.data);
-
- // get the name of the data to show
- tok = mystrsep(&url, "/?&");
- if(tok && *tok) {
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-
- // do we have such a data set?
- RRDSET *st = rrdset_find_byname(tok);
- if(!st) st = rrdset_find(tok);
- if(!st) {
- code = 404;
- buffer_strcat(w->response.data, "Chart is not found: ");
- buffer_strcat_htmlescape(w->response.data, tok);
- debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
- }
- else {
- code = 200;
- debug_flags |= D_RRD_STATS;
- st->debug = !st->debug;
- buffer_sprintf(w->response.data, "Chart has now debug %s: ", st->debug?"enabled":"disabled");
- buffer_strcat_htmlescape(w->response.data, tok);
- debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
- }
- }
- else {
- code = 500;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "debug which chart?\r\n");
- }
- }
- else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
- code = 200;
-
- debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
-
- // replace the zero bytes with spaces
- buffer_char_replace(w->response.data, '\0', ' ');
-
- // just leave the buffer as is
- // it will be copied back to the client
- }
-#endif /* NETDATA_INTERNAL_CHECKS */
- else {
- char filename[FILENAME_MAX+1];
- url = filename;
- strncpyz(filename, w->last_url, FILENAME_MAX);
- tok = mystrsep(&url, "?");
- buffer_flush(w->response.data);
- code = mysendfile(w, (tok && *tok)?tok:"/");
- }
- }
- else {
- char filename[FILENAME_MAX+1];
- url = filename;
- strncpyz(filename, w->last_url, FILENAME_MAX);
- tok = mystrsep(&url, "?");
- buffer_flush(w->response.data);
- code = mysendfile(w, (tok && *tok)?tok:"/");
- }
- }
- }
-
- now_realtime_timeval(&w->tv_ready);
- w->response.sent = 0;
- w->response.code = code;
-
- // set a proper last modified date
- if(unlikely(!w->response.data->date))
- w->response.data->date = w->tv_ready.tv_sec;
-
- if(unlikely(code != 200))
+static inline void web_client_send_http_header(struct web_client *w) {
+ if(unlikely(w->response.code != 200))
buffer_no_cacheable(w->response.data);
// set a proper expiration date, if not already set
if(unlikely(!w->response.data->expires)) {
if(w->response.data->options & WB_CONTENT_NO_CACHEABLE)
- w->response.data->expires = w->tv_ready.tv_sec + rrd_update_every;
+ w->response.data->expires = w->tv_ready.tv_sec + localhost->rrd_update_every;
else
w->response.data->expires = w->tv_ready.tv_sec + 86400;
}
// prepare the HTTP response header
- debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
+ debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, w->response.code);
const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
- const char *code_msg = web_response_code_to_string(code);
+ const char *code_msg = web_response_code_to_string(w->response.code);
// prepare the last modified and expiration dates
char date[32], edate[32];
@@ -2200,61 +901,64 @@ void web_client_process(struct web_client *w) {
}
buffer_sprintf(w->response.header_output,
- "HTTP/1.1 %d %s\r\n"
- "Connection: %s\r\n"
- "Server: NetData Embedded HTTP Server\r\n"
- "Access-Control-Allow-Origin: %s\r\n"
- "Access-Control-Allow-Credentials: true\r\n"
- "Content-Type: %s\r\n"
- "Date: %s\r\n"
- , code, code_msg
- , w->keepalive?"keep-alive":"close"
- , w->origin
- , content_type_string
- , date
- );
+ "HTTP/1.1 %d %s\r\n"
+ "Connection: %s\r\n"
+ "Server: NetData Embedded HTTP Server\r\n"
+ "Access-Control-Allow-Origin: %s\r\n"
+ "Access-Control-Allow-Credentials: true\r\n"
+ "Content-Type: %s\r\n"
+ "Date: %s\r\n"
+ , w->response.code, code_msg
+ , w->keepalive?"keep-alive":"close"
+ , w->origin
+ , content_type_string
+ , date
+ );
+
+ if(unlikely(web_x_frame_options))
+ buffer_sprintf(w->response.header_output, "X-Frame-Options: %s\r\n", web_x_frame_options);
if(w->cookie1[0] || w->cookie2[0]) {
if(w->cookie1[0]) {
buffer_sprintf(w->response.header_output,
- "Set-Cookie: %s\r\n",
- w->cookie1);
+ "Set-Cookie: %s\r\n",
+ w->cookie1);
}
if(w->cookie2[0]) {
buffer_sprintf(w->response.header_output,
- "Set-Cookie: %s\r\n",
- w->cookie2);
+ "Set-Cookie: %s\r\n",
+ w->cookie2);
}
- if(web_donotrack_comply)
+ if(respect_web_browser_do_not_track_policy)
buffer_sprintf(w->response.header_output,
- "Tk: T;cookies\r\n");
+ "Tk: T;cookies\r\n");
}
else {
- if(web_donotrack_comply) {
+ if(respect_web_browser_do_not_track_policy) {
if(w->tracking_required)
buffer_sprintf(w->response.header_output,
- "Tk: T;cookies\r\n");
+ "Tk: T;cookies\r\n");
else
buffer_sprintf(w->response.header_output,
- "Tk: N\r\n");
+ "Tk: N\r\n");
}
}
if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
buffer_strcat(w->response.header_output,
- "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
- "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control\r\n"
- "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
- );
+ "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
+ "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control\r\n"
+ "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
+ );
}
else {
buffer_sprintf(w->response.header_output,
- "Cache-Control: %s\r\n"
- "Expires: %s\r\n",
- (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache":"public",
- edate);
+ "Cache-Control: %s\r\n"
+ "Expires: %s\r\n",
+ (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache":"public",
+ edate);
}
// copy a possibly available custom header
@@ -2264,9 +968,9 @@ void web_client_process(struct web_client *w) {
// headers related to the transfer method
if(likely(w->response.zoutput)) {
buffer_strcat(w->response.header_output,
- "Content-Encoding: gzip\r\n"
- "Transfer-Encoding: chunked\r\n"
- );
+ "Content-Encoding: gzip\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ );
}
else {
if(likely((w->response.data->len || w->response.rlen))) {
@@ -2284,35 +988,284 @@ void web_client_process(struct web_client *w) {
// sent the HTTP header
debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
- , w->id
- , buffer_strlen(w->response.header_output)
- , buffer_tostring(w->response.header_output)
- );
+ , w->id
+ , buffer_strlen(w->response.header_output)
+ , buffer_tostring(w->response.header_output)
+ );
web_client_crock_socket(w);
- bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
+ ssize_t bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
if(bytes > 0)
w->stats_sent_bytes += bytes;
debug(D_WEB_CLIENT, "%llu: HTTP Header failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
- , w->id
- , buffer_strlen(w->response.header_output)
- , bytes);
+ , w->id
+ , buffer_strlen(w->response.header_output)
+ , bytes);
WEB_CLIENT_IS_DEAD(w);
return;
}
- else
+ else
w->stats_sent_bytes += bytes;
+}
+
+static inline int web_client_process_url(RRDHOST *host, struct web_client *w, char *url);
+
+static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t hash_localhost = 0;
+
+ if(unlikely(!hash_localhost)) {
+ hash_localhost = simple_hash("localhost");
+ }
+
+ if(host != localhost) {
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "Nesting of hosts is not allowed.");
+ return 400;
+ }
+
+ char *tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for host with name '%s'.", w->id, tok);
+
+ // copy the URL, we need it to serve files
+ w->last_url[0] = '/';
+ if(url && *url) strncpyz(&w->last_url[1], url, URL_MAX - 1);
+ else w->last_url[1] = '\0';
+
+ uint32_t hash = simple_hash(tok);
+
+ host = rrdhost_find_by_hostname(tok, hash);
+ if(!host) host = rrdhost_find_by_guid(tok, hash);
+
+ if(host) return web_client_process_url(host, w, url);
+ }
+
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_TEXT_HTML;
+ buffer_strcat(w->response.data, "This netdata does not maintain a database for host: ");
+ buffer_strcat_htmlescape(w->response.data, tok?tok:"");
+ return 404;
+}
+
+static inline int web_client_process_url(RRDHOST *host, struct web_client *w, char *url) {
+ static uint32_t
+ hash_api = 0,
+ hash_netdata_conf = 0,
+ hash_data = 0,
+ hash_datasource = 0,
+ hash_graph = 0,
+ hash_list = 0,
+ hash_all_json = 0,
+ hash_host = 0;
+
+#ifdef NETDATA_INTERNAL_CHECKS
+ static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
+#endif
+
+ if(unlikely(!hash_api)) {
+ hash_api = simple_hash("api");
+ hash_netdata_conf = simple_hash("netdata.conf");
+ hash_data = simple_hash(WEB_PATH_DATA);
+ hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
+ hash_graph = simple_hash(WEB_PATH_GRAPH);
+ hash_list = simple_hash("list");
+ hash_all_json = simple_hash("all.json");
+ hash_host = simple_hash("host");
+#ifdef NETDATA_INTERNAL_CHECKS
+ hash_exit = simple_hash("exit");
+ hash_debug = simple_hash("debug");
+ hash_mirror = simple_hash("mirror");
+#endif
+ }
+
+ char *tok = mystrsep(&url, "/?");
+ if(likely(tok && *tok)) {
+ uint32_t hash = simple_hash(tok);
+ debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
+
+ if(unlikely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
+ debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_request);
+ }
+ else if(unlikely(hash == hash_host && strcmp(tok, "host") == 0)) { // host switching
+ debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
+ return web_client_switch_host(host, w, url);
+ }
+ else if(unlikely(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0)) { // old API "data"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API data request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_data_request_json);
+ }
+ else if(unlikely(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0)) { // old API "datasource"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API datasource request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_data_request_jsonp);
+ }
+ else if(unlikely(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0)) { // old API "graph"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API graph request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_graph_request);
+ }
+ else if(unlikely(hash == hash_list && strcmp(tok, "list") == 0)) { // old API "list"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API list request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_list_request);
+ }
+ else if(unlikely(hash == hash_all_json && strcmp(tok, "all.json") == 0)) { // old API "all.json"
+ debug(D_WEB_CLIENT_ACCESS, "%llu: old API all.json request...", w->id);
+ return check_host_and_call(host, w, url, web_client_api_old_all_json);
+ }
+ else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf
+ debug(D_WEB_CLIENT_ACCESS, "%llu: generating netdata.conf ...", w->id);
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+ config_generate(w->response.data, 0);
+ return 200;
+ }
+#ifdef NETDATA_INTERNAL_CHECKS
+ else if(unlikely(hash == hash_exit && strcmp(tok, "exit") == 0)) {
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+
+ if(!netdata_exit)
+ buffer_strcat(w->response.data, "ok, will do...");
+ else
+ buffer_strcat(w->response.data, "I am doing it already");
+
+ error("web request to exit received.");
+ netdata_cleanup_and_exit(0);
+ return 200;
+ }
+ else if(unlikely(hash == hash_debug && strcmp(tok, "debug") == 0)) {
+ buffer_flush(w->response.data);
+
+ // get the name of the data to show
+ tok = mystrsep(&url, "/?&");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+
+ // do we have such a data set?
+ RRDSET *st = rrdset_find_byname(host, tok);
+ if(!st) st = rrdset_find(host, tok);
+ if(!st) {
+ w->response.data->contenttype = CT_TEXT_HTML;
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, tok);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
+ return 404;
+ }
+
+ debug_flags |= D_RRD_STATS;
+
+ if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))
+ rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
+ else
+ rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
+
+ w->response.data->contenttype = CT_TEXT_HTML;
+ buffer_sprintf(w->response.data, "Chart has now debug %s: ", rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
+ buffer_strcat_htmlescape(w->response.data, tok);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
+ return 200;
+ }
+
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "debug which chart?\r\n");
+ return 400;
+ }
+ else if(unlikely(hash == hash_mirror && strcmp(tok, "mirror") == 0)) {
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
+
+ // replace the zero bytes with spaces
+ buffer_char_replace(w->response.data, '\0', ' ');
+
+ // just leave the buffer as is
+ // it will be copied back to the client
+
+ return 200;
+ }
+#endif /* NETDATA_INTERNAL_CHECKS */
+ }
+
+ char filename[FILENAME_MAX+1];
+ url = filename;
+ strncpyz(filename, w->last_url, FILENAME_MAX);
+ tok = mystrsep(&url, "?");
+ buffer_flush(w->response.data);
+ return mysendfile(w, (tok && *tok)?tok:"/");
+}
+
+void web_client_process_request(struct web_client *w) {
+
+ // start timing us
+ now_realtime_timeval(&w->tv_in);
+
+ switch(http_request_validate(w)) {
+ case HTTP_VALIDATION_OK:
+ switch(w->mode) {
+ case WEB_CLIENT_MODE_STREAM:
+ w->response.code = rrdpush_receiver_thread_spawn(localhost, w, w->decoded_url);
+ return;
+
+ case WEB_CLIENT_MODE_OPTIONS:
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "OK");
+ w->response.code = 200;
+ break;
+
+ case WEB_CLIENT_MODE_FILECOPY:
+ case WEB_CLIENT_MODE_NORMAL:
+ w->response.code = web_client_process_url(localhost, w, w->decoded_url);
+ break;
+ }
+ break;
+
+ case HTTP_VALIDATION_INCOMPLETE:
+ if(w->response.data->len > TOO_BIG_REQUEST) {
+ strcpy(w->last_url, "too big request");
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
+
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Received request is too big (%zu bytes).\r\n", w->response.data->len);
+ w->response.code = 400;
+ }
+ else {
+ // wait for more data
+ return;
+ }
+ break;
+
+ case HTTP_VALIDATION_NOT_SUPPORTED:
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
+
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "I don't understand you...\r\n");
+ w->response.code = 400;
+ break;
+ }
+
+ // keep track of the time we done processing
+ now_realtime_timeval(&w->tv_ready);
+
+ w->response.sent = 0;
+
+ // set a proper last modified date
+ if(unlikely(!w->response.data->date))
+ w->response.data->date = w->tv_ready.tv_sec;
+
+ web_client_send_http_header(w);
// enable sending immediately if we have data
if(w->response.data->len) w->wait_send = 1;
else w->wait_send = 0;
- // pretty logging
switch(w->mode) {
+ case WEB_CLIENT_MODE_STREAM:
+ debug(D_WEB_CLIENT, "%llu: STREAM done.", w->id);
+ break;
+
case WEB_CLIENT_MODE_OPTIONS:
debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
break;
@@ -2344,7 +1297,7 @@ void web_client_process(struct web_client *w) {
break;
default:
- fatal("%llu: Unknown client mode %d.", w->id, w->mode);
+ fatal("%llu: Unknown client mode %u.", w->id, w->mode);
break;
}
}
@@ -2666,11 +1619,14 @@ void *web_client_main(void *ptr)
struct web_client *w = ptr;
struct pollfd fds[2], *ifd, *ofd;
- int retval, fdmax = 0, timeout;
+ int retval, timeout;
+ nfds_t fdmax = 0;
log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid());
for(;;) {
+ if(unlikely(netdata_exit)) break;
+
if(unlikely(w->dead)) {
debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
break;
@@ -2722,6 +1678,8 @@ void *web_client_main(void *ptr)
timeout = web_client_timeout * 1000;
retval = poll(fds, fdmax, timeout);
+ if(unlikely(netdata_exit)) break;
+
if(unlikely(retval == -1)) {
if(errno == EAGAIN || errno == EINTR) {
debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id);
@@ -2736,6 +1694,8 @@ void *web_client_main(void *ptr)
break;
}
+ if(unlikely(netdata_exit)) break;
+
int used = 0;
if(w->wait_send && ofd->revents & POLLOUT) {
used++;
@@ -2745,6 +1705,8 @@ void *web_client_main(void *ptr)
}
}
+ if(unlikely(netdata_exit)) break;
+
if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
used++;
if(web_client_receive(w) < 0) {
@@ -2754,7 +1716,12 @@ void *web_client_main(void *ptr)
if(w->mode == WEB_CLIENT_MODE_NORMAL) {
debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id);
- web_client_process(w);
+ web_client_process_request(w);
+
+ // if the sockets are closed, may have transferred this client
+ // to plugins.d
+ if(unlikely(w->mode == WEB_CLIENT_MODE_STREAM))
+ break;
}
}
diff --git a/src/web_client.h b/src/web_client.h
index 2555a0c24..70c5b1ff0 100644
--- a/src/web_client.h
+++ b/src/web_client.h
@@ -5,12 +5,20 @@
extern int web_client_timeout;
#ifdef NETDATA_WITH_ZLIB
-extern int web_enable_gzip, web_gzip_level, web_gzip_strategy, web_donotrack_comply;
+extern int web_enable_gzip,
+ web_gzip_level,
+ web_gzip_strategy;
#endif /* NETDATA_WITH_ZLIB */
-#define WEB_CLIENT_MODE_NORMAL 0
-#define WEB_CLIENT_MODE_FILECOPY 1
-#define WEB_CLIENT_MODE_OPTIONS 2
+extern int respect_web_browser_do_not_track_policy;
+extern char *web_x_frame_options;
+
+typedef enum web_client_mode {
+ WEB_CLIENT_MODE_NORMAL = 0,
+ WEB_CLIENT_MODE_FILECOPY = 1,
+ WEB_CLIENT_MODE_OPTIONS = 2,
+ WEB_CLIENT_MODE_STREAM = 3
+} WEB_CLIENT_MODE;
#define URL_MAX 8192
#define ZLIB_CHUNK 16384
@@ -50,14 +58,14 @@ struct web_client {
uint8_t keepalive:1; // if set to 1, the web client will be re-used
- uint8_t mode:3; // the operational mode of the client
-
uint8_t wait_receive:1; // 1 = we are waiting more input data
uint8_t wait_send:1; // 1 = we have data to send to the client
uint8_t donottrack:1; // 1 = we should not set cookies on this client
uint8_t tracking_required:1; // 1 = if the request requires cookies
+ WEB_CLIENT_MODE mode; // the operational mode of the client
+
int tcp_cork; // 1 = we have a cork on the socket
int ifd;
@@ -98,7 +106,7 @@ extern struct web_client *web_client_create(int listener);
extern struct web_client *web_client_free(struct web_client *w);
extern ssize_t web_client_send(struct web_client *w);
extern ssize_t web_client_receive(struct web_client *w);
-extern void web_client_process(struct web_client *w);
+extern void web_client_process_request(struct web_client *w);
extern void web_client_reset(struct web_client *w);
extern void *web_client_main(void *ptr);
@@ -107,4 +115,7 @@ extern int web_client_api_request_v1_data_group(char *name, int def);
extern const char *group_method2string(int group);
extern void buffer_data_options2string(BUFFER *wb, uint32_t options);
+
+extern int mysendfile(struct web_client *w, char *filename);
+
#endif
diff --git a/src/web_server.c b/src/web_server.c
index 8e942a59d..593a82a57 100644
--- a/src/web_server.c
+++ b/src/web_server.c
@@ -5,7 +5,8 @@ size_t listen_fds_count = 0;
int listen_fds[MAX_LISTEN_FDS] = { [0 ... 99] = -1 };
char *listen_fds_names[MAX_LISTEN_FDS] = { [0 ... 99] = NULL };
int listen_port = LISTEN_PORT;
-int web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
+
+WEB_SERVER_MODE web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
static int shown_server_socket_error = 0;
@@ -83,6 +84,29 @@ int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
}
#endif
+WEB_SERVER_MODE web_server_mode_id(const char *mode) {
+ if(!strcmp(mode, "none"))
+ return WEB_SERVER_MODE_NONE;
+ else if(!strcmp(mode, "single") || !strcmp(mode, "single-threaded"))
+ return WEB_SERVER_MODE_SINGLE_THREADED;
+ else // if(!strcmp(mode, "multi") || !strcmp(mode, "multi-threaded"))
+ return WEB_SERVER_MODE_MULTI_THREADED;
+}
+
+const char *web_server_mode_name(WEB_SERVER_MODE id) {
+ switch(id) {
+ case WEB_SERVER_MODE_NONE:
+ return "none";
+
+ case WEB_SERVER_MODE_SINGLE_THREADED:
+ return "single-threaded";
+
+ default:
+ case WEB_SERVER_MODE_MULTI_THREADED:
+ return "multi-threaded";
+ }
+}
+
int create_listen_socket4(const char *ip, int port, int listen_backlog) {
int sock;
int sockopt = 1;
@@ -316,22 +340,16 @@ static inline int bind_to_one(const char *definition, int default_port, int list
int create_listen_sockets(void) {
shown_server_socket_error = 0;
- listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
-
- if(config_exists("global", "bind socket to IP") && !config_exists("global", "bind to"))
- config_rename("global", "bind socket to IP", "bind to");
-
- if(config_exists("global", "port") && !config_exists("global", "default port"))
- config_rename("global", "port", "default port");
+ listen_backlog = (int) config_get_number(CONFIG_SECTION_WEB, "listen backlog", LISTEN_BACKLOG);
- listen_port = (int) config_get_number("global", "default port", LISTEN_PORT);
+ listen_port = (int) config_get_number(CONFIG_SECTION_WEB, "default port", LISTEN_PORT);
if(listen_port < 1 || listen_port > 65535) {
error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
- listen_port = (int) config_set_number("global", "default port", LISTEN_PORT);
+ listen_port = (int) config_set_number(CONFIG_SECTION_WEB, "default port", LISTEN_PORT);
}
debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
- char *s = config_get("global", "bind to", "*");
+ char *s = config_get(CONFIG_SECTION_WEB, "bind to", "*");
while(*s) {
char *e = s;
@@ -614,7 +632,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
- web_client_process(w);
+ web_client_process_request(w);
}
}
diff --git a/src/web_server.h b/src/web_server.h
index 93adc5b28..41dcfcf09 100644
--- a/src/web_server.h
+++ b/src/web_server.h
@@ -13,9 +13,17 @@
#define MAX_LISTEN_FDS 100
#endif
-#define WEB_SERVER_MODE_MULTI_THREADED 0
-#define WEB_SERVER_MODE_SINGLE_THREADED 1
-extern int web_server_mode;
+typedef enum web_server_mode {
+ WEB_SERVER_MODE_SINGLE_THREADED,
+ WEB_SERVER_MODE_MULTI_THREADED,
+ WEB_SERVER_MODE_NONE
+} WEB_SERVER_MODE;
+
+extern WEB_SERVER_MODE web_server_mode;
+
+extern WEB_SERVER_MODE web_server_mode_id(const char *mode);
+extern const char *web_server_mode_name(WEB_SERVER_MODE id);
+
extern void *socket_listen_main_multi_threaded(void *ptr);
extern void *socket_listen_main_single_threaded(void *ptr);
diff --git a/system/Makefile.in b/system/Makefile.in
index 749b99f4b..aa0a60e02 100644
--- a/system/Makefile.in
+++ b/system/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -15,61 +16,6 @@
@SET_MAKE@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -88,10 +34,12 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+DIST_COMMON = $(dist_noinst_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(top_srcdir)/build/subst.inc
subdir = system
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -100,38 +48,16 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_noinst_DATA) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-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 =
SOURCES =
DIST_SOURCES =
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
DATA = $(dist_noinst_DATA) $(nodist_noinst_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/build/subst.inc
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -155,7 +81,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -169,6 +99,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -312,6 +246,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu system/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu system/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -320,7 +255,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
-$(top_srcdir)/build/subst.inc $(am__empty):
+$(top_srcdir)/build/subst.inc:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -330,11 +265,11 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
-tags TAGS:
-
-ctags CTAGS:
+tags: TAGS
+TAGS:
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -471,18 +406,15 @@ uninstall-am:
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am 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-ps install-ps-am install-strip installcheck \
- installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
- pdf-am ps ps-am tags-am uninstall uninstall-am
-
-.PRECIOUS: Makefile
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am 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-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am
.in:
if sed \
diff --git a/system/netdata.service.in b/system/netdata.service.in
index e260e2738..6bbb84eb5 100644
--- a/system/netdata.service.in
+++ b/system/netdata.service.in
@@ -1,6 +1,6 @@
[Unit]
Description=Real time performance monitoring
-After=network.target httpd.service squid.service nfs-server.service mysqld.service named.service postfix.service
+After=network.target httpd.service squid.service nfs-server.service mysqld.service mysql.service named.service postfix.service
[Service]
Type=simple
diff --git a/web/Makefile.am b/web/Makefile.am
index 396cf0be8..03a487597 100644
--- a/web/Makefile.am
+++ b/web/Makefile.am
@@ -11,6 +11,7 @@ dist_web_DATA = \
dashboard.html \
dashboard.js \
dashboard_info.js \
+ dashboard_info_custom_example.js \
dashboard.css \
dashboard.slate.css \
favicon.ico \
@@ -44,7 +45,7 @@ dist_weblib_DATA = \
lib/d3-3.5.17.min.js \
lib/dygraph-combined-dd74404.js \
lib/dygraph-smooth-plotter-dd74404.js \
- lib/gauge-d5260c3.min.js \
+ lib/gauge-1.3.2.min.js \
lib/jquery-2.2.4.min.js \
lib/jquery.easypiechart-97b5824.min.js \
lib/perfect-scrollbar-0.6.15.min.js \
diff --git a/web/Makefile.in b/web/Makefile.in
index e09392e9e..9ec69e6aa 100644
--- a/web/Makefile.in
+++ b/web/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -15,61 +16,6 @@
@SET_MAKE@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -89,9 +35,14 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = web
+DIST_COMMON = $(dist_web_DATA) $(dist_webcss_DATA) $(dist_webdnt_DATA) \
+ $(dist_webfonts_DATA) $(dist_webimages_DATA) \
+ $(dist_weblib_DATA) $(dist_webold_DATA) \
+ $(dist_webwellknown_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
- $(top_srcdir)/m4/ax_c__generic.m4 \
+ $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
$(top_srcdir)/m4/ax_c_mallinfo.m4 \
$(top_srcdir)/m4/ax_c_mallopt.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
@@ -100,33 +51,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(dist_web_DATA) \
- $(dist_webcss_DATA) $(dist_webdnt_DATA) $(dist_webfonts_DATA) \
- $(dist_webimages_DATA) $(dist_weblib_DATA) $(dist_webold_DATA) \
- $(dist_webwellknown_DATA) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-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 =
SOURCES =
DIST_SOURCES =
-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/||"`;; \
@@ -162,12 +92,9 @@ DATA = $(dist_web_DATA) $(dist_webcss_DATA) $(dist_webdnt_DATA) \
$(dist_webfonts_DATA) $(dist_webimages_DATA) \
$(dist_weblib_DATA) $(dist_webold_DATA) \
$(dist_webwellknown_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -191,7 +118,11 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPMIMONITORING_CFLAGS = @IPMIMONITORING_CFLAGS@
+IPMIMONITORING_LIBS = @IPMIMONITORING_LIBS@
LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
LIBMNL_LIBS = @LIBMNL_LIBS@
LIBOBJS = @LIBOBJS@
@@ -205,6 +136,10 @@ MKDIR_P = @MKDIR_P@
NFACCT_CFLAGS = @NFACCT_CFLAGS@
NFACCT_LIBS = @NFACCT_LIBS@
OBJEXT = @OBJEXT@
+OPTIONAL_IPMIMONITORING_CFLAGS = @OPTIONAL_IPMIMONITORING_CFLAGS@
+OPTIONAL_IPMIMONITORING_LIBS = @OPTIONAL_IPMIMONITORING_LIBS@
+OPTIONAL_LIBCAP_CFLAGS = @OPTIONAL_LIBCAP_CFLAGS@
+OPTIONAL_LIBCAP_LIBS = @OPTIONAL_LIBCAP_LIBS@
OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
@@ -314,6 +249,7 @@ dist_web_DATA = \
dashboard.html \
dashboard.js \
dashboard_info.js \
+ dashboard_info_custom_example.js \
dashboard.css \
dashboard.slate.css \
favicon.ico \
@@ -347,7 +283,7 @@ dist_weblib_DATA = \
lib/d3-3.5.17.min.js \
lib/dygraph-combined-dd74404.js \
lib/dygraph-smooth-plotter-dd74404.js \
- lib/gauge-d5260c3.min.js \
+ lib/gauge-1.3.2.min.js \
lib/jquery-2.2.4.min.js \
lib/jquery.easypiechart-97b5824.min.js \
lib/perfect-scrollbar-0.6.15.min.js \
@@ -432,6 +368,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu web/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu web/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -451,11 +388,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_webDATA: $(dist_web_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webdir)" || $(MKDIR_P) "$(DESTDIR)$(webdir)"
@list='$(dist_web_DATA)'; test -n "$(webdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -472,11 +406,8 @@ uninstall-dist_webDATA:
dir='$(DESTDIR)$(webdir)'; $(am__uninstall_files_from_dir)
install-dist_webcssDATA: $(dist_webcss_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webcssdir)" || $(MKDIR_P) "$(DESTDIR)$(webcssdir)"
@list='$(dist_webcss_DATA)'; test -n "$(webcssdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webcssdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webcssdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -493,11 +424,8 @@ uninstall-dist_webcssDATA:
dir='$(DESTDIR)$(webcssdir)'; $(am__uninstall_files_from_dir)
install-dist_webdntDATA: $(dist_webdnt_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webdntdir)" || $(MKDIR_P) "$(DESTDIR)$(webdntdir)"
@list='$(dist_webdnt_DATA)'; test -n "$(webdntdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webdntdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webdntdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -514,11 +442,8 @@ uninstall-dist_webdntDATA:
dir='$(DESTDIR)$(webdntdir)'; $(am__uninstall_files_from_dir)
install-dist_webfontsDATA: $(dist_webfonts_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webfontsdir)" || $(MKDIR_P) "$(DESTDIR)$(webfontsdir)"
@list='$(dist_webfonts_DATA)'; test -n "$(webfontsdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webfontsdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webfontsdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -535,11 +460,8 @@ uninstall-dist_webfontsDATA:
dir='$(DESTDIR)$(webfontsdir)'; $(am__uninstall_files_from_dir)
install-dist_webimagesDATA: $(dist_webimages_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webimagesdir)" || $(MKDIR_P) "$(DESTDIR)$(webimagesdir)"
@list='$(dist_webimages_DATA)'; test -n "$(webimagesdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webimagesdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webimagesdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -556,11 +478,8 @@ uninstall-dist_webimagesDATA:
dir='$(DESTDIR)$(webimagesdir)'; $(am__uninstall_files_from_dir)
install-dist_weblibDATA: $(dist_weblib_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(weblibdir)" || $(MKDIR_P) "$(DESTDIR)$(weblibdir)"
@list='$(dist_weblib_DATA)'; test -n "$(weblibdir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(weblibdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(weblibdir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -577,11 +496,8 @@ uninstall-dist_weblibDATA:
dir='$(DESTDIR)$(weblibdir)'; $(am__uninstall_files_from_dir)
install-dist_weboldDATA: $(dist_webold_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webolddir)" || $(MKDIR_P) "$(DESTDIR)$(webolddir)"
@list='$(dist_webold_DATA)'; test -n "$(webolddir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webolddir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webolddir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -598,11 +514,8 @@ uninstall-dist_weboldDATA:
dir='$(DESTDIR)$(webolddir)'; $(am__uninstall_files_from_dir)
install-dist_webwellknownDATA: $(dist_webwellknown_DATA)
@$(NORMAL_INSTALL)
+ test -z "$(webwellknowndir)" || $(MKDIR_P) "$(DESTDIR)$(webwellknowndir)"
@list='$(dist_webwellknown_DATA)'; test -n "$(webwellknowndir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(webwellknowndir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(webwellknowndir)" || exit 1; \
- fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -617,11 +530,11 @@ uninstall-dist_webwellknownDATA:
@list='$(dist_webwellknown_DATA)'; test -n "$(webwellknowndir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(webwellknowndir)'; $(am__uninstall_files_from_dir)
-tags TAGS:
-
-ctags CTAGS:
+tags: TAGS
+TAGS:
-cscope cscopelist:
+ctags: CTAGS
+CTAGS:
distdir: $(DISTFILES)
@@ -766,10 +679,10 @@ uninstall-am: uninstall-dist_webDATA uninstall-dist_webcssDATA \
.MAKE: install-am install-strip
-.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
- ctags-am distclean distclean-generic distdir dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-dist_webDATA install-dist_webcssDATA \
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_webDATA install-dist_webcssDATA \
install-dist_webdntDATA install-dist_webfontsDATA \
install-dist_webimagesDATA install-dist_weblibDATA \
install-dist_weboldDATA install-dist_webwellknownDATA \
@@ -778,14 +691,11 @@ uninstall-am: uninstall-dist_webDATA uninstall-dist_webcssDATA \
install-man install-pdf install-pdf-am install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
- uninstall uninstall-am uninstall-dist_webDATA \
- uninstall-dist_webcssDATA uninstall-dist_webdntDATA \
- uninstall-dist_webfontsDATA uninstall-dist_webimagesDATA \
- uninstall-dist_weblibDATA uninstall-dist_weboldDATA \
- uninstall-dist_webwellknownDATA
-
-.PRECIOUS: Makefile
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
+ uninstall-am uninstall-dist_webDATA uninstall-dist_webcssDATA \
+ uninstall-dist_webdntDATA uninstall-dist_webfontsDATA \
+ uninstall-dist_webimagesDATA uninstall-dist_weblibDATA \
+ uninstall-dist_weboldDATA uninstall-dist_webwellknownDATA
version.txt:
diff --git a/web/dashboard.html b/web/dashboard.html
index 342374c8d..75de65ad9 100644
--- a/web/dashboard.html
+++ b/web/dashboard.html
@@ -13,7 +13,7 @@
<meta name="author" content="costa@tsaousis.gr">
<meta property="og:locale" content="en_US" />
- <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/19168687/f6a567be-8c19-11e6-8561-ce8d589e8346.gif"/>
+ <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/22945737/e98cd0c6-f2fd-11e6-96f1-5501934b0955.png"/>
<meta property="og:url" content="http://my-netdata.io/"/>
<meta property="og:type" content="website"/>
<meta property="og:site_name" content="netdata"/>
diff --git a/web/dashboard.js b/web/dashboard.js
index 6fc294204..b34accdec 100644
--- a/web/dashboard.js
+++ b/web/dashboard.js
@@ -1,35 +1,54 @@
+// ----------------------------------------------------------------------------
// You can set the following variables before loading this script:
-//
-// var netdataNoDygraphs = true; // do not use dygraph
-// var netdataNoSparklines = true; // do not use sparkline
-// var netdataNoPeitys = true; // do not use peity
-// var netdataNoGoogleCharts = true; // do not use google
-// var netdataNoMorris = true; // do not use morris
-// var netdataNoEasyPieChart = true; // do not use easy pie chart
-// var netdataNoGauge = true; // do not use gauge.js
-// var netdataNoD3 = true; // do not use D3
-// var netdataNoC3 = true; // do not use C3
-// var netdataNoBootstrap = true; // do not load bootstrap
-// var netdataDontStart = true; // do not start the thread to process the charts
-// var netdataErrorCallback = null; // Callback function that will be invoked upon error
-// var netdataRegistry = true; // Update the registry (default disabled)
-// var netdataRegistryCallback = null; // Callback function that will be invoked with one param,
-// the URLs from the registry
-// var netdataShowHelp = false; // enable/disable help (default enabled)
-// var netdataShowAlarms = true; // enable/disable alarms checks and notifications (default disabled)
-//
-// var netdataRegistryAfterMs = 1500 // the time to consult to registry on startup
-//
-// var netdataCallback = null; // a function to call when netdata is ready
-// // netdata will be running while this is called (call NETDATA.pause to stop it)
-// var netdataPrepCallback = null; // a callback to be called before netdata does anything else
-//
-// You can also set the default netdata server, using the following.
-// When this variable is not set, we assume the page is hosted on your
-// netdata server already.
-// var netdataServer = "http://yourhost:19999"; // set your NetData server
+/*global netdataNoDygraphs *//* boolean, disable dygraph charts
+ * (default: false) */
+/*global netdataNoSparklines *//* boolean, disable sparkline charts
+ * (default: false) */
+/*global netdataNoPeitys *//* boolean, disable peity charts
+ * (default: false) */
+/*global netdataNoGoogleCharts *//* boolean, disable google charts
+ * (default: false) */
+/*global netdataNoMorris *//* boolean, disable morris charts
+ * (default: false) */
+/*global netdataNoEasyPieChart *//* boolean, disable easypiechart charts
+ * (default: false) */
+/*global netdataNoGauge *//* boolean, disable gauge.js charts
+ * (default: false) */
+/*global netdataNoD3 *//* boolean, disable d3 charts
+ * (default: false) */
+/*global netdataNoC3 *//* boolean, disable c3 charts
+ * (default: false) */
+/*global netdataNoBootstrap *//* boolean, disable bootstrap - disables help too
+ * (default: false) */
+/*global netdataDontStart *//* boolean, do not start the thread to process the charts
+ * (default: false) */
+/*global netdataErrorCallback *//* function, callback to be called when the dashboard encounters an error
+ * (default: null) */
+/*global netdataRegistry:true *//* boolean, use the netdata registry
+ * (default: false) */
+/*global netdataNoRegistry *//* boolean, included only for compatibility with existing custom dashboard
+ * (obsolete - do not use this any more) */
+/*global netdataRegistryCallback *//* function, callback that will be invoked with one param: the URLs from the registry
+ * (default: null) */
+/*global netdataShowHelp:true *//* boolean, disable charts help
+ * (default: true) */
+/*global netdataShowAlarms:true *//* boolean, enable alarms checks and notifications
+ * (default: false) */
+/*global netdataRegistryAfterMs:true *//* ms, delay registry use at started
+ * (default: 1500) */
+/*global netdataCallback *//* function, callback to be called when netdata is ready to start
+ * (default: null)
+ * netdata will be running while this is called
+ * (call NETDATA.pause to stop it) */
+/*global netdataPrepCallback *//* function, callback to be called before netdata does anything else
+ * (default: null) */
+/*global netdataServer *//* string, the URL of the netdata server to use
+ * (default: the URL the page is hosted at) */
+
+// ----------------------------------------------------------------------------
// global namespace
+
var NETDATA = window.NETDATA || {};
(function(window, document) {
@@ -111,7 +130,7 @@ var NETDATA = window.NETDATA || {};
NETDATA.peity_js = NETDATA.serverDefault + 'lib/jquery.peity-3.2.0.min.js';
NETDATA.sparkline_js = NETDATA.serverDefault + 'lib/jquery.sparkline-2.1.2.min.js';
NETDATA.easypiechart_js = NETDATA.serverDefault + 'lib/jquery.easypiechart-97b5824.min.js';
- NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge-d5260c3.min.js';
+ NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge-1.3.2.min.js';
NETDATA.dygraph_js = NETDATA.serverDefault + 'lib/dygraph-combined-dd74404.js';
NETDATA.dygraph_smooth_js = NETDATA.serverDefault + 'lib/dygraph-smooth-plotter-dd74404.js';
NETDATA.raphael_js = NETDATA.serverDefault + 'lib/raphael-2.2.4-min.js';
@@ -199,6 +218,29 @@ var NETDATA = window.NETDATA || {};
if(netdataRegistry === false && typeof netdataRegistryCallback === 'function')
netdataRegistry = true;
+
+ // ----------------------------------------------------------------------------------------------------------------
+ // detect if this is probably a slow device
+
+ var isSlowDeviceResult = undefined;
+ var isSlowDevice = function() {
+ if(isSlowDeviceResult !== undefined)
+ return isSlowDeviceResult;
+
+ try {
+ var ua = navigator.userAgent.toLowerCase();
+
+ var iOS = /ipad|iphone|ipod/.test(ua) && !window.MSStream;
+ var android = /android/.test(ua) && !window.MSStream;
+ isSlowDeviceResult = (iOS === true || android === true);
+ }
+ catch (e) {
+ isSlowDeviceResult = false;
+ }
+
+ return isSlowDeviceResult;
+ };
+
// ----------------------------------------------------------------------------------------------------------------
// the defaults for all charts
@@ -214,7 +256,7 @@ var NETDATA = window.NETDATA || {};
before: 0, // panning
after: -600, // panning
pixels_per_point: 1, // the detail of the chart
- fill_luminance: 0.8 // luminance of colors in solit areas
+ fill_luminance: 0.8 // luminance of colors in solid areas
};
// ----------------------------------------------------------------------------------------------------------------
@@ -233,12 +275,12 @@ var NETDATA = window.NETDATA || {};
// new elements we have to check.
auto_refresher_fast_weight: 0, // this is the current time in ms, spent
- // rendering charts continiously.
+ // rendering charts continuously.
// used with .current.fast_render_timeframe
page_is_visible: true, // when true, this page is visible
- auto_refresher_stop_until: 0, // timestamp in ms - used internaly, to stop the
+ auto_refresher_stop_until: 0, // timestamp in ms - used internally, to stop the
// auto-refresher for some time (when a chart is
// performing pan or zoom, we need to stop refreshing
// all other charts, to have the maximum speed for
@@ -252,7 +294,7 @@ var NETDATA = window.NETDATA || {};
// the current profile
// we may have many...
current: {
- pixels_per_point: 1, // the minimum pixels per point for all charts
+ pixels_per_point: isSlowDevice()?5:1, // the minimum pixels per point for all charts
// increase this to speed javascript up
// each chart library has its own limit too
// the max of this and the chart library is used
@@ -262,7 +304,7 @@ var NETDATA = window.NETDATA || {};
idle_between_charts: 100, // ms - how much time to wait between chart updates
- fast_render_timeframe: 200, // ms - render continously until this time of continious
+ fast_render_timeframe: 200, // ms - render continuously until this time of continuous
// rendering has been reached
// this setting is used to make it render e.g. 10
// charts at once, sleep idle_between_charts time
@@ -276,8 +318,8 @@ var NETDATA = window.NETDATA || {};
idle_lost_focus: 500, // ms - when the window does not have focus, check
// if focus has been regained, every this time
- global_pan_sync_time: 1000, // ms - when you pan or zoon a chart, the background
- // autorefreshing of charts is paused for this amount
+ global_pan_sync_time: 1000, // ms - when you pan or zoom a chart, the background
+ // auto-refreshing of charts is paused for this amount
// of time
sync_selection_delay: 1500, // ms - when you pan or zoom a chart, wait this amount
@@ -294,11 +336,11 @@ var NETDATA = window.NETDATA || {};
update_only_visible: true, // enable or disable visibility management
- parallel_refresher: true, // enable parallel refresh of charts
+ parallel_refresher: (isSlowDevice() === false), // enable parallel refresh of charts
concurrent_refreshes: true, // when parallel_refresher is enabled, sync also the charts
- destroy_on_hide: false, // destroy charts when they are not visible
+ destroy_on_hide: (isSlowDevice() === true), // destroy charts when they are not visible
show_help: netdataShowHelp, // when enabled the charts will show some help
show_help_delay_show_ms: 500,
@@ -311,7 +353,7 @@ var NETDATA = window.NETDATA || {};
double_click_speed: 500, // ms - time between clicks / taps to detect double click/tap
- smooth_plot: true, // enable smooth plot, where possible
+ smooth_plot: (isSlowDevice() === false), // enable smooth plot, where possible
charts_selection_animation_delay: 50, // delay to animate charts when syncing selection
@@ -363,6 +405,28 @@ var NETDATA = window.NETDATA || {};
callback: {} // only used for resetting back to defaults
};
+ NETDATA.localStorageTested = -1;
+ NETDATA.localStorageTest = function() {
+ if(NETDATA.localStorageTested !== -1)
+ return NETDATA.localStorageTested;
+
+ if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ var test = 'test';
+ try {
+ localStorage.setItem(test, test);
+ localStorage.removeItem(test);
+ NETDATA.localStorageTested = true;
+ }
+ catch (e) {
+ NETDATA.localStorageTested = false;
+ }
+ }
+ else
+ NETDATA.localStorageTested = false;
+
+ return NETDATA.localStorageTested;
+ };
+
NETDATA.localStorageGet = function(key, def, callback) {
var ret = def;
@@ -371,7 +435,7 @@ var NETDATA = window.NETDATA || {};
NETDATA.localStorage.callback[key.toString()] = callback;
}
- if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ if(NETDATA.localStorageTest() === true) {
try {
// console.log('localStorage: loading "' + key.toString() + '"');
ret = localStorage.getItem(key.toString());
@@ -413,7 +477,7 @@ var NETDATA = window.NETDATA || {};
NETDATA.localStorage.callback[key.toString()] = callback;
}
- if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ if(NETDATA.localStorageTest() === true) {
// console.log('localStorage: saving "' + key.toString() + '" with value "' + JSON.stringify(value) + '"');
try {
localStorage.setItem(key.toString(), JSON.stringify(value));
@@ -719,7 +783,7 @@ var NETDATA = window.NETDATA || {};
// find the common min
var m = min;
for(var i in t)
- if(t[i] < m) m = t[i];
+ if(t.hasOwnProperty(i) && t[i] < m) m = t[i];
//state.log('commonMin ' + state.__commonMin + ' updated: ' + m);
this.latest[name] = m;
@@ -774,7 +838,7 @@ var NETDATA = window.NETDATA || {};
// find the common max
var m = max;
for(var i in t)
- if(t[i] > m) m = t[i];
+ if(t.hasOwnProperty(i) && t[i] > m) m = t[i];
//state.log('commonMax ' + state.__commonMax + ' updated: ' + m);
this.latest[name] = m;
@@ -873,8 +937,8 @@ var NETDATA = window.NETDATA || {};
// every time a chart is panned or zoomed
// we set the timestamp here
// then we use it as a sequence number
- // to find if other charts are syncronized
- // to this timerange
+ // to find if other charts are synchronized
+ // to this time-range
master: null, // the master chart (state), to which all others
// are synchronized
@@ -924,14 +988,12 @@ var NETDATA = window.NETDATA || {};
// is the given state the master of the global
// pan and zoom sync?
isMaster: function(state) {
- if(this.master === state) return true;
- return false;
+ return (this.master === state);
},
// are we currently have a global pan and zoom sync?
isActive: function() {
- if(this.master !== null && this.force_before_ms !== null && this.force_after_ms !== null && this.seq !== 0) return true;
- return false;
+ return (this.master !== null && this.force_before_ms !== null && this.force_after_ms !== null && this.seq !== 0);
},
// check if a chart, other than the master
@@ -943,10 +1005,7 @@ var NETDATA = window.NETDATA || {};
//if(state.needsRecreation())
// return true;
- if(state.tm.pan_and_zoom_seq === this.seq)
- return false;
-
- return true;
+ return (state.tm.pan_and_zoom_seq !== this.seq);
}
};
@@ -956,18 +1015,14 @@ var NETDATA = window.NETDATA || {};
// FIXME
// move color assignment to dimensions, here
- dimensionStatus = function(parent, label, name_div, value_div, color) {
+ var dimensionStatus = function(parent, label, name_div, value_div, color) {
this.enabled = false;
this.parent = parent;
this.label = label;
this.name_div = null;
this.value_div = null;
this.color = NETDATA.themes.current.foreground;
-
- if(parent.unselected_count === 0)
- this.selected = true;
- else
- this.selected = false;
+ this.selected = (parent.unselected_count === 0);
this.setOptions(name_div, value_div, color);
};
@@ -1072,7 +1127,7 @@ var NETDATA = window.NETDATA || {};
// ----------------------------------------------------------------------------------------------------------------
- dimensionsVisibility = function(state) {
+ var dimensionsVisibility = function(state) {
this.state = state;
this.len = 0;
this.dimensions = {};
@@ -1127,7 +1182,7 @@ var NETDATA = window.NETDATA || {};
};
dimensionsVisibility.prototype.selected2BooleanArray = function(array) {
- var ret = new Array();
+ var ret = [];
this.selected_count = 0;
this.unselected_count = 0;
@@ -1181,7 +1236,7 @@ var NETDATA = window.NETDATA || {};
// ----------------------------------------------------------------------------------------------------------------
// Our state object, where all per-chart values are stored
- chartState = function(element) {
+ var chartState = function(element) {
var self = $(element);
this.element = element;
@@ -1292,7 +1347,6 @@ var NETDATA = window.NETDATA || {};
this.override_options = self.data('override-options') || null; // override options to pass to netdata
this.running = false; // boolean - true when the chart is being refreshed now
- this.validated = false; // boolean - has the chart been validated?
this.enabled = true; // boolean - is the chart enabled for refresh?
this.paused = false; // boolean - is the chart paused for any reason?
this.selected = false; // boolean - is the chart shown a selection?
@@ -1309,9 +1363,7 @@ var NETDATA = window.NETDATA || {};
this.value_decimal_detail = -1;
var d = self.data('decimal-digits');
if(typeof d === 'number') {
- this.value_decimal_detail = 1;
- while(d-- > 0)
- this.value_decimal_detail *= 10;
+ this.value_decimal_detail = d;
}
this.auto = {
@@ -1363,8 +1415,9 @@ var NETDATA = window.NETDATA || {};
// find the element that needs to be updated
var refresh_dt_element_name = self.data('dt-element-name') || null; // string - the element to print refresh_dt_ms
- if(refresh_dt_element_name !== null)
+ if(refresh_dt_element_name !== null) {
this.refresh_dt_element = document.getElementById(refresh_dt_element_name) || null;
+ }
else
this.refresh_dt_element = null;
@@ -1555,10 +1608,7 @@ var NETDATA = window.NETDATA || {};
};
var isHidden = function() {
- if(typeof that.___chartIsHidden___ !== 'undefined')
- return true;
-
- return false;
+ return (typeof that.___chartIsHidden___ !== 'undefined');
};
// hide the chart, when it is not visible - called from isVisible()
@@ -1610,10 +1660,7 @@ var NETDATA = window.NETDATA || {};
};
var canBeRendered = function() {
- if(isHidden() === true || that.isVisible(true) === false)
- return false;
-
- return true;
+ return (isHidden() === false && that.isVisible(true) === true);
};
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
@@ -1825,6 +1872,8 @@ var NETDATA = window.NETDATA || {};
this.element_legend_childs.resize_handler.onmouseup =
this.element_legend_childs.resize_handler.ontouchend =
function(e) {
+ void(e);
+
// remove all the hooks
document.onmouseup =
document.onmousemove =
@@ -1899,10 +1948,7 @@ var NETDATA = window.NETDATA || {};
if(NETDATA.options.current.sync_selection === false)
return false;
- if(NETDATA.globalSelectionSync.dont_sync_before > Date.now())
- return false;
-
- return true;
+ return (NETDATA.globalSelectionSync.dont_sync_before <= Date.now());
};
this.globalSelectionSyncIsMaster = function() {
@@ -1937,7 +1983,7 @@ var NETDATA = window.NETDATA || {};
var targets = NETDATA.options.targets;
var len = targets.length;
while(len--) {
- st = targets[len];
+ var st = targets[len];
if(st === this) {
if(this.debug === true)
@@ -1956,14 +2002,11 @@ var NETDATA = window.NETDATA || {};
// can the chart participate to the global selection sync as a slave?
this.globalSelectionSyncIsEligible = function() {
- if(this.enabled === true
+ return (this.enabled === true
&& this.library !== null
&& typeof this.library.setSelection === 'function'
&& this.isVisible() === true
- && this.chart_created === true)
- return true;
-
- return false;
+ && this.chart_created === true);
};
// this chart becomes a slave of the global selection sync
@@ -2022,13 +2065,10 @@ var NETDATA = window.NETDATA || {};
};
this.setSelection = function(t) {
- if(typeof this.library.setSelection === 'function') {
- if(this.library.setSelection(this, t) === true)
- this.selected = true;
- else
- this.selected = false;
- }
- else this.selected = true;
+ if(typeof this.library.setSelection === 'function')
+ this.selected = (this.library.setSelection(this, t) === true);
+ else
+ this.selected = true;
if(this.selected === true && this.debug === true)
this.log('selection set to ' + t.toString());
@@ -2038,13 +2078,10 @@ var NETDATA = window.NETDATA || {};
this.clearSelection = function() {
if(this.selected === true) {
- if(typeof this.library.clearSelection === 'function') {
- if(this.library.clearSelection(this) === true)
- this.selected = false;
- else
- this.selected = true;
- }
- else this.selected = false;
+ if(typeof this.library.clearSelection === 'function')
+ this.selected = (this.library.clearSelection(this) !== true);
+ else
+ this.selected = false;
if(this.selected === false && this.debug === true)
this.log('selection cleared');
@@ -2057,9 +2094,7 @@ var NETDATA = window.NETDATA || {};
// find if a timestamp (ms) is shown in the current chart
this.timeIsVisible = function(t) {
- if(t >= this.data_after && t <= this.data_before)
- return true;
- return false;
+ return (t >= this.data_after && t <= this.data_before);
};
this.calculateRowForTime = function(t) {
@@ -2210,19 +2245,69 @@ var NETDATA = window.NETDATA || {};
return ret;
};
+ var __legendFormatValueChartDecimalsLastMin = undefined;
+ var __legendFormatValueChartDecimalsLastMax = undefined;
+ var __legendFormatValueChartDecimals = -1;
+ this.legendFormatValueDecimalsFromMinMax = function(min, max) {
+ if(min === __legendFormatValueChartDecimalsLastMin && max === __legendFormatValueChartDecimalsLastMax)
+ return;
+
+ __legendFormatValueChartDecimalsLastMin = min;
+ __legendFormatValueChartDecimalsLastMax = max;
+
+ if(this.data !== null && this.data.min === this.data.max)
+ __legendFormatValueChartDecimals = -1;
+
+ else if(this.value_decimal_detail !== -1)
+ __legendFormatValueChartDecimals = this.value_decimal_detail;
+
+ else {
+ var delta;
+
+ if (min === max)
+ delta = Math.abs(min);
+ else
+ delta = Math.abs(max - min);
+
+ if (delta > 1000) __legendFormatValueChartDecimals = 0;
+ else if (delta > 10) __legendFormatValueChartDecimals = 1;
+ else if (delta > 1) __legendFormatValueChartDecimals = 2;
+ else if (delta > 0.1) __legendFormatValueChartDecimals = 2;
+ else __legendFormatValueChartDecimals = 4;
+ }
+ };
+
this.legendFormatValue = function(value) {
- if(value === null || value === 'undefined') return '-';
- if(typeof value !== 'number') return value;
-
- if(this.value_decimal_detail !== -1)
- return (Math.round(value * this.value_decimal_detail) / this.value_decimal_detail).toLocaleString();
-
- var abs = Math.abs(value);
- if(abs >= 1000) return (Math.round(value)).toLocaleString();
- if(abs >= 100 ) return (Math.round(value * 10) / 10).toLocaleString();
- if(abs >= 1 ) return (Math.round(value * 100) / 100).toLocaleString();
- if(abs >= 0.1 ) return (Math.round(value * 1000) / 1000).toLocaleString();
- return (Math.round(value * 10000) / 10000).toLocaleString();
+ if(typeof value !== 'number') return '-';
+
+ var dmin, dmax;
+
+ if(__legendFormatValueChartDecimals < 0) {
+ dmin = 0;
+ var abs = value;
+ if(abs > 1000) dmax = 0;
+ else if(abs > 10 ) dmax = 1;
+ else if(abs > 1) dmax = 2;
+ else if(abs > 0.1) dmax = 2;
+ else dmax = 4;
+ }
+ else {
+ dmin = dmax = __legendFormatValueChartDecimals;
+ }
+
+ if(this.value_decimal_detail !== -1) {
+ dmin = dmax = this.value_decimal_detail;
+ }
+
+ return value.toLocaleString(undefined, {
+ // style: 'decimal',
+ // minimumIntegerDigits: 1,
+ // minimumSignificantDigits: 1,
+ // maximumSignificantDigits: 1,
+ useGrouping: true,
+ minimumFractionDigits: dmin,
+ maximumFractionDigits: dmax
+ });
};
this.legendSetLabelValue = function(label, value) {
@@ -2292,33 +2377,44 @@ var NETDATA = window.NETDATA || {};
}
};
+ this.legendSetDateLast = {
+ ms: 0,
+ date: undefined,
+ time: undefined
+ };
+
this.legendSetDate = function(ms) {
if(typeof ms !== 'number') {
this.legendShowUndefined();
return;
}
- var d = new Date(ms);
+ if(this.legendSetDateLast.ms !== ms) {
+ var d = new Date(ms);
+ this.legendSetDateLast.ms = ms;
+ this.legendSetDateLast.date = d.toLocaleDateString();
+ this.legendSetDateLast.time = d.toLocaleTimeString();
+ }
- if(this.element_legend_childs.title_date)
- this.__legendSetDateString(d.toLocaleDateString());
+ if(this.element_legend_childs.title_date !== null)
+ this.__legendSetDateString(this.legendSetDateLast.date);
- if(this.element_legend_childs.title_time)
- this.__legendSetTimeString(d.toLocaleTimeString());
+ if(this.element_legend_childs.title_time !== null)
+ this.__legendSetTimeString(this.legendSetDateLast.time);
- if(this.element_legend_childs.title_units)
+ if(this.element_legend_childs.title_units !== null)
this.__legendSetUnitsString(this.units)
};
this.legendShowUndefined = function() {
- if(this.element_legend_childs.title_date)
+ if(this.element_legend_childs.title_date !== null)
this.__legendSetDateString(' ');
- if(this.element_legend_childs.title_time)
+ if(this.element_legend_childs.title_time !== null)
this.__legendSetTimeString(this.chart.name);
- if(this.element_legend_childs.title_units)
- this.__legendSetUnitsString(' ')
+ if(this.element_legend_childs.title_units !== null)
+ this.__legendSetUnitsString(' ');
if(this.data && this.element_legend_childs.series !== null) {
var labels = this.data.dimension_names;
@@ -2326,8 +2422,7 @@ var NETDATA = window.NETDATA || {};
while(i--) {
var label = labels[i];
- if(typeof label === 'undefined') continue;
- if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
+ if(typeof label === 'undefined' || typeof this.element_legend_childs.series[label] === 'undefined') continue;
this.legendSetLabelValue(label, null);
}
}
@@ -2400,8 +2495,8 @@ var NETDATA = window.NETDATA || {};
this.chartColors = function() {
if(this.colors !== null) return this.colors;
- this.colors = new Array();
- this.colors_available = new Array();
+ this.colors = [];
+ this.colors_available = [];
// add the standard colors
var len = NETDATA.themes.current.colors.length;
@@ -2526,7 +2621,7 @@ var NETDATA = window.NETDATA || {};
+ state.chart.chart_type
+ '" style="background-color: '
+ 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current['color_fill_opacity_' + state.chart.chart_type] + ')'
- + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>'
+ + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>';
var text = document.createTextNode(' ' + name);
label.name.appendChild(text);
@@ -2739,16 +2834,19 @@ var NETDATA = window.NETDATA || {};
this.element_legend_childs.title_date.className += " netdata-legend-title-date";
this.element_legend.appendChild(this.element_legend_childs.title_date);
+ this.__last_shown_legend_date = undefined;
this.element_legend.appendChild(document.createElement('br'));
this.element_legend_childs.title_time.className += " netdata-legend-title-time";
this.element_legend.appendChild(this.element_legend_childs.title_time);
+ this.__last_shown_legend_time = undefined;
this.element_legend.appendChild(document.createElement('br'));
this.element_legend_childs.title_units.className += " netdata-legend-title-units";
this.element_legend.appendChild(this.element_legend_childs.title_units);
+ this.__last_shown_legend_units = undefined;
this.element_legend.appendChild(document.createElement('br'));
@@ -2767,7 +2865,7 @@ var NETDATA = window.NETDATA || {};
placement: 'bottom',
title: 'Chart Legend',
delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
- content: 'You can click or tap on the values or the labels to select dimentions. By pressing SHIFT or CONTROL, you can enable or disable multiple dimensions.<br/><small>Help, can be disabled from the settings.</small>'
+ content: 'You can click or tap on the values or the labels to select dimensions. By pressing SHIFT or CONTROL, you can enable or disable multiple dimensions.<br/><small>Help, can be disabled from the settings.</small>'
});
}
else {
@@ -2799,7 +2897,7 @@ var NETDATA = window.NETDATA || {};
}
}
else {
- var tmp = new Array();
+ var tmp = [];
keys = Object.keys(this.chart.dimensions);
for(i = 0, len = keys.length; i < len ;i++) {
dim = keys[i];
@@ -3004,12 +3102,12 @@ var NETDATA = window.NETDATA || {};
if(NETDATA.options.current.pan_and_zoom_data_padding === true && this.requested_padding !== null) {
if(this.view_after < this.data_after) {
- // console.log('adusting view_after from ' + this.view_after + ' to ' + this.data_after);
+ // console.log('adjusting view_after from ' + this.view_after + ' to ' + this.data_after);
this.view_after = this.data_after;
}
if(this.view_before > this.data_before) {
- // console.log('adusting view_before from ' + this.view_before + ' to ' + this.data_before);
+ // console.log('adjusting view_before from ' + this.view_before + ' to ' + this.data_before);
this.view_before = this.data_before;
}
}
@@ -3041,7 +3139,8 @@ var NETDATA = window.NETDATA || {};
if(this.debug === true)
this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
- this.chart_created = false;
+ init();
+ return;
}
// check and update the legend
@@ -3582,10 +3681,10 @@ var NETDATA = window.NETDATA || {};
// ----------------------------------------------------------------------------------------------------------------
- // this is purely sequencial charts refresher
+ // this is purely sequential charts refresher
// it is meant to be autonomous
NETDATA.chartRefresherNoParallel = function(index) {
- if(NETDATA.options.debug.mail_loop === true)
+ if(NETDATA.options.debug.main_loop === true)
console.log('NETDATA.chartRefresherNoParallel(' + index + ')');
if(NETDATA.options.updated_dom === true) {
@@ -3628,41 +3727,11 @@ var NETDATA = window.NETDATA || {};
}
};
- // this is part of the parallel refresher
- // its cause is to refresh sequencially all the charts
- // that depend on chart library initialization
- // it will call the parallel refresher back
- // as soon as it sees a chart that its chart library
- // is initialized
- NETDATA.chartRefresher_uninitialized = function() {
- if(NETDATA.options.updated_dom === true) {
- // the dom has been updated
- // get the dom parts again
- NETDATA.parseDom(NETDATA.chartRefresher);
- return;
- }
-
- if(NETDATA.options.sequencial.length === 0)
- NETDATA.chartRefresher();
- else {
- var state = NETDATA.options.sequencial.pop();
- if(state.library.initialized === true)
- NETDATA.chartRefresher();
- else
- state.autoRefresh(NETDATA.chartRefresher_uninitialized);
- }
- };
-
NETDATA.chartRefresherWaitTime = function() {
return NETDATA.options.current.idle_parallel_loops;
};
// the default refresher
- // it will create 2 sets of charts:
- // - the ones that can be refreshed in parallel
- // - the ones that depend on something else
- // the first set will be executed in parallel
- // the second will be given to NETDATA.chartRefresher_uninitialized()
NETDATA.chartRefresher = function() {
// console.log('auto-refresher...');
@@ -3695,7 +3764,7 @@ var NETDATA = window.NETDATA || {};
return;
}
- var parallel = new Array();
+ var parallel = [];
var targets = NETDATA.options.targets;
var len = targets.length;
var state;
@@ -3742,7 +3811,7 @@ var NETDATA = window.NETDATA || {};
if(NETDATA.options.debug.main_loop === true)
console.log('DOM updated - there are ' + targets.length + ' charts on page.');
- NETDATA.options.targets = new Array();
+ NETDATA.options.targets = [];
var len = targets.length;
while(len--) {
// the initialization will take care of sizing
@@ -3788,12 +3857,14 @@ var NETDATA = window.NETDATA || {};
$('a[data-toggle="tab"]').on('shown.bs.tab', NETDATA.onscroll);
// bootstrap modal switching
- $('.modal').on('hidden.bs.modal', NETDATA.onscroll);
- $('.modal').on('shown.bs.modal', NETDATA.onscroll);
+ var $modal = $('.modal');
+ $modal.on('hidden.bs.modal', NETDATA.onscroll);
+ $modal.on('shown.bs.modal', NETDATA.onscroll);
// bootstrap collapse switching
- $('.collapse').on('hidden.bs.collapse', NETDATA.onscroll);
- $('.collapse').on('shown.bs.collapse', NETDATA.onscroll);
+ var $collapse = $('.collapse');
+ $collapse.on('hidden.bs.collapse', NETDATA.onscroll);
+ $collapse.on('shown.bs.collapse', NETDATA.onscroll);
NETDATA.parseDom(NETDATA.chartRefresher);
@@ -4053,7 +4124,7 @@ var NETDATA = window.NETDATA || {};
return true;
};
- NETDATA.dygraphClearSelection = function(state, t) {
+ NETDATA.dygraphClearSelection = function(state) {
if(typeof state.dygraph_instance !== 'undefined') {
state.dygraph_instance.clearSelection();
}
@@ -4200,125 +4271,205 @@ var NETDATA = window.NETDATA || {};
var self = $(state.element);
- var chart_type = state.chart.chart_type;
+ var chart_type = self.data('dygraph-type') || state.chart.chart_type;
if(chart_type === 'stacked' && data.dimensions === 1) chart_type = 'area';
- chart_type = self.data('dygraph-type') || chart_type;
-
- var smooth = (chart_type === 'line' && !NETDATA.chartLibraries.dygraph.isSparkline(state))?true:false;
- smooth = self.data('dygraph-smooth') || smooth;
- if(NETDATA.dygraph.smooth === false)
- smooth = false;
+ var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state) === true)?3:4;
- var strokeWidth = (chart_type === 'stacked')?0.1:((smooth)?1.5:0.7)
- var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state))?3:4;
+ var smooth = (NETDATA.dygraph.smooth === true)
+ ?(self.data('dygraph-smooth') || (chart_type === 'line' && NETDATA.chartLibraries.dygraph.isSparkline(state) === false))
+ :false;
state.dygraph_options = {
- colors: self.data('dygraph-colors') || state.chartColors(),
+ colors: self.data('dygraph-colors') || state.chartColors(),
// leave a few pixels empty on the right of the chart
- rightGap: self.data('dygraph-rightgap') || 5,
- showRangeSelector: self.data('dygraph-showrangeselector') || false,
- showRoller: self.data('dygraph-showroller') || false,
-
- title: self.data('dygraph-title') || state.title,
- titleHeight: self.data('dygraph-titleheight') || 19,
-
- legend: self.data('dygraph-legend') || 'always', // we need this to get selection events
- labels: data.result.labels,
- labelsDiv: self.data('dygraph-labelsdiv') || state.element_legend_childs.hidden,
- labelsDivStyles: self.data('dygraph-labelsdivstyles') || { 'fontSize':'1px' },
- labelsDivWidth: self.data('dygraph-labelsdivwidth') || state.chartWidth() - 70,
- labelsSeparateLines: self.data('dygraph-labelsseparatelines') || true,
- labelsShowZeroValues: self.data('dygraph-labelsshowzerovalues') || true,
- labelsKMB: false,
- labelsKMG2: false,
- showLabelsOnHighlight: self.data('dygraph-showlabelsonhighlight') || true,
- hideOverlayOnMouseOut: self.data('dygraph-hideoverlayonmouseout') || true,
-
- includeZero: self.data('dygraph-includezero') || ((chart_type === 'stacked')? true : false),
- xRangePad: self.data('dygraph-xrangepad') || 0,
- yRangePad: self.data('dygraph-yrangepad') || 1,
-
- valueRange: self.data('dygraph-valuerange') || [ null, null ],
-
- ylabel: state.units,
- yLabelWidth: self.data('dygraph-ylabelwidth') || 12,
-
- // the function to plot the chart
- plotter: null,
-
- // The width of the lines connecting data points. This can be used to increase the contrast or some graphs.
- strokeWidth: self.data('dygraph-strokewidth') || strokeWidth,
- strokePattern: self.data('dygraph-strokepattern') || undefined,
-
- // The size of the dot to draw on each point in pixels (see drawPoints). A dot is always drawn when a point is "isolated",
- // i.e. there is a missing point on either side of it. This also controls the size of those dots.
- drawPoints: self.data('dygraph-drawpoints') || false,
-
- // Draw points at the edges of gaps in the data. This improves visibility of small data segments or other data irregularities.
- drawGapEdgePoints: self.data('dygraph-drawgapedgepoints') || true,
-
- connectSeparatedPoints: self.data('dygraph-connectseparatedpoints') || false,
- pointSize: self.data('dygraph-pointsize') || 1,
-
- // enabling this makes the chart with little square lines
- stepPlot: self.data('dygraph-stepplot') || false,
-
- // Draw a border around graph lines to make crossing lines more easily distinguishable. Useful for graphs with many lines.
- strokeBorderColor: self.data('dygraph-strokebordercolor') || NETDATA.themes.current.background,
- strokeBorderWidth: self.data('dygraph-strokeborderwidth') || (chart_type === 'stacked')?0.0:0.0,
-
- fillGraph: self.data('dygraph-fillgraph') || ((chart_type === 'area' || chart_type === 'stacked')?true:false),
- fillAlpha: self.data('dygraph-fillalpha') || ((chart_type === 'stacked')?NETDATA.options.current.color_fill_opacity_stacked:NETDATA.options.current.color_fill_opacity_area),
- stackedGraph: self.data('dygraph-stackedgraph') || ((chart_type === 'stacked')?true:false),
- stackedGraphNaNFill: self.data('dygraph-stackedgraphnanfill') || 'none',
-
- drawAxis: self.data('dygraph-drawaxis') || true,
- axisLabelFontSize: self.data('dygraph-axislabelfontsize') || 10,
- axisLineColor: self.data('dygraph-axislinecolor') || NETDATA.themes.current.axis,
- axisLineWidth: self.data('dygraph-axislinewidth') || 1.0,
-
- drawGrid: self.data('dygraph-drawgrid') || true,
- gridLinePattern: self.data('dygraph-gridlinepattern') || null,
- gridLineWidth: self.data('dygraph-gridlinewidth') || 1.0,
- gridLineColor: self.data('dygraph-gridlinecolor') || NETDATA.themes.current.grid,
-
- maxNumberWidth: self.data('dygraph-maxnumberwidth') || 8,
- sigFigs: self.data('dygraph-sigfigs') || null,
- digitsAfterDecimal: self.data('dygraph-digitsafterdecimal') || 2,
- valueFormatter: self.data('dygraph-valueformatter') || function(x){ return x.toFixed(2); },
-
- highlightCircleSize: self.data('dygraph-highlightcirclesize') || highlightCircleSize,
- highlightSeriesOpts: self.data('dygraph-highlightseriesopts') || null, // TOO SLOW: { strokeWidth: 1.5 },
- highlightSeriesBackgroundAlpha: self.data('dygraph-highlightseriesbackgroundalpha') || null, // TOO SLOW: (chart_type === 'stacked')?0.7:0.5,
-
- pointClickCallback: self.data('dygraph-pointclickcallback') || undefined,
- visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names),
+ rightGap: self.data('dygraph-rightgap')
+ || 5,
+
+ showRangeSelector: self.data('dygraph-showrangeselector')
+ || false,
+
+ showRoller: self.data('dygraph-showroller')
+ || false,
+
+ title: self.data('dygraph-title')
+ || state.title,
+
+ titleHeight: self.data('dygraph-titleheight')
+ || 19,
+
+ legend: self.data('dygraph-legend')
+ || 'always', // we need this to get selection events
+
+ labels: data.result.labels,
+
+ labelsDiv: self.data('dygraph-labelsdiv')
+ || state.element_legend_childs.hidden,
+
+ labelsDivStyles: self.data('dygraph-labelsdivstyles')
+ || { 'fontSize':'1px' },
+
+ labelsDivWidth: self.data('dygraph-labelsdivwidth')
+ || state.chartWidth() - 70,
+
+ labelsSeparateLines: self.data('dygraph-labelsseparatelines')
+ || true,
+
+ labelsShowZeroValues: self.data('dygraph-labelsshowzerovalues')
+ || true,
+
+ labelsKMB: false,
+ labelsKMG2: false,
+
+ showLabelsOnHighlight: self.data('dygraph-showlabelsonhighlight')
+ || true,
+
+ hideOverlayOnMouseOut: self.data('dygraph-hideoverlayonmouseout')
+ || true,
+
+ includeZero: self.data('dygraph-includezero')
+ || (chart_type === 'stacked'),
+
+ xRangePad: self.data('dygraph-xrangepad')
+ || 0,
+
+ yRangePad: self.data('dygraph-yrangepad')
+ || 1,
+
+ valueRange: self.data('dygraph-valuerange')
+ || [ null, null ],
+
+ ylabel: state.units,
+
+ yLabelWidth: self.data('dygraph-ylabelwidth')
+ || 12,
+
+ // the function to plot the chart
+ plotter: null,
+
+ // The width of the lines connecting data points.
+ // This can be used to increase the contrast or some graphs.
+ strokeWidth: self.data('dygraph-strokewidth')
+ || ((chart_type === 'stacked')?0.1:((smooth === true)?1.5:0.7)),
+
+ strokePattern: self.data('dygraph-strokepattern')
+ || undefined,
+
+ // The size of the dot to draw on each point in pixels (see drawPoints).
+ // A dot is always drawn when a point is "isolated",
+ // i.e. there is a missing point on either side of it.
+ // This also controls the size of those dots.
+ drawPoints: self.data('dygraph-drawpoints')
+ || false,
+
+ // Draw points at the edges of gaps in the data.
+ // This improves visibility of small data segments or other data irregularities.
+ drawGapEdgePoints: self.data('dygraph-drawgapedgepoints')
+ || true,
+
+ connectSeparatedPoints: self.data('dygraph-connectseparatedpoints')
+ || false,
+
+ pointSize: self.data('dygraph-pointsize')
+ || 1,
+
+ // enabling this makes the chart with little square lines
+ stepPlot: self.data('dygraph-stepplot')
+ || false,
+
+ // Draw a border around graph lines to make crossing lines more easily
+ // distinguishable. Useful for graphs with many lines.
+ strokeBorderColor: self.data('dygraph-strokebordercolor')
+ || NETDATA.themes.current.background,
+
+ strokeBorderWidth: self.data('dygraph-strokeborderwidth')
+ || (chart_type === 'stacked')?0.0:0.0,
+
+ fillGraph: self.data('dygraph-fillgraph')
+ || (chart_type === 'area' || chart_type === 'stacked'),
+
+ fillAlpha: self.data('dygraph-fillalpha')
+ || ((chart_type === 'stacked')
+ ?NETDATA.options.current.color_fill_opacity_stacked
+ :NETDATA.options.current.color_fill_opacity_area),
+
+ stackedGraph: self.data('dygraph-stackedgraph')
+ || (chart_type === 'stacked'),
+
+ stackedGraphNaNFill: self.data('dygraph-stackedgraphnanfill')
+ || 'none',
+
+ drawAxis: self.data('dygraph-drawaxis')
+ || true,
+
+ axisLabelFontSize: self.data('dygraph-axislabelfontsize')
+ || 10,
+
+ axisLineColor: self.data('dygraph-axislinecolor')
+ || NETDATA.themes.current.axis,
+
+ axisLineWidth: self.data('dygraph-axislinewidth')
+ || 1.0,
+
+ drawGrid: self.data('dygraph-drawgrid')
+ || true,
+
+ gridLinePattern: self.data('dygraph-gridlinepattern')
+ || null,
+
+ gridLineWidth: self.data('dygraph-gridlinewidth')
+ || 1.0,
+
+ gridLineColor: self.data('dygraph-gridlinecolor')
+ || NETDATA.themes.current.grid,
+
+ maxNumberWidth: self.data('dygraph-maxnumberwidth')
+ || 8,
+
+ sigFigs: self.data('dygraph-sigfigs')
+ || null,
+
+ digitsAfterDecimal: self.data('dygraph-digitsafterdecimal')
+ || 2,
+
+ valueFormatter: self.data('dygraph-valueformatter')
+ || undefined,
+
+ highlightCircleSize: self.data('dygraph-highlightcirclesize')
+ || highlightCircleSize,
+
+ highlightSeriesOpts: self.data('dygraph-highlightseriesopts')
+ || null, // TOO SLOW: { strokeWidth: 1.5 },
+
+ highlightSeriesBackgroundAlpha: self.data('dygraph-highlightseriesbackgroundalpha')
+ || null, // TOO SLOW: (chart_type === 'stacked')?0.7:0.5,
+
+ pointClickCallback: self.data('dygraph-pointclickcallback')
+ || undefined,
+
+ visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names),
+
axes: {
x: {
pixelsPerLabel: 50,
ticker: Dygraph.dateTicker,
axisLabelFormatter: function (d, gran) {
+ void(gran);
return NETDATA.zeropad(d.getHours()) + ":" + NETDATA.zeropad(d.getMinutes()) + ":" + NETDATA.zeropad(d.getSeconds());
- },
- valueFormatter: function (ms) {
- //var d = new Date(ms);
- //return d.toLocaleDateString() + ' ' + d.toLocaleTimeString();
-
- // no need to return anything here
- return ' ';
-
}
},
y: {
pixelsPerLabel: 15,
- valueFormatter: function (x) {
- // we format legends with the state object
- // no need to do anything here
- // return (Math.round(x*100) / 100).toLocaleString();
- // return state.legendFormatValue(x);
- return x;
+ axisLabelFormatter: function (y) {
+
+ // unfortunately, we have to call this every single time
+ state.legendFormatValueDecimalsFromMinMax(
+ this.axes_[0].extremeRange[0],
+ this.axes_[0].extremeRange[1]
+ );
+
+ return state.legendFormatValue(y);
}
}
},
@@ -4359,6 +4510,8 @@ var NETDATA = window.NETDATA || {};
}
},
zoomCallback: function(minDate, maxDate, yRanges) {
+ void(yRanges);
+
if(NETDATA.options.debug.dygraph === true)
state.log('dygraphZoomCallback()');
@@ -4372,6 +4525,8 @@ var NETDATA = window.NETDATA || {};
state.updateChartPanOrZoom(minDate, maxDate);
},
highlightCallback: function(event, x, points, row, seriesName) {
+ void(seriesName);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('dygraphHighlightCallback()');
@@ -4381,7 +4536,7 @@ var NETDATA = window.NETDATA || {};
// the time it thinks is selected is wrong
// here we calculate the time t based on the row number selected
// which is ok
- var t = state.data_after + row * state.data_update_every;
+ // var t = state.data_after + row * state.data_update_every;
// console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t === x)?'SAME':(Math.abs(x-t)<=state.data_update_every)?'SIMILAR':'DIFFERENT') + ', rows in db: ' + state.data_points + ' visible(x) = ' + state.timeIsVisible(x) + ' visible(t) = ' + state.timeIsVisible(t) + ' r(x) = ' + state.calculateRowForTime(x) + ' r(t) = ' + state.calculateRowForTime(t) + ' range: ' + state.data_after + ' - ' + state.data_before + ' real: ' + state.data.after + ' - ' + state.data.before + ' every: ' + state.data_update_every);
state.globalSelectionSync(x);
@@ -4391,6 +4546,8 @@ var NETDATA = window.NETDATA || {};
// state.dygraph_instance.plugins_[0].plugin.legend_div_.style.zIndex = 10000;
},
unhighlightCallback: function(event) {
+ void(event);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('dygraphUnhighlightCallback()');
@@ -4474,17 +4631,26 @@ var NETDATA = window.NETDATA || {};
}
},
click: function(event, dygraph, context) {
+ void(dygraph);
+ void(context);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('interactionModel.click()');
event.preventDefault();
},
dblclick: function(event, dygraph, context) {
+ void(event);
+ void(dygraph);
+ void(context);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('interactionModel.dblclick()');
NETDATA.resetAllCharts(state);
},
wheel: function(event, dygraph, context) {
+ void(context);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('interactionModel.wheel()');
@@ -4496,7 +4662,7 @@ var NETDATA = window.NETDATA || {};
var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
var yar0 = g.yAxisRange(0);
- // This is calculating the pixel of the higest value. (Top pixel)
+ // This is calculating the pixel of the highest value. (Top pixel)
var yOffset = g.toDomCoords(null, yar0[1])[1];
// x y w and h are relative to the corner of the drawing area,
@@ -4607,7 +4773,7 @@ var NETDATA = window.NETDATA || {};
Dygraph.defaultInteractionModel.touchstart(event, dygraph, context);
// we overwrite the touch directions at the end, to overwrite
- // the internal default of dygraphs
+ // the internal default of dygraph
context.touchDirections = { x: true, y: false };
state.dygraph_last_touch_start = Date.now();
@@ -4636,7 +4802,7 @@ var NETDATA = window.NETDATA || {};
// if it didn't move, it is a selection
if(state.dygraph_last_touch_move === 0 && state.dygraph_last_touch_page_x !== 0) {
- // internal api of dygraphs
+ // internal api of dygraph
var pct = (state.dygraph_last_touch_page_x - (dygraph.plotter_.area.x + state.element.getBoundingClientRect().left)) / dygraph.plotter_.area.w;
var t = Math.round(state.data_after + (state.data_before - state.data_after) * pct);
if(NETDATA.dygraphSetSelection(state, t) === true)
@@ -4692,7 +4858,7 @@ var NETDATA = window.NETDATA || {};
state.__commonMax = self.data('common-max') || null;
}
else {
- state.log('incompatible version of dygraphs detected');
+ state.log('incompatible version of Dygraph detected');
state.__commonMin = null;
state.__commonMax = null;
}
@@ -4978,10 +5144,16 @@ var NETDATA = window.NETDATA || {};
};
NETDATA.d3ChartUpdate = function(state, data) {
+ void(state);
+ void(data);
+
return false;
};
NETDATA.d3ChartCreate = function(state, data) {
+ void(state);
+ void(data);
+
return false;
};
@@ -5176,10 +5348,11 @@ var NETDATA = window.NETDATA || {};
NETDATA.easypiechartClearSelection = function(state) {
if(typeof state.easyPieChartEvent !== 'undefined') {
- if(state.easyPieChartEvent.timer !== null)
+ if(state.easyPieChartEvent.timer !== undefined) {
clearTimeout(state.easyPieChartEvent.timer);
+ }
- state.easyPieChartEvent.timer = null;
+ state.easyPieChartEvent.timer = undefined;
}
if(state.isAutoRefreshable() === true && state.data !== null) {
@@ -5204,7 +5377,7 @@ var NETDATA = window.NETDATA || {};
if(typeof state.easyPieChartEvent === 'undefined') {
state.easyPieChartEvent = {
- timer: null,
+ timer: undefined,
value: 0,
pcent: 0
};
@@ -5219,11 +5392,11 @@ var NETDATA = window.NETDATA || {};
state.easyPieChartEvent.pcent = pcent;
state.easyPieChartLabel.innerText = state.legendFormatValue(value);
- if(state.easyPieChartEvent.timer === null) {
+ if(state.easyPieChartEvent.timer === undefined) {
state.easyPieChart_instance.disableAnimation();
state.easyPieChartEvent.timer = setTimeout(function() {
- state.easyPieChartEvent.timer = null;
+ state.easyPieChartEvent.timer = undefined;
state.easyPieChart_instance.update(state.easyPieChartEvent.pcent);
}, NETDATA.options.current.charts_selection_animation_delay);
}
@@ -5423,9 +5596,10 @@ var NETDATA = window.NETDATA || {};
// is always between min and max
var pcent = (value - min) * 100 / (max - min);
- // these should never happen
- if(pcent < 0) pcent = 0;
- if(pcent > 100) pcent = 100;
+ // bug fix for gauge.js 1.3.1
+ // if the value is the absolute min or max, the chart is broken
+ if(pcent < 0.001) pcent = 0.001;
+ if(pcent > 99.999) pcent = 99.999;
state.gauge_instance.set(pcent);
// console.log('gauge set ' + pcent + ', value ' + value + ', min ' + min + ', max ' + max);
@@ -5452,10 +5626,11 @@ var NETDATA = window.NETDATA || {};
NETDATA.gaugeClearSelection = function(state) {
if(typeof state.gaugeEvent !== 'undefined') {
- if(state.gaugeEvent.timer !== null)
+ if(state.gaugeEvent.timer !== undefined) {
clearTimeout(state.gaugeEvent.timer);
+ }
- state.gaugeEvent.timer = null;
+ state.gaugeEvent.timer = undefined;
}
if(state.isAutoRefreshable() === true && state.data !== null) {
@@ -5481,7 +5656,7 @@ var NETDATA = window.NETDATA || {};
if(typeof state.gaugeEvent === 'undefined') {
state.gaugeEvent = {
- timer: null,
+ timer: undefined,
value: 0,
min: 0,
max: 0
@@ -5501,11 +5676,11 @@ var NETDATA = window.NETDATA || {};
state.gaugeEvent.max = max;
NETDATA.gaugeSetLabels(state, value, min, max);
- if(state.gaugeEvent.timer === null) {
+ if(state.gaugeEvent.timer === undefined) {
NETDATA.gaugeAnimation(state, false);
state.gaugeEvent.timer = setTimeout(function() {
- state.gaugeEvent.timer = null;
+ state.gaugeEvent.timer = undefined;
NETDATA.gaugeSet(state, state.gaugeEvent.value, state.gaugeEvent.min, state.gaugeEvent.max);
}, NETDATA.options.current.charts_selection_animation_delay);
}
@@ -5585,19 +5760,22 @@ var NETDATA = window.NETDATA || {};
var options = {
lines: 12, // The number of lines to draw
- angle: 0.15, // The length of each line
- lineWidth: 0.44, // 0.44 The line thickness
+ angle: 0.15, // The span of the gauge arc
+ lineWidth: 0.50, // The line thickness
+ radiusScale: 0.85, // Relative radius
pointer: {
length: 0.8, // 0.9 The radius of the inner circle
strokeWidth: 0.035, // The rotation offset
color: pointerColor // Fill color
},
+ limitMax: true, // If false, the max value of the gauge will be updated if value surpass max
+ limitMin: true, // If true, the min value of the gauge will be fixed unless you set it manually
colorStart: startColor, // Colors
colorStop: stopColor, // just experiment with them
strokeColor: strokeColor, // to see which ones work best for you
- limitMax: true,
- generateGradient: (generateGradient === true)?true:false,
- gradientType: 0
+ generateGradient: (generateGradient === true),
+ gradientType: 0,
+ highDpiSupport: true // High resolution support
};
if (generateGradient.constructor === Array) {
@@ -5607,13 +5785,13 @@ var NETDATA = window.NETDATA || {};
// data-gauge-gradient-percent-color-50="#999900"
// data-gauge-gradient-percent-color-100="#000000"
- options.percentColors = new Array();
+ options.percentColors = [];
var len = generateGradient.length;
while(len--) {
var pcent = generateGradient[len];
- var color = self.data('gauge-gradient-percent-color-' + pcent.toString()) || false;
+ var color = self.attr('data-gauge-gradient-percent-color-' + pcent.toString()) || false;
if(color !== false) {
- var a = new Array();
+ var a = [];
a[0] = pcent / 100;
a[1] = color;
options.percentColors.unshift(a);
@@ -5623,6 +5801,7 @@ var NETDATA = window.NETDATA || {};
delete options.percentColors;
}
else if(generateGradient === false && NETDATA.themes.current.gauge_gradient === true) {
+ //noinspection PointlessArithmeticExpressionJS
options.percentColors = [
[0.0, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 0))],
[0.1, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 1))],
@@ -5724,31 +5903,21 @@ var NETDATA = window.NETDATA || {};
toolboxPanAndZoom: NETDATA.dygraphToolboxPanAndZoom,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return 'ms|flip'; },
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return 'ms|flip'; },
legend: function(state) {
- if(this.isSparkline(state) === false)
- return 'right-side';
- else
- return null;
+ return (this.isSparkline(state) === false)?'right-side':null;
},
- autoresize: function(state) { return true; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return true; },
+ autoresize: function(state) { void(state); return true; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return true; },
pixels_per_point: function(state) {
- if(this.isSparkline(state) === false)
- return 3;
- else
- return 2;
+ return (this.isSparkline(state) === false)?3:2;
},
-
isSparkline: function(state) {
if(typeof state.dygraph_sparkline === 'undefined') {
var t = $(state.element).data('dygraph-theme');
- if(t === 'sparkline')
- state.dygraph_sparkline = true;
- else
- state.dygraph_sparkline = false;
+ state.dygraph_sparkline = (t === 'sparkline');
}
return state.dygraph_sparkline;
}
@@ -5758,126 +5927,126 @@ var NETDATA = window.NETDATA || {};
create: NETDATA.sparklineChartCreate,
update: NETDATA.sparklineChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'array'; },
- options: function(state) { return 'flip|abs'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'array'; },
+ options: function(state) { void(state); return 'flip|abs'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"peity": {
initialize: NETDATA.peityInitialize,
create: NETDATA.peityChartCreate,
update: NETDATA.peityChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'ssvcomma'; },
- options: function(state) { return 'null2zero|flip|abs'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'ssvcomma'; },
+ options: function(state) { void(state); return 'null2zero|flip|abs'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"morris": {
initialize: NETDATA.morrisInitialize,
create: NETDATA.morrisChartCreate,
update: NETDATA.morrisChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return 'objectrows|ms'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 50; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 15; }
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return 'objectrows|ms'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 50; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 15; }
},
"google": {
initialize: NETDATA.googleInitialize,
create: NETDATA.googleChartCreate,
update: NETDATA.googleChartUpdate,
resize: null,
- setSelection: undefined, //function(state, t) { return true; },
- clearSelection: undefined, //function(state) { return true; },
+ setSelection: undefined, //function(state, t) { void(state); return true; },
+ clearSelection: undefined, //function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'datatable'; },
- options: function(state) { return ''; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 300; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 4; }
+ format: function(state) { void(state); return 'datatable'; },
+ options: function(state) { void(state); return ''; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 300; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 4; }
},
"raphael": {
initialize: NETDATA.raphaelInitialize,
create: NETDATA.raphaelChartCreate,
update: NETDATA.raphaelChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return ''; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return ''; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"c3": {
initialize: NETDATA.c3Initialize,
create: NETDATA.c3ChartCreate,
update: NETDATA.c3ChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'csvjsonarray'; },
- options: function(state) { return 'milliseconds'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 15; }
+ format: function(state) { void(state); return 'csvjsonarray'; },
+ options: function(state) { void(state); return 'milliseconds'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 15; }
},
"d3": {
initialize: NETDATA.d3Initialize,
create: NETDATA.d3ChartCreate,
update: NETDATA.d3ChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return ''; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return ''; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"easypiechart": {
initialize: NETDATA.easypiechartInitialize,
@@ -5889,13 +6058,13 @@ var NETDATA = window.NETDATA || {};
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'array'; },
- options: function(state) { return 'absolute'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return true; },
- pixels_per_point: function(state) { return 3; },
+ format: function(state) { void(state); return 'array'; },
+ options: function(state) { void(state); return 'absolute'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return true; },
+ pixels_per_point: function(state) { void(state); return 3; },
aspect_ratio: 100
},
"gauge": {
@@ -5908,13 +6077,13 @@ var NETDATA = window.NETDATA || {};
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'array'; },
- options: function(state) { return 'absolute'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return true; },
- pixels_per_point: function(state) { return 3; },
+ format: function(state) { void(state); return 'array'; },
+ options: function(state) { void(state); return 'absolute'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return true; },
+ pixels_per_point: function(state) { void(state); return 3; },
aspect_ratio: 70
}
};
@@ -5940,10 +6109,7 @@ var NETDATA = window.NETDATA || {};
if(typeof $().emulateTransitionEnd === 'function')
return true;
else {
- if(typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap)
- return true;
- else
- return false;
+ return (typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap === true);
}
}
},
@@ -5957,10 +6123,7 @@ var NETDATA = window.NETDATA || {};
{
url: NETDATA.themes.current.bootstrap_css,
isAlreadyLoaded: function() {
- if(typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap)
- return true;
- else
- return false;
+ return (typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap === true);
}
},
{
@@ -6012,7 +6175,7 @@ var NETDATA = window.NETDATA || {};
if(async === false)
NETDATA.loadRequiredJs(++index, callback);
- })
+ });
if(async === true)
NETDATA.loadRequiredJs(++index, callback);
@@ -6052,7 +6215,7 @@ var NETDATA = window.NETDATA || {};
last_notification_id: 0, // the id of the last alarm_log we have raised an alarm for
first_notification_id: 0, // the id of the first alarm_log entry for this session
// this is used to prevent CLEAR notifications for past events
- // notifications_shown: new Array(),
+ // notifications_shown: [],
server: null, // the server to connect to for fetching alarms
current: null, // the list of raised alarms - updated in the background
@@ -6066,16 +6229,18 @@ var NETDATA = window.NETDATA || {};
return;
}
- var value = entry.value;
+ var value_string = entry.value_string;
+
if(NETDATA.alarms.current !== null) {
+ // get the current value_string
var t = NETDATA.alarms.current.alarms[entry.chart + '.' + entry.name];
- if(typeof t !== 'undefined' && entry.status === t.status)
- value = t.value;
+ if(typeof t !== 'undefined' && entry.status === t.status && typeof t.value_string !== 'undefined')
+ value_string = t.value_string;
}
var name = entry.name.replace(/_/g, ' ');
var status = entry.status.toLowerCase();
- var title = name + ' = ' + ((value === null)?'NaN':Math.floor(value)).toString() + ' ' + entry.units;
+ var title = name + ' = ' + value_string.toString();
var tag = entry.alarm_id;
var icon = 'images/seo-performance-128.png';
var interaction = false;
@@ -6104,8 +6269,12 @@ var NETDATA = window.NETDATA || {};
// console.log('alarm' + entry.unique_id + ' switch to CLEAR from ' + entry.old_status);
return;
}
- title = name + ' back to normal';
- icon = 'images/check-mark-2-128-green.png'
+ if(entry.no_clear_notification === true) {
+ // console.log('alarm' + entry.unique_id + ' is CLEAR but has no_clear_notification flag');
+ return;
+ }
+ title = name + ' back to normal (' + value_string.toString() + ')';
+ icon = 'images/check-mark-2-128-green.png';
interaction = false;
break;
@@ -6121,7 +6290,7 @@ var NETDATA = window.NETDATA || {};
if(entry.old_status === 'WARNING')
status = 'escalated to ' + entry.status.toLowerCase();
- icon = 'images/alert-128-red.png'
+ icon = 'images/alert-128-red.png';
interaction = true;
break;
@@ -6363,12 +6532,12 @@ var NETDATA = window.NETDATA || {};
// Registry of netdata hosts
NETDATA.registry = {
- server: null, // the netdata registry server
- person_guid: null, // the unique ID of this browser / user
- machine_guid: null, // the unique ID the netdata server that served dashboard.js
- hostname: null, // the hostname of the netdata server that served dashboard.js
- machines: null, // the user's other URLs
- machines_array: null, // the user's other URLs in an array
+ server: null, // the netdata registry server
+ person_guid: null, // the unique ID of this browser / user
+ machine_guid: null, // the unique ID the netdata server that served dashboard.js
+ hostname: 'unknown', // the hostname of the netdata server that served dashboard.js
+ machines: null, // the user's other URLs
+ machines_array: null, // the user's other URLs in an array
person_urls: null,
parsePersonUrls: function(person_urls) {
@@ -6377,9 +6546,8 @@ var NETDATA = window.NETDATA || {};
if(person_urls) {
NETDATA.registry.machines = {};
- NETDATA.registry.machines_array = new Array();
+ NETDATA.registry.machines_array = [];
- var now = Date.now();
var apu = person_urls;
var i = apu.length;
while(i--) {
@@ -6392,7 +6560,7 @@ var NETDATA = window.NETDATA || {};
last_t: apu[i][2],
accesses: apu[i][3],
name: apu[i][4],
- alternate_urls: new Array()
+ alternate_urls: []
};
obj.alternate_urls.push(apu[i][1]);
diff --git a/web/dashboard_info.js b/web/dashboard_info.js
index 24a579cfe..c348da30d 100644
--- a/web/dashboard_info.js
+++ b/web/dashboard_info.js
@@ -1,7 +1,9 @@
var netdataDashboard = window.netdataDashboard || {};
-// menu
+// ----------------------------------------------------------------------------
+// menus
+
// information about the main menus
netdataDashboard.menu = {
@@ -12,179 +14,185 @@ netdataDashboard.menu = {
},
'services': {
- title: 'Systemd Services',
+ title: 'systemd Services',
icon: '<i class="fa fa-cogs" aria-hidden="true"></i>',
- info: 'Resources utilization of systemd services.'
+ info: 'Resources utilization of systemd services. netdata monitors all systemd services via cgroups (the resources accounting used by containers). '
},
'ap': {
title: 'Access Points',
icon: '<i class="fa fa-wifi" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for the access points (i.e. wireless interfaces in AP mode) found on the system.'
},
'tc': {
title: 'Quality of Service',
icon: '<i class="fa fa-globe" aria-hidden="true"></i>',
- info: 'Netdata collects and visualizes tc class utilization using its <a href="https://github.com/firehol/netdata/blob/master/plugins.d/tc-qos-helper.sh" target="_blank">tc-helper plugin</a>. If you also use <a href="http://firehol.org/#fireqos" target="_blank">FireQOS</a> for setting up QoS, netdata automatically collects interface and class names. If your QoS configuration includes overheads calculation, the values shown here will include these overheads (the total bandwidth for the same interface as reported in the Network Interfaces section, will be lower than the total bandwidth reported here). Also, data collection may have a slight time difference compared to the interface (QoS data collection is implemented with a BASH script, so a shift in data collection of a few milliseconds should be justified).'
+ info: 'Netdata collects and visualizes <code>tc</code> class utilization using its <a href="https://github.com/firehol/netdata/blob/master/plugins.d/tc-qos-helper.sh" target="_blank">tc-helper plugin</a>. If you also use <a href="http://firehol.org/#fireqos" target="_blank">FireQOS</a> for setting up QoS, netdata automatically collects interface and class names. If your QoS configuration includes overheads calculation, the values shown here will include these overheads (the total bandwidth for the same interface as reported in the Network Interfaces section, will be lower than the total bandwidth reported here). QoS data collection may have a slight time difference compared to the interface (QoS data collection uses a BASH script, so a shift in data collection of a few milliseconds should be justified).'
},
'net': {
title: 'Network Interfaces',
icon: '<i class="fa fa-share-alt" aria-hidden="true"></i>',
- info: 'Per network interface statistics collected from <code>/proc/net/dev</code>.'
+ info: 'Performance metrics for network interfaces.'
},
'ipv4': {
title: 'IPv4 Networking',
icon: '<i class="fa fa-cloud" aria-hidden="true"></i>',
- info: undefined
+ info: 'Metrics for the IPv4 stack of the system. <a href="https://en.wikipedia.org/wiki/IPv4" target="_blank">Internet Protocol version 4 (IPv4)</a> is the fourth version of the Internet Protocol (IP). It is one of the core protocols of standards-based internetworking methods in the Internet. IPv4 is a connectionless protocol for use on packet-switched networks. It operates on a best effort delivery model, in that it does not guarantee delivery, nor does it assure proper sequencing or avoidance of duplicate delivery. These aspects, including data integrity, are addressed by an upper layer transport protocol, such as the Transmission Control Protocol (TCP).'
},
'ipv6': {
title: 'IPv6 Networking',
icon: '<i class="fa fa-cloud" aria-hidden="true"></i>',
- info: undefined
+ info: 'Metrics for the IPv6 stack of the system. <a href="https://en.wikipedia.org/wiki/IPv6" target="_blank">Internet Protocol version 6 (IPv6)</a> is the most recent version of the Internet Protocol (IP), the communications protocol that provides an identification and location system for computers on networks and routes traffic across the Internet. IPv6 was developed by the Internet Engineering Task Force (IETF) to deal with the long-anticipated problem of IPv4 address exhaustion. IPv6 is intended to replace IPv4.'
},
'ipvs': {
title: 'IP Virtual Server',
icon: '<i class="fa fa-eye" aria-hidden="true"></i>',
- info: undefined
+ info: '<a href="http://www.linuxvirtualserver.org/software/ipvs.html" target="_blank">IPVS (IP Virtual Server)</a> implements transport-layer load balancing inside the Linux kernel, so called Layer-4 switching. IPVS running on a host acts as a load balancer at the front of a cluster of real servers, it can direct requests for TCP/UDP based services to the real servers, and makes services of the real servers to appear as a virtual service on a single IP address.'
},
'netfilter': {
title: 'Firewall (netfilter)',
icon: '<i class="fa fa-shield" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics of the netfilter components.'
},
'cpu': {
title: 'CPUs',
icon: '<i class="fa fa-bolt" aria-hidden="true"></i>',
- info: undefined
+ info: 'Detailed information for each CPU of the system. A summary of the system for all CPUs can be found at the <a href="#menu_system">System Overview</a> section.'
},
'mem': {
title: 'Memory',
icon: '<i class="fa fa-bolt" aria-hidden="true"></i>',
- info: undefined
+ info: 'Detailed information about the memory management of the system.'
},
'disk': {
title: 'Disks',
icon: '<i class="fa fa-folder" aria-hidden="true"></i>',
- info: 'Charts with performance information for all the system disks. Special care has been given to present disk performance metrics in a way compatible with <code>iostat -x</code>. netdata by default prevents rendering performance charts for individual partitions and unmounted virtual disks. Disabled charts can still be enabled by altering the relative settings in the netdata configuration file.'
+ info: 'Charts with performance information for all the system disks. Special care has been given to present disk performance metrics in a way compatible with <code>iostat -x</code>. netdata by default prevents rendering performance charts for individual partitions and unmounted virtual disks. Disabled charts can still be enabled by configuring the relative settings in the netdata configuration file.'
},
'sensors': {
title: 'Sensors',
icon: '<i class="fa fa-leaf" aria-hidden="true"></i>',
- info: undefined
+ info: 'Readings of the configured system sensors.'
+ },
+
+ 'ipmi': {
+ title: 'IPMI',
+ icon: '<i class="fa fa-leaf" aria-hidden="true"></i>',
+ info: 'The Intelligent Platform Management Interface (IPMI) is a set of computer interface specifications for an autonomous computer subsystem that provides management and monitoring capabilities independently of the host system\'s CPU, firmware (BIOS or UEFI) and operating system.'
},
'nfsd': {
title: 'NFS Server',
icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics of the Network File Server. NFS is a distributed file system protocol, allowing a user on a client computer to access files over a network, much like local storage is accessed. NFS, like many other protocols, builds on the Open Network Computing Remote Procedure Call (ONC RPC) system. The NFS is an open standard defined in Request for Comments (RFC).'
},
'nfs': {
title: 'NFS Client',
icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics of the NFS operations of this system, acting as an NFS client.'
},
'apps': {
title: 'Applications',
icon: '<i class="fa fa-heartbeat" aria-hidden="true"></i>',
- info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported). The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
+ info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through all processes and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported). The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
height: 1.5
},
'users': {
title: 'Users',
icon: '<i class="fa fa-user" aria-hidden="true"></i>',
- info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
+ info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through all processes and aggregates statistics per user. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
height: 1.5
},
'groups': {
title: 'User Groups',
icon: '<i class="fa fa-users" aria-hidden="true"></i>',
- info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
+ info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through all processes and aggregates statistics per user group. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
height: 1.5
},
'netdata': {
title: 'Netdata Monitoring',
icon: '<i class="fa fa-bar-chart" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for the operation of netdata itself and its plugins.'
},
'example': {
title: 'Example Charts',
- info: undefined
+ info: 'Example charts, demonstrating the external plugin architecture.'
},
'cgroup': {
title: '',
icon: '<i class="fa fa-th" aria-hidden="true"></i>',
- info: undefined
+ info: 'Container resource utilization metrics. Netdata reads this information from <b>cgroups</b> (abbreviated from <b>control groups</b>), a Linux kernel feature that limits and accounts resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes. <b>cgroups</b> together with <b>namespaces</b> (that offer isolation between processes) provide what we usually call: <b>containers</b>.'
},
'cgqemu': {
title: '',
icon: '<i class="fa fa-th-large" aria-hidden="true"></i>',
- info: undefined
+ info: 'QEMU virtual machine resource utilization metrics. QEMU (short for Quick Emulator) is a free and open-source hosted hypervisor that performs hardware virtualization.'
},
'fping': {
title: 'fping',
icon: '<i class="fa fa-exchange" aria-hidden="true"></i>',
- info: undefined
+ info: 'Network latency statistics, via <b>fping</b>. <b>fping</b> is a program to send ICMP echo probes to network hosts, similar to <code>ping</code>, but much better performing when pinging multiple hosts. fping versions after 3.15 can be directly used as netdata plugins.'
},
'memcached': {
title: 'memcached',
icon: '<i class="fa fa-database" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for <b>memcached</b>. Memcached is a general-purpose distributed memory caching system. It is often used to speed up dynamic database-driven websites by caching data and objects in RAM to reduce the number of times an external data source (such as a database or API) must be read.'
},
'mysql': {
title: 'MySQL',
icon: '<i class="fa fa-database" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for <b>mysql</b>, the open-source relational database management system (RDBMS).'
},
'postgres': {
title: 'Postgres',
icon: '<i class="fa fa-database" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for <b>PostgresSQL</b>, the object-relational database (ORDBMS).'
},
'redis': {
title: 'Redis',
icon: '<i class="fa fa-database" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for <b>redis</b>. Redis (REmote DIctionary Server) is a software project that implements data structure servers. It is open-source, networked, in-memory, and stores keys with optional durability.'
},
'retroshare': {
title: 'RetroShare',
icon: '<i class="fa fa-share-alt" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for <b>RetroShare</b>. RetroShare is open source software for encrypted filesharing, serverless email, instant messaging, online chat, and BBS, based on a friend-to-friend network built on GNU Privacy Guard (GPG).'
},
'ipfs': {
title: 'IPFS',
icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for the InterPlanetary File System (IPFS), a content-addressable, peer-to-peer hypermedia distribution protocol.'
},
'phpfpm': {
title: 'PHP-FPM',
icon: '<i class="fa fa-eye" aria-hidden="true"></i>',
- info: undefined
+ info: 'Performance metrics for <b>PHP-FPM</b>, an alternative FastCGI implementation for PHP.'
},
'postfix': {
@@ -217,6 +225,12 @@ netdataDashboard.menu = {
info: undefined
},
+ 'web_log': {
+ title: undefined,
+ icon: '<i class="fa fa-file-text-o" aria-hidden="true"></i>',
+ info: 'Information extracted from a web server log file. <code>web_log</code> plugin incrementally parses the web server log file to provide, in real-time, a break down of key web server performance metrics. An extended log file format may optionally be used (for <code>nginx</code> and <code>apache</code>) offering timing information and bandwidth for both requests and responses. <code>web_log</code> plugin may also be configured to provide a break down of requests per URL pattern (check <a href="https://github.com/firehol/netdata/blob/master/conf.d/python.d/web_log.conf" target="_blank"><code>/etc/netdata/python.d/web_log.conf</code></a>).'
+ },
+
'named': {
title: 'named',
icon: '<i class="fa fa-tag" aria-hidden="true"></i>',
@@ -254,9 +268,31 @@ netdataDashboard.menu = {
}
};
-// submenu
+
+
+// ----------------------------------------------------------------------------
+// submenus
+
+// information to be shown, just below each submenu
+
// information about the submenus
netdataDashboard.submenu = {
+ 'web_log.bandwidth': {
+ info: 'Bandwidth of requests (<code>received</code>) and responses (<code>sent</code>). <code>received</code> requires an extended log format (without it, the web server log does not have this information). This chart may present unusual spikes, since the bandwidth is accounted at the time the log line is saved by the web server, even if the time needed to serve it spans across a longer duration. We suggest to use QoS (e.g. <a href="http://firehol.org/#fireqos" target="_blank">FireQOS</a>) for accurate accounting of the web server bandwidth.'
+ },
+
+ 'web_log.urls': {
+ info: 'Number of requests for each <code>URL pattern</code> defined in <a href="https://github.com/firehol/netdata/blob/master/conf.d/python.d/web_log.conf" target="_blank"><code>/etc/netdata/python.d/web_log.conf</code></a>. This chart counts all requests matching the URL patterns defined, independently of the web server response codes (i.e. both successful and unsuccessful).'
+ },
+
+ 'web_log.clients': {
+ info: 'Charts showing the number of unique client IPs, accessing the web server.'
+ },
+
+ 'web_log.timings': {
+ info: 'Web server response timings - the time the web server needed to prepare and respond to requests. This requires an extended log format and its meaning is web server specific. For most web servers this accounts the time from the reception of a complete request, to the dispatch of the last byte of the response. So, it includes the network delays of responses, but it does not include the network delays of requests.'
+ },
+
'mem.ksm': {
title: 'Memory Deduper',
info: 'Kernel Same-page Merging (KSM) performance monitoring, read from several files in <code>/sys/kernel/mm/ksm/</code>. KSM is a memory-saving de-duplication feature in the Linux kernel (since version 2.6.32). The KSM daemon ksmd periodically scans those areas of user memory which have been registered with it, looking for pages of identical content which can be replaced by a single write-protected page (which is automatically copied if a process later wants to update its content). KSM was originally developed for use with KVM (where it was known as Kernel Shared Memory), to fit more virtual machines into physical memory, by sharing the data common between them. But it can be useful to any application which generates many instances of the same data.'
@@ -272,7 +308,7 @@ netdataDashboard.submenu = {
'netfilter.conntrack': {
title: 'Connection Tracker',
- info: 'Netfilter Connection Tracker performance monitoring, read from <code>/proc/net/stat/nf_conntrack</code>. The connection tracker keeps track of all connections of the machine, inbound and outbound. It works by keeping a database with all open connections, tracking network and address translation and connection expectations.'
+ info: 'Netfilter Connection Tracker performance metrics. The connection tracker keeps track of all connections of the machine, inbound and outbound. It works by keeping a database with all open connections, tracking network and address translation and connection expectations.'
},
'netfilter.nfacct': {
@@ -282,21 +318,35 @@ netdataDashboard.submenu = {
'netfilter.synproxy': {
title: 'DDoS Protection',
- info: 'DDoS Protection performance monitoring read from <code>/proc/net/stat/synproxy</code>. <a href="https://github.com/firehol/firehol/wiki/Working-with-SYNPROXY" target="_blank">SYNPROXY</a> is a TCP SYN packets proxy. It is used to protect any TCP server (like a web server) from SYN floods and similar DDoS attacks. It is a netfilter module, in the Linux kernel (since version 3.12). It is optimized to handle millions of packets per second utilizing all CPUs available without any concurrency locking between the connections. It can be used for any kind of TCP traffic (even encrypted), since it does not interfere with the content itself.'
+ info: 'DDoS protection performance metrics. <a href="https://github.com/firehol/firehol/wiki/Working-with-SYNPROXY" target="_blank">SYNPROXY</a> is a TCP SYN packets proxy. It is used to protect any TCP server (like a web server) from SYN floods and similar DDoS attacks. It is a netfilter module, in the Linux kernel (since version 3.12). It is optimized to handle millions of packets per second utilizing all CPUs available without any concurrency locking between the connections. It can be used for any kind of TCP traffic (even encrypted), since it does not interfere with the content itself.'
},
'system.softnet_stat': {
title: 'softnet',
- info: 'Statistics for CPUs SoftIRQs related to network receive work, read from <code>/proc/net/softnet_stat</code>. Break down per CPU core can be found at <a href="#menu_cpu_submenu_softnet_stat">CPU / softnet statistics</a>. <b>processed</b> states the number of packets processed, <b>dropped</b> is the number packets dropped because the network device backlog was full (to fix them use <code>sysctl</code> to increase <code>net.core.netdev_max_backlog</code>), <b>squeezed</b> is the number of packets dropped because the network device budget ran out (to fix them use <code>sysctl</code> to increase <code>net.core.netdev_budget</code>). More information about identifying and troubleshooting network driver related issues can be found at <a href="https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf" target="_blank">Red Hat Enterprise Linux Network Performance Tuning Guide</a>.'
+ info: function(os) {
+ if(os === 'linux')
+ return 'Statistics for CPUs SoftIRQs related to network receive work. Break down per CPU core can be found at <a href="#menu_cpu_submenu_softnet_stat">CPU / softnet statistics</a>. <b>processed</b> states the number of packets processed, <b>dropped</b> is the number packets dropped because the network device backlog was full (to fix them on Linux use <code>sysctl</code> to increase <code>net.core.netdev_max_backlog</code>), <b>squeezed</b> is the number of packets dropped because the network device budget ran out (to fix them on Linux use <code>sysctl</code> to increase <code>net.core.netdev_budget</code>). More information about identifying and troubleshooting network driver related issues can be found at <a href="https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf" target="_blank">Red Hat Enterprise Linux Network Performance Tuning Guide</a>.';
+ else
+ return 'Statistics for CPUs SoftIRQs related to network receive work.';
+ }
},
'cpu.softnet_stat': {
title: 'softnet',
- info: 'Statistics for per CPUs core SoftIRQs related to network receive work, read from <code>/proc/net/softnet_stat</code>. Total for all CPU cores can be found at <a href="#menu_system_submenu_softnet_stat">System / softnet statistics</a>. <b>processed</b> states the number of packets processed, <b>dropped</b> is the number packets dropped because the network device backlog was full (to fix them use <code>sysctl</code> to increase <code>net.core.netdev_max_backlog</code>), <b>squeezed</b> is the number of packets dropped because the network device budget ran out (to fix them use <code>sysctl</code> to increase <code>net.core.netdev_budget</code>). More information about identifying and troubleshooting network driver related issues can be found at <a href="https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf" target="_blank">Red Hat Enterprise Linux Network Performance Tuning Guide</a>.'
+ info: function(os) {
+ if(os === 'linux')
+ return 'Statistics for per CPUs core SoftIRQs related to network receive work. Total for all CPU cores can be found at <a href="#menu_system_submenu_softnet_stat">System / softnet statistics</a>. <b>processed</b> states the number of packets processed, <b>dropped</b> is the number packets dropped because the network device backlog was full (to fix them on Linux use <code>sysctl</code> to increase <code>net.core.netdev_max_backlog</code>), <b>squeezed</b> is the number of packets dropped because the network device budget ran out (to fix them on Linux use <code>sysctl</code> to increase <code>net.core.netdev_budget</code>). More information about identifying and troubleshooting network driver related issues can be found at <a href="https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf" target="_blank">Red Hat Enterprise Linux Network Performance Tuning Guide</a>.';
+ else
+ return 'Statistics for per CPUs core SoftIRQs related to network receive work. Total for all CPU cores can be found at <a href="#menu_system_submenu_softnet_stat">System / softnet statistics</a>.';
+ }
}
};
+
+
+// ----------------------------------------------------------------------------
// chart
+
// information works on the context of a chart
// Its purpose is to set:
//
@@ -308,60 +358,65 @@ netdataDashboard.submenu = {
//
netdataDashboard.context = {
'system.cpu': {
- info: 'Total CPU utilization (all cores). 100% here means there is no CPU idle time at all. You can get per core usage at the <a href="#menu_cpu">CPUs</a> section and per application usage at the <a href="#menu_apps">Applications Monitoring</a> section.<br/>Keep an eye on <b>iowait</b> ' + sparkline('system.cpu', 'iowait', '%') + '. If it is constantly high, your disks are a bottleneck and they slow your system down.<br/>Another important metric worth monitoring, is <b>softirq</b> ' + sparkline('system.cpu', 'softirq', '%') + '. A constantly high percentage of softirq may indicate network driver issues.',
+ info: function(os) {
+ void(os);
+ return 'Total CPU utilization (all cores). 100% here means there is no CPU idle time at all. You can get per core usage at the <a href="#menu_cpu">CPUs</a> section and per application usage at the <a href="#menu_apps">Applications Monitoring</a> section.'
+ + netdataDashboard.sparkline('<br/>Keep an eye on <b>iowait</b> ', 'system.cpu', 'iowait', '%', '. If it is constantly high, your disks are a bottleneck and they slow your system down.')
+ + netdataDashboard.sparkline('<br/>An important metric worth monitoring, is <b>softirq</b> ', 'system.cpu', 'softirq', '%', '. A constantly high percentage of softirq may indicate network driver issues.');
+ },
valueRange: "[0, 100]"
},
'system.load': {
- info: 'Current system load, i.e. the number of processes using CPU or waiting for system resources (usually CPU and disk). The 3 metrics refer to 1, 5 and 15 minute averages. Linux calculates this once every 5 seconds. Netdata reads them from <code>/proc/loadavg</code>. For more information check <a href="https://en.wikipedia.org/wiki/Load_(computing)" target="_blank">this wikipedia article</a>',
+ info: 'Current system load, i.e. the number of processes using CPU or waiting for system resources (usually CPU and disk). The 3 metrics refer to 1, 5 and 15 minute averages. The system calculates this once every 5 seconds. For more information check <a href="https://en.wikipedia.org/wiki/Load_(computing)" target="_blank">this wikipedia article</a>',
height: 0.7
},
'system.io': {
- info: 'Total Disk I/O, for all disks, read from <code>/proc/vmstat</code>. You can get detailed information about each disk at the <a href="#menu_disk">Disks</a> section and per application Disk usage at the <a href="#menu_apps">Applications Monitoring</a> section.'
+ info: 'Total Disk I/O, for all disks. You can get detailed information about each disk at the <a href="#menu_disk">Disks</a> section and per application Disk usage at the <a href="#menu_apps">Applications Monitoring</a> section.'
},
'system.swapio': {
- info: 'Total Swap I/O, read from <code>/proc/vmstat</code>. (netdata measures both <code>in</code> and <code>out</code>. If either of them is not shown in the chart, it is because it is zero - you can change the page settings to always render all the available dimensions on all charts).'
+ info: 'Total Swap I/O. (netdata measures both <code>in</code> and <code>out</code>. If either of them is not shown in the chart, it is because it is zero - you can change the page settings to always render all the available dimensions on all charts).'
},
'system.pgfaults': {
- info: 'Total page faults, read from <code>/proc/vmstat</code>. <b>Major page faults</b> indicates that the system is using its swap. You can find which applications use the swap at the <a href="#menu_apps">Applications Monitoring</a> section.'
+ info: 'Total page faults. <b>Major page faults</b> indicates that the system is using its swap. You can find which applications use the swap at the <a href="#menu_apps">Applications Monitoring</a> section.'
},
'system.entropy': {
colors: '#CC22AA',
- info: '<a href="https://en.wikipedia.org/wiki/Entropy_(computing)" target="_blank">Entropy</a>, read from <code>/proc/sys/kernel/random/entropy_avail</code>, is like a pool of random numbers (<a href="https://en.wikipedia.org/wiki//dev/random" target="_blank">/dev/random</a>) that are mainly used in cryptography. It is advised that the pool remains always <a href="https://blog.cloudflare.com/ensuring-randomness-with-linuxs-random-number-generator/" target="_blank">above 200</a>. If the pool of entropy gets empty, you risk your security to be predictable and you should install a user-space random numbers generating daemon, like <code>haveged</code> or <code>rng-tools</code> (i.e. <b>rngd</b>), to keep the pool in healthy levels.'
+ info: '<a href="https://en.wikipedia.org/wiki/Entropy_(computing)" target="_blank">Entropy</a>, is like a pool of random numbers (<a href="https://en.wikipedia.org/wiki//dev/random" target="_blank">/dev/random</a>) that are mainly used in cryptography. It is advised that the pool remains always <a href="https://blog.cloudflare.com/ensuring-randomness-with-linuxs-random-number-generator/" target="_blank">above 200</a>. If the pool of entropy gets empty, you risk your security to be predictable and you should install a user-space random numbers generating daemon, like <code>haveged</code> or <code>rng-tools</code> (i.e. <b>rngd</b>), to keep the pool in healthy levels.'
},
'system.forks': {
colors: '#5555DD',
- info: 'The number of new processes created per second, read from <code>/proc/stat</code>.'
+ info: 'Number of new processes created.'
},
'system.intr': {
colors: '#DD5555',
- info: 'Total number of CPU interrupts, read from <code>/proc/stat</code>. Check <code>system.interrupts</code> that gives more detail about each interrupt and also the <a href="#menu_cpu">CPUs</a> section where interrupts are analyzed per CPU core.'
+ info: 'Total number of CPU interrupts. Check <code>system.interrupts</code> that gives more detail about each interrupt and also the <a href="#menu_cpu">CPUs</a> section where interrupts are analyzed per CPU core.'
},
'system.interrupts': {
- info: 'CPU interrupts in detail, read from <code>/proc/interrupts</code>. At the <a href="#menu_cpu">CPUs</a> section, interrupts are analyzed per CPU core.'
+ info: 'CPU interrupts in detail. At the <a href="#menu_cpu">CPUs</a> section, interrupts are analyzed per CPU core.'
},
'system.softirqs': {
- info: 'CPU softirqs in detail, read from <code>/proc/softirqs</code>. At the <a href="#menu_cpu">CPUs</a> section, softirqs are analyzed per CPU core.'
+ info: 'CPU softirqs in detail. At the <a href="#menu_cpu">CPUs</a> section, softirqs are analyzed per CPU core.'
},
'system.processes': {
- info: 'System processes, read from <code>/proc/stat</code>. <b>Running</b> are the processes in the CPU. <b>Blocked</b> are processes that are willing to enter the CPU, but they cannot, e.g. because they wait for disk activity.'
+ info: 'System processes. <b>Running</b> are the processes in the CPU. <b>Blocked</b> are processes that are willing to enter the CPU, but they cannot, e.g. because they wait for disk activity.'
},
'system.active_processes': {
- info: 'All system processes, read from <code>/proc/loadavg</code>.'
+ info: 'All system processes.'
},
'system.ctxt': {
- info: '<a href="https://en.wikipedia.org/wiki/Context_switch" target="_blank">Context Switches</a>, read from <code>/proc/stat</code>, is the switching of the CPU from one process, task or thread to another. If there are many processes or threads willing to execute and very few CPU cores available to handle them, the system is making more context switching to balance the CPU resources among them. The whole process is computationally intensive. The more the context switches, the slower the system gets.'
+ info: '<a href="https://en.wikipedia.org/wiki/Context_switch" target="_blank">Context Switches</a>, is the switching of the CPU from one process, task or thread to another. If there are many processes or threads willing to execute and very few CPU cores available to handle them, the system is making more context switching to balance the CPU resources among them. The whole process is computationally intensive. The more the context switches, the slower the system gets.'
},
'system.idlejitter': {
@@ -370,19 +425,19 @@ netdataDashboard.context = {
},
'system.ipv4': {
- info: 'Total IPv4 Traffic, read from <code>/proc/net/netstat</code>.'
+ info: 'Total IPv4 Traffic.'
},
'system.ipv6': {
- info: 'Total IPv6 Traffic, read from <code>/proc/net/snmp6</code>.'
+ info: 'Total IPv6 Traffic.'
},
'system.ram': {
- info: 'System memory, read from <code>/proc/meminfo</code>.'
+ info: 'System Random Access Memory (i.e. physical memory) usage.'
},
'system.swap': {
- info: 'System swap memory, read from <code>/proc/meminfo</code>.'
+ info: 'System swap memory usage. Swap space is used when the amount of physical memory (RAM) is full. When the system needs more memory resources and the RAM is full, inactive pages in memory are moved to the swap space (usually a disk, a disk partition or a file).'
},
// ------------------------------------------------------------------------
@@ -396,7 +451,8 @@ netdataDashboard.context = {
'mem.ksm_ratios': {
heads: [
- function(id) {
+ function(os, id) {
+ void(os);
return '<div data-netdata="' + id + '"'
+ ' data-gauge-max-value="100"'
+ ' data-chart-library="gauge"'
@@ -412,28 +468,25 @@ netdataDashboard.context = {
]
},
- 'mem.committed': {
- colors: NETDATA.colors[3]
- },
-
'mem.pgfaults': {
- info: 'A <a href="https://en.wikipedia.org/wiki/Page_fault" target="_blank">page fault</a> is a type of interrupt, called trap, raised by computer hardware when a running program accesses a memory page that is mapped into the virtual address space, but not actually loaded into main memory. If the page is loaded in memory at the time the fault is generated, but is not marked in the memory management unit as being loaded in memory, then it is called a <b>minor</b> or soft page fault. A <b>major</b> page fault is generated when the system needs to load the memory page from disk or swap memory. These values are read from <code>/proc/vmstat</code>.'
+ info: 'A <a href="https://en.wikipedia.org/wiki/Page_fault" target="_blank">page fault</a> is a type of interrupt, called trap, raised by computer hardware when a running program accesses a memory page that is mapped into the virtual address space, but not actually loaded into main memory. If the page is loaded in memory at the time the fault is generated, but is not marked in the memory management unit as being loaded in memory, then it is called a <b>minor</b> or soft page fault. A <b>major</b> page fault is generated when the system needs to load the memory page from disk or swap memory.'
},
'mem.committed': {
- info: 'Committed Memory, read from <code>/proc/meminfo</code>, is the sum of all memory which has been allocated by processes.'
+ colors: NETDATA.colors[3],
+ info: 'Committed Memory, is the sum of all memory which has been allocated by processes.'
},
'mem.writeback': {
- info: 'Read from <code>/proc/meminfo</code>, <b>Dirty</b> is the amount of memory waiting to be written to disk. <b>Writeback</b> is how much memory is actively being written to disk.'
+ info: '<b>Dirty</b> is the amount of memory waiting to be written to disk. <b>Writeback</b> is how much memory is actively being written to disk.'
},
'mem.kernel': {
- info: 'Read from <code>/proc/meminfo</code>, This chart displays the total ammount of memory being used by the kernel. <b>Slab</b> is the amount of memory used by the kernel to cache data structures for its own use. <b>KernelStack</b> is the amount of memory allocated for each task done by the kernel. <b>PageTables</b> is the amount of memory decicated to the lowest level of page tables (A page table is used to turn a virtual address into a physical memory address). <b>VmallocUsed</b> is the amount of memory being used as virtual address space.'
+ info: 'The total ammount of memory being used by the kernel. <b>Slab</b> is the amount of memory used by the kernel to cache data structures for its own use. <b>KernelStack</b> is the amount of memory allocated for each task done by the kernel. <b>PageTables</b> is the amount of memory decicated to the lowest level of page tables (A page table is used to turn a virtual address into a physical memory address). <b>VmallocUsed</b> is the amount of memory being used as virtual address space.'
},
'mem.slab': {
- info: 'Read from <code>/proc/meminfo</code>, <b>reclaimable</b> is the amount of memory which the kernel can reuse. <b>unreclaimable</b> can not be reused even when the kernel is lacking memory.'
+ info: '<b>Reclaimable</b> is the amount of memory which the kernel can reuse. <b>Unreclaimable</b> can not be reused even when the kernel is lacking memory.'
},
// ------------------------------------------------------------------------
@@ -528,7 +581,9 @@ netdataDashboard.context = {
'tc.qos': {
heads: [
- function(id) {
+ function(os, id) {
+ void(os);
+
if(id.match(/.*-ifb$/))
return netdataDashboard.gaugeChart('Inbound', '12%', '', '#5555AA');
else
@@ -571,12 +626,12 @@ netdataDashboard.context = {
heads: [
netdataDashboard.gaugeChart('Utilization', '12%', '', '#FF5588')
],
- info: 'Disk Utilization measures the amount of time the disk was busy with something. This is not related to its performance. 100% means that the Linux kernel always had an outstanding operation on the disk. Keep in mind that depending on the underlying technology of the disk, 100% here may or may not be an indication of congestion.'
+ info: 'Disk Utilization measures the amount of time the disk was busy with something. This is not related to its performance. 100% means that the system always had an outstanding operation on the disk. Keep in mind that depending on the underlying technology of the disk, 100% here may or may not be an indication of congestion.'
},
'disk.backlog': {
colors: '#0099CC',
- info: 'Backlog is an indication of the duration of pending disk operations. On every I/O event the Linux kernel is multiplying the time spent doing I/O since the last update of this field with the number of pending operations. While not accurate, this metric can provide an indication of the expected completion time of the operations in progress.'
+ info: 'Backlog is an indication of the duration of pending disk operations. On every I/O event the system is multiplying the time spent doing I/O since the last update of this field with the number of pending operations. While not accurate, this metric can provide an indication of the expected completion time of the operations in progress.'
},
'disk.io': {
@@ -588,7 +643,7 @@ netdataDashboard.context = {
},
'disk.ops': {
- info: 'Completed disk I/O operations. Keep in mind the number of operations requested might be higher, since the Linux kernel is able to merge adjacent to each other (see merged operations chart).'
+ info: 'Completed disk I/O operations. Keep in mind the number of operations requested might be higher, since the system is able to merge adjacent to each other (see merged operations chart).'
},
'disk.qops': {
@@ -601,7 +656,7 @@ netdataDashboard.context = {
},
'disk.mops': {
height: 0.5,
- info: 'The number of merged disk operations. The Linux kernel is able to merge adjacent I/O operations, for example two 4KB reads can become one 8KB read before given to disk.'
+ info: 'The number of merged disk operations. The system is able to merge adjacent I/O operations, for example two 4KB reads can become one 8KB read before given to disk.'
},
'disk.svctm': {
height: 0.5,
@@ -692,7 +747,8 @@ netdataDashboard.context = {
'apache.workers': {
mainheads: [
- function(id) {
+ function(os, id) {
+ void(os);
return '<div data-netdata="' + id + '"'
+ ' data-dimensions="busy"'
+ ' data-append-options="percentage"'
@@ -764,7 +820,8 @@ netdataDashboard.context = {
'retroshare.peers': {
info: 'Number of (connected) RetroShare friends.',
mainheads: [
- function(id) {
+ function(os, id) {
+ void(os);
return '<div data-netdata="' + id + '"'
+ ' data-dimensions="peers_connected"'
+ ' data-append-options="friends"'
@@ -794,6 +851,124 @@ netdataDashboard.context = {
'fping.packets': {
height: 0.5
+ },
+
+ 'web_log.response_statuses': {
+ info: 'Web server responses by type. <code>success</code> includes <b>1xx</b>, <b>2xx</b> and <b>304</b>, <code>error</code> includes <b>5xx</b>, <code>redirect</code> includes <b>3xx</b> except <b>304</b>, <code>bad</code> includes <b>4xx</b>, <code>other</code> are all the other responses.',
+ mainheads: [
+ function(os, id) {
+ void(os);
+ return '<div data-netdata="' + id + '"'
+ + ' data-dimensions="success"'
+ + ' data-chart-library="gauge"'
+ + ' data-title="Successful"'
+ + ' data-units="requests/s"'
+ + ' data-gauge-adjust="width"'
+ + ' data-width="12%"'
+ + ' data-before="0"'
+ + ' data-after="-CHART_DURATION"'
+ + ' data-points="CHART_DURATION"'
+ + ' data-common-max="' + id + '"'
+ + ' data-colors="' + NETDATA.colors[0] + '"'
+ + ' data-decimal-digits="0"'
+ + ' role="application"></div>';
+ },
+
+ function(os, id) {
+ void(os);
+ return '<div data-netdata="' + id + '"'
+ + ' data-dimensions="redirect"'
+ + ' data-chart-library="gauge"'
+ + ' data-title="Redirects"'
+ + ' data-units="requests/s"'
+ + ' data-gauge-adjust="width"'
+ + ' data-width="12%"'
+ + ' data-before="0"'
+ + ' data-after="-CHART_DURATION"'
+ + ' data-points="CHART_DURATION"'
+ + ' data-common-max="' + id + '"'
+ + ' data-colors="' + NETDATA.colors[2] + '"'
+ + ' data-decimal-digits="0"'
+ + ' role="application"></div>';
+ },
+
+ function(os, id) {
+ void(os);
+ return '<div data-netdata="' + id + '"'
+ + ' data-dimensions="bad"'
+ + ' data-chart-library="gauge"'
+ + ' data-title="Bad Requests"'
+ + ' data-units="requests/s"'
+ + ' data-gauge-adjust="width"'
+ + ' data-width="12%"'
+ + ' data-before="0"'
+ + ' data-after="-CHART_DURATION"'
+ + ' data-points="CHART_DURATION"'
+ + ' data-common-max="' + id + '"'
+ + ' data-colors="' + NETDATA.colors[3] + '"'
+ + ' data-decimal-digits="0"'
+ + ' role="application"></div>';
+ },
+
+ function(os, id) {
+ void(os);
+ return '<div data-netdata="' + id + '"'
+ + ' data-dimensions="error"'
+ + ' data-chart-library="gauge"'
+ + ' data-title="Server Errors"'
+ + ' data-units="requests/s"'
+ + ' data-gauge-adjust="width"'
+ + ' data-width="12%"'
+ + ' data-before="0"'
+ + ' data-after="-CHART_DURATION"'
+ + ' data-points="CHART_DURATION"'
+ + ' data-common-max="' + id + '"'
+ + ' data-colors="' + NETDATA.colors[1] + '"'
+ + ' data-decimal-digits="0"'
+ + ' role="application"></div>';
+ }
+ ]
+ },
+
+ 'web_log.response_codes': {
+ info: 'Web server responses by code family. According to the standards <code>1xx</code> are informational responses, <code>2xx</code> are successful responses, <code>3xx</code> are redirects (although they include <b>304</b> which is used as "<b>not modified</b>"), <code>4xx</code> are bad requests, <code>5xx</code> are internal server errors, <code>other</code> are non-standard responses, <code>unmatched</code> counts the lines in the log file that are not matched by the plugin (<a href="https://github.com/firehol/netdata/issues/new?title=web_log%20reports%20unmatched%20lines&body=web_log%20plugin%20reports%20unmatched%20lines.%0A%0AThis%20is%20my%20log:%0A%0A%60%60%60txt%0A%0Aplease%20paste%20your%20web%20server%20log%20here%0A%0A%60%60%60" target="_blank">let us know</a> if you have any unmatched).'
+ },
+
+ 'web_log.response_time': {
+ mainheads: [
+ function(os, id) {
+ void(os);
+ return '<div data-netdata="' + id + '"'
+ + ' data-dimensions="avg"'
+ + ' data-chart-library="gauge"'
+ + ' data-title="Average Response Time"'
+ + ' data-units="milliseconds"'
+ + ' data-gauge-adjust="width"'
+ + ' data-width="12%"'
+ + ' data-before="0"'
+ + ' data-after="-CHART_DURATION"'
+ + ' data-points="CHART_DURATION"'
+ + ' data-colors="' + NETDATA.colors[4] + '"'
+ + ' data-decimal-digits="2"'
+ + ' role="application"></div>';
+ }
+ ]
+ },
+
+ 'web_log.detailed_response_codes': {
+ info: 'Number of responses for each response code individually.'
+ },
+
+ 'web_log.requests_per_ipproto': {
+ info: 'Web server requests received per IP protocol version.'
+ },
+
+ 'web_log.clients': {
+ info: 'Unique client IPs accessing the web server, within each data collection iteration. If data collection is <b>per second</b>, this chart shows <b>unique client IPs per second</b>.'
+ },
+
+ 'web_log.clients_all': {
+ info: 'Unique client IPs accessing the web server since the last restart of netdata. This plugin keeps in memory all the unique IPs that have accessed the web server. On very busy web servers (several millions of unique IPs) you may want to disable this chart (check <a href="https://github.com/firehol/netdata/blob/master/conf.d/python.d/web_log.conf" target="_blank"><code>/etc/netdata/python.d/web_log.conf</code></a>).'
}
};
diff --git a/web/dashboard_info_custom_example.js b/web/dashboard_info_custom_example.js
new file mode 100644
index 000000000..f9e255d77
--- /dev/null
+++ b/web/dashboard_info_custom_example.js
@@ -0,0 +1,58 @@
+/*
+ * Custom netdata information file
+ * -------------------------------
+ *
+ * Use this file to add custom information on netdata dashboards:
+ *
+ * 1. Copy it to a new filename (so that it will not be overwritten with netdata updates)
+ * 2. Edit it to fit your needs
+ * 3. Set the following option to /etc/netdata/netdata.conf :
+ *
+ * [web]
+ * custom dashboard_info.js = your_filename.js
+ *
+ * Using this file you can:
+ *
+ * 1. Overwrite or add messages to menus, submenus and charts.
+ * Use dashboard_info.js to find out what you can define.
+ *
+ * 2. Inject javascript code into the default netdata dashboard.
+ *
+ */
+
+// ----------------------------------------------------------------------------
+// MENU
+//
+// - title the menu title as to be rendered at the charts menu
+// - icon html fragment of the icon to display
+// - info html fragment for the description above all the menu charts
+
+customDashboard.menu = {
+
+};
+
+
+// ----------------------------------------------------------------------------
+// SUBMENU
+//
+// - title the submenu title as to be rendered at the charts menu
+// - info html fragment for the description above all the submenu charts
+
+customDashboard.submenu = {
+
+};
+
+
+// ----------------------------------------------------------------------------
+// CONTEXT (the template each chart is based on)
+//
+// - info html fragment for the description above the chart
+// - height a ratio to the default as a decimal number: 1.0 = 100%
+// - colors a single color or an array of colors to use for the dimensions
+// - valuerange the y-range of the chart as an array [min, max]
+// - heads an array of gauge charts to render above the submenu section
+// - mainheads an array of gauge charts to render at the menu section
+
+customDashboard.context = {
+
+};
diff --git a/web/index.html b/web/index.html
index d8e128234..250dbfed3 100644
--- a/web/index.html
+++ b/web/index.html
@@ -35,7 +35,7 @@
<meta property="og:site_name" content="netdata"/>
<meta property="og:title" content="Get control of your Linux Servers. Simple. Effective. Awesome." />
<meta property="og:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." />
- <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/20910305/65d10354-bb69-11e6-8128-c44b547517b4.png" />
+ <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/22945737/e98cd0c6-f2fd-11e6-96f1-5501934b0955.png" />
<meta property="og:image:type" content="image/png" />
<meta property="fb:app_id" content="1200089276712916" />
@@ -508,16 +508,36 @@
// --------------------------------------------------------------------
// check options that should be processed before loading netdata.js
+ var localStorageTested = -1;
+ function localStorageTest() {
+ if(localStorageTested !== -1)
+ return localStorageTested;
+
+ if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ var test = 'test';
+ try {
+ localStorage.setItem(test, test);
+ localStorage.removeItem(test);
+ localStorageTested = true;
+ }
+ catch (e) {
+ localStorageTested = false;
+ }
+ }
+ else
+ localStorageTested = false;
+
+ return localStorageTested;
+ }
+
function loadLocalStorage(name) {
var ret = null;
try {
- if(typeof Storage !== "undefined" && typeof localStorage === 'object')
+ if(localStorageTest() === true)
ret = localStorage.getItem(name);
}
- catch(error) {
- ;
- }
+ catch(error) {}
if(typeof ret === 'undefined' || ret === null)
return null;
@@ -530,14 +550,12 @@
function saveLocalStorage(name, value) {
// console.log('saving: ' + name.toString() + ' = ' + value.toString());
try {
- if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ if(localStorageTest() === true) {
localStorage.setItem(name, value.toString());
return true;
}
}
- catch(error) {
- ;
- }
+ catch(error) {}
return false;
}
@@ -579,7 +597,52 @@
var netdataRegistryCallback = function(machines_array) {
var el = '';
var a1 = '';
- var found = 0;
+ var found = 0, hosted = 0;
+ var len, i, url, hostname, icon;
+
+ if(options.hosts.length > 1) {
+ // there are mirrored hosts here
+
+ el += '<li><a href="#" onClick="return false;" style="color: #666;" target="_blank">databases available on this host</a></li>';
+ a1 += '<li><a href="#" onClick="return false;"><i class="fa fa-info-circle" aria-hidden="true" style="color: #666;"></i></a></li>';
+
+ var base = document.location.origin.toString() + document.location.pathname.toString();
+ if(base.endsWith("/host/" + options.hostname + "/"))
+ base = base.substring(0, base.length - ("/host/" + options.hostname + "/").toString().length);
+
+ if(base.endsWith("/"))
+ base = base.substring(0, base.length - 1);
+
+ var master = options.hosts[0].hostname;
+ var sorted = options.hosts.sort(function(a, b) {
+ if(a.hostname === master) return -1;
+ if(a.hostname === b.hostname) return 0;
+ else if(a.hostname > b.hostname) return 1;
+ return -1;
+ });
+
+ i = 0;
+ len = sorted.length;
+ while(len--) {
+ hostname = sorted[i].hostname;
+ if(hostname == master) {
+ url = base + "/";
+ icon = "home";
+ }
+ else {
+ url = base + "/host/" + hostname + "/";
+ icon = "window-restore";
+ }
+
+ el += '<li id="registry_server_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '" onClick="return gotoHostedModalHandler(\'' + url + '\');">' + hostname + '</a></li>';
+ a1 += '<li id="registry_action_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '" onClick="return gotoHostedModalHandler(\'' + url + '\');"><i class="fa fa-' + icon + '" aria-hidden="true" style="color: #999;"></i></a></li>';
+ hosted++;
+ i++;
+ }
+
+ el += '<li role="separator" class="divider"></li>';
+ a1 += '<li role="separator" class="divider"></li>';
+ }
if(machines_array === null) {
var ret = loadLocalStorage("registryCallback");
@@ -598,7 +661,7 @@
return 0;
});
- var len = machines.length;
+ len = machines.length;
while(len--) {
var u = machines[len];
found++;
@@ -663,10 +726,7 @@
this_is_demo = true;
}
}
- catch(error) {
- ;
- }
-
+ catch(error) {}
return this_is_demo;
}
@@ -685,15 +745,18 @@
}
function netdataReload(url) {
- var t = netdataURL(url);
- // console.log('netdataReload: ' + t);
- document.location = t;
+ document.location = netdataURL(url);
// since we play with hash
// this is needed to reload the page
location.reload();
}
+ function gotoHostedModalHandler(url) {
+ document.location = url + urlOptions.genHash();
+ return false;
+ }
+
var gotoServerValidateRemaining = 0;
var gotoServerMiddleClick = false;
var gotoServerStop = false;
@@ -830,6 +893,8 @@
var deleteRegistryUrl = null;
function deleteRegistryModalHandler(guid, name, url) {
+ void(guid);
+
deleteRegistryUrl = url;
document.getElementById('deleteRegistryServerName').innerHTML = name;
document.getElementById('deleteRegistryServerName2').innerHTML = name;
@@ -854,47 +919,28 @@
}
var options = {
- sparklines_registry: {},
menus: {},
submenu_names: {},
data: null,
hostname: 'netdata_server', // will be overwritten by the netdata server
- categories: new Array(),
+ version: 'unknown',
+ categories: [],
categories_idx: {},
- families: new Array(),
+ families: [],
families_idx: {},
+ hosts: [],
chartsPerRow: 0,
- chartsMinWidth: 1450,
- chartsHeight: 180,
- sparklinesHeight: 60,
+ // chartsMinWidth: 1450,
+ chartsHeight: 180
};
- // generate a sparkline
- // used in the documentation
- function sparkline(chart, dimension, units) {
- var key = chart + '.' + dimension;
-
- if(typeof units === 'undefined')
- units = '';
-
- if(typeof options.sparklines_registry[key] === 'undefined')
- options.sparklines_registry[key] = { count: 1 };
- else
- options.sparklines_registry[key].count++;
-
- key = key + '.' + options.sparklines_registry[key].count;
-
- var h = '<div data-netdata="' + chart + '" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="' + dimension + '" data-show-value-of-' + dimension + '-at="' + key + '"></div> (<span id="' + key + '" style="display: inline-block; min-width: 50px; text-align: right;">X</span>' + units + ')';
-
- return h;
- }
-
function chartsPerRow(total) {
if(options.chartsPerRow === 0) {
- width = Math.floor(total / options.chartsMinWidth);
- if(width === 0) width = 1;
- return width;
+ return 1;
+ //var width = Math.floor(total / options.chartsMinWidth);
+ //if(width === 0) width = 1;
+ //return width;
}
else return options.chartsPerRow;
}
@@ -908,9 +954,11 @@
function sortObjectByPriority(object) {
var idx = {};
- var sorted = new Array();
+ var sorted = [];
for(var i in object) {
+ if(!object.hasOwnProperty(i)) continue;
+
if(typeof idx[i] === 'undefined') {
idx[i] = object[i];
sorted.push(i);
@@ -944,11 +992,52 @@
// ----------------------------------------------------------------------------
+ // user editable information
+ var customDashboard = {
+ menu: {},
+ submenu: {},
+ context: {}
+ };
+
+ // netdata standard information
var netdataDashboard = {
+ sparklines_registry: {},
+ os: 'unknown',
+
menu: {},
submenu: {},
context: {},
+ // generate a sparkline
+ // used in the documentation
+ sparkline: function (prefix, chart, dimension, units, suffix) {
+ if(options.data === null || typeof options.data.charts === 'undefined')
+ return '';
+
+ if(typeof options.data.charts[chart] === 'undefined')
+ return '';
+
+ if(typeof options.data.charts[chart].dimensions === 'undefined')
+ return '';
+
+ if(typeof options.data.charts[chart].dimensions[dimension] === 'undefined')
+ return '';
+
+ var key = chart + '.' + dimension;
+
+ if(typeof units === 'undefined')
+ units = '';
+
+ if(typeof this.sparklines_registry[key] === 'undefined')
+ this.sparklines_registry[key] = { count: 1 };
+ else
+ this.sparklines_registry[key].count++;
+
+ key = key + '.' + this.sparklines_registry[key].count;
+
+ return prefix + '<div data-netdata="' + chart + '" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="' + dimension + '" data-show-value-of-' + dimension + '-at="' + key + '"></div> (<span id="' + key + '" style="display: inline-block; min-width: 50px; text-align: right;">X</span>' + units + ')' + suffix;
+ },
+
gaugeChart: function(title, width, dimensions, colors) {
if(typeof colors === 'undefined')
colors = '';
@@ -957,53 +1046,69 @@
dimensions = '';
return '<div data-netdata="CHART_UNIQUE_ID"'
- + ' data-dimensions="' + dimensions + '"'
- + ' data-chart-library="gauge"'
- + ' data-gauge-adjust="width"'
- + ' data-title="' + title + '"'
- + ' data-width="' + width + '"'
- + ' data-before="0"'
- + ' data-after="-CHART_DURATION"'
- + ' data-points="CHART_DURATION"'
- + ' data-colors="' + colors + '"'
- + ' role="application"></div>';
+ + ' data-dimensions="' + dimensions + '"'
+ + ' data-chart-library="gauge"'
+ + ' data-gauge-adjust="width"'
+ + ' data-title="' + title + '"'
+ + ' data-width="' + width + '"'
+ + ' data-before="0"'
+ + ' data-after="-CHART_DURATION"'
+ + ' data-points="CHART_DURATION"'
+ + ' data-colors="' + colors + '"'
+ + ' role="application"></div>';
},
anyAttribute: function(obj, attr, key, def) {
- if(typeof obj[key] !== 'undefined') {
- if(typeof obj[key][attr] !== 'undefined')
- return obj[key][attr];
+ if(typeof(obj[key]) !== 'undefined') {
+ var x = obj[key][attr];
+
+ if(typeof(x) === 'undefined')
+ return def;
+
+ if(typeof(x) === 'function') {
+ return x(netdataDashboard.os);
+ }
+
+ return x;
}
+
return def;
},
menuTitle: function(chart) {
if(typeof chart.menu_pattern !== 'undefined') {
- return (netdataDashboard.anyAttribute(netdataDashboard.menu, 'title', chart.menu_pattern, chart.menu_pattern).toString()
+ return (this.anyAttribute(this.menu, 'title', chart.menu_pattern, chart.menu_pattern).toString()
+ '&nbsp;' + chart.type.slice(-(chart.type.length - chart.menu_pattern.length - 1)).toString()).replace(/_/g, ' ');
}
- return (netdataDashboard.anyAttribute(netdataDashboard.menu, 'title', chart.menu, chart.menu)).toString().replace(/_/g, ' ');
+ return (this.anyAttribute(this.menu, 'title', chart.menu, chart.menu)).toString().replace(/_/g, ' ');
},
menuIcon: function(chart) {
if(typeof chart.menu_pattern !== 'undefined')
- return netdataDashboard.anyAttribute(netdataDashboard.menu, 'icon', chart.menu_pattern, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>').toString();
+ return this.anyAttribute(this.menu, 'icon', chart.menu_pattern, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>').toString();
- return netdataDashboard.anyAttribute(netdataDashboard.menu, 'icon', chart.menu, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>');
+ return this.anyAttribute(this.menu, 'icon', chart.menu, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>');
},
- menuInfo: function(menu) {
- return netdataDashboard.anyAttribute(netdataDashboard.menu, 'info', menu, null);
+ menuInfo: function(chart) {
+ if(typeof chart.menu_pattern !== 'undefined')
+ return this.anyAttribute(this.menu, 'info', chart.menu_pattern, null);
+
+ return this.anyAttribute(this.menu, 'info', chart.menu, null);
},
- menuHeight: function(menu, relative) {
- return netdataDashboard.anyAttribute(netdataDashboard.menu, 'height', menu, 1.0) * relative;
+ menuHeight: function(chart) {
+ if(typeof chart.menu_pattern !== 'undefined')
+ return this.anyAttribute(this.menu, 'height', chart.menu_pattern, 1.0);
+
+ return this.anyAttribute(this.menu, 'height', chart.menu, 1.0);
},
submenuTitle: function(menu, submenu) {
var key = menu + '.' + submenu;
- var title = netdataDashboard.anyAttribute(netdataDashboard.submenu, 'title', key, submenu).toString().replace(/_/g, ' ');;
+ // console.log(key);
+ var title = this.anyAttribute(this.submenu, 'title', key, submenu).toString().replace(/_/g, ' ');
if(title.length > 28) {
var a = title.substring(0, 13);
var b = title.substring(title.length - 12, title.length);
@@ -1014,31 +1119,33 @@
submenuInfo: function(menu, submenu) {
var key = menu + '.' + submenu;
- return netdataDashboard.anyAttribute(netdataDashboard.submenu, 'info', key, null);
+ return this.anyAttribute(this.submenu, 'info', key, null);
},
submenuHeight: function(menu, submenu, relative) {
var key = menu + '.' + submenu;
- return netdataDashboard.anyAttribute(netdataDashboard.submenu, 'height', key, 1.0) * relative;
+ return this.anyAttribute(this.submenu, 'height', key, 1.0) * relative;
},
contextInfo: function(id) {
- if(typeof netdataDashboard.context[id] !== 'undefined' && typeof netdataDashboard.context[id].info !== 'undefined')
- return '<div class="chart-message netdata-chart-alignment" role="document">' + netdataDashboard.context[id].info + '</div>';
+ var x = this.anyAttribute(this.context, 'info', id, null);
+
+ if(x !== null)
+ return '<div class="chart-message netdata-chart-alignment" role="document">' + x + '</div>';
else
return '';
},
contextValueRange: function(id) {
- if(typeof netdataDashboard.context[id] !== 'undefined' && typeof netdataDashboard.context[id].valueRange !== 'undefined')
- return netdataDashboard.context[id].valueRange;
+ if(typeof this.context[id] !== 'undefined' && typeof this.context[id].valueRange !== 'undefined')
+ return this.context[id].valueRange;
else
return '[null, null]';
},
contextHeight: function(id, def) {
- if(typeof netdataDashboard.context[id] !== 'undefined' && typeof netdataDashboard.context[id].height !== 'undefined')
- return def * netdataDashboard.context[id].height;
+ if(typeof this.context[id] !== 'undefined' && typeof this.context[id].height !== 'undefined')
+ return def * this.context[id].height;
else
return def;
}
@@ -1048,8 +1155,10 @@
// enrich the data structure returned by netdata
// to reflect our menu system and content
+ // FIXME: this is a shame - we should fix charts naming (issue #807)
function enrichChartData(chart) {
- var tmp = chart.type.split('_')[0];
+ var parts = chart.type.split('_');
+ var tmp = parts[0];
switch(tmp) {
case 'ap':
@@ -1058,6 +1167,22 @@
chart.menu = tmp;
break;
+ case 'apache':
+ chart.menu = chart.type;
+ if(parts.length > 2 && parts[1] === 'cache')
+ chart.menu_pattern = tmp + '_' + parts[1];
+ else if(parts.length > 1)
+ chart.menu_pattern = tmp;
+ break;
+
+ case 'bind':
+ chart.menu = chart.type;
+ if(parts.length > 2 && parts[1] === 'rndc')
+ chart.menu_pattern = tmp + '_' + parts[1];
+ else if(parts.length > 1)
+ chart.menu_pattern = tmp;
+ break;
+
case 'cgroup':
chart.menu = chart.type;
if(chart.id.match(/.*[\._\/-:]qemu[\._\/-:]*/) || chart.id.match(/.*[\._\/-:]kvm[\._\/-:]*/))
@@ -1066,27 +1191,29 @@
chart.menu_pattern = 'cgroup';
break;
- case 'apache':
- case 'exim':
- case 'dovecot':
- case 'hddtemp':
- case 'ipfs':
- case 'memcached':
- case 'mysql':
- case 'named':
- case 'nginx':
- case 'nut':
- case 'phpfpm':
- case 'postfix':
- case 'postgres':
- case 'redis':
- case 'retroshare':
- case 'smawebbox':
- case 'snmp':
- case 'squid':
- case 'tomcat':
+ case 'isc':
chart.menu = chart.type;
- chart.menu_pattern = tmp;
+ if(parts.length > 2 && parts[1] === 'dhcpd')
+ chart.menu_pattern = tmp + '_' + parts[1];
+ else if(parts.length > 1)
+ chart.menu_pattern = tmp;
+ break;
+
+ case 'ovpn':
+ chart.menu = chart.type;
+ if(parts.length > 3 && parts[1] === 'status' && parts[2] === 'log')
+ chart.menu_pattern = tmp + '_' + parts[1];
+ else if(parts.length > 1)
+ chart.menu_pattern = tmp;
+ break;
+
+ case 'smartd':
+ case 'web':
+ chart.menu = chart.type;
+ if(parts.length > 2 && parts[1] === 'log')
+ chart.menu_pattern = tmp + '_' + parts[1];
+ else if(parts.length > 1)
+ chart.menu_pattern = tmp;
break;
case 'tc':
@@ -1094,7 +1221,7 @@
// find a name for this device from fireqos info
// we strip '_(in|out)' or '(in|out)_'
- if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family) {
+ if(chart.context === 'tc.qos' && (typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family)) {
var n = chart.name.split('.')[1];
if(n.endsWith('_in'))
options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
@@ -1104,6 +1231,8 @@
options.submenu_names[chart.family] = n.slice(3, n.length);
else if(n.startsWith('out_'))
options.submenu_names[chart.family] = n.slice(4, n.length);
+ else
+ options.submenu_names[chart.family] = n;
}
// increase the priority of IFB devices
@@ -1115,6 +1244,8 @@
default:
chart.menu = chart.type;
+ if(parts.length > 1)
+ chart.menu_pattern = tmp;
break;
}
@@ -1123,7 +1254,9 @@
// ----------------------------------------------------------------------------
- function headMain(charts, duration) {
+ function headMain(os, charts, duration) {
+ void(os);
+
var head = '';
if(typeof charts['system.swap'] !== 'undefined')
@@ -1244,7 +1377,7 @@
var hi = 0, hlen = hcharts.length;
while(hi < hlen) {
if(typeof hcharts[hi] === 'function')
- head += hcharts[hi](chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
+ head += hcharts[hi](netdataDashboard.os, chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
else
head += hcharts[hi].replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
hi++;
@@ -1261,7 +1394,7 @@
var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
var html = '';
var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">';
- var mainhead = headMain(data.charts, duration);
+ var mainhead = headMain(netdataDashboard.os, data.charts, duration);
// sort the menus
var main = sortObjectByPriority(menus);
@@ -1338,7 +1471,7 @@
sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/firehol/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more charts</a></li>';
sidebar += '<li class=""><a href="https://github.com/firehol/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more alarms</a></li>';
- sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every == 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + Math.round(data.history / (3600/data.update_every)).toLocaleString() + ' ' + ((data.history == (3600/data.update_every))?'hour':'hours').toString() + ' of real-time history.</small></li>';
+ sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every == 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + seconds4human(data.update_every * data.history) + ' of real-time history.<br/>&nbsp;<br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>';
sidebar += '</ul>';
div.innerHTML = html;
document.getElementById('sidebar').innerHTML = sidebar;
@@ -1348,53 +1481,71 @@
function renderChartsAndMenu(data) {
var menus = options.menus;
var charts = data.charts;
+ var m, menu_key;
for(var c in charts) {
- enrichChartData(charts[c]);
+ if(!charts.hasOwnProperty(c)) continue;
+
+ var chart = charts[c];
+ enrichChartData(chart);
+ m = chart.menu;
// create the menu
- if(typeof menus[charts[c].menu] === 'undefined') {
- menus[charts[c].menu] = {
- priority: charts[c].priority,
+ if(typeof menus[m] === 'undefined') {
+ menus[m] = {
+ menu_pattern: chart.menu_pattern,
+ priority: chart.priority,
submenus: {},
- title: netdataDashboard.menuTitle(charts[c]),
- icon: netdataDashboard.menuIcon(charts[c]),
- info: netdataDashboard.menuInfo(charts[c].menu),
- height: netdataDashboard.menuHeight(charts[c].menu, options.chartsHeight)
+ title: netdataDashboard.menuTitle(chart),
+ icon: netdataDashboard.menuIcon(chart),
+ info: netdataDashboard.menuInfo(chart),
+ height: netdataDashboard.menuHeight(chart) * options.chartsHeight
};
}
+ else {
+ if(typeof(menus[m].menu_pattern) === 'undefined')
+ menus[m].menu_pattern = chart.menu_pattern;
+
+ if(chart.priority < menus[m].priority)
+ menus[m].priority = chart.priority;
+ }
- if(charts[c].priority < menus[charts[c].menu].priority)
- menus[charts[c].menu].priority = charts[c].priority;
+ menu_key = (typeof(menus[m].menu_pattern) !== 'undefined')?menus[m].menu_pattern:m;
// create the submenu
- if(typeof menus[charts[c].menu].submenus[charts[c].submenu] === 'undefined') {
- menus[charts[c].menu].submenus[charts[c].submenu] = {
- priority: charts[c].priority,
- charts: new Array(),
+ if(typeof menus[m].submenus[chart.submenu] === 'undefined') {
+ menus[m].submenus[chart.submenu] = {
+ priority: chart.priority,
+ charts: [],
title: null,
- info: netdataDashboard.submenuInfo(charts[c].menu, charts[c].submenu),
- height: netdataDashboard.submenuHeight(charts[c].menu, charts[c].submenu, menus[charts[c].menu].height)
+ info: netdataDashboard.submenuInfo(menu_key, chart.submenu),
+ height: netdataDashboard.submenuHeight(menu_key, chart.submenu, menus[m].height)
};
}
-
- if(charts[c].priority < menus[charts[c].menu].submenus[charts[c].submenu].priority)
- menus[charts[c].menu].submenus[charts[c].submenu].priority = charts[c].priority;
+ else {
+ if (chart.priority < menus[m].submenus[chart.submenu].priority)
+ menus[m].submenus[chart.submenu].priority = chart.priority;
+ }
// index the chart in the menu/submenu
- menus[charts[c].menu].submenus[charts[c].submenu].charts.push(charts[c]);
+ menus[m].submenus[chart.submenu].charts.push(chart);
}
// propagate the descriptive subname given to QoS
// to all the other submenus with the same name
- for(var m in menus) {
+ for(m in menus) {
+ if(!menus.hasOwnProperty(m)) continue;
+
for(var s in menus[m].submenus) {
+ if(!menus[m].submenus.hasOwnProperty(s)) continue;
+
// set the family using a name
if(typeof options.submenu_names[s] !== 'undefined') {
menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')';
}
else {
- menus[m].submenus[s].title = netdataDashboard.submenuTitle(m, s);
+ menu_key = (typeof(menus[m].menu_pattern) !== 'undefined')?menus[m].menu_pattern:m;
+ menus[m].submenus[s].title = netdataDashboard.submenuTitle(menu_key, s);
}
}
}
@@ -1423,7 +1574,7 @@
var bootstrapTableLoaded = false;
function loadBootstrapTable(callback) {
if(bootstrapTableLoaded === false) {
- bootstrapTableLoaded === true;
+ bootstrapTableLoaded = true;
loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-1.11.0.min.js', function() {
loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-export-1.11.0.min.js', function() {
loadJs(NETDATA.serverDefault + 'lib/tableExport-1.6.0.min.js', callback);
@@ -1439,7 +1590,7 @@
var footer = '<hr/><a href="https://github.com/firehol/netdata/wiki/Generating-Badges" target="_blank">netdata badges</a> refresh automatically. Their color indicates the state of the alarm: <span style="color: #e05d44"><b>&nbsp;red&nbsp;</b></span> is critical, <span style="color:#fe7d37"><b>&nbsp;orange&nbsp;</b></span> is warning, <span style="color: #4c1"><b>&nbsp;bright green&nbsp;</b></span> is ok, <span style="color: #9f9f9f"><b>&nbsp;light grey&nbsp;</b></span> is undefined (i.e. no data or no status), <span style="color: #000"><b>&nbsp;black&nbsp;</b></span> is not initialized. You can copy and paste their URLs to embed them in any web page.<br/>netdata can send notifications for these alarms. Check <a href="https://github.com/firehol/netdata/blob/master/conf.d/health_alarm_notify.conf">this configuration file</a> for more information.';
NETDATA.alarms.get('all', function(data) {
- options.alarm_families = new Array();
+ options.alarm_families = [];
alarmsCallback(data);
@@ -1474,70 +1625,6 @@
return t.toLocaleDateString() + space + t.toLocaleTimeString();
}
- function seconds4human(seconds, options) {
- var default_options = {
- now: 'now',
- space: '&nbsp;',
- negative_suffix: 'ago',
- hour: 'hour',
- hours: 'hours',
- minute: 'minute',
- minutes: 'minutes',
- second: 'second',
- seconds: 'seconds',
- and: 'and'
- };
-
- if(typeof options !== 'object')
- options = default_options;
- else {
- var x;
- for(x in default_options) {
- if(typeof options[x] !== 'string')
- options[x] = default_options[x];
- }
- }
-
- if(typeof seconds === 'string')
- seconds = parseInt(seconds);
-
- if(seconds === 0)
- return options.now;
-
- var suffix = '';
- if(seconds < 0) {
- seconds = -seconds;
- if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
- }
-
- var hours = Math.floor(seconds / 3600);
- seconds -= (hours * 3600);
-
- var minutes = Math.floor(seconds / 60);
- seconds -= (minutes * 60);
-
- var txt = '';
-
- if(hours > 1) txt += hours.toString() + options.space + options.hours;
- else if(hours === 1) txt += hours.toString() + options.space + options.hour;
-
- if(hours > 0 && minutes > 0 && seconds == 0)
- txt += options.space + options.and + options.space;
- else if(hours > 0 && minutes > 0 && seconds > 0)
- txt += ',' + options.space;
-
- if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
- else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
-
- if((minutes > 0 || minutes > 0) && seconds > 0)
- txt += options.space + options.and + options.space;
-
- if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
- else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
-
- return txt + suffix;
- }
-
function alarm_lookup_explain(alarm, chart) {
var dimensions = ' of all values ';
@@ -1562,7 +1649,14 @@
function alarm_to_html(alarm, full) {
var chart = options.data.charts[alarm.chart];
- var has_alarm = ((typeof alarm.warn !== 'undefined' || typeof alarm.crit !== 'undefined')?true:false);
+ if(typeof(chart) === 'undefined') {
+ // this means the charts loaded are incomplete
+ // probably netdata was restarted and more charts
+ // are now available.
+ return '';
+ }
+
+ var has_alarm = (typeof alarm.warn !== 'undefined' || typeof alarm.crit !== 'undefined');
var role_href = ((has_alarm === true)?('<br/>&nbsp;<br/>role: <b>' + alarm.recipient + '</b><br/>&nbsp;<br/><b><i class="fa fa-line-chart" aria-hidden="true"></i></b><small>&nbsp;&nbsp;<a href="#" onClick="NETDATA.alarms.scrollToChart(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;">jump to chart</a></small>'):('&nbsp;'));
@@ -1572,10 +1666,13 @@
+ ((typeof alarm.crit !== 'undefined')?('<tr><td width="10%" style="text-align:right">critical&nbsp;when</td><td><span style="font-family: monospace; color: #e05d44; font-weight: bold;">' + alarm.crit + '</span></td></tr>'):'');
if(full === true) {
- html += ((typeof alarm.lookup_after !== 'undefined')?('<tr><td width="10%" style="text-align:right">db&nbsp;lookup</td><td>' + alarm_lookup_explain(alarm, chart) + '</td></tr>'):'')
+ var units = chart.units;
+ if(units === '%') units = '&#37;';
+
+ html += ((typeof alarm.lookup_after !== 'undefined')?('<tr><td width="10%" style="text-align:right">db&nbsp;lookup</td><td>' + alarm_lookup_explain(alarm, chart) + '</td></tr>'):'')
+ ((typeof alarm.calc !== 'undefined')?('<tr><td width="10%" style="text-align:right">calculation</td><td><span style="font-family: monospace;">' + alarm.calc + '</span></td></tr>'):'')
- + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + chart.units + '</code></td></tr>'):'')
- + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + chart.units + '</code></td></tr>'):'');
+ + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green&nbsp;threshold</td><td><code>' + chart.green + ' ' + units + '</code></td></tr>'):'')
+ + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red&nbsp;threshold</td><td><code>' + chart.red + ' ' + units + '</code></td></tr>'):'');
}
var delay = '';
@@ -1622,14 +1719,16 @@
// find the proper family of each alarm
var now = Date.now();
- var x;
+ var x, family, alarm;
var count_active = 0;
var count_all = 0;
var families = {};
- var families_sort = new Array();
+ var families_sort = [];
for(x in data.alarms) {
- var alarm = data.alarms[x];
- var family = alarm.family;
+ if(!data.alarms.hasOwnProperty(x)) continue;
+
+ alarm = data.alarms[x];
+ family = alarm.family;
// find the chart
var chart = options.data.charts[alarm.chart];
@@ -1648,7 +1747,7 @@
if(typeof families[family] === 'undefined') {
families[family] = {
name: family,
- arr: new Array(),
+ arr: [],
priority: chart.priority
};
@@ -1671,7 +1770,7 @@
var fc = 0;
var len = families_sorted.length;
while(len--) {
- var family = families_sorted[len].name;
+ family = families_sorted[len].name;
var active_family_added = false;
var expanded = 'true';
var collapsed = '';
@@ -1680,7 +1779,7 @@
if(fc !== 0) {
all += "</table></div></div></div>";
expanded = 'false';
- collapsed = 'class="collapsed"'
+ collapsed = 'class="collapsed"';
cin = '';
}
@@ -1693,7 +1792,7 @@
var arr = families[family].arr;
var c = arr.length;
while(c--) {
- var alarm = arr[c];
+ alarm = arr[c];
if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
if(!active_family_added) {
active_family_added = true;
@@ -1726,12 +1825,13 @@
if(families_sorted.length > 0) alarm_family_show(0);
// register bootstrap events
- $('#alarms_all_accordion').on('show.bs.collapse', function (d) {
+ var $accordion = $('#alarms_all_accordion');
+ $accordion.on('show.bs.collapse', function (d) {
var target = $(d.target);
var id = $(target).data('alarm-id');
alarm_family_show(id);
});
- $('#alarms_all_accordion').on('hidden.bs.collapse', function (d) {
+ $accordion.on('hidden.bs.collapse', function (d) {
var target = $(d.target);
var id = $(target).data('alarm-id');
$('#alarm_all_' + id.toString()).html('');
@@ -1756,6 +1856,8 @@
fileName: 'netdata_alarm_log'
},
rowStyle: function(row, index) {
+ void(index);
+
switch(row.status) {
case 'CRITICAL' : return { classes: 'danger' }; break;
case 'WARNING' : return { classes: 'warning' }; break;
@@ -1776,9 +1878,8 @@
title: 'Event Date',
valign: 'middle',
titleTooltip: 'The date and time the even took place',
- formatter: function(value, row, index) { return timestamp4human(value, ' '); },
+ formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); },
align: 'center',
- valign: 'middle',
switchable: false,
sortable: true
},
@@ -1788,7 +1889,6 @@
valign: 'middle',
titleTooltip: 'The host that generated this event',
align: 'center',
- valign: 'middle',
visible: false,
sortable: true
},
@@ -1796,7 +1896,7 @@
field: 'unique_id',
title: 'Unique ID',
titleTooltip: 'The host unique ID for this event',
- formatter: function(value, row, index) { return alarmid4human(value); },
+ formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
align: 'center',
valign: 'middle',
visible: false,
@@ -1806,7 +1906,7 @@
field: 'alarm_id',
title: 'Alarm ID',
titleTooltip: 'The ID of the alarm that generated this event',
- formatter: function(value, row, index) { return alarmid4human(value); },
+ formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
align: 'center',
valign: 'middle',
visible: false,
@@ -1816,7 +1916,7 @@
field: 'alarm_event_id',
title: 'Alarm Event ID',
titleTooltip: 'The incremental ID of this event for the given alarm',
- formatter: function(value, row, index) { return alarmid4human(value); },
+ formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
align: 'center',
valign: 'middle',
visible: false,
@@ -1845,6 +1945,8 @@
title: 'Alarm',
titleTooltip: 'The alarm name that generated this event',
formatter: function(value, row, index) {
+ void(row);
+ void(index);
return value.toString().replace(/_/g, ' ');
},
align: 'center',
@@ -1853,10 +1955,29 @@
sortable: true
},
{
+ field: 'value_string',
+ title: 'Friendly Value',
+ titleTooltip: 'The value of the alarm, that triggered this event',
+ align: 'right',
+ valign: 'middle',
+ sortable: true
+ },
+ {
+ field: 'old_value_string',
+ title: 'Friendly Old Value',
+ titleTooltip: 'The value of the alarm, just before this event',
+ align: 'right',
+ valign: 'middle',
+ visible: false,
+ sortable: true
+ },
+ {
field: 'old_value',
title: 'Old Value',
titleTooltip: 'The value of the alarm, just before this event',
formatter: function(value, row, index) {
+ void(row);
+ void(index);
return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
},
align: 'center',
@@ -1869,10 +1990,13 @@
title: 'Value',
titleTooltip: 'The value of the alarm, that triggered this event',
formatter: function(value, row, index) {
+ void(row);
+ void(index);
return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
},
align: 'right',
valign: 'middle',
+ visible: false,
sortable: true
},
{
@@ -1881,6 +2005,7 @@
titleTooltip: 'The units of the value of the alarm',
align: 'left',
valign: 'middle',
+ visible: false,
sortable: true
},
{
@@ -1905,7 +2030,11 @@
field: 'duration',
title: 'Last Duration',
titleTooltip: 'The duration the alarm was at its previous state, just before this event',
- formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
+ formatter: function(value, row, index) {
+ void(row);
+ void(index);
+ return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
+ },
align: 'center',
valign: 'middle',
visible: false,
@@ -1915,7 +2044,11 @@
field: 'non_clear_duration',
title: 'Raised Duration',
titleTooltip: 'The duration the alarm was raised, just before this event',
- formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
+ formatter: function(value, row, index) {
+ void(row);
+ void(index);
+ return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
+ },
align: 'center',
valign: 'middle',
visible: false,
@@ -1935,6 +2068,9 @@
title: 'Processed Status',
titleTooltip: 'True when this event is processed',
formatter: function(value, row, index) {
+ void(row);
+ void(index);
+
if(value === true)
return 'DONE';
else
@@ -1950,6 +2086,9 @@
title: 'Updated Status',
titleTooltip: 'True when this event has been updated by another event',
formatter: function(value, row, index) {
+ void(row);
+ void(index);
+
if(value === true)
return 'UPDATED';
else
@@ -1964,7 +2103,7 @@
field: 'updated_by_id',
title: 'Updated By ID',
titleTooltip: 'The unique ID of the event that obsoleted this one',
- formatter: function(value, row, index) { return alarmid4human(value); },
+ formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
align: 'center',
valign: 'middle',
visible: false,
@@ -1974,7 +2113,7 @@
field: 'updates_id',
title: 'Updates ID',
titleTooltip: 'The unique ID of the event obsoleted because of this event',
- formatter: function(value, row, index) { return alarmid4human(value); },
+ formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
align: 'center',
valign: 'middle',
visible: false,
@@ -1993,7 +2132,7 @@
field: 'exec_run',
title: 'Script Run At',
titleTooltip: 'The date and time the script has been ran',
- formatter: function(value, row, index) { return timestamp4human(value, ' '); },
+ formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); },
align: 'center',
valign: 'middle',
visible: false,
@@ -2004,6 +2143,9 @@
title: 'Script Return Value',
titleTooltip: 'The return code of the script',
formatter: function(value, row, index) {
+ void(row);
+ void(index);
+
if(value === 0)
return 'OK (returned 0)';
else
@@ -2018,7 +2160,12 @@
field: 'delay',
title: 'Script Delay',
titleTooltip: 'The hysteresis of the notification',
- formatter: function(value, row, index) { return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); },
+ formatter: function(value, row, index) {
+ void(row);
+ void(index);
+
+ return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
+ },
align: 'center',
valign: 'middle',
visible: false,
@@ -2028,7 +2175,7 @@
field: 'delay_up_to_timestamp',
title: 'Script Delay Run At',
titleTooltip: 'The date and time the script should be run, after hysteresis',
- formatter: function(value, row, index) { return timestamp4human(value, ' '); },
+ formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); },
align: 'center',
valign: 'middle',
visible: false,
@@ -2059,9 +2206,75 @@
});
}
+ function seconds4human(seconds, options) {
+ var default_options = {
+ now: 'now',
+ space: '&nbsp;',
+ negative_suffix: 'ago',
+ hour: 'hour',
+ hours: 'hours',
+ minute: 'minute',
+ minutes: 'minutes',
+ second: 'second',
+ seconds: 'seconds',
+ and: 'and'
+ };
+
+ if(typeof options !== 'object')
+ options = default_options;
+ else {
+ var x;
+ for(x in default_options) {
+ if(typeof options[x] !== 'string')
+ options[x] = default_options[x];
+ }
+ }
+
+ if(typeof seconds === 'string')
+ seconds = parseInt(seconds);
+
+ if(seconds === 0)
+ return options.now;
+
+ var suffix = '';
+ if(seconds < 0) {
+ seconds = -seconds;
+ if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
+ }
+
+ var hours = Math.floor(seconds / 3600);
+ seconds -= (hours * 3600);
+
+ var minutes = Math.floor(seconds / 60);
+ seconds -= (minutes * 60);
+
+ var txt = '';
+
+ if(hours > 1) txt += hours.toString() + options.space + options.hours;
+ else if(hours === 1) txt += hours.toString() + options.space + options.hour;
+
+ if(hours > 0 && minutes > 0 && seconds == 0)
+ txt += options.space + options.and + options.space;
+ else if(hours > 0 && minutes > 0 && seconds > 0)
+ txt += ',' + options.space;
+
+ if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
+ else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
+
+ if((minutes > 0 || minutes > 0) && seconds > 0)
+ txt += options.space + options.and + options.space;
+
+ if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
+ else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
+
+ return txt + suffix;
+ }
+
function alarmsCallback(data) {
var count = 0;
for(x in data.alarms) {
+ if(!data.alarms.hasOwnProperty(x)) continue;
+
var alarm = data.alarms[x];
if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
count++;
@@ -2073,6 +2286,43 @@
document.getElementById('alarms_count_badge').innerHTML = '';
}
+ function initializeDynamicDashboardWithData(data) {
+ if(data !== null) {
+ options.hostname = data.hostname;
+ options.data = data;
+ options.version = data.version;
+ netdataDashboard.os = data.os;
+
+ if(typeof data.hosts != 'undefined')
+ options.hosts = data.hosts;
+
+ // update the dashboard hostname
+ document.getElementById('hostname').innerHTML = options.hostname;
+ document.getElementById('hostname').href = NETDATA.serverDefault;
+ document.getElementById('netdataVersion').innerHTML = options.version;
+
+ // update the dashboard title
+ document.title = options.hostname + ' netdata dashboard';
+
+ // close the splash screen
+ $("#loadOverlay").css("display","none");
+
+ // create a chart_by_name index
+ data.charts_by_name = {};
+ var charts = data.charts;
+ var x;
+ for(x in charts) {
+ if(!charts.hasOwnProperty(x)) continue;
+
+ var chart = charts[x];
+ data.charts_by_name[chart.name] = chart;
+ }
+
+ // render all charts
+ renderChartsAndMenu(data);
+ }
+ }
+
function initializeDynamicDashboard(netdata_url) {
if(typeof netdata_url === 'undefined' || netdata_url === null)
netdata_url = NETDATA.serverDefault;
@@ -2087,31 +2337,16 @@
// download all the charts the server knows
NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
- if(data !== null) {
- options.hostname = data.hostname;
- options.data = data;
-
- // update the dashboard hostname
- document.getElementById('hostname').innerHTML = options.hostname;
- document.getElementById('hostname').href = NETDATA.serverDefault;
-
- // update the dashboard title
- document.title = options.hostname + ' netdata dashboard';
-
- // close the splash screen
- $("#loadOverlay").css("display","none");
-
- // create a chart_by_name index
- data.charts_by_name = {};
- var charts = data.charts;
- var x;
- for(x in charts) {
- var chart = charts[x];
- data.charts_by_name[chart.name] = chart;
+ if(data != null) {
+ if(typeof data.custom_info !== 'undefined' && data.custom_info !== "") {
+ loadJs(data.custom_info, function () {
+ $.extend(true, netdataDashboard, customDashboard);
+ initializeDynamicDashboardWithData(data);
+ });
+ }
+ else {
+ initializeDynamicDashboardWithData(data);
}
-
- // render all charts
- renderChartsAndMenu(data);
}
});
});
@@ -2123,8 +2358,23 @@
document.getElementById('versionCheckLog').innerHTML = msg;
}
- function getNetdataVersion(callback) {
- versionLog('Downloading installed version info from netdata...');
+ function getNetdataCommitIdFromVersion() {
+ var s = options.version.split('-');
+
+ if(s.length !== 3) return null;
+ if(s[2][0] == 'g') {
+ var v = s[2].split('_')[0].substring(1, 8);
+ if(v.length === 7) {
+ versionLog('Installed git commit id of netdata is ' + v);
+ document.getElementById('netdataCommitId').innerHTML = v;
+ return v;
+ }
+ }
+ return null;
+ }
+
+ function getNetdataCommitId(force, callback) {
+ versionLog('Downloading installed git commit id from netdata...');
$.ajax({
url: 'version.txt',
@@ -2134,24 +2384,34 @@
})
.done(function(data) {
data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
- if(data.length !== 40) {
- versionLog('Received version string is invalid.');
- callback(null);
+
+ var c = getNetdataCommitIdFromVersion();
+ if(c !== null && data.length === 40 && data.substring(0, 7) !== c) {
+ versionLog('Installed files commit id and internal netdata git commit id do not match');
+ data = c;
}
- else {
- versionLog('Installed version of netdata is ' + data);
- document.getElementById('netdataVersion').innerHTML = data;
+
+ if(data.length >= 7) {
+ versionLog('Installed git commit id of netdata is ' + data);
+ document.getElementById('netdataCommitId').innerHTML = data.substring(0, 7);
callback(data);
}
})
.fail(function() {
- versionLog('Failed to download installed version info from netdata!');
- callback(null);
+ versionLog('Failed to download installed git commit id from netdata!');
+
+ if(force === true) {
+ var c = getNetdataCommitIdFromVersion();
+ if(c === null) versionLog('Cannot find the git commit id of netdata.');
+ callback(c);
+ }
+ else
+ callback(null);
});
}
function getGithubLatestCommit(callback) {
- versionLog('Downloading latest version info from github...');
+ versionLog('Downloading latest git commit id info from github...');
$.ajax({
url: 'https://api.github.com/repos/firehol/netdata/commits',
@@ -2159,17 +2419,17 @@
cache: false
})
.done(function(data) {
- versionLog('Latest version info from github is ' + data[0].sha);
+ versionLog('Latest git commit id from github is ' + data[0].sha);
callback(data[0].sha);
})
.fail(function() {
- versionLog('Failed to download installed version info from github!');
+ versionLog('Failed to download installed git commit id from github!');
callback(null);
});
}
- function checkForUpdate(callback) {
- getNetdataVersion(function(sha1) {
+ function checkForUpdate(force, callback) {
+ getNetdataCommitId(force, function(sha1) {
if(sha1 === null) callback(null, null);
getGithubLatestCommit(function(sha2) {
@@ -2199,26 +2459,26 @@
}
}
- checkForUpdate(function(sha1, sha2) {
+ checkForUpdate(force, function(sha1, sha2) {
var save = false;
if(sha1 === null) {
save = false;
- versionLog('<p><big>Failed to get your netdata version!</big></p><p>You can always get the latest version of netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
+ versionLog('<p><big>Failed to get your netdata git commit id!</big></p><p>You can always get the latest netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
}
else if(sha2 === null) {
save = false;
- versionLog('<p><big>Failed to get the latest version from github.</big></p><p>You can always get the latest version of netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
+ versionLog('<p><big>Failed to get the latest git commit id from github.</big></p><p>You can always get the latest netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
}
else if(sha1 === sha2) {
save = true;
- versionLog('<p><big>You already have the latest version of netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/firehol/netdata" target="_blank">give netdata a <b>Star</b> at its github page</a>.</p>');
+ versionLog('<p><big>You already have the latest netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/firehol/netdata" target="_blank">give netdata a <b>Star</b> at its github page</a>.</p>');
}
else {
save = true;
var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
- versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest version: ' + sha2.toString() + '</p><p><a href="' + compare + '" target="_blank">Click here for the changes log</a> since your installed version, and<br/><a href="https://github.com/firehol/netdata/wiki/Updating-Netdata" target="_blank">click here for directions on updating</a> your netdata installation.</p><p>We suggest to review the changes log for new features you may be interested, or important bug fixes you may need.<br/>Keeping your netdata updated, is generally a good idea.</p>');
+ versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest commit: <b><code>' + sha2.substring(0, 7).toString() + '</code></b></p><p><a href="' + compare + '" target="_blank">Click here for the changes log</a> since your installed version, and<br/><a href="https://github.com/firehol/netdata/wiki/Updating-Netdata" target="_blank">click here for directions on updating</a> your netdata installation.</p><p>We suggest to review the changes log for new features you may be interested, or important bug fixes you may need.<br/>Keeping your netdata updated, is generally a good idea.</p>');
document.getElementById('update_badge').innerHTML = '!';
}
@@ -2345,7 +2605,7 @@
{
//console.log('They were open tags');
//console.log(openTags);
- for (j = 0; j < openTags.length; j++) {
+ for (var j = 0; j < openTags.length; j++) {
//console.log('Cierro tag ' + openTags[j]);
bag += '</' + openTags[j] + '>'; // Close all tags that were opened
@@ -2391,8 +2651,9 @@
//console.log('hash = ' + urlOptions.hash);
}
+ var $sidebar = $('#sidebar');
/* activate bootstrap sidebar (affix) */
- $('#sidebar').affix({
+ $sidebar.affix({
offset: {
top: (isdemo())?150:0,
bottom: 0
@@ -2402,7 +2663,7 @@
/* fix scrolling of very long affix lists
http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
*/
- $('#sidebar').on('affixed.bs.affix', function() {
+ $sidebar.on('affixed.bs.affix', function() {
$(this).removeAttr('style');
});
@@ -2413,7 +2674,7 @@
});
// change the URL based on the current position of the screen
- $('#sidebar').on('activate.bs.scrollspy', function (e) {
+ $sidebar.on('activate.bs.scrollspy', function (e) {
// console.log(e);
var el = $(e.target);
//if(el.find('ul').size() == 0) {
@@ -2440,13 +2701,13 @@
// console.log('switching ' + option.toString());
self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
}
- }
+ };
var theme_sync_option = function(option) {
var self = $('#' + option);
self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
- }
+ };
sync_option('eliminate_zero_dimensions');
sync_option('destroy_on_hide');
@@ -2504,19 +2765,21 @@
netdataReload();
});
- $('#updateModal').on('show.bs.modal', function() {
+ var $updateModal = $('#updateModal');
+ $updateModal.on('show.bs.modal', function() {
versionLog('checking, please wait...');
});
- $('#updateModal').on('shown.bs.modal', function() {
+ $updateModal.on('shown.bs.modal', function() {
notifyForUpdate(true);
});
- $('#alarmsModal').on('shown.bs.modal', function() {
+ var $alarmsModal = $('#alarmsModal');
+ $alarmsModal.on('shown.bs.modal', function() {
NETDATA.pause(alarmsUpdateModal);
});
- $('#alarmsModal').on('hidden.bs.modal', function() {
+ $alarmsModal.on('hidden.bs.modal', function() {
NETDATA.unpause();
document.getElementById('alarms_active').innerHTML =
document.getElementById('alarms_all').innerHTML =
@@ -2632,7 +2895,7 @@
});
NETDATA.requiredJs.push({
- url: NETDATA.serverDefault + 'dashboard_info.js?v20170115-1',
+ url: NETDATA.serverDefault + 'dashboard_info.js?v20170308-1',
async: false,
isAlreadyLoaded: function() { return false; }
});
@@ -3144,7 +3407,8 @@
<h4 class="modal-title" id="updateModalLabel">Update Check</h4>
</div>
<div class="modal-body">
- Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b>
+ Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b><br/>
+ Your netdata commit: <b><code><span id="netdataCommitId">Unknown</span></code></b>
<br/>
<div style="padding: 10px;"></div>
<div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
@@ -3259,4 +3523,4 @@
</div>
</body>
</html>
-<script type="text/javascript" src="dashboard.js?v20170118-11"></script>
+<script type="text/javascript" src="dashboard.js?v20170211-2"></script>
diff --git a/web/lib/gauge-1.3.2.min.js b/web/lib/gauge-1.3.2.min.js
new file mode 100644
index 000000000..be327fe58
--- /dev/null
+++ b/web/lib/gauge-1.3.2.min.js
@@ -0,0 +1 @@
+(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p=[].slice,q={}.hasOwnProperty,r=function(a,b){function d(){this.constructor=a}for(var c in b)q.call(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};!function(){var a,b,c,d,e,f,g;for(g=["ms","moz","webkit","o"],c=0,e=g.length;c<e&&(f=g[c],!window.requestAnimationFrame);c++)window.requestAnimationFrame=window[f+"RequestAnimationFrame"],window.cancelAnimationFrame=window[f+"CancelAnimationFrame"]||window[f+"CancelRequestAnimationFrame"];return a=null,d=0,b={},requestAnimationFrame?window.cancelAnimationFrame?void 0:(a=window.requestAnimationFrame,window.requestAnimationFrame=function(c,e){var f;return f=++d,a(function(){if(!b[f])return c()},e),f},window.cancelAnimationFrame=function(a){return b[a]=!0}):(window.requestAnimationFrame=function(a,b){var c,d,e,f;return c=(new Date).getTime(),f=Math.max(0,16-(c-e)),d=window.setTimeout(function(){return a(c+f)},f),e=c+f,d},window.cancelAnimationFrame=function(a){return clearTimeout(a)})}(),String.prototype.hashCode=function(){var a,b,c,d,e;if(b=0,0===this.length)return b;for(c=d=0,e=this.length;0<=e?d<e:d>e;c=0<=e?++d:--d)a=this.charCodeAt(c),b=(b<<5)-b+a,b&=b;return b},o=function(a){var b,c;for(b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60),a-=3600*b+60*c,a+="",c+="";c.length<2;)c="0"+c;for(;a.length<2;)a="0"+a;return b=b?b+":":"",b+c+":"+a},m=function(){var a,b,c;return b=1<=arguments.length?p.call(arguments,0):[],c=b[0],a=b[1],k(c.toFixed(a))},n=function(a,b){var c,d,e;d={};for(c in a)q.call(a,c)&&(e=a[c],d[c]=e);for(c in b)q.call(b,c)&&(e=b[c],d[c]=e);return d},k=function(a){var b,c,d,e;for(a+="",c=a.split("."),d=c[0],e="",c.length>1&&(e="."+c[1]),b=/(\d+)(\d{3})/;b.test(d);)d=d.replace(b,"$1,$2");return d+e},l=function(a){return"#"===a.charAt(0)?a.substring(1,7):a},j=function(){function a(a,b){null==a&&(a=!0),this.clear=null==b||b,a&&AnimationUpdater.add(this)}return a.prototype.animationSpeed=32,a.prototype.update=function(a){var b;return null==a&&(a=!1),!(!a&&this.displayedValue===this.value)&&(this.ctx&&this.clear&&this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),b=this.value-this.displayedValue,Math.abs(b/this.animationSpeed)<=.001?this.displayedValue=this.value:this.displayedValue=this.displayedValue+b/this.animationSpeed,this.render(),!0)},a}(),e=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return r(b,a),b.prototype.displayScale=1,b.prototype.setTextField=function(a,b){return this.textField=a instanceof i?a:new i(a,b)},b.prototype.setMinValue=function(a,b){var c,d,e,f,g;if(this.minValue=a,null==b&&(b=!0),b){for(this.displayedValue=this.minValue,f=this.gp||[],g=[],d=0,e=f.length;d<e;d++)c=f[d],g.push(c.displayedValue=this.minValue);return g}},b.prototype.setOptions=function(a){return null==a&&(a=null),this.options=n(this.options,a),this.textField&&(this.textField.el.style.fontSize=a.fontSize+"px"),this.options.angle>.5&&(this.options.angle=.5),this.configDisplayScale(),this},b.prototype.configDisplayScale=function(){var a,b,c,d,e;return d=this.displayScale,this.options.highDpiSupport===!1?delete this.displayScale:(b=window.devicePixelRatio||1,a=this.ctx.webkitBackingStorePixelRatio||this.ctx.mozBackingStorePixelRatio||this.ctx.msBackingStorePixelRatio||this.ctx.oBackingStorePixelRatio||this.ctx.backingStorePixelRatio||1,this.displayScale=b/a),this.displayScale!==d&&(e=this.canvas.G__width||this.canvas.width,c=this.canvas.G__height||this.canvas.height,this.canvas.width=e*this.displayScale,this.canvas.height=c*this.displayScale,this.canvas.style.width=e+"px",this.canvas.style.height=c+"px",this.canvas.G__width=e,this.canvas.G__height=c),this},b}(j),i=function(){function a(a,b){this.el=a,this.fractionDigits=b}return a.prototype.render=function(a){return this.el.innerHTML=m(a.displayedValue,this.fractionDigits)},a}(),a=function(a){function b(a,b){this.elem=a,this.text=null!=b&&b,this.value=1*this.elem.innerHTML,this.text&&(this.value=0)}return r(b,a),b.prototype.displayedValue=0,b.prototype.value=0,b.prototype.setVal=function(a){return this.value=1*a},b.prototype.render=function(){var a;return a=this.text?o(this.displayedValue.toFixed(0)):k(m(this.displayedValue)),this.elem.innerHTML=a},b}(j),b={create:function(b){var c,d,e,f;for(f=[],d=0,e=b.length;d<e;d++)c=b[d],f.push(new a(c));return f}},h=function(a){function b(a){this.gauge=a,this.ctx=this.gauge.ctx,this.canvas=this.gauge.canvas,b.__super__.constructor.call(this,!1,!1),this.setOptions()}return r(b,a),b.prototype.displayedValue=0,b.prototype.value=0,b.prototype.options={strokeWidth:.035,length:.1,color:"#000000"},b.prototype.setOptions=function(a){return null==a&&(a=null),this.options=n(this.options,a),this.length=2*this.gauge.radius*this.gauge.options.radiusScale*this.options.length,this.strokeWidth=this.canvas.height*this.options.strokeWidth,this.maxValue=this.gauge.maxValue,this.minValue=this.gauge.minValue,this.animationSpeed=this.gauge.animationSpeed,this.options.angle=this.gauge.options.angle},b.prototype.render=function(){var a,b,c,d,e,f,g;return a=this.gauge.getAngle.call(this,this.displayedValue),f=Math.round(this.length*Math.cos(a)),g=Math.round(this.length*Math.sin(a)),d=Math.round(this.strokeWidth*Math.cos(a-Math.PI/2)),e=Math.round(this.strokeWidth*Math.sin(a-Math.PI/2)),b=Math.round(this.strokeWidth*Math.cos(a+Math.PI/2)),c=Math.round(this.strokeWidth*Math.sin(a+Math.PI/2)),this.ctx.fillStyle=this.options.color,this.ctx.beginPath(),this.ctx.arc(0,0,this.strokeWidth,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.beginPath(),this.ctx.moveTo(d,e),this.ctx.lineTo(f,g),this.ctx.lineTo(b,c),this.ctx.fill()},b}(j),c=function(){function a(a){this.elem=a}return a.prototype.updateValues=function(a){return this.value=a[0],this.maxValue=a[1],this.avgValue=a[2],this.render()},a.prototype.render=function(){var a,b;return this.textField&&this.textField.text(m(this.value)),0===this.maxValue&&(this.maxValue=2*this.avgValue),b=this.value/this.maxValue*100,a=this.avgValue/this.maxValue*100,$(".bar-value",this.elem).css({width:b+"%"}),$(".typical-value",this.elem).css({width:a+"%"})},a}(),g=function(a){function b(a){var c,d;this.canvas=a,b.__super__.constructor.call(this),this.percentColors=null,this.forceUpdate=!0,"undefined"!=typeof G_vmlCanvasManager&&(this.canvas=window.G_vmlCanvasManager.initElement(this.canvas)),this.ctx=this.canvas.getContext("2d"),c=this.canvas.clientHeight,d=this.canvas.clientWidth,this.canvas.height=c,this.canvas.width=d,this.gp=[new h(this)],this.setOptions(),this.render()}return r(b,a),b.prototype.elem=null,b.prototype.value=[20],b.prototype.maxValue=80,b.prototype.minValue=0,b.prototype.displayedAngle=0,b.prototype.displayedValue=0,b.prototype.lineWidth=40,b.prototype.paddingTop=.1,b.prototype.paddingBottom=.1,b.prototype.percentColors=null,b.prototype.options={colorStart:"#6fadcf",colorStop:void 0,gradientType:0,strokeColor:"#e0e0e0",pointer:{length:.8,strokeWidth:.035},angle:.15,lineWidth:.44,radiusScale:1,fontSize:40,limitMax:!1,limitMin:!1},b.prototype.setOptions=function(a){var c,d,e,f,g;for(null==a&&(a=null),b.__super__.setOptions.call(this,a),this.configPercentColors(),this.extraPadding=0,this.options.angle<0&&(f=Math.PI*(1+this.options.angle),this.extraPadding=Math.sin(f)),this.availableHeight=this.canvas.height*(1-this.paddingTop-this.paddingBottom),this.lineWidth=this.availableHeight*this.options.lineWidth,this.radius=(this.availableHeight-this.lineWidth/2)/(1+this.extraPadding),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),g=this.gp,d=0,e=g.length;d<e;d++)c=g[d],c.setOptions(this.options.pointer),c.render();return this},b.prototype.configPercentColors=function(){var a,b,c,d,e,f,g;if(this.percentColors=null,void 0!==this.options.percentColors){for(this.percentColors=new Array,f=[],c=d=0,e=this.options.percentColors.length-1;0<=e?d<=e:d>=e;c=0<=e?++d:--d)g=parseInt(l(this.options.percentColors[c][1]).substring(0,2),16),b=parseInt(l(this.options.percentColors[c][1]).substring(2,4),16),a=parseInt(l(this.options.percentColors[c][1]).substring(4,6),16),f.push(this.percentColors[c]={pct:this.options.percentColors[c][0],color:{r:g,g:b,b:a}});return f}},b.prototype.set=function(a){var b,c,d,e,f,g,i;if(a instanceof Array||(a=[a]),a.length>this.gp.length)for(c=d=0,g=a.length-this.gp.length;0<=g?d<g:d>g;c=0<=g?++d:--d)b=new h(this),b.setOptions(this.options.pointer),this.gp.push(b);else a.length<this.gp.length&&(this.gp=this.gp.slice(this.gp.length-a.length));for(c=0,e=0,f=a.length;e<f;e++)i=a[e],i>this.maxValue?this.options.limitMax?i=this.maxValue:this.maxValue=i+1:i<this.minValue&&(this.options.limitMin?i=this.minValue:this.minValue=i-1),this.gp[c].value=i,this.gp[c++].setOptions({minValue:this.minValue,maxValue:this.maxValue,angle:this.options.angle});return this.value=Math.max(Math.min(a[a.length-1],this.maxValue),this.minValue),AnimationUpdater.run(this.forceUpdate),this.forceUpdate=!1},b.prototype.getAngle=function(a){return(1+this.options.angle)*Math.PI+(a-this.minValue)/(this.maxValue-this.minValue)*(1-2*this.options.angle)*Math.PI},b.prototype.getColorForPercentage=function(a,b){var c,d,e,f,g,h,i;if(0===a)c=this.percentColors[0].color;else for(c=this.percentColors[this.percentColors.length-1].color,e=f=0,h=this.percentColors.length-1;0<=h?f<=h:f>=h;e=0<=h?++f:--f)if(a<=this.percentColors[e].pct){b===!0?(i=this.percentColors[e-1]||this.percentColors[0],d=this.percentColors[e],g=(a-i.pct)/(d.pct-i.pct),c={r:Math.floor(i.color.r*(1-g)+d.color.r*g),g:Math.floor(i.color.g*(1-g)+d.color.g*g),b:Math.floor(i.color.b*(1-g)+d.color.b*g)}):c=this.percentColors[e].color;break}return"rgb("+[c.r,c.g,c.b].join(",")+")"},b.prototype.getColorForValue=function(a,b){var c;return c=(a-this.minValue)/(this.maxValue-this.minValue),this.getColorForPercentage(c,b)},b.prototype.renderStaticLabels=function(a,b,c,d){var e,f,g,h,i,j,k,l,n,o;for(this.ctx.save(),this.ctx.translate(b,c),e=a.font||"10px Times",j=/\d+\.?\d?/,i=e.match(j)[0],l=e.slice(i.length),f=parseFloat(i)*this.displayScale,this.ctx.font=f+l,this.ctx.fillStyle=a.color||"#000000",this.ctx.textBaseline="bottom",this.ctx.textAlign="center",k=a.labels,g=0,h=k.length;g<h;g++)o=k[g],(!this.options.limitMin||o>=this.minValue)&&(!this.options.limitMax||o<=this.maxValue)&&(n=this.getAngle(o)-3*Math.PI/2,this.ctx.rotate(n),this.ctx.fillText(m(o,a.fractionDigits),0,-d-this.lineWidth/2),this.ctx.rotate(-n));return this.ctx.restore()},b.prototype.render=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o;if(n=this.canvas.width/2,d=this.canvas.height*this.paddingTop+this.availableHeight-(this.radius+this.lineWidth/2)*this.extraPadding,a=this.getAngle(this.displayedValue),this.textField&&this.textField.render(this),this.ctx.lineCap="butt",k=this.radius*this.options.radiusScale,this.options.staticLabels&&this.renderStaticLabels(this.options.staticLabels,n,d,k),this.options.staticZones){for(this.ctx.save(),this.ctx.translate(n,d),this.ctx.lineWidth=this.lineWidth,l=this.options.staticZones,e=0,g=l.length;e<g;e++)o=l[e],j=o.min,this.options.limitMin&&j<this.minValue&&(j=this.minValue),i=o.max,this.options.limitMax&&i>this.maxValue&&(i=this.maxValue),this.ctx.strokeStyle=o.strokeStyle,this.ctx.beginPath(),this.ctx.arc(0,0,k,this.getAngle(j),this.getAngle(i),!1),this.ctx.stroke();this.ctx.restore()}else void 0!==this.options.customFillStyle?b=this.options.customFillStyle(this):null!==this.percentColors?b=this.getColorForValue(this.displayedValue,!0):void 0!==this.options.colorStop?(b=0===this.options.gradientType?this.ctx.createRadialGradient(n,d,9,n,d,70):this.ctx.createLinearGradient(0,0,n,0),b.addColorStop(0,this.options.colorStart),b.addColorStop(1,this.options.colorStop)):b=this.options.colorStart,this.ctx.strokeStyle=b,this.ctx.beginPath(),this.ctx.arc(n,d,k,(1+this.options.angle)*Math.PI,a,!1),this.ctx.lineWidth=this.lineWidth,this.ctx.stroke(),this.ctx.strokeStyle=this.options.strokeColor,this.ctx.beginPath(),this.ctx.arc(n,d,k,a,(2-this.options.angle)*Math.PI,!1),this.ctx.stroke();for(this.ctx.translate(n,d),m=this.gp,f=0,h=m.length;f<h;f++)c=m[f],c.update(!0);return this.ctx.translate(-n,-d)},b}(e),d=function(a){function b(a){this.canvas=a,b.__super__.constructor.call(this),"undefined"!=typeof G_vmlCanvasManager&&(this.canvas=window.G_vmlCanvasManager.initElement(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.setOptions(),this.render()}return r(b,a),b.prototype.lineWidth=15,b.prototype.displayedValue=0,b.prototype.value=33,b.prototype.maxValue=80,b.prototype.minValue=0,b.prototype.options={lineWidth:.1,colorStart:"#6f6ea0",colorStop:"#c0c0db",strokeColor:"#eeeeee",shadowColor:"#d5d5d5",angle:.35,radiusScale:1},b.prototype.getAngle=function(a){return(1-this.options.angle)*Math.PI+(a-this.minValue)/(this.maxValue-this.minValue)*(2+this.options.angle-(1-this.options.angle))*Math.PI},b.prototype.setOptions=function(a){return null==a&&(a=null),b.__super__.setOptions.call(this,a),this.lineWidth=this.canvas.height*this.options.lineWidth,this.radius=this.options.radiusScale*(this.canvas.height/2-this.lineWidth/2),this},b.prototype.set=function(a){return this.value=a,this.value>this.maxValue&&(this.maxValue=1.1*this.value),AnimationUpdater.run()},b.prototype.render=function(){var a,b,c,d,e,f;return a=this.getAngle(this.displayedValue),f=this.canvas.width/2,c=this.canvas.height/2,this.textField&&this.textField.render(this),b=this.ctx.createRadialGradient(f,c,39,f,c,70),b.addColorStop(0,this.options.colorStart),b.addColorStop(1,this.options.colorStop),d=this.radius-this.lineWidth/2,e=this.radius+this.lineWidth/2,this.ctx.strokeStyle=this.options.strokeColor,this.ctx.beginPath(),this.ctx.arc(f,c,this.radius,(1-this.options.angle)*Math.PI,(2+this.options.angle)*Math.PI,!1),this.ctx.lineWidth=this.lineWidth,this.ctx.lineCap="round",this.ctx.stroke(),this.ctx.strokeStyle=b,this.ctx.beginPath(),this.ctx.arc(f,c,this.radius,(1-this.options.angle)*Math.PI,a,!1),this.ctx.stroke()},b}(e),f=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return r(b,a),b.prototype.strokeGradient=function(a,b,c,d){var e;return e=this.ctx.createRadialGradient(a,b,c,a,b,d),e.addColorStop(0,this.options.shadowColor),e.addColorStop(.12,this.options._orgStrokeColor),e.addColorStop(.88,this.options._orgStrokeColor),e.addColorStop(1,this.options.shadowColor),e},b.prototype.setOptions=function(a){var c,d,e,f;return null==a&&(a=null),b.__super__.setOptions.call(this,a),f=this.canvas.width/2,c=this.canvas.height/2,d=this.radius-this.lineWidth/2,e=this.radius+this.lineWidth/2,this.options._orgStrokeColor=this.options.strokeColor,this.options.strokeColor=this.strokeGradient(f,c,d,e),this},b}(d),window.AnimationUpdater={elements:[],animId:null,addAll:function(a){var b,c,d,e;for(e=[],c=0,d=a.length;c<d;c++)b=a[c],e.push(AnimationUpdater.elements.push(b));return e},add:function(a){return AnimationUpdater.elements.push(a)},run:function(a){var b,c,d,e,f;for(null==a&&(a=!1),b=!0,f=AnimationUpdater.elements,d=0,e=f.length;d<e;d++)c=f[d],c.update(a===!0)&&(b=!1);return b?cancelAnimationFrame(AnimationUpdater.animId):AnimationUpdater.animId=requestAnimationFrame(AnimationUpdater.run)}},"function"==typeof window.define&&null!=window.define.amd?define(function(){return{Gauge:g,Donut:f,BaseDonut:d,TextRenderer:i}}):"undefined"!=typeof module&&null!=module.exports?module.exports={Gauge:g,Donut:f,BaseDonut:d,TextRenderer:i}:(window.Gauge=g,window.Donut=f,window.BaseDonut=d,window.TextRenderer=i)}).call(this); \ No newline at end of file
diff --git a/web/lib/gauge-d5260c3.min.js b/web/lib/gauge-d5260c3.min.js
deleted file mode 100644
index 733d502a2..000000000
--- a/web/lib/gauge-d5260c3.min.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q={}.hasOwnProperty,r=function(a,b){function c(){this.constructor=a}for(var d in b)q.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};!function(){var a,b,c,d,e,f,g;for(g=["ms","moz","webkit","o"],c=0,e=g.length;e>c&&(f=g[c],!window.requestAnimationFrame);c++)window.requestAnimationFrame=window[f+"RequestAnimationFrame"],window.cancelAnimationFrame=window[f+"CancelAnimationFrame"]||window[f+"CancelRequestAnimationFrame"];return a=null,d=0,b={},requestAnimationFrame?window.cancelAnimationFrame?void 0:(a=window.requestAnimationFrame,window.requestAnimationFrame=function(c,e){var f;return f=++d,a(function(){return b[f]?void 0:c()},e),f},window.cancelAnimationFrame=function(a){return b[a]=!0}):(window.requestAnimationFrame=function(a,b){var c,d,e,f;return c=(new Date).getTime(),f=Math.max(0,16-(c-e)),d=window.setTimeout(function(){return a(c+f)},f),e=c+f,d},window.cancelAnimationFrame=function(a){return clearTimeout(a)})}(),String.prototype.hashCode=function(){var a,b,c,d,e;if(b=0,0===this.length)return b;for(c=d=0,e=this.length;e>=0?e>d:d>e;c=e>=0?++d:--d)a=this.charCodeAt(c),b=(b<<5)-b+a,b&=b;return b},o=function(a){var b,c;for(b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60),a-=3600*b+60*c,a+="",c+="";c.length<2;)c="0"+c;for(;a.length<2;)a="0"+a;return b=b?b+":":"",b+c+":"+a},m=function(a){return k(a.toFixed(0))},p=function(a,b){var c,d;for(c in b)q.call(b,c)&&(d=b[c],a[c]=d);return a},n=function(a,b){var c,d,e;d={};for(c in a)q.call(a,c)&&(e=a[c],d[c]=e);for(c in b)q.call(b,c)&&(e=b[c],d[c]=e);return d},k=function(a){var b,c,d,e;for(a+="",c=a.split("."),d=c[0],e="",c.length>1&&(e="."+c[1]),b=/(\d+)(\d{3})/;b.test(d);)d=d.replace(b,"$1,$2");return d+e},l=function(a){return"#"===a.charAt(0)?a.substring(1,7):a},j=function(){function a(a,b){null==a&&(a=!0),this.clear=null!=b?b:!0,a&&AnimationUpdater.add(this)}return a.prototype.animationSpeed=32,a.prototype.update=function(a){var b;return null==a&&(a=!1),a||this.displayedValue!==this.value?(this.ctx&&this.clear&&this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),b=this.value-this.displayedValue,Math.abs(b/this.animationSpeed)<=.001?this.displayedValue=this.value:this.displayedValue=this.displayedValue+b/this.animationSpeed,this.render(),!0):!1},a}(),e=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return r(b,a),b.prototype.displayScale=1,b.prototype.setTextField=function(a){return this.textField=a instanceof i?a:new i(a)},b.prototype.setMinValue=function(a,b){var c,d,e,f,g;if(this.minValue=a,null==b&&(b=!0),b){for(this.displayedValue=this.minValue,f=this.gp||[],g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.displayedValue=this.minValue);return g}},b.prototype.setOptions=function(a){return null==a&&(a=null),this.options=n(this.options,a),this.textField&&(this.textField.el.style.fontSize=a.fontSize+"px"),this.options.angle>.5&&(this.gauge.options.angle=.5),this.configDisplayScale(),this},b.prototype.configDisplayScale=function(){var a,b,c,d,e;return d=this.displayScale,this.options.highDpiSupport===!1?delete this.displayScale:(b=window.devicePixelRatio||1,a=this.ctx.webkitBackingStorePixelRatio||this.ctx.mozBackingStorePixelRatio||this.ctx.msBackingStorePixelRatio||this.ctx.oBackingStorePixelRatio||this.ctx.backingStorePixelRatio||1,this.displayScale=b/a),this.displayScale!==d&&(e=this.canvas.G__width||this.canvas.width,c=this.canvas.G__height||this.canvas.height,this.canvas.width=e*this.displayScale,this.canvas.height=c*this.displayScale,this.canvas.style.width=e+"px",this.canvas.style.height=c+"px",this.canvas.G__width=e,this.canvas.G__height=c),this},b}(j),i=function(){function a(a){this.el=a}return a.prototype.render=function(a){return this.el.innerHTML=m(a.displayedValue)},a}(),a=function(a){function b(a,b){this.elem=a,this.text=null!=b?b:!1,this.value=1*this.elem.innerHTML,this.text&&(this.value=0)}return r(b,a),b.prototype.displayedValue=0,b.prototype.value=0,b.prototype.setVal=function(a){return this.value=1*a},b.prototype.render=function(){var a;return a=this.text?o(this.displayedValue.toFixed(0)):k(m(this.displayedValue)),this.elem.innerHTML=a},b}(j),b={create:function(b){var c,d,e,f;for(f=[],d=0,e=b.length;e>d;d++)c=b[d],f.push(new a(c));return f}},h=function(a){function b(a){this.gauge=a,this.ctx=this.gauge.ctx,this.canvas=this.gauge.canvas,b.__super__.constructor.call(this,!1,!1),this.setOptions()}return r(b,a),b.prototype.displayedValue=0,b.prototype.value=0,b.prototype.options={strokeWidth:.035,length:.1,color:"#000000"},b.prototype.setOptions=function(a){return null==a&&(a=null),p(this.options,a),this.length=this.canvas.height*this.options.length,this.strokeWidth=this.canvas.height*this.options.strokeWidth,this.maxValue=this.gauge.maxValue,this.minValue=this.gauge.minValue,this.animationSpeed=this.gauge.animationSpeed,this.options.angle=this.gauge.options.angle},b.prototype.render=function(){var a,b,c,d,e,f,g,h,i;return a=this.gauge.getAngle.call(this,this.displayedValue),b=this.canvas.width/2,c=.9*this.canvas.height,h=Math.round(b+this.length*Math.cos(a)),i=Math.round(c+this.length*Math.sin(a)),f=Math.round(b+this.strokeWidth*Math.cos(a-Math.PI/2)),g=Math.round(c+this.strokeWidth*Math.sin(a-Math.PI/2)),d=Math.round(b+this.strokeWidth*Math.cos(a+Math.PI/2)),e=Math.round(c+this.strokeWidth*Math.sin(a+Math.PI/2)),this.ctx.fillStyle=this.options.color,this.ctx.beginPath(),this.ctx.arc(b,c,this.strokeWidth,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.beginPath(),this.ctx.moveTo(f,g),this.ctx.lineTo(h,i),this.ctx.lineTo(d,e),this.ctx.fill()},b}(j),c=function(){function a(a){this.elem=a}return a.prototype.updateValues=function(a){return this.value=a[0],this.maxValue=a[1],this.avgValue=a[2],this.render()},a.prototype.render=function(){var a,b;return this.textField&&this.textField.text(m(this.value)),0===this.maxValue&&(this.maxValue=2*this.avgValue),b=this.value/this.maxValue*100,a=this.avgValue/this.maxValue*100,$(".bar-value",this.elem).css({width:b+"%"}),$(".typical-value",this.elem).css({width:a+"%"})},a}(),g=function(a){function b(a){this.canvas=a,b.__super__.constructor.call(this),this.percentColors=null,"undefined"!=typeof G_vmlCanvasManager&&(this.canvas=window.G_vmlCanvasManager.initElement(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.gp=[new h(this)],this.setOptions(),this.render()}return r(b,a),b.prototype.elem=null,b.prototype.value=[20],b.prototype.maxValue=80,b.prototype.minValue=0,b.prototype.displayedAngle=0,b.prototype.displayedValue=0,b.prototype.lineWidth=40,b.prototype.paddingBottom=.1,b.prototype.percentColors=null,b.prototype.options={colorStart:"#6fadcf",colorStop:void 0,gradientType:0,strokeColor:"#e0e0e0",pointer:{length:.8,strokeWidth:.035},angle:.15,lineWidth:.44,fontSize:40,limitMax:!1},b.prototype.setOptions=function(a){var c,d,e,f;for(null==a&&(a=null),b.__super__.setOptions.call(this,a),this.configPercentColors(),this.lineWidth=this.canvas.height*(1-this.paddingBottom)*this.options.lineWidth,this.radius=this.canvas.height*(1-this.paddingBottom)-this.lineWidth,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.render(),f=this.gp,d=0,e=f.length;e>d;d++)c=f[d],c.setOptions(this.options.pointer),c.render();return this},b.prototype.configPercentColors=function(){var a,b,c,d,e,f,g;if(this.percentColors=null,void 0!==this.options.percentColors){for(this.percentColors=new Array,f=[],c=d=0,e=this.options.percentColors.length-1;e>=0?e>=d:d>=e;c=e>=0?++d:--d)g=parseInt(l(this.options.percentColors[c][1]).substring(0,2),16),b=parseInt(l(this.options.percentColors[c][1]).substring(2,4),16),a=parseInt(l(this.options.percentColors[c][1]).substring(4,6),16),f.push(this.percentColors[c]={pct:this.options.percentColors[c][0],color:{r:g,g:b,b:a}});return f}},b.prototype.set=function(a){var b,c,d,e,f,g,i;if(a instanceof Array||(a=[a]),a.length>this.gp.length)for(b=c=0,g=a.length-this.gp.length;g>=0?g>c:c>g;b=g>=0?++c:--c)this.gp.push(new h(this));for(b=0,f=!1,d=0,e=a.length;e>d;d++)i=a[d],i>this.maxValue&&(this.maxValue=1.1*this.value,f=!0),this.gp[b].value=i,this.gp[b++].setOptions({maxValue:this.maxValue,angle:this.options.angle});return this.value=a[a.length-1],f&&this.options.limitMax?void 0:AnimationUpdater.run()},b.prototype.getAngle=function(a){return(1+this.options.angle)*Math.PI+(a-this.minValue)/(this.maxValue-this.minValue)*(1-2*this.options.angle)*Math.PI},b.prototype.getColorForPercentage=function(a,b){var c,d,e,f,g,h,i;if(0===a)c=this.percentColors[0].color;else for(c=this.percentColors[this.percentColors.length-1].color,e=f=0,h=this.percentColors.length-1;h>=0?h>=f:f>=h;e=h>=0?++f:--f)if(a<=this.percentColors[e].pct){b===!0?(i=this.percentColors[e-1],d=this.percentColors[e],g=(a-i.pct)/(d.pct-i.pct),c={r:Math.floor(i.color.r*(1-g)+d.color.r*g),g:Math.floor(i.color.g*(1-g)+d.color.g*g),b:Math.floor(i.color.b*(1-g)+d.color.b*g)}):c=this.percentColors[e].color;break}return"rgb("+[c.r,c.g,c.b].join(",")+")"},b.prototype.getColorForValue=function(a,b){var c;return c=(a-this.minValue)/(this.maxValue-this.minValue),this.getColorForPercentage(c,b)},b.prototype.render=function(){var a,b,c,d,e,f,g,h,i;for(i=this.canvas.width/2,d=this.canvas.height*(1-this.paddingBottom),a=this.getAngle(this.displayedValue),this.textField&&this.textField.render(this),this.ctx.lineCap="butt",void 0!==this.options.customFillStyle?b=this.options.customFillStyle(this):null!==this.percentColors?b=this.getColorForValue(this.displayedValue,!0):void 0!==this.options.colorStop?(b=0===this.options.gradientType?this.ctx.createRadialGradient(i,d,9,i,d,70):this.ctx.createLinearGradient(0,0,i,0),b.addColorStop(0,this.options.colorStart),b.addColorStop(1,this.options.colorStop)):b=this.options.colorStart,this.ctx.strokeStyle=b,this.ctx.beginPath(),this.ctx.arc(i,d,this.radius,(1+this.options.angle)*Math.PI,a,!1),this.ctx.lineWidth=this.lineWidth,this.ctx.stroke(),this.ctx.strokeStyle=this.options.strokeColor,this.ctx.beginPath(),this.ctx.arc(i,d,this.radius,a,(2-this.options.angle)*Math.PI,!1),this.ctx.stroke(),g=this.gp,h=[],e=0,f=g.length;f>e;e++)c=g[e],h.push(c.update(!0));return h},b}(e),d=function(a){function b(a){this.canvas=a,b.__super__.constructor.call(this),"undefined"!=typeof G_vmlCanvasManager&&(this.canvas=window.G_vmlCanvasManager.initElement(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.setOptions(),this.render()}return r(b,a),b.prototype.lineWidth=15,b.prototype.displayedValue=0,b.prototype.value=33,b.prototype.maxValue=80,b.prototype.minValue=0,b.prototype.options={lineWidth:.1,colorStart:"#6f6ea0",colorStop:"#c0c0db",strokeColor:"#eeeeee",shadowColor:"#d5d5d5",angle:.35},b.prototype.getAngle=function(a){return(1-this.options.angle)*Math.PI+(a-this.minValue)/(this.maxValue-this.minValue)*(2+this.options.angle-(1-this.options.angle))*Math.PI},b.prototype.setOptions=function(a){return null==a&&(a=null),b.__super__.setOptions.call(this,a),this.lineWidth=this.canvas.height*this.options.lineWidth,this.radius=this.canvas.height/2-this.lineWidth/2,this},b.prototype.set=function(a){return this.value=a,this.value>this.maxValue&&(this.maxValue=1.1*this.value),AnimationUpdater.run()},b.prototype.render=function(){var a,b,c,d,e,f;return a=this.getAngle(this.displayedValue),f=this.canvas.width/2,c=this.canvas.height/2,this.textField&&this.textField.render(this),b=this.ctx.createRadialGradient(f,c,39,f,c,70),b.addColorStop(0,this.options.colorStart),b.addColorStop(1,this.options.colorStop),d=this.radius-this.lineWidth/2,e=this.radius+this.lineWidth/2,this.ctx.strokeStyle=this.options.strokeColor,this.ctx.beginPath(),this.ctx.arc(f,c,this.radius,(1-this.options.angle)*Math.PI,(2+this.options.angle)*Math.PI,!1),this.ctx.lineWidth=this.lineWidth,this.ctx.lineCap="round",this.ctx.stroke(),this.ctx.strokeStyle=b,this.ctx.beginPath(),this.ctx.arc(f,c,this.radius,(1-this.options.angle)*Math.PI,a,!1),this.ctx.stroke()},b}(e),f=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return r(b,a),b.prototype.strokeGradient=function(a,b,c,d){var e;return e=this.ctx.createRadialGradient(a,b,c,a,b,d),e.addColorStop(0,this.options.shadowColor),e.addColorStop(.12,this.options._orgStrokeColor),e.addColorStop(.88,this.options._orgStrokeColor),e.addColorStop(1,this.options.shadowColor),e},b.prototype.setOptions=function(a){var c,d,e,f;return null==a&&(a=null),b.__super__.setOptions.call(this,a),f=this.canvas.width/2,c=this.canvas.height/2,d=this.radius-this.lineWidth/2,e=this.radius+this.lineWidth/2,this.options._orgStrokeColor=this.options.strokeColor,this.options.strokeColor=this.strokeGradient(f,c,d,e),this},b}(d),window.AnimationUpdater={elements:[],animId:null,addAll:function(a){var b,c,d,e;for(e=[],c=0,d=a.length;d>c;c++)b=a[c],e.push(AnimationUpdater.elements.push(b));return e},add:function(a){return AnimationUpdater.elements.push(a)},run:function(){var a,b,c,d,e;for(a=!0,e=AnimationUpdater.elements,c=0,d=e.length;d>c;c++)b=e[c],b.update()&&(a=!1);return a?cancelAnimationFrame(AnimationUpdater.animId):AnimationUpdater.animId=requestAnimationFrame(AnimationUpdater.run)}},"function"==typeof window.define&&null!=window.define.amd?define(function(){return{Gauge:g,Donut:f,BaseDonut:d,TextRenderer:i}}):"undefined"!=typeof module&&null!=module.exports?module.exports={Gauge:g,Donut:f,BaseDonut:d,TextRenderer:i}:(window.Gauge=g,window.Donut=f,window.BaseDonut=d,window.TextRenderer=i)}).call(this); \ No newline at end of file
diff --git a/web/netdata-swagger.json b/web/netdata-swagger.json
index ad424abad..404944d12 100644
--- a/web/netdata-swagger.json
+++ b/web/netdata-swagger.json
@@ -3,7 +3,7 @@
"info": {
"title": "NetData API",
"description": "Real time data collection and graphs...",
- "version": "1.4.1_master"
+ "version": "1.5.1_rolling"
},
"host": "registry.my-netdata.io",
"schemes": [
@@ -396,6 +396,34 @@
}
}
}
+ },
+ "/allmetrics": {
+ "get": {
+ "summary": "Get a value of all the metrics maintained by netdata",
+ "description": "The charts endpoint returns the latest value of all charts and dimensions stored in the netdata server.",
+ "parameters": [
+ {
+ "name": "format",
+ "in": "query",
+ "description": "The format of the response to be returned",
+ "required": true,
+ "type": "string",
+ "enum": [
+ "shell",
+ "prometheus"
+ ],
+ "default": "shell"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "All the metrics returned in the format requested"
+ },
+ "400": {
+ "description": "The format requested is not supported"
+ }
+ }
+ }
}
},
"definitions": {
@@ -406,6 +434,23 @@
"type": "string",
"description": "The hostname of the netdata server."
},
+ "version": {
+ "type": "string",
+ "description": "netdata version of the server."
+ },
+ "os": {
+ "type": "string",
+ "description": "The netdata server host operating system.",
+ "enum": [
+ "macos",
+ "linux",
+ "freebsd"
+ ]
+ },
+ "history": {
+ "type": "number",
+ "description": "The duration, in seconds, of the round robin database maintained by netdata."
+ },
"update_every": {
"type": "number",
"description": "The default update frequency of the netdata server. All charts have an update frequency equal or bigger than this."
@@ -418,6 +463,22 @@
"$ref": "#/definitions/chart"
}
}
+ },
+ "charts_count": {
+ "type": "number",
+ "description": "The number of charts."
+ },
+ "dimensions_count": {
+ "type": "number",
+ "description": "The total number of dimensions."
+ },
+ "alarms_count": {
+ "type": "number",
+ "description": "The number of alarms."
+ },
+ "rrd_memory_bytes": {
+ "type": "number",
+ "description": "The size of the round robin database in bytes."
}
}
},
@@ -493,6 +554,14 @@
"$ref": "#/definitions/dimension"
}
}
+ },
+ "green": {
+ "type": "number",
+ "description": "Chart health green threshold"
+ },
+ "red": {
+ "type": "number",
+ "description": "Chart health red trheshold"
}
}
},
diff --git a/web/netdata-swagger.yaml b/web/netdata-swagger.yaml
index 00a038ce7..a74d66f5d 100644
--- a/web/netdata-swagger.yaml
+++ b/web/netdata-swagger.yaml
@@ -2,7 +2,7 @@ swagger: '2.0'
info:
title: NetData API
description: 'Real time data collection and graphs...'
- version: 1.4.1_master
+ version: 1.5.1_rolling
host: registry.my-netdata.io
schemes:
- http
@@ -283,6 +283,16 @@ definitions:
hostname:
type: string
description: 'The hostname of the netdata server.'
+ version:
+ type: string
+ description: 'netdata version of the server.'
+ os:
+ type: string
+ description: 'The netdata server host operating system.'
+ enum: [ 'macos', 'linux', 'freebsd' ]
+ history:
+ type: number
+ description: 'The duration, in seconds, of the round robin database maintained by netdata.'
update_every:
type: number
description: 'The default update frequency of the netdata server. All charts have an update frequency equal or bigger than this.'
@@ -292,6 +302,18 @@ definitions:
properties:
key:
$ref: '#/definitions/chart'
+ charts_count:
+ type: number
+ description: 'The number of charts.'
+ dimensions_count:
+ type: number
+ description: 'The total number of dimensions.'
+ alarms_count:
+ type: number
+ description: 'The number of alarms.'
+ rrd_memory_bytes:
+ type: number
+ description: 'The size of the round robin database in bytes.'
chart:
type: object
properties:
@@ -344,13 +366,19 @@ definitions:
properties:
key:
$ref: '#/definitions/dimension'
+ green:
+ type: number
+ description: 'Chart health green threshold'
+ red:
+ type: number
+ description: 'Chart health red trheshold'
dimension:
type: object
properties:
name:
type: string
description: 'The name of the dimension'
-
+
json_wrap:
type: object
properties:
diff --git a/web/registry.html b/web/registry.html
index 3af60a84b..f40f5f2af 100644
--- a/web/registry.html
+++ b/web/registry.html
@@ -12,7 +12,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta property="og:locale" content="en_US" />
- <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/19168687/f6a567be-8c19-11e6-8561-ce8d589e8346.gif"/>
+ <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/22945737/e98cd0c6-f2fd-11e6-96f1-5501934b0955.png"/>
<meta property="og:url" content="http://my-netdata.io/"/>
<meta property="og:type" content="website"/>
<meta property="og:site_name" content="netdata"/>
diff --git a/web/tv.html b/web/tv.html
index bd55e852f..04cc01ccb 100644
--- a/web/tv.html
+++ b/web/tv.html
@@ -12,7 +12,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta property="og:locale" content="en_US" />
- <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/19168687/f6a567be-8c19-11e6-8561-ce8d589e8346.gif"/>
+ <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/22945737/e98cd0c6-f2fd-11e6-96f1-5501934b0955.png"/>
<meta property="og:url" content="http://my-netdata.io/"/>
<meta property="og:type" content="website"/>
<meta property="og:site_name" content="netdata"/>
diff --git a/web/version.txt b/web/version.txt
index 58abac87d..a7ffee85b 100644
--- a/web/version.txt
+++ b/web/version.txt
@@ -1 +1 @@
-3bd41a09fccccbc6b095805556d3009b9ebf6213
+f5fa346a188e906a8f2cce3c2cf32a88ce81c666